chia-blockchain 2.5.1rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1042) hide show
  1. chia/__init__.py +10 -0
  2. chia/__main__.py +5 -0
  3. chia/_tests/README.md +53 -0
  4. chia/_tests/__init__.py +0 -0
  5. chia/_tests/blockchain/__init__.py +0 -0
  6. chia/_tests/blockchain/blockchain_test_utils.py +195 -0
  7. chia/_tests/blockchain/config.py +4 -0
  8. chia/_tests/blockchain/test_augmented_chain.py +145 -0
  9. chia/_tests/blockchain/test_blockchain.py +4202 -0
  10. chia/_tests/blockchain/test_blockchain_transactions.py +1031 -0
  11. chia/_tests/blockchain/test_build_chains.py +59 -0
  12. chia/_tests/blockchain/test_get_block_generator.py +72 -0
  13. chia/_tests/blockchain/test_lookup_fork_chain.py +194 -0
  14. chia/_tests/build-init-files.py +92 -0
  15. chia/_tests/build-job-matrix.py +204 -0
  16. chia/_tests/check_pytest_monitor_output.py +34 -0
  17. chia/_tests/check_sql_statements.py +72 -0
  18. chia/_tests/chia-start-sim +42 -0
  19. chia/_tests/clvm/__init__.py +0 -0
  20. chia/_tests/clvm/benchmark_costs.py +23 -0
  21. chia/_tests/clvm/coin_store.py +149 -0
  22. chia/_tests/clvm/test_chialisp_deserialization.py +101 -0
  23. chia/_tests/clvm/test_clvm_step.py +37 -0
  24. chia/_tests/clvm/test_condition_codes.py +13 -0
  25. chia/_tests/clvm/test_curry_and_treehash.py +55 -0
  26. chia/_tests/clvm/test_message_conditions.py +184 -0
  27. chia/_tests/clvm/test_program.py +150 -0
  28. chia/_tests/clvm/test_puzzle_compression.py +143 -0
  29. chia/_tests/clvm/test_puzzle_drivers.py +45 -0
  30. chia/_tests/clvm/test_puzzles.py +242 -0
  31. chia/_tests/clvm/test_singletons.py +540 -0
  32. chia/_tests/clvm/test_spend_sim.py +181 -0
  33. chia/_tests/cmds/__init__.py +0 -0
  34. chia/_tests/cmds/cmd_test_utils.py +469 -0
  35. chia/_tests/cmds/config.py +3 -0
  36. chia/_tests/cmds/conftest.py +23 -0
  37. chia/_tests/cmds/test_click_types.py +200 -0
  38. chia/_tests/cmds/test_cmd_framework.py +620 -0
  39. chia/_tests/cmds/test_cmds_util.py +97 -0
  40. chia/_tests/cmds/test_daemon.py +92 -0
  41. chia/_tests/cmds/test_dev_gh.py +131 -0
  42. chia/_tests/cmds/test_farm_cmd.py +66 -0
  43. chia/_tests/cmds/test_show.py +116 -0
  44. chia/_tests/cmds/test_sim.py +207 -0
  45. chia/_tests/cmds/test_timelock_args.py +75 -0
  46. chia/_tests/cmds/test_tx_config_args.py +154 -0
  47. chia/_tests/cmds/testing_classes.py +59 -0
  48. chia/_tests/cmds/wallet/__init__.py +0 -0
  49. chia/_tests/cmds/wallet/test_consts.py +47 -0
  50. chia/_tests/cmds/wallet/test_dao.py +565 -0
  51. chia/_tests/cmds/wallet/test_did.py +403 -0
  52. chia/_tests/cmds/wallet/test_nft.py +471 -0
  53. chia/_tests/cmds/wallet/test_notifications.py +124 -0
  54. chia/_tests/cmds/wallet/test_offer.toffer +1 -0
  55. chia/_tests/cmds/wallet/test_tx_decorators.py +27 -0
  56. chia/_tests/cmds/wallet/test_vcs.py +400 -0
  57. chia/_tests/cmds/wallet/test_wallet.py +1125 -0
  58. chia/_tests/cmds/wallet/test_wallet_check.py +109 -0
  59. chia/_tests/conftest.py +1419 -0
  60. chia/_tests/connection_utils.py +125 -0
  61. chia/_tests/core/__init__.py +0 -0
  62. chia/_tests/core/cmds/__init__.py +0 -0
  63. chia/_tests/core/cmds/test_beta.py +382 -0
  64. chia/_tests/core/cmds/test_keys.py +1734 -0
  65. chia/_tests/core/cmds/test_wallet.py +126 -0
  66. chia/_tests/core/config.py +3 -0
  67. chia/_tests/core/consensus/__init__.py +0 -0
  68. chia/_tests/core/consensus/test_block_creation.py +54 -0
  69. chia/_tests/core/consensus/test_pot_iterations.py +117 -0
  70. chia/_tests/core/custom_types/__init__.py +0 -0
  71. chia/_tests/core/custom_types/test_coin.py +107 -0
  72. chia/_tests/core/custom_types/test_proof_of_space.py +144 -0
  73. chia/_tests/core/custom_types/test_spend_bundle.py +70 -0
  74. chia/_tests/core/daemon/__init__.py +0 -0
  75. chia/_tests/core/daemon/config.py +4 -0
  76. chia/_tests/core/daemon/test_daemon.py +2128 -0
  77. chia/_tests/core/daemon/test_daemon_register.py +109 -0
  78. chia/_tests/core/daemon/test_keychain_proxy.py +101 -0
  79. chia/_tests/core/data_layer/__init__.py +0 -0
  80. chia/_tests/core/data_layer/config.py +5 -0
  81. chia/_tests/core/data_layer/conftest.py +106 -0
  82. chia/_tests/core/data_layer/test_data_cli.py +56 -0
  83. chia/_tests/core/data_layer/test_data_layer.py +83 -0
  84. chia/_tests/core/data_layer/test_data_layer_util.py +218 -0
  85. chia/_tests/core/data_layer/test_data_rpc.py +3847 -0
  86. chia/_tests/core/data_layer/test_data_store.py +2424 -0
  87. chia/_tests/core/data_layer/test_data_store_schema.py +381 -0
  88. chia/_tests/core/data_layer/test_plugin.py +91 -0
  89. chia/_tests/core/data_layer/util.py +233 -0
  90. chia/_tests/core/farmer/__init__.py +0 -0
  91. chia/_tests/core/farmer/config.py +3 -0
  92. chia/_tests/core/farmer/test_farmer_api.py +103 -0
  93. chia/_tests/core/full_node/__init__.py +0 -0
  94. chia/_tests/core/full_node/config.py +4 -0
  95. chia/_tests/core/full_node/dos/__init__.py +0 -0
  96. chia/_tests/core/full_node/dos/config.py +3 -0
  97. chia/_tests/core/full_node/full_sync/__init__.py +0 -0
  98. chia/_tests/core/full_node/full_sync/config.py +4 -0
  99. chia/_tests/core/full_node/full_sync/test_full_sync.py +443 -0
  100. chia/_tests/core/full_node/ram_db.py +27 -0
  101. chia/_tests/core/full_node/stores/__init__.py +0 -0
  102. chia/_tests/core/full_node/stores/config.py +4 -0
  103. chia/_tests/core/full_node/stores/test_block_store.py +590 -0
  104. chia/_tests/core/full_node/stores/test_coin_store.py +897 -0
  105. chia/_tests/core/full_node/stores/test_full_node_store.py +1219 -0
  106. chia/_tests/core/full_node/stores/test_hint_store.py +229 -0
  107. chia/_tests/core/full_node/stores/test_sync_store.py +135 -0
  108. chia/_tests/core/full_node/test_address_manager.py +588 -0
  109. chia/_tests/core/full_node/test_block_height_map.py +556 -0
  110. chia/_tests/core/full_node/test_conditions.py +556 -0
  111. chia/_tests/core/full_node/test_full_node.py +2700 -0
  112. chia/_tests/core/full_node/test_generator_tools.py +82 -0
  113. chia/_tests/core/full_node/test_hint_management.py +104 -0
  114. chia/_tests/core/full_node/test_node_load.py +34 -0
  115. chia/_tests/core/full_node/test_performance.py +179 -0
  116. chia/_tests/core/full_node/test_subscriptions.py +492 -0
  117. chia/_tests/core/full_node/test_transactions.py +203 -0
  118. chia/_tests/core/full_node/test_tx_processing_queue.py +155 -0
  119. chia/_tests/core/large_block.py +2388 -0
  120. chia/_tests/core/make_block_generator.py +70 -0
  121. chia/_tests/core/mempool/__init__.py +0 -0
  122. chia/_tests/core/mempool/config.py +4 -0
  123. chia/_tests/core/mempool/test_mempool.py +3255 -0
  124. chia/_tests/core/mempool/test_mempool_fee_estimator.py +104 -0
  125. chia/_tests/core/mempool/test_mempool_fee_protocol.py +55 -0
  126. chia/_tests/core/mempool/test_mempool_item_queries.py +190 -0
  127. chia/_tests/core/mempool/test_mempool_manager.py +2084 -0
  128. chia/_tests/core/mempool/test_mempool_performance.py +64 -0
  129. chia/_tests/core/mempool/test_singleton_fast_forward.py +567 -0
  130. chia/_tests/core/node_height.py +28 -0
  131. chia/_tests/core/server/__init__.py +0 -0
  132. chia/_tests/core/server/config.py +3 -0
  133. chia/_tests/core/server/flood.py +84 -0
  134. chia/_tests/core/server/serve.py +135 -0
  135. chia/_tests/core/server/test_api_protocol.py +21 -0
  136. chia/_tests/core/server/test_capabilities.py +66 -0
  137. chia/_tests/core/server/test_dos.py +319 -0
  138. chia/_tests/core/server/test_event_loop.py +109 -0
  139. chia/_tests/core/server/test_loop.py +294 -0
  140. chia/_tests/core/server/test_node_discovery.py +73 -0
  141. chia/_tests/core/server/test_rate_limits.py +482 -0
  142. chia/_tests/core/server/test_server.py +226 -0
  143. chia/_tests/core/server/test_upnp.py +8 -0
  144. chia/_tests/core/services/__init__.py +0 -0
  145. chia/_tests/core/services/config.py +3 -0
  146. chia/_tests/core/services/test_services.py +188 -0
  147. chia/_tests/core/ssl/__init__.py +0 -0
  148. chia/_tests/core/ssl/config.py +3 -0
  149. chia/_tests/core/ssl/test_ssl.py +202 -0
  150. chia/_tests/core/test_coins.py +33 -0
  151. chia/_tests/core/test_cost_calculation.py +313 -0
  152. chia/_tests/core/test_crawler.py +175 -0
  153. chia/_tests/core/test_crawler_rpc.py +53 -0
  154. chia/_tests/core/test_daemon_rpc.py +24 -0
  155. chia/_tests/core/test_db_conversion.py +130 -0
  156. chia/_tests/core/test_db_validation.py +162 -0
  157. chia/_tests/core/test_farmer_harvester_rpc.py +505 -0
  158. chia/_tests/core/test_filter.py +35 -0
  159. chia/_tests/core/test_full_node_rpc.py +768 -0
  160. chia/_tests/core/test_merkle_set.py +343 -0
  161. chia/_tests/core/test_program.py +47 -0
  162. chia/_tests/core/test_rpc_util.py +86 -0
  163. chia/_tests/core/test_seeder.py +420 -0
  164. chia/_tests/core/test_setproctitle.py +13 -0
  165. chia/_tests/core/util/__init__.py +0 -0
  166. chia/_tests/core/util/config.py +4 -0
  167. chia/_tests/core/util/test_block_cache.py +44 -0
  168. chia/_tests/core/util/test_cached_bls.py +57 -0
  169. chia/_tests/core/util/test_config.py +337 -0
  170. chia/_tests/core/util/test_file_keyring_synchronization.py +105 -0
  171. chia/_tests/core/util/test_files.py +391 -0
  172. chia/_tests/core/util/test_jsonify.py +146 -0
  173. chia/_tests/core/util/test_keychain.py +522 -0
  174. chia/_tests/core/util/test_keyring_wrapper.py +491 -0
  175. chia/_tests/core/util/test_lockfile.py +380 -0
  176. chia/_tests/core/util/test_log_exceptions.py +187 -0
  177. chia/_tests/core/util/test_lru_cache.py +56 -0
  178. chia/_tests/core/util/test_significant_bits.py +40 -0
  179. chia/_tests/core/util/test_streamable.py +883 -0
  180. chia/_tests/db/__init__.py +0 -0
  181. chia/_tests/db/test_db_wrapper.py +566 -0
  182. chia/_tests/environments/__init__.py +0 -0
  183. chia/_tests/environments/common.py +35 -0
  184. chia/_tests/environments/full_node.py +47 -0
  185. chia/_tests/environments/wallet.py +429 -0
  186. chia/_tests/ether.py +19 -0
  187. chia/_tests/farmer_harvester/__init__.py +0 -0
  188. chia/_tests/farmer_harvester/config.py +3 -0
  189. chia/_tests/farmer_harvester/test_farmer.py +1264 -0
  190. chia/_tests/farmer_harvester/test_farmer_harvester.py +292 -0
  191. chia/_tests/farmer_harvester/test_filter_prefix_bits.py +131 -0
  192. chia/_tests/farmer_harvester/test_third_party_harvesters.py +528 -0
  193. chia/_tests/farmer_harvester/test_third_party_harvesters_data.json +29 -0
  194. chia/_tests/fee_estimation/__init__.py +0 -0
  195. chia/_tests/fee_estimation/config.py +3 -0
  196. chia/_tests/fee_estimation/test_fee_estimation_integration.py +262 -0
  197. chia/_tests/fee_estimation/test_fee_estimation_rpc.py +287 -0
  198. chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +144 -0
  199. chia/_tests/fee_estimation/test_mempoolitem_height_added.py +146 -0
  200. chia/_tests/generator/__init__.py +0 -0
  201. chia/_tests/generator/puzzles/__init__.py +0 -0
  202. chia/_tests/generator/puzzles/test_generator_deserialize.clsp +3 -0
  203. chia/_tests/generator/puzzles/test_generator_deserialize.clsp.hex +1 -0
  204. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp +19 -0
  205. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp.hex +1 -0
  206. chia/_tests/generator/test_compression.py +201 -0
  207. chia/_tests/generator/test_generator_types.py +44 -0
  208. chia/_tests/generator/test_rom.py +180 -0
  209. chia/_tests/plot_sync/__init__.py +0 -0
  210. chia/_tests/plot_sync/config.py +3 -0
  211. chia/_tests/plot_sync/test_delta.py +101 -0
  212. chia/_tests/plot_sync/test_plot_sync.py +618 -0
  213. chia/_tests/plot_sync/test_receiver.py +451 -0
  214. chia/_tests/plot_sync/test_sender.py +116 -0
  215. chia/_tests/plot_sync/test_sync_simulated.py +451 -0
  216. chia/_tests/plot_sync/util.py +68 -0
  217. chia/_tests/plotting/__init__.py +0 -0
  218. chia/_tests/plotting/config.py +3 -0
  219. chia/_tests/plotting/test_plot_manager.py +781 -0
  220. chia/_tests/plotting/util.py +12 -0
  221. chia/_tests/pools/__init__.py +0 -0
  222. chia/_tests/pools/config.py +5 -0
  223. chia/_tests/pools/test_pool_cli_parsing.py +128 -0
  224. chia/_tests/pools/test_pool_cmdline.py +1001 -0
  225. chia/_tests/pools/test_pool_config.py +42 -0
  226. chia/_tests/pools/test_pool_puzzles_lifecycle.py +397 -0
  227. chia/_tests/pools/test_pool_rpc.py +1123 -0
  228. chia/_tests/pools/test_pool_wallet.py +205 -0
  229. chia/_tests/pools/test_wallet_pool_store.py +161 -0
  230. chia/_tests/process_junit.py +348 -0
  231. chia/_tests/rpc/__init__.py +0 -0
  232. chia/_tests/rpc/test_rpc_client.py +138 -0
  233. chia/_tests/rpc/test_rpc_server.py +183 -0
  234. chia/_tests/simulation/__init__.py +0 -0
  235. chia/_tests/simulation/config.py +6 -0
  236. chia/_tests/simulation/test_simulation.py +501 -0
  237. chia/_tests/simulation/test_simulator.py +232 -0
  238. chia/_tests/simulation/test_start_simulator.py +107 -0
  239. chia/_tests/testconfig.py +13 -0
  240. chia/_tests/timelord/__init__.py +0 -0
  241. chia/_tests/timelord/config.py +3 -0
  242. chia/_tests/timelord/test_new_peak.py +437 -0
  243. chia/_tests/timelord/test_timelord.py +11 -0
  244. chia/_tests/tools/1315537.json +170 -0
  245. chia/_tests/tools/1315544.json +160 -0
  246. chia/_tests/tools/1315630.json +150 -0
  247. chia/_tests/tools/300000.json +105 -0
  248. chia/_tests/tools/442734.json +140 -0
  249. chia/_tests/tools/466212.json +130 -0
  250. chia/_tests/tools/__init__.py +0 -0
  251. chia/_tests/tools/config.py +5 -0
  252. chia/_tests/tools/test-blockchain-db.sqlite +0 -0
  253. chia/_tests/tools/test_full_sync.py +30 -0
  254. chia/_tests/tools/test_legacy_keyring.py +82 -0
  255. chia/_tests/tools/test_run_block.py +128 -0
  256. chia/_tests/tools/test_virtual_project.py +591 -0
  257. chia/_tests/util/__init__.py +0 -0
  258. chia/_tests/util/benchmark_cost.py +170 -0
  259. chia/_tests/util/benchmarks.py +153 -0
  260. chia/_tests/util/bip39_test_vectors.json +148 -0
  261. chia/_tests/util/blockchain.py +134 -0
  262. chia/_tests/util/blockchain_mock.py +132 -0
  263. chia/_tests/util/build_network_protocol_files.py +302 -0
  264. chia/_tests/util/clvm_generator.bin +0 -0
  265. chia/_tests/util/config.py +3 -0
  266. chia/_tests/util/constants.py +20 -0
  267. chia/_tests/util/db_connection.py +37 -0
  268. chia/_tests/util/full_sync.py +253 -0
  269. chia/_tests/util/gen_ssl_certs.py +114 -0
  270. chia/_tests/util/generator_tools_testing.py +45 -0
  271. chia/_tests/util/get_name_puzzle_conditions.py +52 -0
  272. chia/_tests/util/key_tool.py +36 -0
  273. chia/_tests/util/misc.py +675 -0
  274. chia/_tests/util/network_protocol_data.py +1072 -0
  275. chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
  276. chia/_tests/util/protocol_messages_json.py +2701 -0
  277. chia/_tests/util/rpc.py +26 -0
  278. chia/_tests/util/run_block.py +163 -0
  279. chia/_tests/util/setup_nodes.py +481 -0
  280. chia/_tests/util/spend_sim.py +492 -0
  281. chia/_tests/util/split_managers.py +102 -0
  282. chia/_tests/util/temp_file.py +14 -0
  283. chia/_tests/util/test_action_scope.py +144 -0
  284. chia/_tests/util/test_async_pool.py +366 -0
  285. chia/_tests/util/test_build_job_matrix.py +42 -0
  286. chia/_tests/util/test_build_network_protocol_files.py +7 -0
  287. chia/_tests/util/test_chia_version.py +50 -0
  288. chia/_tests/util/test_collection.py +11 -0
  289. chia/_tests/util/test_condition_tools.py +229 -0
  290. chia/_tests/util/test_config.py +426 -0
  291. chia/_tests/util/test_dump_keyring.py +60 -0
  292. chia/_tests/util/test_errors.py +10 -0
  293. chia/_tests/util/test_full_block_utils.py +279 -0
  294. chia/_tests/util/test_installed.py +20 -0
  295. chia/_tests/util/test_limited_semaphore.py +53 -0
  296. chia/_tests/util/test_logging_filter.py +42 -0
  297. chia/_tests/util/test_misc.py +445 -0
  298. chia/_tests/util/test_network.py +73 -0
  299. chia/_tests/util/test_network_protocol_files.py +578 -0
  300. chia/_tests/util/test_network_protocol_json.py +267 -0
  301. chia/_tests/util/test_network_protocol_test.py +256 -0
  302. chia/_tests/util/test_paginator.py +71 -0
  303. chia/_tests/util/test_pprint.py +17 -0
  304. chia/_tests/util/test_priority_mutex.py +488 -0
  305. chia/_tests/util/test_recursive_replace.py +116 -0
  306. chia/_tests/util/test_replace_str_to_bytes.py +137 -0
  307. chia/_tests/util/test_service_groups.py +15 -0
  308. chia/_tests/util/test_ssl_check.py +31 -0
  309. chia/_tests/util/test_testnet_overrides.py +19 -0
  310. chia/_tests/util/test_tests_misc.py +38 -0
  311. chia/_tests/util/test_timing.py +37 -0
  312. chia/_tests/util/test_trusted_peer.py +51 -0
  313. chia/_tests/util/time_out_assert.py +191 -0
  314. chia/_tests/wallet/__init__.py +0 -0
  315. chia/_tests/wallet/cat_wallet/__init__.py +0 -0
  316. chia/_tests/wallet/cat_wallet/config.py +4 -0
  317. chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +468 -0
  318. chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +69 -0
  319. chia/_tests/wallet/cat_wallet/test_cat_wallet.py +1826 -0
  320. chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +291 -0
  321. chia/_tests/wallet/cat_wallet/test_trades.py +2600 -0
  322. chia/_tests/wallet/clawback/__init__.py +0 -0
  323. chia/_tests/wallet/clawback/config.py +3 -0
  324. chia/_tests/wallet/clawback/test_clawback_decorator.py +78 -0
  325. chia/_tests/wallet/clawback/test_clawback_lifecycle.py +292 -0
  326. chia/_tests/wallet/clawback/test_clawback_metadata.py +50 -0
  327. chia/_tests/wallet/config.py +4 -0
  328. chia/_tests/wallet/conftest.py +278 -0
  329. chia/_tests/wallet/dao_wallet/__init__.py +0 -0
  330. chia/_tests/wallet/dao_wallet/config.py +3 -0
  331. chia/_tests/wallet/dao_wallet/test_dao_clvm.py +1330 -0
  332. chia/_tests/wallet/dao_wallet/test_dao_wallets.py +3488 -0
  333. chia/_tests/wallet/db_wallet/__init__.py +0 -0
  334. chia/_tests/wallet/db_wallet/config.py +3 -0
  335. chia/_tests/wallet/db_wallet/test_db_graftroot.py +141 -0
  336. chia/_tests/wallet/db_wallet/test_dl_offers.py +491 -0
  337. chia/_tests/wallet/db_wallet/test_dl_wallet.py +823 -0
  338. chia/_tests/wallet/did_wallet/__init__.py +0 -0
  339. chia/_tests/wallet/did_wallet/config.py +4 -0
  340. chia/_tests/wallet/did_wallet/test_did.py +2284 -0
  341. chia/_tests/wallet/nft_wallet/__init__.py +0 -0
  342. chia/_tests/wallet/nft_wallet/config.py +4 -0
  343. chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +1493 -0
  344. chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +1024 -0
  345. chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +375 -0
  346. chia/_tests/wallet/nft_wallet/test_nft_offers.py +1209 -0
  347. chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +172 -0
  348. chia/_tests/wallet/nft_wallet/test_nft_wallet.py +2584 -0
  349. chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +70 -0
  350. chia/_tests/wallet/rpc/__init__.py +0 -0
  351. chia/_tests/wallet/rpc/config.py +4 -0
  352. chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +285 -0
  353. chia/_tests/wallet/rpc/test_wallet_rpc.py +3153 -0
  354. chia/_tests/wallet/simple_sync/__init__.py +0 -0
  355. chia/_tests/wallet/simple_sync/config.py +3 -0
  356. chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +718 -0
  357. chia/_tests/wallet/sync/__init__.py +0 -0
  358. chia/_tests/wallet/sync/config.py +4 -0
  359. chia/_tests/wallet/sync/test_wallet_sync.py +1692 -0
  360. chia/_tests/wallet/test_address_type.py +189 -0
  361. chia/_tests/wallet/test_bech32m.py +45 -0
  362. chia/_tests/wallet/test_clvm_streamable.py +244 -0
  363. chia/_tests/wallet/test_coin_management.py +354 -0
  364. chia/_tests/wallet/test_coin_selection.py +588 -0
  365. chia/_tests/wallet/test_conditions.py +400 -0
  366. chia/_tests/wallet/test_debug_spend_bundle.py +218 -0
  367. chia/_tests/wallet/test_new_wallet_protocol.py +1174 -0
  368. chia/_tests/wallet/test_nft_store.py +192 -0
  369. chia/_tests/wallet/test_notifications.py +196 -0
  370. chia/_tests/wallet/test_offer_parsing_performance.py +48 -0
  371. chia/_tests/wallet/test_puzzle_store.py +132 -0
  372. chia/_tests/wallet/test_sign_coin_spends.py +159 -0
  373. chia/_tests/wallet/test_signer_protocol.py +947 -0
  374. chia/_tests/wallet/test_singleton.py +122 -0
  375. chia/_tests/wallet/test_singleton_lifecycle_fast.py +772 -0
  376. chia/_tests/wallet/test_singleton_store.py +152 -0
  377. chia/_tests/wallet/test_taproot.py +19 -0
  378. chia/_tests/wallet/test_transaction_store.py +945 -0
  379. chia/_tests/wallet/test_util.py +185 -0
  380. chia/_tests/wallet/test_wallet.py +2139 -0
  381. chia/_tests/wallet/test_wallet_action_scope.py +85 -0
  382. chia/_tests/wallet/test_wallet_blockchain.py +111 -0
  383. chia/_tests/wallet/test_wallet_coin_store.py +1002 -0
  384. chia/_tests/wallet/test_wallet_interested_store.py +43 -0
  385. chia/_tests/wallet/test_wallet_key_val_store.py +40 -0
  386. chia/_tests/wallet/test_wallet_node.py +780 -0
  387. chia/_tests/wallet/test_wallet_retry.py +95 -0
  388. chia/_tests/wallet/test_wallet_state_manager.py +259 -0
  389. chia/_tests/wallet/test_wallet_test_framework.py +275 -0
  390. chia/_tests/wallet/test_wallet_trade_store.py +218 -0
  391. chia/_tests/wallet/test_wallet_user_store.py +34 -0
  392. chia/_tests/wallet/test_wallet_utils.py +156 -0
  393. chia/_tests/wallet/vc_wallet/__init__.py +0 -0
  394. chia/_tests/wallet/vc_wallet/config.py +3 -0
  395. chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +70 -0
  396. chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +883 -0
  397. chia/_tests/wallet/vc_wallet/test_vc_wallet.py +830 -0
  398. chia/_tests/wallet/wallet_block_tools.py +327 -0
  399. chia/_tests/weight_proof/__init__.py +0 -0
  400. chia/_tests/weight_proof/config.py +3 -0
  401. chia/_tests/weight_proof/test_weight_proof.py +528 -0
  402. chia/apis.py +19 -0
  403. chia/clvm/__init__.py +0 -0
  404. chia/cmds/__init__.py +0 -0
  405. chia/cmds/beta.py +184 -0
  406. chia/cmds/beta_funcs.py +137 -0
  407. chia/cmds/check_wallet_db.py +420 -0
  408. chia/cmds/chia.py +151 -0
  409. chia/cmds/cmd_classes.py +323 -0
  410. chia/cmds/cmd_helpers.py +242 -0
  411. chia/cmds/cmds_util.py +488 -0
  412. chia/cmds/coin_funcs.py +275 -0
  413. chia/cmds/coins.py +182 -0
  414. chia/cmds/completion.py +49 -0
  415. chia/cmds/configure.py +332 -0
  416. chia/cmds/dao.py +1064 -0
  417. chia/cmds/dao_funcs.py +598 -0
  418. chia/cmds/data.py +708 -0
  419. chia/cmds/data_funcs.py +385 -0
  420. chia/cmds/db.py +87 -0
  421. chia/cmds/db_backup_func.py +77 -0
  422. chia/cmds/db_upgrade_func.py +452 -0
  423. chia/cmds/db_validate_func.py +184 -0
  424. chia/cmds/dev.py +18 -0
  425. chia/cmds/farm.py +100 -0
  426. chia/cmds/farm_funcs.py +200 -0
  427. chia/cmds/gh.py +275 -0
  428. chia/cmds/init.py +63 -0
  429. chia/cmds/init_funcs.py +367 -0
  430. chia/cmds/installers.py +131 -0
  431. chia/cmds/keys.py +527 -0
  432. chia/cmds/keys_funcs.py +863 -0
  433. chia/cmds/netspace.py +50 -0
  434. chia/cmds/netspace_funcs.py +54 -0
  435. chia/cmds/options.py +32 -0
  436. chia/cmds/param_types.py +238 -0
  437. chia/cmds/passphrase.py +131 -0
  438. chia/cmds/passphrase_funcs.py +292 -0
  439. chia/cmds/peer.py +51 -0
  440. chia/cmds/peer_funcs.py +129 -0
  441. chia/cmds/plotnft.py +260 -0
  442. chia/cmds/plotnft_funcs.py +405 -0
  443. chia/cmds/plots.py +230 -0
  444. chia/cmds/plotters.py +18 -0
  445. chia/cmds/rpc.py +208 -0
  446. chia/cmds/show.py +72 -0
  447. chia/cmds/show_funcs.py +215 -0
  448. chia/cmds/signer.py +296 -0
  449. chia/cmds/sim.py +225 -0
  450. chia/cmds/sim_funcs.py +509 -0
  451. chia/cmds/start.py +24 -0
  452. chia/cmds/start_funcs.py +109 -0
  453. chia/cmds/stop.py +62 -0
  454. chia/cmds/units.py +9 -0
  455. chia/cmds/wallet.py +1901 -0
  456. chia/cmds/wallet_funcs.py +1874 -0
  457. chia/consensus/__init__.py +0 -0
  458. chia/consensus/block_body_validation.py +562 -0
  459. chia/consensus/block_creation.py +546 -0
  460. chia/consensus/block_header_validation.py +1059 -0
  461. chia/consensus/block_record.py +31 -0
  462. chia/consensus/block_rewards.py +53 -0
  463. chia/consensus/blockchain.py +1087 -0
  464. chia/consensus/blockchain_interface.py +56 -0
  465. chia/consensus/coinbase.py +30 -0
  466. chia/consensus/condition_costs.py +9 -0
  467. chia/consensus/constants.py +49 -0
  468. chia/consensus/cost_calculator.py +15 -0
  469. chia/consensus/default_constants.py +89 -0
  470. chia/consensus/deficit.py +55 -0
  471. chia/consensus/difficulty_adjustment.py +412 -0
  472. chia/consensus/find_fork_point.py +111 -0
  473. chia/consensus/full_block_to_block_record.py +167 -0
  474. chia/consensus/get_block_challenge.py +106 -0
  475. chia/consensus/get_block_generator.py +27 -0
  476. chia/consensus/make_sub_epoch_summary.py +210 -0
  477. chia/consensus/multiprocess_validation.py +268 -0
  478. chia/consensus/pos_quality.py +19 -0
  479. chia/consensus/pot_iterations.py +67 -0
  480. chia/consensus/puzzles/__init__.py +0 -0
  481. chia/consensus/puzzles/chialisp_deserialisation.clsp +69 -0
  482. chia/consensus/puzzles/chialisp_deserialisation.clsp.hex +1 -0
  483. chia/consensus/puzzles/rom_bootstrap_generator.clsp +37 -0
  484. chia/consensus/puzzles/rom_bootstrap_generator.clsp.hex +1 -0
  485. chia/consensus/vdf_info_computation.py +156 -0
  486. chia/daemon/__init__.py +0 -0
  487. chia/daemon/client.py +252 -0
  488. chia/daemon/keychain_proxy.py +502 -0
  489. chia/daemon/keychain_server.py +365 -0
  490. chia/daemon/server.py +1606 -0
  491. chia/daemon/windows_signal.py +56 -0
  492. chia/data_layer/__init__.py +0 -0
  493. chia/data_layer/data_layer.py +1291 -0
  494. chia/data_layer/data_layer_api.py +33 -0
  495. chia/data_layer/data_layer_errors.py +50 -0
  496. chia/data_layer/data_layer_server.py +170 -0
  497. chia/data_layer/data_layer_util.py +985 -0
  498. chia/data_layer/data_layer_wallet.py +1311 -0
  499. chia/data_layer/data_store.py +2267 -0
  500. chia/data_layer/dl_wallet_store.py +407 -0
  501. chia/data_layer/download_data.py +389 -0
  502. chia/data_layer/puzzles/__init__.py +0 -0
  503. chia/data_layer/puzzles/graftroot_dl_offers.clsp +100 -0
  504. chia/data_layer/puzzles/graftroot_dl_offers.clsp.hex +1 -0
  505. chia/data_layer/s3_plugin_config.yml +33 -0
  506. chia/data_layer/s3_plugin_service.py +468 -0
  507. chia/data_layer/util/__init__.py +0 -0
  508. chia/data_layer/util/benchmark.py +107 -0
  509. chia/data_layer/util/plugin.py +40 -0
  510. chia/farmer/__init__.py +0 -0
  511. chia/farmer/farmer.py +923 -0
  512. chia/farmer/farmer_api.py +820 -0
  513. chia/full_node/__init__.py +0 -0
  514. chia/full_node/bitcoin_fee_estimator.py +85 -0
  515. chia/full_node/block_height_map.py +271 -0
  516. chia/full_node/block_store.py +576 -0
  517. chia/full_node/bundle_tools.py +19 -0
  518. chia/full_node/coin_store.py +647 -0
  519. chia/full_node/fee_estimate.py +54 -0
  520. chia/full_node/fee_estimate_store.py +24 -0
  521. chia/full_node/fee_estimation.py +92 -0
  522. chia/full_node/fee_estimator.py +90 -0
  523. chia/full_node/fee_estimator_constants.py +38 -0
  524. chia/full_node/fee_estimator_interface.py +42 -0
  525. chia/full_node/fee_history.py +25 -0
  526. chia/full_node/fee_tracker.py +564 -0
  527. chia/full_node/full_node.py +3327 -0
  528. chia/full_node/full_node_api.py +2025 -0
  529. chia/full_node/full_node_store.py +1033 -0
  530. chia/full_node/hint_management.py +56 -0
  531. chia/full_node/hint_store.py +93 -0
  532. chia/full_node/mempool.py +589 -0
  533. chia/full_node/mempool_check_conditions.py +146 -0
  534. chia/full_node/mempool_manager.py +853 -0
  535. chia/full_node/pending_tx_cache.py +112 -0
  536. chia/full_node/puzzles/__init__.py +0 -0
  537. chia/full_node/puzzles/block_program_zero.clsp +14 -0
  538. chia/full_node/puzzles/block_program_zero.clsp.hex +1 -0
  539. chia/full_node/puzzles/decompress_coin_spend_entry.clsp +5 -0
  540. chia/full_node/puzzles/decompress_coin_spend_entry.clsp.hex +1 -0
  541. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp +7 -0
  542. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp.hex +1 -0
  543. chia/full_node/puzzles/decompress_puzzle.clsp +6 -0
  544. chia/full_node/puzzles/decompress_puzzle.clsp.hex +1 -0
  545. chia/full_node/signage_point.py +16 -0
  546. chia/full_node/subscriptions.py +247 -0
  547. chia/full_node/sync_store.py +146 -0
  548. chia/full_node/tx_processing_queue.py +78 -0
  549. chia/full_node/util/__init__.py +0 -0
  550. chia/full_node/weight_proof.py +1720 -0
  551. chia/harvester/__init__.py +0 -0
  552. chia/harvester/harvester.py +272 -0
  553. chia/harvester/harvester_api.py +380 -0
  554. chia/introducer/__init__.py +0 -0
  555. chia/introducer/introducer.py +122 -0
  556. chia/introducer/introducer_api.py +70 -0
  557. chia/legacy/__init__.py +0 -0
  558. chia/legacy/keyring.py +155 -0
  559. chia/plot_sync/__init__.py +0 -0
  560. chia/plot_sync/delta.py +61 -0
  561. chia/plot_sync/exceptions.py +56 -0
  562. chia/plot_sync/receiver.py +386 -0
  563. chia/plot_sync/sender.py +340 -0
  564. chia/plot_sync/util.py +43 -0
  565. chia/plotters/__init__.py +0 -0
  566. chia/plotters/bladebit.py +388 -0
  567. chia/plotters/chiapos.py +63 -0
  568. chia/plotters/madmax.py +224 -0
  569. chia/plotters/plotters.py +577 -0
  570. chia/plotters/plotters_util.py +133 -0
  571. chia/plotting/__init__.py +0 -0
  572. chia/plotting/cache.py +213 -0
  573. chia/plotting/check_plots.py +283 -0
  574. chia/plotting/create_plots.py +278 -0
  575. chia/plotting/manager.py +436 -0
  576. chia/plotting/util.py +336 -0
  577. chia/pools/__init__.py +0 -0
  578. chia/pools/pool_config.py +110 -0
  579. chia/pools/pool_puzzles.py +459 -0
  580. chia/pools/pool_wallet.py +933 -0
  581. chia/pools/pool_wallet_info.py +118 -0
  582. chia/pools/puzzles/__init__.py +0 -0
  583. chia/pools/puzzles/pool_member_innerpuz.clsp +70 -0
  584. chia/pools/puzzles/pool_member_innerpuz.clsp.hex +1 -0
  585. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp +69 -0
  586. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp.hex +1 -0
  587. chia/protocols/__init__.py +0 -0
  588. chia/protocols/farmer_protocol.py +102 -0
  589. chia/protocols/full_node_protocol.py +219 -0
  590. chia/protocols/harvester_protocol.py +216 -0
  591. chia/protocols/introducer_protocol.py +25 -0
  592. chia/protocols/pool_protocol.py +177 -0
  593. chia/protocols/protocol_message_types.py +139 -0
  594. chia/protocols/protocol_state_machine.py +87 -0
  595. chia/protocols/protocol_timing.py +8 -0
  596. chia/protocols/shared_protocol.py +86 -0
  597. chia/protocols/timelord_protocol.py +93 -0
  598. chia/protocols/wallet_protocol.py +401 -0
  599. chia/py.typed +0 -0
  600. chia/rpc/__init__.py +0 -0
  601. chia/rpc/crawler_rpc_api.py +80 -0
  602. chia/rpc/data_layer_rpc_api.py +644 -0
  603. chia/rpc/data_layer_rpc_client.py +188 -0
  604. chia/rpc/data_layer_rpc_util.py +58 -0
  605. chia/rpc/farmer_rpc_api.py +365 -0
  606. chia/rpc/farmer_rpc_client.py +86 -0
  607. chia/rpc/full_node_rpc_api.py +959 -0
  608. chia/rpc/full_node_rpc_client.py +292 -0
  609. chia/rpc/harvester_rpc_api.py +141 -0
  610. chia/rpc/harvester_rpc_client.py +54 -0
  611. chia/rpc/rpc_client.py +164 -0
  612. chia/rpc/rpc_server.py +521 -0
  613. chia/rpc/timelord_rpc_api.py +32 -0
  614. chia/rpc/util.py +93 -0
  615. chia/rpc/wallet_request_types.py +904 -0
  616. chia/rpc/wallet_rpc_api.py +4943 -0
  617. chia/rpc/wallet_rpc_client.py +1814 -0
  618. chia/seeder/__init__.py +0 -0
  619. chia/seeder/crawl_store.py +425 -0
  620. chia/seeder/crawler.py +410 -0
  621. chia/seeder/crawler_api.py +135 -0
  622. chia/seeder/dns_server.py +593 -0
  623. chia/seeder/peer_record.py +146 -0
  624. chia/seeder/start_crawler.py +92 -0
  625. chia/server/__init__.py +0 -0
  626. chia/server/address_manager.py +658 -0
  627. chia/server/address_manager_store.py +237 -0
  628. chia/server/api_protocol.py +116 -0
  629. chia/server/capabilities.py +24 -0
  630. chia/server/chia_policy.py +346 -0
  631. chia/server/introducer_peers.py +76 -0
  632. chia/server/node_discovery.py +714 -0
  633. chia/server/outbound_message.py +33 -0
  634. chia/server/rate_limit_numbers.py +214 -0
  635. chia/server/rate_limits.py +153 -0
  636. chia/server/server.py +741 -0
  637. chia/server/signal_handlers.py +120 -0
  638. chia/server/ssl_context.py +32 -0
  639. chia/server/start_data_layer.py +151 -0
  640. chia/server/start_farmer.py +98 -0
  641. chia/server/start_full_node.py +112 -0
  642. chia/server/start_harvester.py +93 -0
  643. chia/server/start_introducer.py +81 -0
  644. chia/server/start_service.py +316 -0
  645. chia/server/start_timelord.py +89 -0
  646. chia/server/start_wallet.py +113 -0
  647. chia/server/upnp.py +118 -0
  648. chia/server/ws_connection.py +766 -0
  649. chia/simulator/__init__.py +0 -0
  650. chia/simulator/add_blocks_in_batches.py +54 -0
  651. chia/simulator/block_tools.py +2054 -0
  652. chia/simulator/full_node_simulator.py +794 -0
  653. chia/simulator/keyring.py +128 -0
  654. chia/simulator/setup_services.py +506 -0
  655. chia/simulator/simulator_constants.py +13 -0
  656. chia/simulator/simulator_full_node_rpc_api.py +99 -0
  657. chia/simulator/simulator_full_node_rpc_client.py +60 -0
  658. chia/simulator/simulator_protocol.py +29 -0
  659. chia/simulator/simulator_test_tools.py +164 -0
  660. chia/simulator/socket.py +24 -0
  661. chia/simulator/ssl_certs.py +114 -0
  662. chia/simulator/ssl_certs_1.py +697 -0
  663. chia/simulator/ssl_certs_10.py +697 -0
  664. chia/simulator/ssl_certs_2.py +697 -0
  665. chia/simulator/ssl_certs_3.py +697 -0
  666. chia/simulator/ssl_certs_4.py +697 -0
  667. chia/simulator/ssl_certs_5.py +697 -0
  668. chia/simulator/ssl_certs_6.py +697 -0
  669. chia/simulator/ssl_certs_7.py +697 -0
  670. chia/simulator/ssl_certs_8.py +697 -0
  671. chia/simulator/ssl_certs_9.py +697 -0
  672. chia/simulator/start_simulator.py +143 -0
  673. chia/simulator/wallet_tools.py +246 -0
  674. chia/ssl/__init__.py +0 -0
  675. chia/ssl/chia_ca.crt +19 -0
  676. chia/ssl/chia_ca.key +28 -0
  677. chia/ssl/create_ssl.py +249 -0
  678. chia/ssl/dst_root_ca.pem +20 -0
  679. chia/timelord/__init__.py +0 -0
  680. chia/timelord/iters_from_block.py +50 -0
  681. chia/timelord/timelord.py +1226 -0
  682. chia/timelord/timelord_api.py +138 -0
  683. chia/timelord/timelord_launcher.py +190 -0
  684. chia/timelord/timelord_state.py +244 -0
  685. chia/timelord/types.py +22 -0
  686. chia/types/__init__.py +0 -0
  687. chia/types/aliases.py +35 -0
  688. chia/types/block_protocol.py +20 -0
  689. chia/types/blockchain_format/__init__.py +0 -0
  690. chia/types/blockchain_format/classgroup.py +5 -0
  691. chia/types/blockchain_format/coin.py +28 -0
  692. chia/types/blockchain_format/foliage.py +8 -0
  693. chia/types/blockchain_format/pool_target.py +5 -0
  694. chia/types/blockchain_format/program.py +269 -0
  695. chia/types/blockchain_format/proof_of_space.py +135 -0
  696. chia/types/blockchain_format/reward_chain_block.py +6 -0
  697. chia/types/blockchain_format/serialized_program.py +5 -0
  698. chia/types/blockchain_format/sized_bytes.py +11 -0
  699. chia/types/blockchain_format/slots.py +9 -0
  700. chia/types/blockchain_format/sub_epoch_summary.py +5 -0
  701. chia/types/blockchain_format/tree_hash.py +72 -0
  702. chia/types/blockchain_format/vdf.py +86 -0
  703. chia/types/clvm_cost.py +13 -0
  704. chia/types/coin_record.py +43 -0
  705. chia/types/coin_spend.py +115 -0
  706. chia/types/condition_opcodes.py +73 -0
  707. chia/types/condition_with_args.py +16 -0
  708. chia/types/eligible_coin_spends.py +365 -0
  709. chia/types/end_of_slot_bundle.py +5 -0
  710. chia/types/fee_rate.py +38 -0
  711. chia/types/full_block.py +5 -0
  712. chia/types/generator_types.py +13 -0
  713. chia/types/header_block.py +5 -0
  714. chia/types/internal_mempool_item.py +18 -0
  715. chia/types/mempool_inclusion_status.py +9 -0
  716. chia/types/mempool_item.py +85 -0
  717. chia/types/mempool_submission_status.py +30 -0
  718. chia/types/mojos.py +7 -0
  719. chia/types/peer_info.py +64 -0
  720. chia/types/signing_mode.py +29 -0
  721. chia/types/spend_bundle.py +30 -0
  722. chia/types/spend_bundle_conditions.py +7 -0
  723. chia/types/transaction_queue_entry.py +55 -0
  724. chia/types/unfinished_block.py +5 -0
  725. chia/types/unfinished_header_block.py +37 -0
  726. chia/types/validation_state.py +14 -0
  727. chia/types/weight_proof.py +49 -0
  728. chia/util/__init__.py +0 -0
  729. chia/util/action_scope.py +168 -0
  730. chia/util/async_pool.py +226 -0
  731. chia/util/augmented_chain.py +134 -0
  732. chia/util/batches.py +42 -0
  733. chia/util/bech32m.py +126 -0
  734. chia/util/beta_metrics.py +119 -0
  735. chia/util/block_cache.py +56 -0
  736. chia/util/byte_types.py +12 -0
  737. chia/util/check_fork_next_block.py +33 -0
  738. chia/util/chia_logging.py +144 -0
  739. chia/util/chia_version.py +33 -0
  740. chia/util/collection.py +17 -0
  741. chia/util/condition_tools.py +201 -0
  742. chia/util/config.py +367 -0
  743. chia/util/cpu.py +22 -0
  744. chia/util/db_synchronous.py +23 -0
  745. chia/util/db_version.py +32 -0
  746. chia/util/db_wrapper.py +430 -0
  747. chia/util/default_root.py +27 -0
  748. chia/util/dump_keyring.py +93 -0
  749. chia/util/english.txt +2048 -0
  750. chia/util/errors.py +353 -0
  751. chia/util/file_keyring.py +469 -0
  752. chia/util/files.py +97 -0
  753. chia/util/full_block_utils.py +345 -0
  754. chia/util/generator_tools.py +72 -0
  755. chia/util/hash.py +31 -0
  756. chia/util/initial-config.yaml +694 -0
  757. chia/util/inline_executor.py +26 -0
  758. chia/util/ints.py +19 -0
  759. chia/util/ip_address.py +39 -0
  760. chia/util/json_util.py +37 -0
  761. chia/util/keychain.py +676 -0
  762. chia/util/keyring_wrapper.py +327 -0
  763. chia/util/limited_semaphore.py +41 -0
  764. chia/util/lock.py +49 -0
  765. chia/util/log_exceptions.py +32 -0
  766. chia/util/logging.py +36 -0
  767. chia/util/lru_cache.py +31 -0
  768. chia/util/math.py +20 -0
  769. chia/util/network.py +182 -0
  770. chia/util/paginator.py +48 -0
  771. chia/util/path.py +31 -0
  772. chia/util/permissions.py +20 -0
  773. chia/util/prev_transaction_block.py +21 -0
  774. chia/util/priority_mutex.py +95 -0
  775. chia/util/profiler.py +197 -0
  776. chia/util/recursive_replace.py +24 -0
  777. chia/util/safe_cancel_task.py +16 -0
  778. chia/util/service_groups.py +47 -0
  779. chia/util/setproctitle.py +22 -0
  780. chia/util/significant_bits.py +32 -0
  781. chia/util/ssl_check.py +213 -0
  782. chia/util/streamable.py +642 -0
  783. chia/util/task_referencer.py +59 -0
  784. chia/util/task_timing.py +382 -0
  785. chia/util/timing.py +67 -0
  786. chia/util/vdf_prover.py +30 -0
  787. chia/util/virtual_project_analysis.py +540 -0
  788. chia/util/ws_message.py +66 -0
  789. chia/wallet/__init__.py +0 -0
  790. chia/wallet/cat_wallet/__init__.py +0 -0
  791. chia/wallet/cat_wallet/cat_constants.py +75 -0
  792. chia/wallet/cat_wallet/cat_info.py +47 -0
  793. chia/wallet/cat_wallet/cat_outer_puzzle.py +120 -0
  794. chia/wallet/cat_wallet/cat_utils.py +164 -0
  795. chia/wallet/cat_wallet/cat_wallet.py +855 -0
  796. chia/wallet/cat_wallet/dao_cat_info.py +28 -0
  797. chia/wallet/cat_wallet/dao_cat_wallet.py +669 -0
  798. chia/wallet/cat_wallet/lineage_store.py +74 -0
  799. chia/wallet/cat_wallet/puzzles/__init__.py +0 -0
  800. chia/wallet/cat_wallet/puzzles/cat_truths.clib +31 -0
  801. chia/wallet/cat_wallet/puzzles/cat_v2.clsp +397 -0
  802. chia/wallet/cat_wallet/puzzles/cat_v2.clsp.hex +1 -0
  803. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp +25 -0
  804. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp.hex +1 -0
  805. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp +15 -0
  806. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp.hex +1 -0
  807. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp +26 -0
  808. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp.hex +1 -0
  809. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp +42 -0
  810. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp.hex +1 -0
  811. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp +24 -0
  812. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp.hex +1 -0
  813. chia/wallet/coin_selection.py +188 -0
  814. chia/wallet/conditions.py +1512 -0
  815. chia/wallet/dao_wallet/__init__.py +0 -0
  816. chia/wallet/dao_wallet/dao_info.py +61 -0
  817. chia/wallet/dao_wallet/dao_utils.py +811 -0
  818. chia/wallet/dao_wallet/dao_wallet.py +2119 -0
  819. chia/wallet/db_wallet/__init__.py +0 -0
  820. chia/wallet/db_wallet/db_wallet_puzzles.py +111 -0
  821. chia/wallet/derivation_record.py +30 -0
  822. chia/wallet/derive_keys.py +146 -0
  823. chia/wallet/did_wallet/__init__.py +0 -0
  824. chia/wallet/did_wallet/did_info.py +39 -0
  825. chia/wallet/did_wallet/did_wallet.py +1494 -0
  826. chia/wallet/did_wallet/did_wallet_puzzles.py +221 -0
  827. chia/wallet/did_wallet/puzzles/__init__.py +0 -0
  828. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp +135 -0
  829. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp.hex +1 -0
  830. chia/wallet/driver_protocol.py +26 -0
  831. chia/wallet/key_val_store.py +55 -0
  832. chia/wallet/lineage_proof.py +58 -0
  833. chia/wallet/nft_wallet/__init__.py +0 -0
  834. chia/wallet/nft_wallet/metadata_outer_puzzle.py +92 -0
  835. chia/wallet/nft_wallet/nft_info.py +120 -0
  836. chia/wallet/nft_wallet/nft_puzzles.py +305 -0
  837. chia/wallet/nft_wallet/nft_wallet.py +1687 -0
  838. chia/wallet/nft_wallet/ownership_outer_puzzle.py +101 -0
  839. chia/wallet/nft_wallet/puzzles/__init__.py +0 -0
  840. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp +6 -0
  841. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp.hex +1 -0
  842. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp +6 -0
  843. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp.hex +1 -0
  844. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp +30 -0
  845. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp.hex +1 -0
  846. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp +28 -0
  847. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp.hex +1 -0
  848. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp +100 -0
  849. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp.hex +1 -0
  850. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp +78 -0
  851. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp.hex +1 -0
  852. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp +74 -0
  853. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp.hex +1 -0
  854. chia/wallet/nft_wallet/singleton_outer_puzzle.py +101 -0
  855. chia/wallet/nft_wallet/transfer_program_puzzle.py +82 -0
  856. chia/wallet/nft_wallet/uncurry_nft.py +217 -0
  857. chia/wallet/notification_manager.py +117 -0
  858. chia/wallet/notification_store.py +178 -0
  859. chia/wallet/outer_puzzles.py +84 -0
  860. chia/wallet/payment.py +33 -0
  861. chia/wallet/puzzle_drivers.py +118 -0
  862. chia/wallet/puzzles/__init__.py +0 -0
  863. chia/wallet/puzzles/augmented_condition.clsp +13 -0
  864. chia/wallet/puzzles/augmented_condition.clsp.hex +1 -0
  865. chia/wallet/puzzles/clawback/__init__.py +0 -0
  866. chia/wallet/puzzles/clawback/drivers.py +188 -0
  867. chia/wallet/puzzles/clawback/metadata.py +38 -0
  868. chia/wallet/puzzles/clawback/puzzle_decorator.py +67 -0
  869. chia/wallet/puzzles/condition_codes.clib +77 -0
  870. chia/wallet/puzzles/curry-and-treehash.clib +102 -0
  871. chia/wallet/puzzles/curry.clib +135 -0
  872. chia/wallet/puzzles/curry_by_index.clib +16 -0
  873. chia/wallet/puzzles/dao_cat_eve.clsp +17 -0
  874. chia/wallet/puzzles/dao_cat_eve.clsp.hex +1 -0
  875. chia/wallet/puzzles/dao_cat_launcher.clsp +36 -0
  876. chia/wallet/puzzles/dao_cat_launcher.clsp.hex +1 -0
  877. chia/wallet/puzzles/dao_finished_state.clsp +35 -0
  878. chia/wallet/puzzles/dao_finished_state.clsp.hex +1 -0
  879. chia/wallet/puzzles/dao_finished_state.clsp.hex.sha256tree +1 -0
  880. chia/wallet/puzzles/dao_lockup.clsp +288 -0
  881. chia/wallet/puzzles/dao_lockup.clsp.hex +1 -0
  882. chia/wallet/puzzles/dao_lockup.clsp.hex.sha256tree +1 -0
  883. chia/wallet/puzzles/dao_proposal.clsp +377 -0
  884. chia/wallet/puzzles/dao_proposal.clsp.hex +1 -0
  885. chia/wallet/puzzles/dao_proposal.clsp.hex.sha256tree +1 -0
  886. chia/wallet/puzzles/dao_proposal_timer.clsp +78 -0
  887. chia/wallet/puzzles/dao_proposal_timer.clsp.hex +1 -0
  888. chia/wallet/puzzles/dao_proposal_timer.clsp.hex.sha256tree +1 -0
  889. chia/wallet/puzzles/dao_proposal_validator.clsp +87 -0
  890. chia/wallet/puzzles/dao_proposal_validator.clsp.hex +1 -0
  891. chia/wallet/puzzles/dao_proposal_validator.clsp.hex.sha256tree +1 -0
  892. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp +240 -0
  893. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex +1 -0
  894. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex.sha256tree +1 -0
  895. chia/wallet/puzzles/dao_treasury.clsp +115 -0
  896. chia/wallet/puzzles/dao_treasury.clsp.hex +1 -0
  897. chia/wallet/puzzles/dao_update_proposal.clsp +44 -0
  898. chia/wallet/puzzles/dao_update_proposal.clsp.hex +1 -0
  899. chia/wallet/puzzles/deployed_puzzle_hashes.json +67 -0
  900. chia/wallet/puzzles/json.clib +25 -0
  901. chia/wallet/puzzles/load_clvm.py +161 -0
  902. chia/wallet/puzzles/merkle_utils.clib +18 -0
  903. chia/wallet/puzzles/notification.clsp +7 -0
  904. chia/wallet/puzzles/notification.clsp.hex +1 -0
  905. chia/wallet/puzzles/p2_1_of_n.clsp +22 -0
  906. chia/wallet/puzzles/p2_1_of_n.clsp.hex +1 -0
  907. chia/wallet/puzzles/p2_conditions.clsp +3 -0
  908. chia/wallet/puzzles/p2_conditions.clsp.hex +1 -0
  909. chia/wallet/puzzles/p2_conditions.py +26 -0
  910. chia/wallet/puzzles/p2_delegated_conditions.clsp +18 -0
  911. chia/wallet/puzzles/p2_delegated_conditions.clsp.hex +1 -0
  912. chia/wallet/puzzles/p2_delegated_conditions.py +21 -0
  913. chia/wallet/puzzles/p2_delegated_puzzle.clsp +19 -0
  914. chia/wallet/puzzles/p2_delegated_puzzle.clsp.hex +1 -0
  915. chia/wallet/puzzles/p2_delegated_puzzle.py +34 -0
  916. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp +91 -0
  917. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp.hex +1 -0
  918. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +160 -0
  919. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp +108 -0
  920. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp.hex +1 -0
  921. chia/wallet/puzzles/p2_m_of_n_delegate_direct.py +21 -0
  922. chia/wallet/puzzles/p2_parent.clsp +19 -0
  923. chia/wallet/puzzles/p2_parent.clsp.hex +1 -0
  924. chia/wallet/puzzles/p2_puzzle_hash.clsp +18 -0
  925. chia/wallet/puzzles/p2_puzzle_hash.clsp.hex +1 -0
  926. chia/wallet/puzzles/p2_puzzle_hash.py +27 -0
  927. chia/wallet/puzzles/p2_singleton.clsp +30 -0
  928. chia/wallet/puzzles/p2_singleton.clsp.hex +1 -0
  929. chia/wallet/puzzles/p2_singleton_aggregator.clsp +81 -0
  930. chia/wallet/puzzles/p2_singleton_aggregator.clsp.hex +1 -0
  931. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp +50 -0
  932. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp.hex +1 -0
  933. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp +47 -0
  934. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp.hex +1 -0
  935. chia/wallet/puzzles/puzzle_utils.py +34 -0
  936. chia/wallet/puzzles/settlement_payments.clsp +49 -0
  937. chia/wallet/puzzles/settlement_payments.clsp.hex +1 -0
  938. chia/wallet/puzzles/sha256tree.clib +11 -0
  939. chia/wallet/puzzles/singleton_launcher.clsp +16 -0
  940. chia/wallet/puzzles/singleton_launcher.clsp.hex +1 -0
  941. chia/wallet/puzzles/singleton_top_layer.clsp +177 -0
  942. chia/wallet/puzzles/singleton_top_layer.clsp.hex +1 -0
  943. chia/wallet/puzzles/singleton_top_layer.py +296 -0
  944. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp +107 -0
  945. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp.hex +1 -0
  946. chia/wallet/puzzles/singleton_top_layer_v1_1.py +345 -0
  947. chia/wallet/puzzles/singleton_truths.clib +21 -0
  948. chia/wallet/puzzles/tails.py +348 -0
  949. chia/wallet/puzzles/utility_macros.clib +48 -0
  950. chia/wallet/signer_protocol.py +125 -0
  951. chia/wallet/singleton.py +106 -0
  952. chia/wallet/singleton_record.py +30 -0
  953. chia/wallet/trade_manager.py +1102 -0
  954. chia/wallet/trade_record.py +67 -0
  955. chia/wallet/trading/__init__.py +0 -0
  956. chia/wallet/trading/offer.py +702 -0
  957. chia/wallet/trading/trade_status.py +13 -0
  958. chia/wallet/trading/trade_store.py +526 -0
  959. chia/wallet/transaction_record.py +158 -0
  960. chia/wallet/transaction_sorting.py +14 -0
  961. chia/wallet/uncurried_puzzle.py +17 -0
  962. chia/wallet/util/__init__.py +0 -0
  963. chia/wallet/util/address_type.py +55 -0
  964. chia/wallet/util/blind_signer_tl.py +164 -0
  965. chia/wallet/util/clvm_streamable.py +203 -0
  966. chia/wallet/util/compute_hints.py +66 -0
  967. chia/wallet/util/compute_memos.py +43 -0
  968. chia/wallet/util/curry_and_treehash.py +91 -0
  969. chia/wallet/util/debug_spend_bundle.py +232 -0
  970. chia/wallet/util/merkle_tree.py +100 -0
  971. chia/wallet/util/merkle_utils.py +102 -0
  972. chia/wallet/util/new_peak_queue.py +82 -0
  973. chia/wallet/util/notifications.py +12 -0
  974. chia/wallet/util/peer_request_cache.py +174 -0
  975. chia/wallet/util/pprint.py +39 -0
  976. chia/wallet/util/puzzle_compression.py +95 -0
  977. chia/wallet/util/puzzle_decorator.py +100 -0
  978. chia/wallet/util/puzzle_decorator_type.py +7 -0
  979. chia/wallet/util/query_filter.py +59 -0
  980. chia/wallet/util/transaction_type.py +23 -0
  981. chia/wallet/util/tx_config.py +158 -0
  982. chia/wallet/util/wallet_sync_utils.py +351 -0
  983. chia/wallet/util/wallet_types.py +72 -0
  984. chia/wallet/vc_wallet/__init__.py +0 -0
  985. chia/wallet/vc_wallet/cr_cat_drivers.py +664 -0
  986. chia/wallet/vc_wallet/cr_cat_wallet.py +877 -0
  987. chia/wallet/vc_wallet/cr_outer_puzzle.py +102 -0
  988. chia/wallet/vc_wallet/cr_puzzles/__init__.py +0 -0
  989. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp +3 -0
  990. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp.hex +1 -0
  991. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp +304 -0
  992. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp.hex +1 -0
  993. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp +45 -0
  994. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp.hex +1 -0
  995. chia/wallet/vc_wallet/vc_drivers.py +838 -0
  996. chia/wallet/vc_wallet/vc_puzzles/__init__.py +0 -0
  997. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp +30 -0
  998. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp.hex +1 -0
  999. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp +75 -0
  1000. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp.hex +1 -0
  1001. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp +32 -0
  1002. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp.hex +1 -0
  1003. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp +80 -0
  1004. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp.hex +1 -0
  1005. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp +163 -0
  1006. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp.hex +1 -0
  1007. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp +16 -0
  1008. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp.hex +1 -0
  1009. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp +74 -0
  1010. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp.hex +1 -0
  1011. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp +23 -0
  1012. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp.hex +1 -0
  1013. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp +64 -0
  1014. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp.hex +1 -0
  1015. chia/wallet/vc_wallet/vc_store.py +263 -0
  1016. chia/wallet/vc_wallet/vc_wallet.py +638 -0
  1017. chia/wallet/wallet.py +698 -0
  1018. chia/wallet/wallet_action_scope.py +96 -0
  1019. chia/wallet/wallet_blockchain.py +244 -0
  1020. chia/wallet/wallet_coin_record.py +72 -0
  1021. chia/wallet/wallet_coin_store.py +351 -0
  1022. chia/wallet/wallet_info.py +35 -0
  1023. chia/wallet/wallet_interested_store.py +188 -0
  1024. chia/wallet/wallet_nft_store.py +279 -0
  1025. chia/wallet/wallet_node.py +1765 -0
  1026. chia/wallet/wallet_node_api.py +207 -0
  1027. chia/wallet/wallet_pool_store.py +119 -0
  1028. chia/wallet/wallet_protocol.py +90 -0
  1029. chia/wallet/wallet_puzzle_store.py +396 -0
  1030. chia/wallet/wallet_retry_store.py +70 -0
  1031. chia/wallet/wallet_singleton_store.py +259 -0
  1032. chia/wallet/wallet_spend_bundle.py +25 -0
  1033. chia/wallet/wallet_state_manager.py +2819 -0
  1034. chia/wallet/wallet_transaction_store.py +496 -0
  1035. chia/wallet/wallet_user_store.py +110 -0
  1036. chia/wallet/wallet_weight_proof_handler.py +126 -0
  1037. chia_blockchain-2.5.1rc1.dist-info/LICENSE +201 -0
  1038. chia_blockchain-2.5.1rc1.dist-info/METADATA +156 -0
  1039. chia_blockchain-2.5.1rc1.dist-info/RECORD +1042 -0
  1040. chia_blockchain-2.5.1rc1.dist-info/WHEEL +4 -0
  1041. chia_blockchain-2.5.1rc1.dist-info/entry_points.txt +17 -0
  1042. mozilla-ca/cacert.pem +3611 -0
@@ -0,0 +1,2128 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib.metadata
4
+ import json
5
+ from dataclasses import dataclass, field, replace
6
+ from pathlib import Path
7
+ from typing import Any, Optional, Union, cast
8
+
9
+ import aiohttp
10
+ import pytest
11
+ from aiohttp import WSMessage
12
+ from aiohttp.web_ws import WebSocketResponse
13
+ from chia_rs import G1Element
14
+ from pytest_mock import MockerFixture
15
+
16
+ from chia._tests.util.misc import Marks, datacases
17
+ from chia._tests.util.time_out_assert import time_out_assert_not_none
18
+ from chia.daemon.client import DaemonProxy, connect_to_daemon
19
+ from chia.daemon.keychain_server import (
20
+ DeleteLabelRequest,
21
+ GetKeyRequest,
22
+ GetKeyResponse,
23
+ GetKeysResponse,
24
+ GetPublicKeyResponse,
25
+ GetPublicKeysResponse,
26
+ SetLabelRequest,
27
+ )
28
+ from chia.daemon.server import WebSocketServer, plotter_log_path, service_plotter
29
+ from chia.plotters.plotters import call_plotters
30
+ from chia.simulator.block_tools import BlockTools
31
+ from chia.simulator.keyring import TempKeyring
32
+ from chia.simulator.setup_services import setup_full_node
33
+ from chia.util.config import load_config
34
+ from chia.util.json_util import dict_to_json_str
35
+ from chia.util.keychain import Keychain, KeyData, supports_os_passphrase_storage
36
+ from chia.util.keyring_wrapper import DEFAULT_PASSPHRASE_IF_NO_MASTER_PASSPHRASE, KeyringWrapper
37
+ from chia.util.ws_message import create_payload, create_payload_dict
38
+ from chia.wallet.derive_keys import master_sk_to_farmer_sk, master_sk_to_pool_sk
39
+
40
+ chiapos_version = importlib.metadata.version("chiapos")
41
+
42
+
43
+ @dataclass
44
+ class RouteCase:
45
+ route: str
46
+ description: str
47
+ request: dict[str, Any]
48
+ response: dict[str, Any]
49
+ marks: Marks = ()
50
+
51
+ @property
52
+ def id(self) -> str:
53
+ return f"{self.route}: {self.description}"
54
+
55
+
56
+ @dataclass
57
+ class RouteStatusCase:
58
+ route: str
59
+ description: str
60
+ request: dict[str, Any]
61
+ response: dict[str, Any]
62
+ status: dict[str, Any]
63
+ marks: Marks = ()
64
+
65
+ @property
66
+ def id(self) -> str:
67
+ return f"{self.route}: {self.description}"
68
+
69
+
70
+ @dataclass
71
+ class WalletAddressCase:
72
+ id: str
73
+ request: dict[str, Any]
74
+ response: dict[str, Any]
75
+ pubkeys_only: bool = field(default=False)
76
+ marks: Marks = ()
77
+
78
+
79
+ @dataclass
80
+ class KeysForPlotCase:
81
+ id: str
82
+ request: dict[str, Any]
83
+ response: dict[str, Any]
84
+ marks: Marks = ()
85
+
86
+
87
+ @dataclass
88
+ class ChiaPlottersBladebitArgsCase:
89
+ case_id: str
90
+ plot_type: str
91
+ count: int = 1
92
+ threads: int = 0
93
+ pool_contract: str = "txch1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
94
+ compress: int = 1
95
+ device: int = 0
96
+ hybrid_disk_mode: Optional[int] = None
97
+ farmer_pk: str = ""
98
+ final_dir: str = ""
99
+ marks: Marks = ()
100
+
101
+ @property
102
+ def id(self) -> str:
103
+ return self.case_id
104
+
105
+ def to_command_array(self) -> list[str]:
106
+ command: list[str] = ["bladebit", self.plot_type]
107
+ command += ["-r", str(self.threads)]
108
+ command += ["-n", str(self.count)]
109
+ command += ["-c", self.pool_contract]
110
+ command += ["-f", self.farmer_pk]
111
+ command += ["--compress", str(self.compress)]
112
+ if self.plot_type == "cudaplot":
113
+ command += ["--device", str(self.device)]
114
+ if self.hybrid_disk_mode is not None:
115
+ command += [f"--disk-{self.hybrid_disk_mode}"]
116
+ command += ["-d", str(self.final_dir)]
117
+
118
+ return command
119
+
120
+ def expected_raw_command_args(self):
121
+ raw_args = []
122
+ raw_args += [
123
+ "--threads",
124
+ str(self.threads),
125
+ "--count",
126
+ str(self.count),
127
+ "--farmer-key",
128
+ str(self.farmer_pk),
129
+ "--pool-contract",
130
+ str(self.pool_contract),
131
+ ]
132
+ # --compress is "1" by default
133
+ raw_args += ["--compress", str(self.compress) if self.compress is not None else "1"]
134
+ raw_args += [self.plot_type]
135
+ if self.plot_type == "cudaplot":
136
+ # --device is "0" by default
137
+ raw_args += ["--device", str(self.device) if self.device is not None else "0"]
138
+ if self.hybrid_disk_mode is not None:
139
+ raw_args += [f"--disk-{self.hybrid_disk_mode}"]
140
+ raw_args += [str(self.final_dir)]
141
+ return raw_args
142
+
143
+
144
+ # Simple class that responds to a poll() call used by WebSocketServer.is_running()
145
+ @dataclass
146
+ class Service:
147
+ running: bool
148
+
149
+ def poll(self) -> Optional[int]:
150
+ return None if self.running else 1
151
+
152
+
153
+ # Mock daemon server that forwards to WebSocketServer
154
+ @dataclass
155
+ class Daemon:
156
+ # Instance variables used by WebSocketServer.is_running()
157
+ services: dict[str, Union[list[Service], Service]]
158
+ connections: dict[str, Optional[list[Any]]]
159
+
160
+ # Instance variables used by WebSocketServer.get_wallet_addresses()
161
+ net_config: dict[str, Any] = field(default_factory=dict)
162
+
163
+ def get_command_mapping(self) -> dict[str, Any]:
164
+ return {
165
+ "get_routes": None,
166
+ "example_one": None,
167
+ "example_two": None,
168
+ "example_three": None,
169
+ }
170
+
171
+ def is_service_running(self, service_name: str) -> bool:
172
+ return WebSocketServer.is_service_running(cast(WebSocketServer, self), service_name)
173
+
174
+ async def running_services(self) -> dict[str, Any]:
175
+ return await WebSocketServer.running_services(cast(WebSocketServer, self))
176
+
177
+ async def is_running(self, request: dict[str, Any]) -> dict[str, Any]:
178
+ return await WebSocketServer.is_running(cast(WebSocketServer, self), request)
179
+
180
+ async def get_routes(self, request: dict[str, Any]) -> dict[str, Any]:
181
+ return await WebSocketServer.get_routes(
182
+ cast(WebSocketServer, self), websocket=WebSocketResponse(), request=request
183
+ )
184
+
185
+ async def get_wallet_addresses(self, request: dict[str, Any]) -> dict[str, Any]:
186
+ return await WebSocketServer.get_wallet_addresses(
187
+ cast(WebSocketServer, self), websocket=WebSocketResponse(), request=request
188
+ )
189
+
190
+ async def get_keys_for_plotting(self, request: dict[str, Any]) -> dict[str, Any]:
191
+ return await WebSocketServer.get_keys_for_plotting(
192
+ cast(WebSocketServer, self), websocket=WebSocketResponse(), request=request
193
+ )
194
+
195
+
196
+ test_key_data = KeyData.from_mnemonic(
197
+ "grief lock ketchup video day owner torch young work "
198
+ "another venue evidence spread season bright private "
199
+ "tomato remind jaguar original blur embody project can"
200
+ )
201
+ test_key_data_no_secrets = replace(test_key_data, secrets=None)
202
+
203
+ test_key_data_2 = KeyData.from_mnemonic(
204
+ "banana boat fragile ghost fortune beyond aerobic access "
205
+ "hammer stable page grunt venture purse canyon discover "
206
+ "egg vivid spare immune awake code announce message"
207
+ )
208
+
209
+ success_response_data = {
210
+ "success": True,
211
+ }
212
+
213
+ plotter_request_ref = {
214
+ "service": "chia_plotter",
215
+ "plotter": "chiapos",
216
+ "k": 25,
217
+ "r": 2,
218
+ "u": 128,
219
+ "e": True,
220
+ "parallel": False,
221
+ "n": 1,
222
+ "queue": "default",
223
+ "d": "unknown",
224
+ "t": "unknown",
225
+ "t2": "",
226
+ "f": "",
227
+ "plotNFTContractAddr": "",
228
+ "x": True,
229
+ "b": 512,
230
+ "overrideK": True,
231
+ "delay": 0,
232
+ "a": 3598820529,
233
+ "c": "xxx",
234
+ }
235
+
236
+
237
+ def add_private_key_response_data(fingerprint: int) -> dict[str, object]:
238
+ return {
239
+ "success": True,
240
+ "fingerprint": fingerprint,
241
+ }
242
+
243
+
244
+ def fingerprint_missing_response_data(request_type: type[object]) -> dict[str, object]:
245
+ return {
246
+ "success": False,
247
+ "error": "malformed request",
248
+ "error_details": {"message": f"1 field missing for {request_type.__name__}: fingerprint"},
249
+ }
250
+
251
+
252
+ def fingerprint_not_found_response_data(fingerprint: int) -> dict[str, object]:
253
+ return {
254
+ "success": False,
255
+ "error": "key not found",
256
+ "error_details": {
257
+ "fingerprint": fingerprint,
258
+ },
259
+ }
260
+
261
+
262
+ def get_key_response_data(key: KeyData) -> dict[str, object]:
263
+ return {"success": True, **GetKeyResponse(key=key).to_json_dict()}
264
+
265
+
266
+ def get_keys_response_data(keys: list[KeyData]) -> dict[str, object]:
267
+ return {"success": True, **GetKeysResponse(keys=keys).to_json_dict()}
268
+
269
+
270
+ def get_public_key_response_data(key: KeyData) -> dict[str, object]:
271
+ return {"success": True, **GetPublicKeyResponse(key=key).to_json_dict()}
272
+
273
+
274
+ def get_public_keys_response_data(keys: list[KeyData]) -> dict[str, object]:
275
+ return {"success": True, **GetPublicKeysResponse(keys=keys).to_json_dict()}
276
+
277
+
278
+ def label_missing_response_data(request_type: type[Any]) -> dict[str, Any]:
279
+ return {
280
+ "success": False,
281
+ "error": "malformed request",
282
+ "error_details": {"message": f"1 field missing for {request_type.__name__}: label"},
283
+ }
284
+
285
+
286
+ def label_exists_response_data(fingerprint: int, label: str) -> dict[str, Any]:
287
+ return {
288
+ "success": False,
289
+ "error": "malformed request",
290
+ "error_details": {"message": f"label {label!r} already exists for fingerprint {str(fingerprint)!r}"},
291
+ }
292
+
293
+
294
+ label_empty_response_data = {
295
+ "success": False,
296
+ "error": "malformed request",
297
+ "error_details": {"message": "label can't be empty or whitespace only"},
298
+ }
299
+
300
+ label_too_long_response_data = {
301
+ "success": False,
302
+ "error": "malformed request",
303
+ "error_details": {"message": "label exceeds max length: 66/65"},
304
+ }
305
+
306
+ label_newline_or_tab_response_data = {
307
+ "success": False,
308
+ "error": "malformed request",
309
+ "error_details": {"message": "label can't contain newline or tab"},
310
+ }
311
+
312
+
313
+ def assert_response(
314
+ response: aiohttp.http_websocket.WSMessage,
315
+ expected_response_data: dict[str, Any],
316
+ request_id: Optional[str] = None,
317
+ ack: bool = True,
318
+ command: Optional[str] = None,
319
+ ) -> None:
320
+ # Expect: JSON response
321
+ assert response.type == aiohttp.WSMsgType.TEXT
322
+ message = json.loads(response.data.strip())
323
+ # Expect: daemon handled the request
324
+ assert message["ack"] is ack
325
+ if request_id is not None:
326
+ assert message["request_id"] == request_id
327
+ if command is not None:
328
+ assert message["command"] == command
329
+ # Expect: data matches the expected data
330
+ assert message["data"] == expected_response_data
331
+
332
+
333
+ def assert_response_success_only(
334
+ response: aiohttp.http_websocket.WSMessage, request_id: Optional[str] = None
335
+ ) -> dict[str, Any]:
336
+ # Expect: JSON response
337
+ assert response.type == aiohttp.WSMsgType.TEXT
338
+ message = json.loads(response.data.strip())
339
+ # Expect: {"success": True}
340
+ if request_id is not None:
341
+ assert message["request_id"] == request_id
342
+ assert message["data"]["success"] is True
343
+ return message
344
+
345
+
346
+ def assert_running_services_response(response_dict: dict[str, Any], expected_response_dict: dict[str, Any]) -> None:
347
+ for k, v in expected_response_dict.items():
348
+ if k == "running_services":
349
+ # Order of services is not guaranteed
350
+ assert len(response_dict[k]) == len(v)
351
+ assert set(response_dict[k]) == set(v)
352
+ else:
353
+ assert response_dict[k] == v
354
+
355
+
356
+ @pytest.fixture(scope="session")
357
+ def mock_lonely_daemon():
358
+ # Mock daemon server without any registered services/connections
359
+ return Daemon(services={}, connections={}, net_config={})
360
+
361
+
362
+ @pytest.fixture(scope="session")
363
+ def mock_daemon_with_services():
364
+ # Mock daemon server with a couple running services, a plotter, and one stopped service
365
+ return Daemon(
366
+ services={
367
+ "my_refrigerator": [Service(True)],
368
+ "the_river": [Service(True)],
369
+ "your_nose": [Service(False)],
370
+ "chia_plotter": [Service(True), Service(True)],
371
+ },
372
+ connections={},
373
+ net_config={},
374
+ )
375
+
376
+
377
+ @pytest.fixture(scope="session")
378
+ def mock_daemon_with_services_and_connections():
379
+ # Mock daemon server with a couple running services, a plotter, and a couple active connections
380
+ return Daemon(
381
+ services={
382
+ "my_refrigerator": [Service(True)],
383
+ "chia_plotter": [Service(True), Service(True)],
384
+ "apple": [Service(True)],
385
+ },
386
+ connections={
387
+ "apple": [1],
388
+ "banana": [1, 2],
389
+ },
390
+ net_config={},
391
+ )
392
+
393
+
394
+ @pytest.fixture(scope="function")
395
+ def get_keychain_for_function():
396
+ with TempKeyring() as keychain:
397
+ yield keychain
398
+ KeyringWrapper.cleanup_shared_instance()
399
+
400
+
401
+ @pytest.fixture(scope="function")
402
+ def mock_daemon_with_config_and_keys(get_keychain_for_function, root_path_populated_with_config):
403
+ root_path = root_path_populated_with_config
404
+ config = load_config(root_path, "config.yaml")
405
+ keychain = Keychain()
406
+
407
+ # populate the keychain with some test keys
408
+ keychain.add_key(test_key_data.mnemonic_str())
409
+ keychain.add_key(test_key_data_2.mnemonic_str())
410
+
411
+ # Throw in an unused pubkey-only entry
412
+ keychain.add_key(bytes(G1Element()).hex(), private=False)
413
+
414
+ # Mock daemon server with net_config set for mainnet
415
+ return Daemon(services={}, connections={}, net_config=config)
416
+
417
+
418
+ @pytest.fixture(scope="function")
419
+ async def daemon_client_with_config_and_keys(get_keychain_for_function, get_daemon, bt):
420
+ keychain = Keychain()
421
+
422
+ # populate the keychain with some test keys
423
+ keychain.add_key(test_key_data.mnemonic_str())
424
+ keychain.add_key(test_key_data_2.mnemonic_str())
425
+
426
+ daemon = get_daemon
427
+ client = await connect_to_daemon(
428
+ daemon.self_hostname,
429
+ daemon.daemon_port,
430
+ 50 * 1000 * 1000,
431
+ bt.get_daemon_ssl_context(),
432
+ heartbeat=daemon.heartbeat,
433
+ )
434
+ return client
435
+
436
+
437
+ @pytest.mark.anyio
438
+ async def test_daemon_passthru(get_daemon, bt):
439
+ ws_server = get_daemon
440
+ config = bt.config
441
+ daemon_port = config["daemon_port"]
442
+
443
+ async with aiohttp.ClientSession() as client:
444
+ async with client.ws_connect(
445
+ f"wss://127.0.0.1:{daemon_port}",
446
+ autoclose=True,
447
+ autoping=True,
448
+ ssl=bt.get_daemon_ssl_context(),
449
+ max_msg_size=100 * 1024 * 1024,
450
+ ) as ws:
451
+ service_name = "test_service_name"
452
+ data = {"service": service_name}
453
+ payload = create_payload("register_service", data, service_name, "daemon")
454
+ await ws.send_str(payload)
455
+ assert_response_success_only(await ws.receive())
456
+
457
+ async with setup_full_node(
458
+ consensus_constants=bt.constants,
459
+ db_name="sim-test.db",
460
+ self_hostname="localhost",
461
+ local_bt=bt,
462
+ simulator=False,
463
+ db_version=2,
464
+ connect_to_daemon=True,
465
+ ) as _:
466
+ await time_out_assert_not_none(30, ws_server.connections.get, "chia_full_node")
467
+
468
+ payload = create_payload("get_blockchain_state", {}, service_name, "chia_full_node")
469
+ await ws.send_str(payload)
470
+
471
+ response = await ws.receive()
472
+ message = assert_response_success_only(response)
473
+ assert message["command"] == "get_blockchain_state"
474
+ assert message["origin"] == "chia_full_node"
475
+ assert message["data"]["blockchain_state"]["genesis_challenge_initialized"] is True
476
+
477
+
478
+ @pytest.mark.parametrize(
479
+ "service, expected_result",
480
+ [
481
+ (
482
+ "my_refrigerator",
483
+ False,
484
+ ),
485
+ (
486
+ service_plotter,
487
+ False,
488
+ ),
489
+ ],
490
+ )
491
+ def test_is_service_running_no_services(mock_lonely_daemon, service, expected_result):
492
+ daemon = mock_lonely_daemon
493
+ assert daemon.is_service_running(service) == expected_result
494
+
495
+
496
+ @pytest.mark.parametrize(
497
+ "service, expected_result",
498
+ [
499
+ (
500
+ "my_refrigerator",
501
+ True,
502
+ ),
503
+ (
504
+ service_plotter,
505
+ True,
506
+ ),
507
+ (
508
+ "your_nose",
509
+ False,
510
+ ),
511
+ (
512
+ "the_river",
513
+ True,
514
+ ),
515
+ (
516
+ "the_clock",
517
+ False,
518
+ ),
519
+ ],
520
+ )
521
+ def test_is_service_running_with_services(mock_daemon_with_services, service, expected_result):
522
+ daemon = mock_daemon_with_services
523
+ assert daemon.is_service_running(service) == expected_result
524
+
525
+
526
+ @pytest.mark.parametrize(
527
+ "service, expected_result",
528
+ [
529
+ (
530
+ "my_refrigerator",
531
+ True,
532
+ ),
533
+ (
534
+ service_plotter,
535
+ True,
536
+ ),
537
+ (
538
+ "apple",
539
+ True,
540
+ ),
541
+ (
542
+ "banana",
543
+ True,
544
+ ),
545
+ (
546
+ "orange",
547
+ False,
548
+ ),
549
+ ],
550
+ )
551
+ def test_is_service_running_with_services_and_connections(
552
+ mock_daemon_with_services_and_connections, service, expected_result
553
+ ):
554
+ daemon = mock_daemon_with_services_and_connections
555
+ assert daemon.is_service_running(service) == expected_result
556
+
557
+
558
+ @pytest.mark.anyio
559
+ async def test_running_services_no_services(mock_lonely_daemon):
560
+ daemon = mock_lonely_daemon
561
+ response = await daemon.running_services()
562
+ assert_running_services_response(response, {"success": True, "running_services": []})
563
+
564
+
565
+ @pytest.mark.anyio
566
+ async def test_running_services_with_services(mock_daemon_with_services):
567
+ daemon = mock_daemon_with_services
568
+ response = await daemon.running_services()
569
+ assert_running_services_response(
570
+ response, {"success": True, "running_services": ["my_refrigerator", "the_river", service_plotter]}
571
+ )
572
+
573
+
574
+ @pytest.mark.anyio
575
+ async def test_running_services_with_services_and_connections(mock_daemon_with_services_and_connections):
576
+ daemon = mock_daemon_with_services_and_connections
577
+ response = await daemon.running_services()
578
+ assert_running_services_response(
579
+ response, {"success": True, "running_services": ["my_refrigerator", "apple", "banana", service_plotter]}
580
+ )
581
+
582
+
583
+ @pytest.mark.anyio
584
+ async def test_get_routes(mock_lonely_daemon):
585
+ daemon = mock_lonely_daemon
586
+ response = await daemon.get_routes({})
587
+ assert response == {
588
+ "success": True,
589
+ "routes": ["get_routes", "example_one", "example_two", "example_three"],
590
+ }
591
+
592
+
593
+ @pytest.mark.anyio
594
+ async def test_get_network_info(daemon_client_with_config_and_keys: DaemonProxy):
595
+ client = daemon_client_with_config_and_keys
596
+ response = await client.get_network_info()
597
+ assert response["data"] == {
598
+ "success": True,
599
+ "network_name": "testnet0",
600
+ "network_prefix": "txch",
601
+ "genesis_challenge": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
602
+ }
603
+
604
+
605
+ @datacases(
606
+ WalletAddressCase(
607
+ id="no params",
608
+ request={},
609
+ response={
610
+ "success": True,
611
+ "wallet_addresses": {
612
+ G1Element().get_fingerprint(): [
613
+ {
614
+ "address": "xch1dr2sj4jqdt6nj4l32d4f5dk7mrwak3qw5hsykty5lhhd00053y0szaz8zj",
615
+ "hd_path": "m/12381/8444/2/0",
616
+ }
617
+ ],
618
+ test_key_data.fingerprint: [
619
+ {
620
+ "address": "xch1zze67l3jgxuvyaxhjhu7326sezxxve7lgzvq0497ddggzhff7c9s2pdcwh",
621
+ "hd_path": "m/12381/8444/2/0",
622
+ },
623
+ ],
624
+ test_key_data_2.fingerprint: [
625
+ {
626
+ "address": "xch1fra5h0qnsezrxenjyslyxx7y4l268gq52m0rgenh58vn8f577uzswzvk4v",
627
+ "hd_path": "m/12381/8444/2/0",
628
+ }
629
+ ],
630
+ },
631
+ },
632
+ ),
633
+ WalletAddressCase(
634
+ id="list of fingerprints",
635
+ request={"fingerprints": [test_key_data.fingerprint]},
636
+ response={
637
+ "success": True,
638
+ "wallet_addresses": {
639
+ test_key_data.fingerprint: [
640
+ {
641
+ "address": "xch1zze67l3jgxuvyaxhjhu7326sezxxve7lgzvq0497ddggzhff7c9s2pdcwh",
642
+ "hd_path": "m/12381/8444/2/0",
643
+ },
644
+ ],
645
+ },
646
+ },
647
+ ),
648
+ WalletAddressCase(
649
+ id="count and index",
650
+ request={"fingerprints": [test_key_data.fingerprint], "count": 2, "index": 1},
651
+ response={
652
+ "success": True,
653
+ "wallet_addresses": {
654
+ test_key_data.fingerprint: [
655
+ {
656
+ "address": "xch16jqcaguq27z8xvpu89j7eaqfzn6k89hdrrlm0rffku85n8n7m7sqqmmahh",
657
+ "hd_path": "m/12381/8444/2/1",
658
+ },
659
+ {
660
+ "address": "xch1955vj0gx5tqe7v5tceajn2p4z4pup8d4g2exs0cz4xjqses8ru6qu8zp3y",
661
+ "hd_path": "m/12381/8444/2/2",
662
+ },
663
+ ]
664
+ },
665
+ },
666
+ ),
667
+ WalletAddressCase(
668
+ id="hardened derivations",
669
+ request={"fingerprints": [test_key_data.fingerprint], "non_observer_derivation": True},
670
+ response={
671
+ "success": True,
672
+ "wallet_addresses": {
673
+ test_key_data.fingerprint: [
674
+ {
675
+ "address": "xch1k996a7h3agygjhqtrf0ycpa7wfd6k5ye2plkf54ukcmdj44gkqkq880l7n",
676
+ "hd_path": "m/12381n/8444n/2n/0n",
677
+ }
678
+ ]
679
+ },
680
+ },
681
+ ),
682
+ WalletAddressCase(
683
+ id="invalid fingerprint",
684
+ request={"fingerprints": [999999]},
685
+ response={
686
+ "success": False,
687
+ "error": "key(s) not found for fingerprint(s) {999999}",
688
+ },
689
+ ),
690
+ WalletAddressCase(
691
+ id="missing private key hardened",
692
+ request={"fingerprints": [test_key_data.fingerprint], "non_observer_derivation": True},
693
+ response={
694
+ "success": False,
695
+ "error": f"missing private key for key with fingerprint {test_key_data.fingerprint}",
696
+ },
697
+ pubkeys_only=True,
698
+ ),
699
+ WalletAddressCase(
700
+ id="missing private key unhardened",
701
+ request={"fingerprints": [test_key_data.fingerprint]},
702
+ response={
703
+ "success": True,
704
+ "wallet_addresses": {
705
+ test_key_data.fingerprint: [
706
+ {
707
+ "address": "xch1zze67l3jgxuvyaxhjhu7326sezxxve7lgzvq0497ddggzhff7c9s2pdcwh",
708
+ "hd_path": "m/12381/8444/2/0",
709
+ },
710
+ ],
711
+ },
712
+ },
713
+ pubkeys_only=True,
714
+ ),
715
+ )
716
+ @pytest.mark.anyio
717
+ async def test_get_wallet_addresses(
718
+ mock_daemon_with_config_and_keys,
719
+ monkeypatch,
720
+ case: WalletAddressCase,
721
+ ):
722
+ daemon = mock_daemon_with_config_and_keys
723
+
724
+ original_get_keys = Keychain.get_keys
725
+
726
+ def get_keys_no_secrets(self, include_secrets):
727
+ return original_get_keys(self, include_secrets=False)
728
+
729
+ # in the pubkeys_only case, we're ensuring that only pubkeys are returned by get_keys,
730
+ # which will have the effect of causing get_wallet_addresses to raise an exception
731
+ if case.pubkeys_only:
732
+ # monkeypatch Keychain.get_keys() to always call get_keys() with include_secrets=False
733
+ monkeypatch.setattr(Keychain, "get_keys", get_keys_no_secrets)
734
+
735
+ assert case.response == await daemon.get_wallet_addresses(case.request)
736
+
737
+
738
+ @datacases(
739
+ KeysForPlotCase(
740
+ id="no params",
741
+ # When not specifying exact fingerprints, `get_keys_for_plotting` returns
742
+ # all farmer_pk/pool_pk data for available fingerprints
743
+ request={},
744
+ response={
745
+ "success": True,
746
+ "keys": {
747
+ test_key_data.fingerprint: {
748
+ "farmer_public_key": bytes(master_sk_to_farmer_sk(test_key_data.private_key).get_g1()).hex(),
749
+ "pool_public_key": bytes(master_sk_to_pool_sk(test_key_data.private_key).get_g1()).hex(),
750
+ },
751
+ test_key_data_2.fingerprint: {
752
+ "farmer_public_key": bytes(master_sk_to_farmer_sk(test_key_data_2.private_key).get_g1()).hex(),
753
+ "pool_public_key": bytes(master_sk_to_pool_sk(test_key_data_2.private_key).get_g1()).hex(),
754
+ },
755
+ },
756
+ },
757
+ ),
758
+ KeysForPlotCase(
759
+ id="list of fingerprints",
760
+ request={"fingerprints": [test_key_data.fingerprint]},
761
+ response={
762
+ "success": True,
763
+ "keys": {
764
+ test_key_data.fingerprint: {
765
+ "farmer_public_key": bytes(master_sk_to_farmer_sk(test_key_data.private_key).get_g1()).hex(),
766
+ "pool_public_key": bytes(master_sk_to_pool_sk(test_key_data.private_key).get_g1()).hex(),
767
+ },
768
+ },
769
+ },
770
+ ),
771
+ KeysForPlotCase(
772
+ id="invalid fingerprint",
773
+ request={"fingerprints": [999999]},
774
+ response={
775
+ "success": False,
776
+ "error": "key(s) not found for fingerprint(s) {999999}",
777
+ },
778
+ ),
779
+ )
780
+ @pytest.mark.anyio
781
+ async def test_get_keys_for_plotting(
782
+ mock_daemon_with_config_and_keys,
783
+ monkeypatch,
784
+ case: KeysForPlotCase,
785
+ ):
786
+ daemon = mock_daemon_with_config_and_keys
787
+ assert case.response == await daemon.get_keys_for_plotting(case.request)
788
+
789
+
790
+ @datacases(
791
+ KeysForPlotCase(
792
+ id="invalid request format",
793
+ request={"fingerprints": test_key_data.fingerprint},
794
+ response={},
795
+ ),
796
+ )
797
+ @pytest.mark.anyio
798
+ async def test_get_keys_for_plotting_error(
799
+ mock_daemon_with_config_and_keys,
800
+ monkeypatch,
801
+ case: KeysForPlotCase,
802
+ ):
803
+ daemon = mock_daemon_with_config_and_keys
804
+ with pytest.raises(ValueError, match="fingerprints must be a list of integer"):
805
+ await daemon.get_keys_for_plotting(case.request)
806
+
807
+
808
+ @pytest.mark.anyio
809
+ async def test_get_keys_for_plotting_client(daemon_client_with_config_and_keys):
810
+ client = daemon_client_with_config_and_keys
811
+ response = await client.get_keys_for_plotting()
812
+ assert response["data"]["success"] is True
813
+ assert len(response["data"]["keys"]) == 2
814
+ assert str(test_key_data.fingerprint) in response["data"]["keys"]
815
+ assert str(test_key_data_2.fingerprint) in response["data"]["keys"]
816
+ response = await client.get_keys_for_plotting([test_key_data.fingerprint])
817
+ assert response["data"]["success"] is True
818
+ assert len(response["data"]["keys"]) == 1
819
+ assert str(test_key_data.fingerprint) in response["data"]["keys"]
820
+ assert str(test_key_data_2.fingerprint) not in response["data"]["keys"]
821
+ await client.close()
822
+
823
+
824
+ @pytest.mark.anyio
825
+ @pytest.mark.parametrize(
826
+ "service_request, expected_result, expected_exception",
827
+ [
828
+ ({}, None, KeyError),
829
+ (
830
+ {"service": "my_refrigerator"},
831
+ {"success": True, "service_name": "my_refrigerator", "is_running": False},
832
+ None,
833
+ ),
834
+ ],
835
+ )
836
+ async def test_is_running_no_services(mock_lonely_daemon, service_request, expected_result, expected_exception):
837
+ daemon = mock_lonely_daemon
838
+ if expected_exception is not None:
839
+ with pytest.raises(expected_exception):
840
+ await daemon.is_running(service_request)
841
+ else:
842
+ response = await daemon.is_running(service_request)
843
+ assert response == expected_result
844
+
845
+
846
+ @pytest.mark.anyio
847
+ @pytest.mark.parametrize(
848
+ "service_request, expected_result, expected_exception",
849
+ [
850
+ ({}, None, KeyError),
851
+ (
852
+ {"service": "my_refrigerator"},
853
+ {"success": True, "service_name": "my_refrigerator", "is_running": True},
854
+ None,
855
+ ),
856
+ (
857
+ {"service": "your_nose"},
858
+ {"success": True, "service_name": "your_nose", "is_running": False},
859
+ None,
860
+ ),
861
+ (
862
+ {"service": "the_river"},
863
+ {"success": True, "service_name": "the_river", "is_running": True},
864
+ None,
865
+ ),
866
+ (
867
+ {"service": service_plotter},
868
+ {"success": True, "service_name": service_plotter, "is_running": True},
869
+ None,
870
+ ),
871
+ ],
872
+ )
873
+ async def test_is_running_with_services(
874
+ mock_daemon_with_services, service_request, expected_result, expected_exception
875
+ ):
876
+ daemon = mock_daemon_with_services
877
+ if expected_exception is not None:
878
+ with pytest.raises(expected_exception):
879
+ await daemon.is_running(service_request)
880
+ else:
881
+ response = await daemon.is_running(service_request)
882
+ assert response == expected_result
883
+
884
+
885
+ @pytest.mark.anyio
886
+ @pytest.mark.parametrize(
887
+ "service_request, expected_result, expected_exception",
888
+ [
889
+ ({}, None, KeyError),
890
+ (
891
+ {"service": "my_refrigerator"},
892
+ {"success": True, "service_name": "my_refrigerator", "is_running": True},
893
+ None,
894
+ ),
895
+ (
896
+ {"service": "your_nose"},
897
+ {"success": True, "service_name": "your_nose", "is_running": False},
898
+ None,
899
+ ),
900
+ (
901
+ {"service": "apple"},
902
+ {"success": True, "service_name": "apple", "is_running": True},
903
+ None,
904
+ ),
905
+ (
906
+ {"service": "banana"},
907
+ {"success": True, "service_name": "banana", "is_running": True},
908
+ None,
909
+ ),
910
+ (
911
+ {"service": "orange"},
912
+ {"success": True, "service_name": "orange", "is_running": False},
913
+ None,
914
+ ),
915
+ ],
916
+ )
917
+ async def test_is_running_with_services_and_connections(
918
+ mock_daemon_with_services_and_connections, service_request, expected_result, expected_exception
919
+ ):
920
+ daemon = mock_daemon_with_services_and_connections
921
+ if expected_exception is not None:
922
+ with pytest.raises(expected_exception):
923
+ await daemon.is_running(service_request)
924
+ else:
925
+ response = await daemon.is_running(service_request)
926
+ assert response == expected_result
927
+
928
+
929
+ @pytest.mark.anyio
930
+ async def test_validate_keyring_passphrase_rpc(daemon_connection_and_temp_keychain):
931
+ ws, keychain = daemon_connection_and_temp_keychain
932
+
933
+ # When: the keychain has a master passphrase set
934
+ keychain.set_master_passphrase(
935
+ current_passphrase=DEFAULT_PASSPHRASE_IF_NO_MASTER_PASSPHRASE, new_passphrase="the correct passphrase"
936
+ )
937
+
938
+ bad_passphrase_case_response_data = {
939
+ "success": False,
940
+ "error": None,
941
+ }
942
+
943
+ missing_passphrase_response_data = {
944
+ "success": False,
945
+ "error": "missing key",
946
+ }
947
+
948
+ empty_passphrase_response_data = {
949
+ "success": False,
950
+ "error": None,
951
+ }
952
+
953
+ # When: using the correct passphrase
954
+ await ws.send_str(
955
+ create_payload("validate_keyring_passphrase", {"key": "the correct passphrase"}, "test", "daemon")
956
+ )
957
+ # Expect: validation succeeds
958
+ # TODO: unify error responses in the server, sometimes we add `error: None` sometimes not.
959
+ assert_response(await ws.receive(), {**success_response_data, "error": None})
960
+
961
+ # When: using the wrong passphrase
962
+ await ws.send_str(create_payload("validate_keyring_passphrase", {"key": "the wrong passphrase"}, "test", "daemon"))
963
+ # Expect: validation failure
964
+ assert_response(await ws.receive(), bad_passphrase_case_response_data)
965
+
966
+ # When: not including the passphrase in the payload
967
+ await ws.send_str(create_payload("validate_keyring_passphrase", {}, "test", "daemon"))
968
+ # Expect: validation failure
969
+ assert_response(await ws.receive(), missing_passphrase_response_data)
970
+
971
+ # When: including an empty passphrase in the payload
972
+ await ws.send_str(create_payload("validate_keyring_passphrase", {"key": ""}, "test", "daemon"))
973
+ # Expect: validation failure
974
+ assert_response(await ws.receive(), empty_passphrase_response_data)
975
+
976
+
977
+ @pytest.mark.anyio
978
+ async def test_add_private_key(daemon_connection_and_temp_keychain):
979
+ ws, keychain = daemon_connection_and_temp_keychain
980
+
981
+ mnemonic_with_typo = f"{test_key_data.mnemonic_str()}xyz" # intentional typo: can -> canxyz
982
+ mnemonic_with_missing_word = " ".join(test_key_data.mnemonic_str()[:-1]) # missing last word
983
+
984
+ missing_mnemonic_response_data = {
985
+ "success": False,
986
+ "error": "malformed request",
987
+ "error_details": {"message": "missing key information"},
988
+ }
989
+
990
+ mnemonic_with_typo_response_data = {
991
+ "success": False,
992
+ "error": "'canxyz' is not in the mnemonic dictionary; may be misspelled",
993
+ }
994
+
995
+ invalid_mnemonic_length_response_data = {
996
+ "success": False,
997
+ "error": "Invalid mnemonic length",
998
+ }
999
+
1000
+ invalid_mnemonic_response_data = {
1001
+ "success": False,
1002
+ "error": "Invalid order of mnemonic words",
1003
+ }
1004
+
1005
+ # Expect the key hasn't been added yet
1006
+ assert keychain.get_private_key_by_fingerprint(test_key_data.fingerprint) is None
1007
+
1008
+ await ws.send_str(create_payload("add_private_key", {"mnemonic": test_key_data.mnemonic_str()}, "test", "daemon"))
1009
+ # Expect: key was added successfully
1010
+ assert_response(await ws.receive(), add_private_key_response_data(test_key_data.fingerprint))
1011
+
1012
+ # When: missing mnemonic
1013
+ await ws.send_str(create_payload("add_private_key", {}, "test", "daemon"))
1014
+ # Expect: Failure due to missing mnemonic
1015
+ assert_response(await ws.receive(), missing_mnemonic_response_data)
1016
+
1017
+ # When: using a mmnemonic with an incorrect word (typo)
1018
+ await ws.send_str(create_payload("add_private_key", {"mnemonic": mnemonic_with_typo}, "test", "daemon"))
1019
+ # Expect: Failure due to misspelled mnemonic
1020
+ assert_response(await ws.receive(), mnemonic_with_typo_response_data)
1021
+
1022
+ # When: using a mnemonic with an incorrect word count
1023
+ await ws.send_str(create_payload("add_private_key", {"mnemonic": mnemonic_with_missing_word}, "test", "daemon"))
1024
+ # Expect: Failure due to invalid mnemonic
1025
+ assert_response(await ws.receive(), invalid_mnemonic_length_response_data)
1026
+
1027
+ # When: using an incorrect mnemnonic
1028
+ await ws.send_str(create_payload("add_private_key", {"mnemonic": " ".join(["abandon"] * 24)}, "test", "daemon"))
1029
+ # Expect: Failure due to checksum error
1030
+ assert_response(await ws.receive(), invalid_mnemonic_response_data)
1031
+
1032
+
1033
+ @pytest.mark.anyio
1034
+ async def test_add_private_key_label(daemon_connection_and_temp_keychain):
1035
+ ws, _keychain = daemon_connection_and_temp_keychain
1036
+
1037
+ async def assert_add_private_key_with_label(
1038
+ key_data: KeyData, request: dict[str, object], add_private_key_response: dict[str, object]
1039
+ ) -> None:
1040
+ await ws.send_str(create_payload("add_private_key", request, "test", "daemon"))
1041
+ assert_response(await ws.receive(), add_private_key_response)
1042
+ await ws.send_str(
1043
+ create_payload("get_key", {"fingerprint": key_data.fingerprint, "include_secrets": True}, "test", "daemon")
1044
+ )
1045
+ assert_response(await ws.receive(), get_key_response_data(key_data))
1046
+
1047
+ # without `label` parameter
1048
+ key_data_0 = KeyData.generate()
1049
+ await assert_add_private_key_with_label(
1050
+ key_data_0,
1051
+ {"mnemonic": key_data_0.mnemonic_str()},
1052
+ add_private_key_response_data(key_data_0.fingerprint),
1053
+ )
1054
+ # with `label=None`
1055
+ key_data_1 = KeyData.generate()
1056
+ await assert_add_private_key_with_label(
1057
+ key_data_1,
1058
+ {"mnemonic": key_data_1.mnemonic_str(), "label": None},
1059
+ add_private_key_response_data(key_data_1.fingerprint),
1060
+ )
1061
+ # with `label="key_2"`
1062
+ key_data_2 = KeyData.generate("key_2")
1063
+ await assert_add_private_key_with_label(
1064
+ key_data_1,
1065
+ {"mnemonic": key_data_2.mnemonic_str(), "label": key_data_2.label},
1066
+ add_private_key_response_data(key_data_2.fingerprint),
1067
+ )
1068
+
1069
+
1070
+ @pytest.mark.anyio
1071
+ async def test_get_key(daemon_connection_and_temp_keychain):
1072
+ ws, keychain = daemon_connection_and_temp_keychain
1073
+
1074
+ await ws.send_str(create_payload("get_key", {"fingerprint": test_key_data.fingerprint}, "test", "daemon"))
1075
+ assert_response(await ws.receive(), fingerprint_not_found_response_data(test_key_data.fingerprint))
1076
+
1077
+ keychain.add_key(test_key_data.mnemonic_str())
1078
+
1079
+ # without `include_secrets`
1080
+ await ws.send_str(create_payload("get_key", {"fingerprint": test_key_data.fingerprint}, "test", "daemon"))
1081
+ assert_response(await ws.receive(), get_key_response_data(test_key_data_no_secrets))
1082
+
1083
+ # with `include_secrets=False`
1084
+ await ws.send_str(
1085
+ create_payload(
1086
+ "get_key", {"fingerprint": test_key_data.fingerprint, "include_secrets": False}, "test", "daemon"
1087
+ )
1088
+ )
1089
+ assert_response(await ws.receive(), get_key_response_data(test_key_data_no_secrets))
1090
+
1091
+ # with `include_secrets=True`
1092
+ await ws.send_str(
1093
+ create_payload("get_key", {"fingerprint": test_key_data.fingerprint, "include_secrets": True}, "test", "daemon")
1094
+ )
1095
+ assert_response(await ws.receive(), get_key_response_data(test_key_data))
1096
+
1097
+ await ws.send_str(create_payload("get_key", {}, "test", "daemon"))
1098
+ assert_response(await ws.receive(), fingerprint_missing_response_data(GetKeyRequest))
1099
+
1100
+ await ws.send_str(create_payload("get_key", {"fingerprint": 123456}, "test", "daemon"))
1101
+ assert_response(await ws.receive(), fingerprint_not_found_response_data(123456))
1102
+
1103
+
1104
+ @pytest.mark.anyio
1105
+ async def test_get_keys(daemon_connection_and_temp_keychain):
1106
+ ws, keychain = daemon_connection_and_temp_keychain
1107
+
1108
+ # empty keychain
1109
+ await ws.send_str(create_payload("get_keys", {}, "test", "daemon"))
1110
+ assert_response(await ws.receive(), get_keys_response_data([]))
1111
+
1112
+ keys = [KeyData.generate() for _ in range(5)]
1113
+ keys_added = []
1114
+ for key_data in keys:
1115
+ keychain.add_key(key_data.mnemonic_str())
1116
+ keys_added.append(key_data)
1117
+
1118
+ get_keys_response_data_without_secrets = get_keys_response_data(
1119
+ [replace(key, secrets=None) for key in keys_added]
1120
+ )
1121
+
1122
+ # without `include_secrets`
1123
+ await ws.send_str(create_payload("get_keys", {}, "test", "daemon"))
1124
+ assert_response(await ws.receive(), get_keys_response_data_without_secrets)
1125
+
1126
+ # with `include_secrets=False`
1127
+ await ws.send_str(create_payload("get_keys", {"include_secrets": False}, "test", "daemon"))
1128
+ assert_response(await ws.receive(), get_keys_response_data_without_secrets)
1129
+
1130
+ # with `include_secrets=True`
1131
+ await ws.send_str(create_payload("get_keys", {"include_secrets": True}, "test", "daemon"))
1132
+ assert_response(await ws.receive(), get_keys_response_data(keys_added))
1133
+
1134
+
1135
+ @pytest.mark.anyio
1136
+ async def test_get_public_key(daemon_connection_and_temp_keychain):
1137
+ ws, keychain = daemon_connection_and_temp_keychain
1138
+
1139
+ # empty keychain
1140
+ await ws.send_str(create_payload("get_public_key", {"fingerprint": test_key_data.fingerprint}, "test", "daemon"))
1141
+ assert_response(await ws.receive(), fingerprint_not_found_response_data(test_key_data.fingerprint))
1142
+
1143
+ keychain.add_key(test_key_data.mnemonic_str())
1144
+
1145
+ await ws.send_str(create_payload("get_public_key", {"fingerprint": test_key_data.fingerprint}, "test", "daemon"))
1146
+ response = await ws.receive()
1147
+ assert_response(response, get_public_key_response_data(test_key_data))
1148
+
1149
+ # Only allowed_keys are allowed in the key dict
1150
+ key_dict = json.loads(response.data)["data"]["key"]
1151
+ keys_in_response = [key for key in key_dict.keys()]
1152
+ allowed_keys = ["fingerprint", "public_key", "label"]
1153
+ for key in keys_in_response:
1154
+ assert key in allowed_keys, f"Unexpected key '{key}' found in response."
1155
+
1156
+
1157
+ @pytest.mark.anyio
1158
+ async def test_get_public_keys(daemon_connection_and_temp_keychain):
1159
+ ws, keychain = daemon_connection_and_temp_keychain
1160
+
1161
+ # empty keychain
1162
+ await ws.send_str(create_payload("get_public_keys", {}, "test", "daemon"))
1163
+ assert_response(await ws.receive(), get_public_keys_response_data([]))
1164
+
1165
+ # populate keychain
1166
+ keys = [KeyData.generate() for _ in range(5)]
1167
+ keys_added = []
1168
+ for key_data in keys:
1169
+ keychain.add_key(key_data.mnemonic_str())
1170
+ keys_added.append(key_data)
1171
+
1172
+ get_public_keys_response = get_public_keys_response_data(keys_added)
1173
+ await ws.send_str(create_payload("get_public_keys", {}, "test", "daemon"))
1174
+ response = await ws.receive()
1175
+ assert_response(response, get_public_keys_response)
1176
+
1177
+ # Only allowed_keys are allowed in the key dict
1178
+ allowed_keys = ["fingerprint", "public_key", "label"]
1179
+ keys_array = json.loads(response.data)["data"]["keys"]
1180
+ for key_dict in keys_array:
1181
+ keys_in_response = [key for key in key_dict.keys()]
1182
+ for key in keys_in_response:
1183
+ assert key in allowed_keys, f"Unexpected key '{key}' found in response."
1184
+
1185
+
1186
+ @pytest.mark.anyio
1187
+ async def test_key_renaming(daemon_connection_and_temp_keychain):
1188
+ ws, keychain = daemon_connection_and_temp_keychain
1189
+ keychain.add_key(test_key_data.mnemonic_str())
1190
+ # Rename the key three times
1191
+ for i in range(3):
1192
+ key_data = replace(test_key_data_no_secrets, label=f"renaming_{i}")
1193
+ await ws.send_str(
1194
+ create_payload(
1195
+ "set_label", {"fingerprint": key_data.fingerprint, "label": key_data.label}, "test", "daemon"
1196
+ )
1197
+ )
1198
+ assert_response(await ws.receive(), success_response_data)
1199
+
1200
+ await ws.send_str(create_payload("get_key", {"fingerprint": key_data.fingerprint}, "test", "daemon"))
1201
+ assert_response(
1202
+ await ws.receive(),
1203
+ {
1204
+ "success": True,
1205
+ "key": key_data.to_json_dict(),
1206
+ },
1207
+ )
1208
+
1209
+
1210
+ @pytest.mark.anyio
1211
+ async def test_key_label_deletion(daemon_connection_and_temp_keychain):
1212
+ ws, keychain = daemon_connection_and_temp_keychain
1213
+
1214
+ keychain.add_key(test_key_data.mnemonic_str(), "key_0")
1215
+ assert keychain.get_key(test_key_data.fingerprint).label == "key_0"
1216
+ await ws.send_str(create_payload("delete_label", {"fingerprint": test_key_data.fingerprint}, "test", "daemon"))
1217
+ assert_response(await ws.receive(), success_response_data)
1218
+ assert keychain.get_key(test_key_data.fingerprint).label is None
1219
+ await ws.send_str(create_payload("delete_label", {"fingerprint": test_key_data.fingerprint}, "test", "daemon"))
1220
+ assert_response(await ws.receive(), fingerprint_not_found_response_data(test_key_data.fingerprint))
1221
+
1222
+
1223
+ @pytest.mark.parametrize(
1224
+ "method, parameter, response_data_dict",
1225
+ [
1226
+ (
1227
+ "set_label",
1228
+ {"fingerprint": test_key_data.fingerprint, "label": "new_label"},
1229
+ success_response_data,
1230
+ ),
1231
+ (
1232
+ "set_label",
1233
+ {"label": "new_label"},
1234
+ fingerprint_missing_response_data(SetLabelRequest),
1235
+ ),
1236
+ (
1237
+ "set_label",
1238
+ {"fingerprint": test_key_data.fingerprint},
1239
+ label_missing_response_data(SetLabelRequest),
1240
+ ),
1241
+ (
1242
+ "set_label",
1243
+ {"fingerprint": test_key_data.fingerprint, "label": ""},
1244
+ label_empty_response_data,
1245
+ ),
1246
+ (
1247
+ "set_label",
1248
+ {"fingerprint": test_key_data.fingerprint, "label": "a" * 66},
1249
+ label_too_long_response_data,
1250
+ ),
1251
+ (
1252
+ "set_label",
1253
+ {"fingerprint": test_key_data.fingerprint, "label": "a\nb"},
1254
+ label_newline_or_tab_response_data,
1255
+ ),
1256
+ (
1257
+ "set_label",
1258
+ {"fingerprint": test_key_data.fingerprint, "label": "a\tb"},
1259
+ label_newline_or_tab_response_data,
1260
+ ),
1261
+ (
1262
+ "set_label",
1263
+ {"fingerprint": test_key_data.fingerprint, "label": "key_0"},
1264
+ label_exists_response_data(test_key_data.fingerprint, "key_0"),
1265
+ ),
1266
+ (
1267
+ "delete_label",
1268
+ {"fingerprint": test_key_data.fingerprint},
1269
+ success_response_data,
1270
+ ),
1271
+ (
1272
+ "delete_label",
1273
+ {},
1274
+ fingerprint_missing_response_data(DeleteLabelRequest),
1275
+ ),
1276
+ (
1277
+ "delete_label",
1278
+ {"fingerprint": 123456},
1279
+ fingerprint_not_found_response_data(123456),
1280
+ ),
1281
+ ],
1282
+ )
1283
+ @pytest.mark.anyio
1284
+ async def test_key_label_methods(
1285
+ daemon_connection_and_temp_keychain, method: str, parameter: dict[str, Any], response_data_dict: dict[str, Any]
1286
+ ) -> None:
1287
+ ws, keychain = daemon_connection_and_temp_keychain
1288
+ keychain.add_key(test_key_data.mnemonic_str(), "key_0")
1289
+ await ws.send_str(create_payload(method, parameter, "test", "daemon"))
1290
+ assert_response(await ws.receive(), response_data_dict)
1291
+
1292
+
1293
+ @pytest.mark.anyio
1294
+ async def test_bad_json(daemon_connection_and_temp_keychain: tuple[aiohttp.ClientWebSocketResponse, Keychain]) -> None:
1295
+ ws, _ = daemon_connection_and_temp_keychain
1296
+
1297
+ await ws.send_str("{doo: '12'}") # send some bad json
1298
+ response = await ws.receive()
1299
+
1300
+ # check for error response
1301
+ assert response.type == aiohttp.WSMsgType.TEXT
1302
+ message = json.loads(response.data.strip())
1303
+ assert message["data"]["success"] is False
1304
+ assert message["data"]["error"].startswith("Expecting property name")
1305
+
1306
+ # properly register a service
1307
+ service_name = "test_service"
1308
+ data = {"service": service_name}
1309
+ payload = create_payload("register_service", data, service_name, "daemon")
1310
+ await ws.send_str(payload)
1311
+ await ws.receive()
1312
+
1313
+ # send some more bad json
1314
+ await ws.send_str("{doo: '12'}") # send some bad json
1315
+ response = await ws.receive()
1316
+ assert response.type == aiohttp.WSMsgType.TEXT
1317
+ message = json.loads(response.data.strip())
1318
+ assert message["command"] != "register_service"
1319
+ assert message["data"]["success"] is False
1320
+ assert message["data"]["error"].startswith("Expecting property name")
1321
+
1322
+
1323
+ @datacases(
1324
+ RouteCase(
1325
+ route="register_service",
1326
+ description="no service name",
1327
+ request={
1328
+ "fred": "barney",
1329
+ },
1330
+ response={"success": False},
1331
+ ),
1332
+ RouteCase(
1333
+ route="register_service",
1334
+ description="chia_plotter",
1335
+ request={
1336
+ "service": "chia_plotter",
1337
+ },
1338
+ response={"success": True, "service": "chia_plotter", "queue": []},
1339
+ ),
1340
+ RouteCase(
1341
+ route="unknown_command",
1342
+ description="non-existant route",
1343
+ request={},
1344
+ response={"success": False, "error": "unknown_command unknown_command"},
1345
+ ),
1346
+ RouteCase(
1347
+ route="running_services",
1348
+ description="successful",
1349
+ request={},
1350
+ response={"success": True, "running_services": []},
1351
+ ),
1352
+ RouteCase(
1353
+ route="keyring_status",
1354
+ description="successful",
1355
+ request={},
1356
+ response={
1357
+ "can_save_passphrase": supports_os_passphrase_storage(),
1358
+ "can_set_passphrase_hint": True,
1359
+ "is_keyring_locked": False,
1360
+ "passphrase_hint": "",
1361
+ "passphrase_requirements": {"is_optional": True, "min_length": 8},
1362
+ "success": True,
1363
+ "user_passphrase_is_set": False,
1364
+ },
1365
+ ),
1366
+ RouteCase(
1367
+ route="get_status",
1368
+ description="successful",
1369
+ request={},
1370
+ response={"success": True, "genesis_initialized": True},
1371
+ ),
1372
+ RouteCase(
1373
+ route="get_plotters",
1374
+ description="successful",
1375
+ request={},
1376
+ response={
1377
+ "success": True,
1378
+ "plotters": {
1379
+ "bladebit": {
1380
+ "can_install": True,
1381
+ "cuda_support": False,
1382
+ "display_name": "BladeBit Plotter",
1383
+ "installed": False,
1384
+ },
1385
+ "chiapos": {"display_name": "Chia Proof of Space", "installed": True, "version": chiapos_version},
1386
+ "madmax": {"can_install": True, "display_name": "madMAx Plotter", "installed": False},
1387
+ },
1388
+ },
1389
+ ),
1390
+ )
1391
+ @pytest.mark.anyio
1392
+ async def test_misc_daemon_ws(
1393
+ daemon_connection_and_temp_keychain: tuple[aiohttp.ClientWebSocketResponse, Keychain],
1394
+ case: RouteCase,
1395
+ ) -> None:
1396
+ ws, _ = daemon_connection_and_temp_keychain
1397
+
1398
+ payload = create_payload(case.route, case.request, "service_name", "daemon")
1399
+ await ws.send_str(payload)
1400
+ response = await ws.receive()
1401
+
1402
+ assert_response(response, case.response)
1403
+
1404
+
1405
+ @pytest.mark.anyio
1406
+ async def test_unexpected_json(
1407
+ daemon_connection_and_temp_keychain: tuple[aiohttp.ClientWebSocketResponse, Keychain],
1408
+ ) -> None:
1409
+ ws, _ = daemon_connection_and_temp_keychain
1410
+
1411
+ await ws.send_str('{"this": "is valid but not expected"}') # send some valid but unexpected json
1412
+ response = await ws.receive()
1413
+
1414
+ # check for error response
1415
+ assert response.type == aiohttp.WSMsgType.TEXT
1416
+ message = json.loads(response.data.strip())
1417
+ assert message["data"]["success"] is False
1418
+ assert message["data"]["error"].startswith("'command'")
1419
+
1420
+
1421
+ @pytest.mark.parametrize(
1422
+ "command_to_test",
1423
+ [("start_service"), ("stop_service"), ("start_plotting"), ("stop_plotting"), ("is_running"), ("register_service")],
1424
+ )
1425
+ @pytest.mark.anyio
1426
+ async def test_commands_with_no_data(
1427
+ daemon_connection_and_temp_keychain: tuple[aiohttp.ClientWebSocketResponse, Keychain], command_to_test: str
1428
+ ) -> None:
1429
+ ws, _ = daemon_connection_and_temp_keychain
1430
+
1431
+ payload = create_payload(command_to_test, {}, "service_name", "daemon")
1432
+
1433
+ await ws.send_str(payload)
1434
+ response = await ws.receive()
1435
+
1436
+ assert_response(response, {"success": False, "error": f'{command_to_test} requires "data"'})
1437
+
1438
+
1439
+ @datacases(
1440
+ RouteCase(
1441
+ route="set_keyring_passphrase",
1442
+ description="no passphrase",
1443
+ request={
1444
+ "passphrase_hint": "this is a hint",
1445
+ "save_passphrase": False,
1446
+ },
1447
+ response={"success": False, "error": "missing new_passphrase"},
1448
+ ),
1449
+ RouteCase(
1450
+ route="set_keyring_passphrase",
1451
+ description="incorrect type",
1452
+ request={
1453
+ "passphrase_hint": "this is a hint",
1454
+ "save_passphrase": False,
1455
+ "new_passphrase": True,
1456
+ },
1457
+ response={"success": False, "error": "missing new_passphrase"},
1458
+ ),
1459
+ RouteCase(
1460
+ route="set_keyring_passphrase",
1461
+ description="correct",
1462
+ request={
1463
+ "passphrase_hint": "this is a hint",
1464
+ "new_passphrase": "this is a passphrase",
1465
+ },
1466
+ response={"success": True, "error": None},
1467
+ ),
1468
+ )
1469
+ @pytest.mark.anyio
1470
+ async def test_set_keyring_passphrase_ws(
1471
+ daemon_connection_and_temp_keychain: tuple[aiohttp.ClientWebSocketResponse, Keychain],
1472
+ case: RouteCase,
1473
+ ) -> None:
1474
+ ws, _ = daemon_connection_and_temp_keychain
1475
+
1476
+ payload = create_payload(case.route, case.request, "service_name", "daemon")
1477
+ await ws.send_str(payload)
1478
+ response = await ws.receive()
1479
+
1480
+ assert_response(response, case.response)
1481
+
1482
+
1483
+ @datacases(
1484
+ RouteCase(
1485
+ route="remove_keyring_passphrase",
1486
+ description="wrong current passphrase",
1487
+ request={"current_passphrase": "wrong passphrase"},
1488
+ response={"success": False, "error": "current passphrase is invalid"},
1489
+ ),
1490
+ RouteCase(
1491
+ route="remove_keyring_passphrase",
1492
+ description="incorrect type",
1493
+ request={"current_passphrase": True},
1494
+ response={"success": False, "error": "missing current_passphrase"},
1495
+ ),
1496
+ RouteCase(
1497
+ route="remove_keyring_passphrase",
1498
+ description="missing current passphrase",
1499
+ request={},
1500
+ response={"success": False, "error": "missing current_passphrase"},
1501
+ ),
1502
+ RouteCase(
1503
+ route="remove_keyring_passphrase",
1504
+ description="correct",
1505
+ request={"current_passphrase": "this is a passphrase"},
1506
+ response={"success": True, "error": None},
1507
+ ),
1508
+ RouteCase(
1509
+ route="unlock_keyring",
1510
+ description="wrong current passphrase",
1511
+ request={"key": "wrong passphrase"},
1512
+ response={"success": False, "error": "bad passphrase"},
1513
+ ),
1514
+ RouteCase(
1515
+ route="unlock_keyring",
1516
+ description="incorrect type",
1517
+ request={"key": True},
1518
+ response={"success": False, "error": "missing key"},
1519
+ ),
1520
+ RouteCase(
1521
+ route="unlock_keyring",
1522
+ description="missing data",
1523
+ request={},
1524
+ response={"success": False, "error": "missing key"},
1525
+ ),
1526
+ RouteCase(
1527
+ route="unlock_keyring",
1528
+ description="correct",
1529
+ request={"key": "this is a passphrase"},
1530
+ response={"success": True, "error": None},
1531
+ ),
1532
+ RouteCase(
1533
+ route="set_keyring_passphrase",
1534
+ description="no current passphrase",
1535
+ request={
1536
+ "save_passphrase": False,
1537
+ "new_passphrase": "another new passphrase",
1538
+ },
1539
+ response={"success": False, "error": "missing current_passphrase"},
1540
+ ),
1541
+ RouteCase(
1542
+ route="set_keyring_passphrase",
1543
+ description="incorrect current passphrase",
1544
+ request={
1545
+ "save_passphrase": False,
1546
+ "current_passphrase": "none",
1547
+ "new_passphrase": "another new passphrase",
1548
+ },
1549
+ response={"success": False, "error": "current passphrase is invalid"},
1550
+ ),
1551
+ RouteCase(
1552
+ route="set_keyring_passphrase",
1553
+ description="incorrect type",
1554
+ request={
1555
+ "save_passphrase": False,
1556
+ "current_passphrase": False,
1557
+ "new_passphrase": "another new passphrase",
1558
+ },
1559
+ response={"success": False, "error": "missing current_passphrase"},
1560
+ ),
1561
+ RouteCase(
1562
+ route="set_keyring_passphrase",
1563
+ description="correct",
1564
+ request={
1565
+ "save_passphrase": False,
1566
+ "current_passphrase": "this is a passphrase",
1567
+ "new_passphrase": "another new passphrase",
1568
+ },
1569
+ response={"success": True, "error": None},
1570
+ ),
1571
+ )
1572
+ @pytest.mark.anyio
1573
+ async def test_passphrase_apis(
1574
+ daemon_connection_and_temp_keychain: tuple[aiohttp.ClientWebSocketResponse, Keychain],
1575
+ case: RouteCase,
1576
+ ) -> None:
1577
+ ws, keychain = daemon_connection_and_temp_keychain
1578
+
1579
+ # register for keyring_status_changed messages
1580
+ service_name = "wallet_ui"
1581
+ data = {"service": service_name}
1582
+ payload = create_payload("register_service", data, "wallet_ui", "daemon")
1583
+ await ws.send_str(payload)
1584
+ response = await ws.receive()
1585
+ assert_response_success_only(response)
1586
+
1587
+ keychain.set_master_passphrase(
1588
+ current_passphrase=DEFAULT_PASSPHRASE_IF_NO_MASTER_PASSPHRASE, new_passphrase="this is a passphrase"
1589
+ )
1590
+
1591
+ payload = create_payload(
1592
+ case.route,
1593
+ case.request,
1594
+ "service_name",
1595
+ "daemon",
1596
+ )
1597
+ await ws.send_str(payload)
1598
+ response = await ws.receive()
1599
+ assert_response(response, case.response)
1600
+
1601
+
1602
+ @datacases(
1603
+ RouteStatusCase(
1604
+ route="remove_keyring_passphrase",
1605
+ description="correct",
1606
+ request={"current_passphrase": "this is a passphrase"},
1607
+ response={"success": True, "error": None},
1608
+ status={
1609
+ "can_save_passphrase": supports_os_passphrase_storage(),
1610
+ "can_set_passphrase_hint": True,
1611
+ "is_keyring_locked": False,
1612
+ "passphrase_hint": "",
1613
+ "passphrase_requirements": {"is_optional": True, "min_length": 8},
1614
+ "success": True,
1615
+ "user_passphrase_is_set": False,
1616
+ },
1617
+ ),
1618
+ RouteStatusCase(
1619
+ route="unlock_keyring",
1620
+ description="correct",
1621
+ request={"key": "this is a passphrase"},
1622
+ response={"success": True, "error": None},
1623
+ status={
1624
+ "can_save_passphrase": supports_os_passphrase_storage(),
1625
+ "can_set_passphrase_hint": True,
1626
+ "is_keyring_locked": False,
1627
+ "passphrase_hint": "",
1628
+ "passphrase_requirements": {"is_optional": True, "min_length": 8},
1629
+ "success": True,
1630
+ "user_passphrase_is_set": True,
1631
+ },
1632
+ ),
1633
+ RouteStatusCase(
1634
+ route="set_keyring_passphrase",
1635
+ description="correct",
1636
+ request={
1637
+ "save_passphrase": False,
1638
+ "current_passphrase": "this is a passphrase",
1639
+ "new_passphrase": "another new passphrase",
1640
+ },
1641
+ response={"success": True, "error": None},
1642
+ status={
1643
+ "can_save_passphrase": supports_os_passphrase_storage(),
1644
+ "can_set_passphrase_hint": True,
1645
+ "is_keyring_locked": False,
1646
+ "passphrase_hint": "",
1647
+ "passphrase_requirements": {"is_optional": True, "min_length": 8},
1648
+ "success": True,
1649
+ "user_passphrase_is_set": True,
1650
+ },
1651
+ ),
1652
+ )
1653
+ @pytest.mark.anyio
1654
+ async def test_keychain_status_messages(
1655
+ daemon_connection_and_temp_keychain: tuple[aiohttp.ClientWebSocketResponse, Keychain],
1656
+ case: RouteStatusCase,
1657
+ ) -> None:
1658
+ ws, keychain = daemon_connection_and_temp_keychain
1659
+
1660
+ # register for keyring_status_changed messages
1661
+ service_name = "wallet_ui"
1662
+ data = {"service": service_name}
1663
+ payload = create_payload("register_service", data, "wallet_ui", "daemon")
1664
+ await ws.send_str(payload)
1665
+ response = await ws.receive()
1666
+ assert_response_success_only(response)
1667
+
1668
+ keychain.set_master_passphrase(
1669
+ current_passphrase=DEFAULT_PASSPHRASE_IF_NO_MASTER_PASSPHRASE, new_passphrase="this is a passphrase"
1670
+ )
1671
+
1672
+ payload = create_payload(
1673
+ case.route,
1674
+ case.request,
1675
+ "service_name",
1676
+ "daemon",
1677
+ )
1678
+ await ws.send_str(payload)
1679
+ response = await ws.receive()
1680
+ assert_response(response, case.response)
1681
+
1682
+ # wait for the status msg
1683
+ status_msg = await ws.receive()
1684
+ assert_response(status_msg, case.status, ack=False, command="keyring_status_changed")
1685
+
1686
+
1687
+ @datacases(
1688
+ RouteCase(
1689
+ route="unlock_keyring",
1690
+ description="exception",
1691
+ request={"key": "this is a passphrase"},
1692
+ response={"success": False, "error": "validation exception"},
1693
+ ),
1694
+ RouteCase(
1695
+ route="validate_keyring_passphrase",
1696
+ description="exception",
1697
+ request={"key": "this is a passphrase"},
1698
+ response={"success": False, "error": "validation exception"},
1699
+ ),
1700
+ )
1701
+ @pytest.mark.anyio
1702
+ async def test_keyring_file_deleted(
1703
+ daemon_connection_and_temp_keychain: tuple[aiohttp.ClientWebSocketResponse, Keychain],
1704
+ case: RouteCase,
1705
+ ) -> None:
1706
+ ws, keychain = daemon_connection_and_temp_keychain
1707
+
1708
+ keychain.set_master_passphrase(
1709
+ current_passphrase=DEFAULT_PASSPHRASE_IF_NO_MASTER_PASSPHRASE, new_passphrase="this is a passphrase"
1710
+ )
1711
+ keychain.keyring_wrapper.keyring.keyring_path.unlink()
1712
+
1713
+ payload = create_payload(
1714
+ case.route,
1715
+ case.request,
1716
+ "service_name",
1717
+ "daemon",
1718
+ )
1719
+ await ws.send_str(payload)
1720
+ response = await ws.receive()
1721
+
1722
+ assert_response(response, case.response)
1723
+
1724
+
1725
+ @datacases(
1726
+ RouteCase(
1727
+ route="start_plotting",
1728
+ description="chiapos - missing k",
1729
+ request={k: v for k, v in plotter_request_ref.items() if k != "k"},
1730
+ response={"success": False, "error": "'k'"},
1731
+ ),
1732
+ RouteCase(
1733
+ route="start_plotting",
1734
+ description="chiapos - missing d",
1735
+ request={k: v for k, v in plotter_request_ref.items() if k != "d"},
1736
+ response={"success": False, "error": "'d'"},
1737
+ ),
1738
+ RouteCase(
1739
+ route="start_plotting",
1740
+ description="chiapos - missing t",
1741
+ request={k: v for k, v in plotter_request_ref.items() if k != "t"},
1742
+ response={"success": False, "error": "'t'"},
1743
+ ),
1744
+ RouteCase(
1745
+ route="start_plotting",
1746
+ description="chiapos - both c and p",
1747
+ request={
1748
+ **plotter_request_ref,
1749
+ "c": "hello",
1750
+ "p": "goodbye",
1751
+ },
1752
+ response={
1753
+ "success": False,
1754
+ "service_name": "chia_plotter",
1755
+ "error": "Choose one of pool_contract_address and pool_public_key",
1756
+ },
1757
+ ),
1758
+ )
1759
+ @pytest.mark.anyio
1760
+ async def test_plotter_errors(
1761
+ daemon_connection_and_temp_keychain: tuple[aiohttp.ClientWebSocketResponse, Keychain], case: RouteCase
1762
+ ) -> None:
1763
+ ws, _keychain = daemon_connection_and_temp_keychain
1764
+
1765
+ payload = create_payload(
1766
+ case.route,
1767
+ case.request,
1768
+ "test_service_name",
1769
+ "daemon",
1770
+ )
1771
+ await ws.send_str(payload)
1772
+ response = await ws.receive()
1773
+
1774
+ assert_response(response, case.response)
1775
+
1776
+
1777
+ @datacases(
1778
+ RouteCase(
1779
+ route="start_plotting",
1780
+ description="bladebit - ramplot",
1781
+ request={
1782
+ **plotter_request_ref,
1783
+ "plotter": "bladebit",
1784
+ "plot_type": "ramplot",
1785
+ "w": True,
1786
+ "m": True,
1787
+ "no_cpu_affinity": True,
1788
+ "e": False,
1789
+ },
1790
+ response={
1791
+ "success": True,
1792
+ },
1793
+ ),
1794
+ RouteCase(
1795
+ route="start_plotting",
1796
+ description="bladebit - diskplot",
1797
+ request={
1798
+ **plotter_request_ref,
1799
+ "plotter": "bladebit",
1800
+ "plot_type": "diskplot",
1801
+ "w": True,
1802
+ "m": True,
1803
+ "no_cpu_affinity": True,
1804
+ "e": False,
1805
+ "cache": "cache",
1806
+ "f1_threads": 5,
1807
+ "fp_threads": 6,
1808
+ "c_threads": 4,
1809
+ "p2_threads": 4,
1810
+ "p3_threads": 4,
1811
+ "alternate": True,
1812
+ "no_t1_direct": True,
1813
+ "no_t2_direct": True,
1814
+ },
1815
+ response={
1816
+ "success": True,
1817
+ },
1818
+ ),
1819
+ RouteCase(
1820
+ route="start_plotting",
1821
+ description="bladebit - cudaplot - hybrid 128 mode",
1822
+ request={
1823
+ **plotter_request_ref,
1824
+ "plotter": "bladebit",
1825
+ "plot_type": "cudaplot",
1826
+ "w": True,
1827
+ "m": True,
1828
+ "no_cpu_affinity": True,
1829
+ "e": False,
1830
+ "compress": 1,
1831
+ "disk_128": True,
1832
+ },
1833
+ response={
1834
+ "success": True,
1835
+ },
1836
+ ),
1837
+ RouteCase(
1838
+ route="start_plotting",
1839
+ description="bladebit - cudaplot - hybrid 16 mode",
1840
+ request={
1841
+ **plotter_request_ref,
1842
+ "plotter": "bladebit",
1843
+ "plot_type": "cudaplot",
1844
+ "w": True,
1845
+ "m": True,
1846
+ "no_cpu_affinity": True,
1847
+ "e": False,
1848
+ "compress": 1,
1849
+ "disk_16": True,
1850
+ },
1851
+ response={
1852
+ "success": True,
1853
+ },
1854
+ ),
1855
+ RouteCase(
1856
+ route="start_plotting",
1857
+ description="madmax",
1858
+ request={
1859
+ **plotter_request_ref,
1860
+ "plotter": "madmax",
1861
+ "w": True,
1862
+ "m": True,
1863
+ "no_cpu_affinity": True,
1864
+ "t2": "testing",
1865
+ "v": 128,
1866
+ },
1867
+ response={
1868
+ "success": True,
1869
+ },
1870
+ ),
1871
+ )
1872
+ @pytest.mark.anyio
1873
+ async def test_plotter_options(
1874
+ daemon_connection_and_temp_keychain: tuple[aiohttp.ClientWebSocketResponse, Keychain],
1875
+ get_b_tools: BlockTools,
1876
+ case: RouteCase,
1877
+ ) -> None:
1878
+ ws, _keychain = daemon_connection_and_temp_keychain
1879
+
1880
+ # register for chia_plotter events
1881
+ service_name = "chia_plotter"
1882
+ data = {"service": service_name}
1883
+ payload = create_payload("register_service", data, "chia_plotter", "daemon")
1884
+ await ws.send_str(payload)
1885
+ response = await ws.receive()
1886
+ assert_response_success_only(response)
1887
+
1888
+ case.request["t"] = str(get_b_tools.root_path)
1889
+ case.request["d"] = str(get_b_tools.root_path)
1890
+
1891
+ payload_rpc = create_payload_dict(
1892
+ case.route,
1893
+ case.request,
1894
+ "test_service_name",
1895
+ "daemon",
1896
+ )
1897
+ payload = dict_to_json_str(payload_rpc)
1898
+ await ws.send_str(payload)
1899
+ response = await ws.receive()
1900
+
1901
+ assert_response_success_only(response, payload_rpc["request_id"])
1902
+
1903
+
1904
+ def assert_plot_queue_response(
1905
+ response: aiohttp.http_websocket.WSMessage,
1906
+ expected_command: str,
1907
+ expected_message_state: str,
1908
+ expected_plot_id: str,
1909
+ expected_plot_state: str,
1910
+ ) -> None:
1911
+ assert response.type == aiohttp.WSMsgType.TEXT
1912
+ message = json.loads(response.data.strip())
1913
+ assert message["command"] == expected_command
1914
+ assert message["data"]["state"] == expected_message_state
1915
+ plot_info = message["data"]["queue"][0]
1916
+ assert plot_info["id"] == expected_plot_id
1917
+ assert plot_info["state"] == expected_plot_state
1918
+
1919
+
1920
+ def check_plot_queue_log(
1921
+ response: aiohttp.http_websocket.WSMessage,
1922
+ expected_command: str,
1923
+ expected_message_state: str,
1924
+ expected_plot_id: str,
1925
+ expected_plot_state: str,
1926
+ expected_log_entry: str,
1927
+ ) -> bool:
1928
+ assert_plot_queue_response(
1929
+ response, expected_command, expected_message_state, expected_plot_id, expected_plot_state
1930
+ )
1931
+
1932
+ message = json.loads(response.data.strip())
1933
+ plot_info = message["data"]["queue"][0]
1934
+
1935
+ return plot_info["log_new"].startswith(expected_log_entry)
1936
+
1937
+
1938
+ @pytest.mark.anyio
1939
+ async def test_plotter_roundtrip(
1940
+ daemon_connection_and_temp_keychain: tuple[aiohttp.ClientWebSocketResponse, Keychain], get_b_tools: BlockTools
1941
+ ) -> None:
1942
+ ws, _keychain = daemon_connection_and_temp_keychain
1943
+
1944
+ # register for chia_plotter events
1945
+ service_name = "chia_plotter"
1946
+ data = {"service": service_name}
1947
+ payload = create_payload("register_service", data, "chia_plotter", "daemon")
1948
+ await ws.send_str(payload)
1949
+ response = await ws.receive()
1950
+ assert_response_success_only(response)
1951
+
1952
+ root_path = get_b_tools.root_path
1953
+
1954
+ plotting_request: dict[str, Any] = {
1955
+ **plotter_request_ref,
1956
+ "d": str(root_path),
1957
+ "t": str(root_path),
1958
+ "p": "xxx",
1959
+ }
1960
+ plotting_request.pop("c", None)
1961
+
1962
+ payload_rpc = create_payload_dict(
1963
+ "start_plotting",
1964
+ plotting_request,
1965
+ "test_service_name",
1966
+ "daemon",
1967
+ )
1968
+ payload = dict_to_json_str(payload_rpc)
1969
+ await ws.send_str(payload)
1970
+
1971
+ # should first get response to start_plottin
1972
+ response = await ws.receive()
1973
+ assert response.type == aiohttp.WSMsgType.TEXT
1974
+ message = json.loads(response.data.strip())
1975
+ assert message["data"]["success"] is True
1976
+ assert message["request_id"] == payload_rpc["request_id"]
1977
+ plot_id = message["data"]["ids"][0]
1978
+
1979
+ # 1) Submitted
1980
+ response = await ws.receive()
1981
+ assert_plot_queue_response(response, "state_changed", "state_changed", plot_id, "SUBMITTED")
1982
+
1983
+ # 2) Running
1984
+ response = await ws.receive()
1985
+ assert_plot_queue_response(response, "state_changed", "state_changed", plot_id, "RUNNING")
1986
+
1987
+ # Write chiapos magic words to the log file to signal finished
1988
+ plot_log_path = plotter_log_path(root_path, plot_id)
1989
+ with open(plot_log_path, "a") as f:
1990
+ f.write("Renamed final file")
1991
+ f.flush()
1992
+
1993
+ # 3) log_changed
1994
+ final_log_entry = False
1995
+ while not final_log_entry:
1996
+ response = await ws.receive()
1997
+ final_log_entry = check_plot_queue_log(
1998
+ response, "state_changed", "log_changed", plot_id, "RUNNING", "Renamed final file"
1999
+ )
2000
+ if not final_log_entry:
2001
+ with open(plot_log_path, "a") as f:
2002
+ f.write("Renamed final file")
2003
+ f.flush()
2004
+
2005
+ # 4) Finished
2006
+ response = await ws.receive()
2007
+ assert_plot_queue_response(response, "state_changed", "state_changed", plot_id, "FINISHED")
2008
+
2009
+
2010
+ @pytest.mark.anyio
2011
+ async def test_plotter_stop_plotting(
2012
+ daemon_connection_and_temp_keychain: tuple[aiohttp.ClientWebSocketResponse, Keychain], get_b_tools: BlockTools
2013
+ ) -> None:
2014
+ ws, _keychain = daemon_connection_and_temp_keychain
2015
+
2016
+ # register for chia_plotter events
2017
+ service_name = "chia_plotter"
2018
+ data = {"service": service_name}
2019
+ payload = create_payload("register_service", data, "chia_plotter", "daemon")
2020
+ await ws.send_str(payload)
2021
+ response = await ws.receive()
2022
+ assert_response_success_only(response)
2023
+
2024
+ root_path = get_b_tools.root_path
2025
+
2026
+ plotting_request: dict[str, Any] = {
2027
+ **plotter_request_ref,
2028
+ "d": str(root_path),
2029
+ "t": str(root_path),
2030
+ }
2031
+
2032
+ payload_rpc = create_payload_dict(
2033
+ "start_plotting",
2034
+ plotting_request,
2035
+ "test_service_name",
2036
+ "daemon",
2037
+ )
2038
+ payload = dict_to_json_str(payload_rpc)
2039
+ await ws.send_str(payload)
2040
+
2041
+ # should first get response to start_plotting
2042
+ response = await ws.receive()
2043
+ assert response.type == aiohttp.WSMsgType.TEXT
2044
+ message = json.loads(response.data.strip())
2045
+ assert message["data"]["success"] is True
2046
+ # make sure matches the start_plotting request
2047
+ assert message["request_id"] == payload_rpc["request_id"]
2048
+ plot_id = message["data"]["ids"][0]
2049
+
2050
+ # 1) Submitted
2051
+ response = await ws.receive()
2052
+ assert_plot_queue_response(response, "state_changed", "state_changed", plot_id, "SUBMITTED")
2053
+
2054
+ # 2) Running
2055
+ response = await ws.receive()
2056
+ assert_plot_queue_response(response, "state_changed", "state_changed", plot_id, "RUNNING")
2057
+
2058
+ payload_rpc = create_payload_dict(
2059
+ "stop_plotting",
2060
+ {"id": plot_id},
2061
+ "service_name",
2062
+ "daemon",
2063
+ )
2064
+
2065
+ stop_plotting_request_id = payload_rpc["request_id"]
2066
+ payload = dict_to_json_str(payload_rpc)
2067
+ await ws.send_str(payload)
2068
+
2069
+ responses: list[WSMessage] = []
2070
+
2071
+ # 3, 4, and 5)
2072
+ # Removing
2073
+ # Finished
2074
+ # Finally, get the "ack" for the stop_plotting payload
2075
+ for _ in range(3):
2076
+ responses.append(await ws.receive())
2077
+
2078
+ state_changes: list[WSMessage] = []
2079
+ finished: list[WSMessage] = []
2080
+
2081
+ for response in responses:
2082
+ message = json.loads(response.data.strip())
2083
+ command = message.get("command")
2084
+ if command == "state_changed":
2085
+ state_changes.append(response)
2086
+ else:
2087
+ finished.append(response)
2088
+
2089
+ assert len(state_changes) == 2
2090
+ assert len(finished) == 1
2091
+
2092
+ assert_plot_queue_response(state_changes[0], "state_changed", "state_changed", plot_id, "REMOVING")
2093
+ assert_plot_queue_response(state_changes[1], "state_changed", "state_changed", plot_id, "FINISHED")
2094
+ assert_response(finished[0], {"success": True}, stop_plotting_request_id)
2095
+
2096
+
2097
+ @datacases(
2098
+ ChiaPlottersBladebitArgsCase(case_id="1", plot_type="cudaplot"),
2099
+ ChiaPlottersBladebitArgsCase(case_id="2", plot_type="cudaplot", hybrid_disk_mode=16),
2100
+ ChiaPlottersBladebitArgsCase(case_id="3", plot_type="cudaplot", hybrid_disk_mode=128),
2101
+ )
2102
+ def test_run_plotter_bladebit(
2103
+ mocker: MockerFixture,
2104
+ mock_daemon_with_config_and_keys,
2105
+ bt: BlockTools,
2106
+ case: ChiaPlottersBladebitArgsCase,
2107
+ ) -> None:
2108
+ root_path = bt.root_path
2109
+
2110
+ case.farmer_pk = bytes(bt.farmer_pk).hex()
2111
+ case.final_dir = str(bt.plot_dir)
2112
+
2113
+ def bladebit_exists(x: Path) -> bool:
2114
+ return True if isinstance(x, Path) and x.parent == root_path / "plotters" else mocker.DEFAULT
2115
+
2116
+ def get_bladebit_version(_: Path) -> tuple[bool, list[str]]:
2117
+ return True, ["3", "0", "0"]
2118
+
2119
+ mocker.patch("os.path.exists", side_effect=bladebit_exists)
2120
+ mocker.patch("chia.plotters.bladebit.get_bladebit_version", side_effect=get_bladebit_version)
2121
+ mock_run_plotter = mocker.patch("chia.plotters.bladebit.run_plotter")
2122
+
2123
+ call_plotters(root_path, case.to_command_array())
2124
+
2125
+ assert mock_run_plotter.call_args.args[0] == root_path
2126
+ assert mock_run_plotter.call_args.args[1] == "bladebit"
2127
+ assert mock_run_plotter.call_args.args[2][1:] == case.expected_raw_command_args()
2128
+ mock_run_plotter.assert_called_once()