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,2139 @@
1
+ from __future__ import annotations
2
+
3
+ import dataclasses
4
+ from pathlib import Path
5
+ from typing import Any, Optional
6
+
7
+ import pytest
8
+ from chia_rs import AugSchemeMPL, G1Element, G2Element
9
+
10
+ from chia._tests.environments.wallet import WalletStateTransition, WalletTestFramework
11
+ from chia._tests.util.time_out_assert import time_out_assert
12
+ from chia.rpc.wallet_request_types import GetTransactionMemo
13
+ from chia.server.server import ChiaServer
14
+ from chia.simulator.block_tools import BlockTools
15
+ from chia.simulator.full_node_simulator import FullNodeSimulator
16
+ from chia.simulator.simulator_protocol import ReorgProtocol
17
+ from chia.types.blockchain_format.program import Program
18
+ from chia.types.blockchain_format.sized_bytes import bytes32
19
+ from chia.types.coin_spend import CoinSpend, compute_additions
20
+ from chia.types.peer_info import PeerInfo
21
+ from chia.types.signing_mode import CHIP_0002_SIGN_MESSAGE_PREFIX
22
+ from chia.types.spend_bundle import estimate_fees
23
+ from chia.util.bech32m import encode_puzzle_hash
24
+ from chia.util.errors import Err
25
+ from chia.util.ints import uint16, uint32, uint64
26
+ from chia.wallet.conditions import ConditionValidTimes
27
+ from chia.wallet.derive_keys import master_sk_to_wallet_sk
28
+ from chia.wallet.payment import Payment
29
+ from chia.wallet.puzzles.clawback.metadata import AutoClaimSettings
30
+ from chia.wallet.transaction_record import TransactionRecord
31
+ from chia.wallet.util.query_filter import TransactionTypeFilter
32
+ from chia.wallet.util.transaction_type import TransactionType
33
+ from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
34
+ from chia.wallet.util.wallet_types import CoinType
35
+ from chia.wallet.wallet_node import WalletNode, get_wallet_db_path
36
+
37
+
38
+ class TestWalletSimulator:
39
+ @pytest.mark.parametrize(
40
+ "wallet_environments",
41
+ [{"num_environments": 1, "blocks_needed": [10], "reuse_puzhash": True}],
42
+ indirect=True,
43
+ )
44
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
45
+ @pytest.mark.anyio
46
+ async def test_wallet_coinbase(self, wallet_environments: WalletTestFramework) -> None:
47
+ env = wallet_environments.environments[0]
48
+ wsm = env.wallet_state_manager
49
+
50
+ all_txs = await wsm.get_all_transactions(1)
51
+ assert len(all_txs) == 20
52
+
53
+ pool_rewards = 0
54
+ farm_rewards = 0
55
+
56
+ for tx in all_txs:
57
+ if TransactionType(tx.type) == TransactionType.COINBASE_REWARD:
58
+ pool_rewards += 1
59
+ elif TransactionType(tx.type) == TransactionType.FEE_REWARD:
60
+ farm_rewards += 1
61
+
62
+ assert pool_rewards == 10
63
+ assert farm_rewards == 10
64
+
65
+ @pytest.mark.parametrize(
66
+ "wallet_environments",
67
+ [{"num_environments": 1, "blocks_needed": [1]}],
68
+ indirect=True,
69
+ )
70
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
71
+ @pytest.mark.anyio
72
+ async def test_wallet_make_transaction(self, wallet_environments: WalletTestFramework) -> None:
73
+ env = wallet_environments.environments[0]
74
+ wallet = env.xch_wallet
75
+
76
+ tx_amount = 10
77
+
78
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
79
+ await wallet.generate_signed_transaction(
80
+ uint64(tx_amount),
81
+ bytes32.zeros,
82
+ action_scope,
83
+ uint64(0),
84
+ )
85
+
86
+ await wallet_environments.process_pending_states(
87
+ [
88
+ WalletStateTransition(
89
+ pre_block_balance_updates={
90
+ 1: {
91
+ "unconfirmed_wallet_balance": -1 * tx_amount,
92
+ "<=#spendable_balance": -1 * tx_amount,
93
+ "<=#max_send_amount": -1 * tx_amount,
94
+ ">=#pending_change": 1, # any amount increase
95
+ "pending_coin_removal_count": 1,
96
+ }
97
+ },
98
+ post_block_balance_updates={
99
+ 1: {
100
+ "confirmed_wallet_balance": -1 * tx_amount,
101
+ ">=#spendable_balance": 1,
102
+ ">=#max_send_amount": 1,
103
+ "<=#pending_change": 1, # any amount decrease
104
+ "pending_coin_removal_count": -1,
105
+ }
106
+ },
107
+ )
108
+ ]
109
+ )
110
+
111
+ # Test match_hinted_coin
112
+ async with wallet.wallet_state_manager.new_action_scope(
113
+ wallet_environments.tx_config, push=False
114
+ ) as action_scope:
115
+ selected_coin = next(iter(await wallet.select_coins(uint64(0), action_scope)))
116
+ assert await wallet.match_hinted_coin(selected_coin, selected_coin.puzzle_hash)
117
+
118
+ @pytest.mark.parametrize(
119
+ "wallet_environments",
120
+ [{"num_environments": 1, "blocks_needed": [1], "reuse_puzhash": True}],
121
+ indirect=True,
122
+ )
123
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
124
+ @pytest.mark.anyio
125
+ async def test_wallet_reuse_address(self, wallet_environments: WalletTestFramework) -> None:
126
+ env = wallet_environments.environments[0]
127
+ wallet = env.xch_wallet
128
+
129
+ tx_amount = 10
130
+
131
+ async with wallet.wallet_state_manager.new_action_scope(
132
+ DEFAULT_TX_CONFIG.override(reuse_puzhash=True), push=True
133
+ ) as action_scope:
134
+ await wallet.generate_signed_transaction(
135
+ uint64(tx_amount),
136
+ bytes32.zeros,
137
+ action_scope,
138
+ uint64(0),
139
+ )
140
+ [tx] = action_scope.side_effects.transactions
141
+ assert tx.spend_bundle is not None
142
+ assert len(tx.spend_bundle.coin_spends) == 1
143
+ new_puzhash = [c.puzzle_hash.hex() for c in tx.additions]
144
+ assert tx.spend_bundle.coin_spends[0].coin.puzzle_hash.hex() in new_puzhash
145
+ [tx] = await wallet.wallet_state_manager.add_pending_transactions([tx])
146
+
147
+ await wallet_environments.process_pending_states(
148
+ [
149
+ WalletStateTransition(
150
+ pre_block_balance_updates={
151
+ 1: {
152
+ "unconfirmed_wallet_balance": -1 * tx_amount,
153
+ "<=#spendable_balance": -1 * tx_amount,
154
+ "<=#max_send_amount": -1 * tx_amount,
155
+ ">=#pending_change": 1, # any amount increase
156
+ "pending_coin_removal_count": 1,
157
+ }
158
+ },
159
+ post_block_balance_updates={
160
+ 1: {
161
+ "confirmed_wallet_balance": -1 * tx_amount,
162
+ ">=#spendable_balance": 1,
163
+ ">=#max_send_amount": 1,
164
+ "<=#pending_change": 1, # any amount decrease
165
+ "pending_coin_removal_count": -1,
166
+ }
167
+ },
168
+ )
169
+ ]
170
+ )
171
+
172
+ @pytest.mark.parametrize(
173
+ "wallet_environments",
174
+ [{"num_environments": 2, "blocks_needed": [2, 1], "reuse_puzhash": True}],
175
+ indirect=True,
176
+ )
177
+ @pytest.mark.parametrize("number_of_coins", [1, 3])
178
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
179
+ @pytest.mark.anyio
180
+ async def test_wallet_clawback_claim_auto(
181
+ self, wallet_environments: WalletTestFramework, number_of_coins: int
182
+ ) -> None:
183
+ env = wallet_environments.environments[0]
184
+ env_1 = wallet_environments.environments[1]
185
+ wallet = env.xch_wallet
186
+ wallet_1 = env_1.xch_wallet
187
+ wsm = env.wallet_state_manager
188
+ wsm_1 = env_1.wallet_state_manager
189
+
190
+ tx_amount = 500
191
+ normal_puzhash = await wallet_1.get_new_puzzlehash()
192
+
193
+ # Transfer to normal wallet
194
+ for _ in range(0, number_of_coins):
195
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
196
+ await wallet.generate_signed_transaction(
197
+ uint64(tx_amount),
198
+ normal_puzhash,
199
+ action_scope,
200
+ uint64(0),
201
+ puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 10}],
202
+ )
203
+
204
+ await wallet_environments.process_pending_states(
205
+ [
206
+ WalletStateTransition(
207
+ pre_block_balance_updates={
208
+ 1: {
209
+ "unconfirmed_wallet_balance": -1 * tx_amount * number_of_coins,
210
+ "<=#spendable_balance": -1 * tx_amount * number_of_coins,
211
+ "<=#max_send_amount": -1 * tx_amount * number_of_coins,
212
+ ">=#pending_change": 1, # any amount increase
213
+ "pending_coin_removal_count": number_of_coins,
214
+ }
215
+ },
216
+ post_block_balance_updates={
217
+ 1: {
218
+ "confirmed_wallet_balance": -1 * tx_amount * number_of_coins,
219
+ ">=#spendable_balance": 1, # any amount increase
220
+ ">=#max_send_amount": 1, # any amount increase
221
+ "<=#pending_change": -1, # any amount decrease
222
+ "pending_coin_removal_count": -number_of_coins,
223
+ }
224
+ },
225
+ ),
226
+ WalletStateTransition(
227
+ pre_block_balance_updates={},
228
+ post_block_balance_updates={},
229
+ ),
230
+ ]
231
+ )
232
+
233
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, number_of_coins, tx_amount * 2, CoinType.CLAWBACK)
234
+ await time_out_assert(
235
+ 20, wsm_1.coin_store.count_small_unspent, number_of_coins, tx_amount * 2, CoinType.CLAWBACK
236
+ )
237
+
238
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
239
+ await wallet.generate_signed_transaction(
240
+ uint64(tx_amount),
241
+ normal_puzhash,
242
+ action_scope,
243
+ uint64(0),
244
+ puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 10}],
245
+ )
246
+ [tx_bad] = action_scope.side_effects.transactions
247
+
248
+ await wallet_environments.process_pending_states(
249
+ [
250
+ WalletStateTransition(
251
+ pre_block_balance_updates={
252
+ 1: {
253
+ "unconfirmed_wallet_balance": -1 * tx_amount,
254
+ "<=#spendable_balance": -1 * tx_amount,
255
+ "<=#max_send_amount": -1 * tx_amount,
256
+ ">=#pending_change": 1, # any amount increase
257
+ "pending_coin_removal_count": 1,
258
+ }
259
+ },
260
+ post_block_balance_updates={
261
+ 1: {
262
+ "confirmed_wallet_balance": -1 * tx_amount,
263
+ ">=#spendable_balance": 1, # any amount increase
264
+ ">=#max_send_amount": 1, # any amount increase
265
+ "<=#pending_change": -1, # any amount decrease
266
+ "pending_coin_removal_count": -1,
267
+ }
268
+ },
269
+ ),
270
+ WalletStateTransition(
271
+ pre_block_balance_updates={},
272
+ post_block_balance_updates={},
273
+ ),
274
+ ]
275
+ )
276
+
277
+ # Change one coin to test missing metadata case
278
+ clawback_coin_id = tx_bad.additions[0].name()
279
+ coin_record = await wsm_1.coin_store.get_coin_record(clawback_coin_id)
280
+ assert coin_record is not None
281
+ await wsm_1.coin_store.add_coin_record(dataclasses.replace(coin_record, metadata=None))
282
+ # Claim merkle coin
283
+ env_1.node.set_auto_claim(AutoClaimSettings(enabled=True, batch_size=uint16(2)))
284
+ # Trigger auto claim
285
+ await wallet_environments.process_pending_states(
286
+ [
287
+ WalletStateTransition(),
288
+ WalletStateTransition(
289
+ pre_block_balance_updates={},
290
+ # After auto claim is set, the next block will trigger submission of clawback claims
291
+ post_block_balance_updates={
292
+ 1: {
293
+ "unconfirmed_wallet_balance": tx_amount * number_of_coins,
294
+ "pending_change": tx_amount
295
+ * number_of_coins, # This is a little weird but I think intentional and correct
296
+ "pending_coin_removal_count": number_of_coins,
297
+ }
298
+ },
299
+ ),
300
+ ]
301
+ )
302
+ await wallet_environments.process_pending_states(
303
+ [
304
+ WalletStateTransition(),
305
+ WalletStateTransition(
306
+ pre_block_balance_updates={},
307
+ post_block_balance_updates={
308
+ 1: {
309
+ "confirmed_wallet_balance": tx_amount * number_of_coins,
310
+ "spendable_balance": tx_amount * number_of_coins,
311
+ "max_send_amount": tx_amount * number_of_coins,
312
+ "unspent_coin_count": number_of_coins,
313
+ "pending_change": -tx_amount * number_of_coins,
314
+ "pending_coin_removal_count": -1 * number_of_coins,
315
+ }
316
+ },
317
+ ),
318
+ ]
319
+ )
320
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 1, tx_amount * 2, CoinType.CLAWBACK)
321
+ await time_out_assert(20, wsm_1.coin_store.count_small_unspent, 1, tx_amount * 2, CoinType.CLAWBACK)
322
+
323
+ @pytest.mark.parametrize(
324
+ "wallet_environments",
325
+ [{"num_environments": 2, "blocks_needed": [1, 1], "reuse_puzhash": True}],
326
+ indirect=True,
327
+ )
328
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
329
+ @pytest.mark.anyio
330
+ async def test_wallet_clawback_clawback(self, wallet_environments: WalletTestFramework) -> None:
331
+ env = wallet_environments.environments[0]
332
+ env_2 = wallet_environments.environments[1]
333
+ wsm = env.wallet_state_manager
334
+ wsm_2 = env_2.wallet_state_manager
335
+ wallet = env.xch_wallet
336
+ wallet_1 = env_2.xch_wallet
337
+ api_0 = env.rpc_api
338
+ api_1 = env_2.rpc_api
339
+
340
+ tx_amount = 500
341
+ normal_puzhash = await wallet_1.get_new_puzzlehash()
342
+ # Transfer to normal wallet
343
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
344
+ await wallet.generate_signed_transaction(
345
+ uint64(tx_amount),
346
+ normal_puzhash,
347
+ action_scope,
348
+ uint64(0),
349
+ puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 500}],
350
+ memos=[b"Test"],
351
+ )
352
+
353
+ await wallet_environments.process_pending_states(
354
+ [
355
+ WalletStateTransition(
356
+ pre_block_balance_updates={
357
+ 1: {
358
+ "unconfirmed_wallet_balance": -1 * tx_amount,
359
+ "<=#spendable_balance": -1 * tx_amount,
360
+ "<=#max_send_amount": -1 * tx_amount,
361
+ ">=#pending_change": 1, # any amount increase
362
+ "pending_coin_removal_count": 1,
363
+ }
364
+ },
365
+ post_block_balance_updates={
366
+ 1: {
367
+ "confirmed_wallet_balance": -1 * tx_amount,
368
+ ">=#spendable_balance": 1, # any amount increase
369
+ ">=#max_send_amount": 1, # any amount increase
370
+ "<=#pending_change": -1, # any amount decrease
371
+ "pending_coin_removal_count": -1,
372
+ }
373
+ },
374
+ ),
375
+ WalletStateTransition(
376
+ pre_block_balance_updates={},
377
+ post_block_balance_updates={},
378
+ ),
379
+ ]
380
+ )
381
+
382
+ # Check merkle coins
383
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
384
+ await time_out_assert(20, wsm_2.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
385
+ txs = await api_0.get_transactions(
386
+ dict(type_filter={"values": [TransactionType.INCOMING_CLAWBACK_SEND], "mode": 1}, wallet_id=1)
387
+ )
388
+ # clawback merkle coin
389
+ [tx] = action_scope.side_effects.transactions
390
+ merkle_coin = tx.additions[0] if tx.additions[0].amount == tx_amount else tx.additions[1]
391
+ interested_coins = await wsm_2.interested_store.get_interested_coin_ids()
392
+ assert merkle_coin.name() in set(interested_coins)
393
+ assert len(txs["transactions"]) == 1
394
+ assert not txs["transactions"][0]["confirmed"]
395
+ assert txs["transactions"][0]["metadata"]["recipient_puzzle_hash"][2:] == normal_puzhash.hex()
396
+ assert txs["transactions"][0]["metadata"]["coin_id"] == merkle_coin.name().hex()
397
+ with pytest.raises(ValueError):
398
+ await api_0.spend_clawback_coins({})
399
+
400
+ test_fee = 10
401
+ resp = await api_0.spend_clawback_coins(
402
+ {"coin_ids": [normal_puzhash.hex(), merkle_coin.name().hex()], "fee": test_fee}
403
+ )
404
+ assert resp["success"]
405
+ assert len(resp["transaction_ids"]) == 1
406
+
407
+ await wallet_environments.process_pending_states(
408
+ [
409
+ WalletStateTransition(
410
+ pre_block_balance_updates={
411
+ 1: {
412
+ "unconfirmed_wallet_balance": tx_amount - test_fee,
413
+ "<=#spendable_balance": -1,
414
+ "<=#max_send_amount": -1,
415
+ ">=#pending_change": 1,
416
+ "pending_coin_removal_count": 2, # 1 for fee, one for clawback
417
+ }
418
+ },
419
+ post_block_balance_updates={
420
+ 1: {
421
+ "confirmed_wallet_balance": tx_amount - test_fee,
422
+ ">=#spendable_balance": 1,
423
+ ">=#max_send_amount": 1,
424
+ "<=#pending_change": -1,
425
+ "unspent_coin_count": 1,
426
+ "pending_coin_removal_count": -2,
427
+ }
428
+ },
429
+ ),
430
+ WalletStateTransition(
431
+ pre_block_balance_updates={},
432
+ post_block_balance_updates={},
433
+ ),
434
+ ]
435
+ )
436
+
437
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 0, 1000, CoinType.CLAWBACK)
438
+ await time_out_assert(20, wsm_2.coin_store.count_small_unspent, 0, 1000, CoinType.CLAWBACK)
439
+ txs = await api_0.get_transactions(
440
+ dict(
441
+ type_filter={
442
+ "values": [TransactionType.INCOMING_CLAWBACK_SEND.value, TransactionType.OUTGOING_CLAWBACK.value],
443
+ "mode": 1,
444
+ },
445
+ wallet_id=1,
446
+ )
447
+ )
448
+ assert len(txs["transactions"]) == 2
449
+ assert txs["transactions"][0]["confirmed"]
450
+ assert txs["transactions"][1]["confirmed"]
451
+
452
+ txs = await api_1.get_transactions(
453
+ dict(
454
+ type_filter={
455
+ "values": [
456
+ TransactionType.INCOMING_CLAWBACK_RECEIVE.value,
457
+ TransactionType.OUTGOING_CLAWBACK.value,
458
+ ],
459
+ "mode": 1,
460
+ },
461
+ wallet_id=1,
462
+ )
463
+ )
464
+ assert len(txs["transactions"]) == 1
465
+ assert txs["transactions"][0]["confirmed"]
466
+ interested_coins = await wsm_2.interested_store.get_interested_coin_ids()
467
+ assert merkle_coin.name() not in set(interested_coins)
468
+
469
+ @pytest.mark.parametrize(
470
+ "wallet_environments",
471
+ [{"num_environments": 1, "blocks_needed": [1], "reuse_puzhash": True}],
472
+ indirect=True,
473
+ )
474
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
475
+ @pytest.mark.anyio
476
+ async def test_wallet_clawback_sent_self(self, wallet_environments: WalletTestFramework) -> None:
477
+ env = wallet_environments.environments[0]
478
+ wsm = env.wallet_state_manager
479
+ wallet = env.xch_wallet
480
+ api_0 = env.rpc_api
481
+
482
+ tx_amount = 500
483
+ normal_puzhash = await wallet.get_new_puzzlehash()
484
+ # Transfer to normal wallet
485
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
486
+ await wallet.generate_signed_transaction(
487
+ uint64(tx_amount),
488
+ normal_puzhash,
489
+ action_scope,
490
+ uint64(0),
491
+ puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
492
+ memos=[b"Test"],
493
+ )
494
+
495
+ await wallet_environments.process_pending_states(
496
+ [
497
+ WalletStateTransition(
498
+ pre_block_balance_updates={
499
+ 1: {
500
+ "unconfirmed_wallet_balance": -1 * tx_amount,
501
+ "<=#spendable_balance": -1 * tx_amount,
502
+ "<=#max_send_amount": -1 * tx_amount,
503
+ ">=#pending_change": 1, # any amount increase
504
+ "pending_coin_removal_count": 1,
505
+ }
506
+ },
507
+ post_block_balance_updates={
508
+ 1: {
509
+ "confirmed_wallet_balance": -1 * tx_amount,
510
+ ">=#spendable_balance": 1, # any amount increase
511
+ ">=#max_send_amount": 1, # any amount increase
512
+ "<=#pending_change": -1, # any amount decrease
513
+ "pending_coin_removal_count": -1,
514
+ }
515
+ },
516
+ ),
517
+ WalletStateTransition(
518
+ pre_block_balance_updates={},
519
+ post_block_balance_updates={},
520
+ ),
521
+ ]
522
+ )
523
+
524
+ # Check merkle coins
525
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
526
+ # Claim merkle coin
527
+ [tx] = action_scope.side_effects.transactions
528
+ merkle_coin = tx.additions[0] if tx.additions[0].amount == tx_amount else tx.additions[1]
529
+ test_fee = 10
530
+ resp = await api_0.spend_clawback_coins(
531
+ {"coin_ids": [merkle_coin.name().hex(), normal_puzhash.hex()], "fee": test_fee}
532
+ )
533
+ assert resp["success"]
534
+ assert len(resp["transaction_ids"]) == 1
535
+ # Wait mempool update
536
+ await wallet_environments.process_pending_states(
537
+ [
538
+ WalletStateTransition(
539
+ pre_block_balance_updates={
540
+ 1: {
541
+ "unconfirmed_wallet_balance": tx_amount - test_fee,
542
+ "<=#spendable_balance": -1,
543
+ "<=#max_send_amount": -1,
544
+ ">=#pending_change": 1,
545
+ "pending_coin_removal_count": 2, # 1 for fee, one for clawback
546
+ }
547
+ },
548
+ post_block_balance_updates={
549
+ 1: {
550
+ "confirmed_wallet_balance": tx_amount - test_fee,
551
+ ">=#spendable_balance": 1,
552
+ ">=#max_send_amount": 1,
553
+ "<=#pending_change": -1,
554
+ "unspent_coin_count": 1,
555
+ "pending_coin_removal_count": -2,
556
+ }
557
+ },
558
+ ),
559
+ WalletStateTransition(
560
+ pre_block_balance_updates={},
561
+ post_block_balance_updates={},
562
+ ),
563
+ ]
564
+ )
565
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 0, 1000, CoinType.CLAWBACK)
566
+
567
+ txs = await api_0.get_transactions(
568
+ dict(
569
+ type_filter={
570
+ "values": [TransactionType.INCOMING_CLAWBACK_SEND.value, TransactionType.OUTGOING_CLAWBACK.value],
571
+ "mode": 1,
572
+ },
573
+ wallet_id=1,
574
+ )
575
+ )
576
+ assert len(txs["transactions"]) == 2
577
+ assert txs["transactions"][0]["confirmed"]
578
+ assert txs["transactions"][1]["confirmed"]
579
+ assert txs["transactions"][0]["memos"] != txs["transactions"][1]["memos"]
580
+ assert next(iter(txs["transactions"][0]["memos"].values())) == b"Test".hex()
581
+
582
+ @pytest.mark.parametrize(
583
+ "wallet_environments",
584
+ [{"num_environments": 2, "blocks_needed": [1, 1], "reuse_puzhash": True}],
585
+ indirect=True,
586
+ )
587
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
588
+ @pytest.mark.anyio
589
+ async def test_wallet_clawback_claim_manual(self, wallet_environments: WalletTestFramework) -> None:
590
+ env = wallet_environments.environments[0]
591
+ env_2 = wallet_environments.environments[1]
592
+ wsm = env.wallet_state_manager
593
+ wsm_2 = env_2.wallet_state_manager
594
+ wallet = env.xch_wallet
595
+ wallet_1 = env_2.xch_wallet
596
+ api_0 = env.rpc_api
597
+ api_1 = env_2.rpc_api
598
+
599
+ tx_amount = 500
600
+ normal_puzhash = await wallet_1.get_new_puzzlehash()
601
+ # Transfer to normal wallet
602
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
603
+ await wallet.generate_signed_transaction(
604
+ uint64(tx_amount),
605
+ normal_puzhash,
606
+ action_scope,
607
+ uint64(0),
608
+ puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
609
+ )
610
+
611
+ await wallet_environments.process_pending_states(
612
+ [
613
+ WalletStateTransition(
614
+ pre_block_balance_updates={
615
+ 1: {
616
+ "unconfirmed_wallet_balance": -1 * tx_amount,
617
+ "<=#spendable_balance": -1 * tx_amount,
618
+ "<=#max_send_amount": -1 * tx_amount,
619
+ ">=#pending_change": 1, # any amount increase
620
+ "pending_coin_removal_count": 1,
621
+ }
622
+ },
623
+ post_block_balance_updates={
624
+ 1: {
625
+ "confirmed_wallet_balance": -1 * tx_amount,
626
+ ">=#spendable_balance": 1, # any amount increase
627
+ ">=#max_send_amount": 1, # any amount increase
628
+ "<=#pending_change": -1, # any amount decrease
629
+ "pending_coin_removal_count": -1,
630
+ }
631
+ },
632
+ ),
633
+ WalletStateTransition(
634
+ pre_block_balance_updates={},
635
+ post_block_balance_updates={},
636
+ ),
637
+ ]
638
+ )
639
+
640
+ # Check merkle coins
641
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
642
+ await time_out_assert(20, wsm_2.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
643
+
644
+ # Farm a block to pass timelock
645
+ await wallet_environments.process_pending_states(
646
+ [
647
+ WalletStateTransition(
648
+ pre_block_balance_updates={},
649
+ post_block_balance_updates={},
650
+ ),
651
+ WalletStateTransition(
652
+ pre_block_balance_updates={},
653
+ post_block_balance_updates={},
654
+ ),
655
+ ]
656
+ )
657
+
658
+ # Claim merkle coin
659
+ [tx] = action_scope.side_effects.transactions
660
+ merkle_coin = tx.additions[0] if tx.additions[0].amount == tx_amount else tx.additions[1]
661
+ test_fee = 10
662
+ resp = await api_1.spend_clawback_coins(
663
+ {"coin_ids": [merkle_coin.name().hex(), normal_puzhash.hex()], "fee": test_fee}
664
+ )
665
+ assert resp["success"]
666
+ assert len(resp["transaction_ids"]) == 1
667
+
668
+ await wallet_environments.process_pending_states(
669
+ [
670
+ WalletStateTransition(
671
+ pre_block_balance_updates={},
672
+ post_block_balance_updates={},
673
+ ),
674
+ WalletStateTransition(
675
+ pre_block_balance_updates={
676
+ 1: {
677
+ "unconfirmed_wallet_balance": tx_amount - test_fee,
678
+ "<=#spendable_balance": -1 * tx_amount,
679
+ "<=#max_send_amount": -1 * tx_amount,
680
+ ">=#pending_change": 1, # any amount increase
681
+ "pending_coin_removal_count": 2, # 1 for fee, 1 for clawback
682
+ }
683
+ },
684
+ post_block_balance_updates={
685
+ 1: {
686
+ "confirmed_wallet_balance": tx_amount - test_fee,
687
+ ">=#spendable_balance": 1, # any amount increase
688
+ ">=#max_send_amount": 1, # any amount increase
689
+ "<=#pending_change": -1, # any amount decrease
690
+ "unspent_coin_count": 1,
691
+ "pending_coin_removal_count": -2,
692
+ }
693
+ },
694
+ ),
695
+ ]
696
+ )
697
+
698
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 0, 1000, CoinType.CLAWBACK)
699
+ await time_out_assert(20, wsm_2.coin_store.count_small_unspent, 0, 1000, CoinType.CLAWBACK)
700
+
701
+ txs = await api_0.get_transactions(
702
+ dict(
703
+ type_filter={
704
+ "values": [
705
+ TransactionType.INCOMING_CLAWBACK_SEND.value,
706
+ ],
707
+ "mode": 1,
708
+ },
709
+ wallet_id=1,
710
+ )
711
+ )
712
+ assert len(txs["transactions"]) == 1
713
+ assert txs["transactions"][0]["confirmed"]
714
+
715
+ @pytest.mark.parametrize(
716
+ "wallet_environments",
717
+ [{"num_environments": 2, "blocks_needed": [1, 1], "reuse_puzhash": True}],
718
+ indirect=True,
719
+ )
720
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
721
+ @pytest.mark.anyio
722
+ async def test_wallet_clawback_reorg(self, wallet_environments: WalletTestFramework) -> None:
723
+ full_node_api = wallet_environments.full_node
724
+ env = wallet_environments.environments[0]
725
+ env_2 = wallet_environments.environments[1]
726
+ wsm = env.wallet_state_manager
727
+ wsm_2 = env_2.wallet_state_manager
728
+ wallet = env.xch_wallet
729
+ wallet_1 = env_2.xch_wallet
730
+
731
+ tx_amount = 500
732
+ normal_puzhash = await wallet_1.get_new_puzzlehash()
733
+ # Transfer to normal wallet
734
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
735
+ await wallet.generate_signed_transaction(
736
+ uint64(tx_amount),
737
+ normal_puzhash,
738
+ action_scope,
739
+ uint64(0),
740
+ puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
741
+ )
742
+
743
+ await wallet_environments.process_pending_states(
744
+ [
745
+ WalletStateTransition(
746
+ pre_block_balance_updates={
747
+ 1: {
748
+ "unconfirmed_wallet_balance": -1 * tx_amount,
749
+ "<=#spendable_balance": -1 * tx_amount,
750
+ "<=#max_send_amount": -1 * tx_amount,
751
+ ">=#pending_change": 1, # any amount increase
752
+ "pending_coin_removal_count": 1,
753
+ }
754
+ },
755
+ post_block_balance_updates={
756
+ 1: {
757
+ "confirmed_wallet_balance": -1 * tx_amount,
758
+ ">=#spendable_balance": 1, # any amount increase
759
+ ">=#max_send_amount": 1, # any amount increase
760
+ "<=#pending_change": -1, # any amount decrease
761
+ "pending_coin_removal_count": -1,
762
+ }
763
+ },
764
+ ),
765
+ WalletStateTransition(
766
+ pre_block_balance_updates={},
767
+ post_block_balance_updates={},
768
+ ),
769
+ ]
770
+ )
771
+
772
+ # Check merkle coins
773
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
774
+ await time_out_assert(20, wsm_2.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
775
+ # Reorg before claim
776
+ # Test Reorg mint
777
+ height = full_node_api.full_node.blockchain.get_peak_height()
778
+ assert height is not None
779
+ await full_node_api.reorg_from_index_to_new_index(
780
+ ReorgProtocol(uint32(height - 2), uint32(height + 1), bytes32.zeros, None)
781
+ )
782
+
783
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 0, 1000, CoinType.CLAWBACK)
784
+ await time_out_assert(20, wsm_2.coin_store.count_small_unspent, 0, 1000, CoinType.CLAWBACK)
785
+
786
+ await wallet_environments.process_pending_states(
787
+ [
788
+ WalletStateTransition(
789
+ pre_block_balance_updates={
790
+ 1: {
791
+ "confirmed_wallet_balance": tx_amount, # confirmed balance comes back
792
+ # clawback transaction is now outstanding
793
+ "<=#spendable_balance": -1 * tx_amount,
794
+ "<=#max_send_amount": -1 * tx_amount,
795
+ ">=#pending_change": 1, # any amount increase
796
+ "pending_coin_removal_count": 1,
797
+ }
798
+ },
799
+ post_block_balance_updates={
800
+ 1: {
801
+ "confirmed_wallet_balance": -1 * tx_amount,
802
+ ">=#spendable_balance": 1, # any amount increase
803
+ ">=#max_send_amount": 1, # any amount increase
804
+ "<=#pending_change": -1, # any amount decrease
805
+ "pending_coin_removal_count": -1,
806
+ }
807
+ },
808
+ ),
809
+ WalletStateTransition(
810
+ pre_block_balance_updates={},
811
+ post_block_balance_updates={},
812
+ ),
813
+ ]
814
+ )
815
+
816
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
817
+ await time_out_assert(20, wsm_2.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
818
+
819
+ # Claim merkle coin
820
+ env_2.node.set_auto_claim(AutoClaimSettings(enabled=True))
821
+ # clawback merkle coin
822
+ await wallet_environments.process_pending_states(
823
+ [
824
+ WalletStateTransition(),
825
+ WalletStateTransition(
826
+ pre_block_balance_updates={},
827
+ # After auto claim is set, the next block will trigger submission of clawback claims
828
+ post_block_balance_updates={
829
+ 1: {
830
+ "unconfirmed_wallet_balance": tx_amount,
831
+ "pending_change": tx_amount, # This is a little weird but I think intentional and correct
832
+ "pending_coin_removal_count": 1,
833
+ }
834
+ },
835
+ ),
836
+ ]
837
+ )
838
+ await wallet_environments.process_pending_states(
839
+ [
840
+ WalletStateTransition(),
841
+ WalletStateTransition(
842
+ pre_block_balance_updates={},
843
+ post_block_balance_updates={
844
+ 1: {
845
+ "confirmed_wallet_balance": tx_amount,
846
+ "spendable_balance": tx_amount,
847
+ "max_send_amount": tx_amount,
848
+ "unspent_coin_count": 1,
849
+ "pending_change": -1 * tx_amount,
850
+ "pending_coin_removal_count": -1,
851
+ }
852
+ },
853
+ ),
854
+ ]
855
+ )
856
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 0, 1000, CoinType.CLAWBACK)
857
+ await time_out_assert(20, wsm_2.coin_store.count_small_unspent, 0, 1000, CoinType.CLAWBACK)
858
+ # Reorg after claim
859
+ height = full_node_api.full_node.blockchain.get_peak_height()
860
+ assert height is not None
861
+ await full_node_api.reorg_from_index_to_new_index(
862
+ ReorgProtocol(uint32(height - 1), uint32(height + 1), bytes32.zeros, None)
863
+ )
864
+
865
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
866
+ await time_out_assert(20, wsm_2.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
867
+
868
+ await wallet_environments.process_pending_states(
869
+ [
870
+ WalletStateTransition(
871
+ pre_block_balance_updates={},
872
+ post_block_balance_updates={},
873
+ ),
874
+ WalletStateTransition(
875
+ pre_block_balance_updates={
876
+ 1: {
877
+ "confirmed_wallet_balance": -1 * tx_amount,
878
+ "spendable_balance": -1 * tx_amount,
879
+ "max_send_amount": -1 * tx_amount,
880
+ "unspent_coin_count": -1,
881
+ "pending_change": tx_amount,
882
+ "pending_coin_removal_count": 1,
883
+ }
884
+ },
885
+ post_block_balance_updates={
886
+ 1: {
887
+ "confirmed_wallet_balance": tx_amount,
888
+ "spendable_balance": tx_amount,
889
+ "max_send_amount": tx_amount,
890
+ "unspent_coin_count": 1,
891
+ "pending_change": -1 * tx_amount,
892
+ "pending_coin_removal_count": -1,
893
+ }
894
+ },
895
+ ),
896
+ ]
897
+ )
898
+
899
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 0, 1000, CoinType.CLAWBACK)
900
+ await time_out_assert(20, wsm_2.coin_store.count_small_unspent, 0, 1000, CoinType.CLAWBACK)
901
+
902
+ @pytest.mark.parametrize(
903
+ "wallet_environments",
904
+ [{"num_environments": 1, "blocks_needed": [1], "trusted": True, "reuse_puzhash": True}],
905
+ indirect=True,
906
+ )
907
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
908
+ @pytest.mark.anyio
909
+ async def test_get_clawback_coins(self, wallet_environments: WalletTestFramework) -> None:
910
+ env = wallet_environments.environments[0]
911
+ wsm = env.wallet_state_manager
912
+ wallet = env.xch_wallet
913
+
914
+ tx_amount = 500
915
+ # Transfer to normal wallet
916
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
917
+ await wallet.generate_signed_transaction(
918
+ uint64(tx_amount),
919
+ bytes32.zeros,
920
+ action_scope,
921
+ uint64(0),
922
+ puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 500}],
923
+ )
924
+
925
+ await wallet_environments.process_pending_states(
926
+ [
927
+ WalletStateTransition(
928
+ pre_block_balance_updates={
929
+ 1: {
930
+ "unconfirmed_wallet_balance": -1 * tx_amount,
931
+ "<=#spendable_balance": -1 * tx_amount,
932
+ "<=#max_send_amount": -1 * tx_amount,
933
+ ">=#pending_change": 1, # any amount increase
934
+ "pending_coin_removal_count": 1,
935
+ }
936
+ },
937
+ post_block_balance_updates={
938
+ 1: {
939
+ "confirmed_wallet_balance": -1 * tx_amount,
940
+ ">=#spendable_balance": 1, # any amount increase
941
+ ">=#max_send_amount": 1, # any amount increase
942
+ "<=#pending_change": -1, # any amount decrease
943
+ "pending_coin_removal_count": -1,
944
+ }
945
+ },
946
+ ),
947
+ WalletStateTransition(
948
+ pre_block_balance_updates={},
949
+ post_block_balance_updates={},
950
+ ),
951
+ ]
952
+ )
953
+
954
+ # Check merkle coins
955
+ await time_out_assert(20, wsm.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
956
+ # clawback merkle coin
957
+ [tx] = action_scope.side_effects.transactions
958
+ merkle_coin = tx.additions[0] if tx.additions[0].amount == tx_amount else tx.additions[1]
959
+ resp = await env.rpc_api.get_coin_records({"wallet_id": 1, "coin_type": 1})
960
+ assert len(resp["coin_records"]) == 1
961
+ assert resp["coin_records"][0]["id"][2:] == merkle_coin.name().hex()
962
+
963
+ @pytest.mark.parametrize(
964
+ "wallet_environments",
965
+ [{"num_environments": 2, "blocks_needed": [1, 1], "reuse_puzhash": False}],
966
+ indirect=True,
967
+ )
968
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
969
+ @pytest.mark.anyio
970
+ async def test_clawback_resync(self, self_hostname: str, wallet_environments: WalletTestFramework) -> None:
971
+ full_node_api = wallet_environments.full_node
972
+ env_1 = wallet_environments.environments[0]
973
+ env_2 = wallet_environments.environments[1]
974
+ wsm_1 = env_1.wallet_state_manager
975
+ wsm_2 = env_2.wallet_state_manager
976
+ wallet_1 = env_1.xch_wallet
977
+ wallet_2 = env_2.xch_wallet
978
+ api_1 = env_1.rpc_api
979
+
980
+ wallet_1_puzhash = await wallet_1.get_new_puzzlehash()
981
+ wallet_2_puzhash = await wallet_2.get_new_puzzlehash()
982
+
983
+ tx_amount = 500
984
+ # Transfer to normal wallet
985
+ async with wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
986
+ await wallet_1.generate_signed_transaction(
987
+ uint64(tx_amount),
988
+ wallet_2_puzhash,
989
+ action_scope,
990
+ uint64(0),
991
+ puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
992
+ )
993
+
994
+ [tx1] = action_scope.side_effects.transactions
995
+ clawback_coin_id_1 = tx1.additions[0].name()
996
+ assert tx1.spend_bundle is not None
997
+
998
+ await wallet_environments.process_pending_states(
999
+ [
1000
+ WalletStateTransition(
1001
+ pre_block_balance_updates={
1002
+ 1: {
1003
+ "unconfirmed_wallet_balance": -1 * tx_amount,
1004
+ "<=#spendable_balance": -1 * tx_amount,
1005
+ "<=#max_send_amount": -1 * tx_amount,
1006
+ ">=#pending_change": 1, # any amount increase
1007
+ "pending_coin_removal_count": 1,
1008
+ }
1009
+ },
1010
+ post_block_balance_updates={
1011
+ 1: {
1012
+ "confirmed_wallet_balance": -1 * tx_amount,
1013
+ ">=#spendable_balance": 1, # any amount increase
1014
+ ">=#max_send_amount": 1, # any amount increase
1015
+ "<=#pending_change": -1, # any amount decrease
1016
+ "pending_coin_removal_count": -1,
1017
+ }
1018
+ },
1019
+ ),
1020
+ WalletStateTransition(
1021
+ pre_block_balance_updates={},
1022
+ post_block_balance_updates={},
1023
+ ),
1024
+ ]
1025
+ )
1026
+
1027
+ # Check merkle coins
1028
+ await time_out_assert(20, wsm_1.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
1029
+ await time_out_assert(20, wsm_2.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
1030
+
1031
+ tx_amount2 = 700
1032
+ async with wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1033
+ await wallet_1.generate_signed_transaction(
1034
+ uint64(tx_amount2),
1035
+ wallet_1_puzhash,
1036
+ action_scope,
1037
+ uint64(0),
1038
+ puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
1039
+ )
1040
+ [tx2] = action_scope.side_effects.transactions
1041
+ clawback_coin_id_2 = tx2.additions[0].name()
1042
+ assert tx2.spend_bundle is not None
1043
+
1044
+ await wallet_environments.process_pending_states(
1045
+ [
1046
+ WalletStateTransition(
1047
+ pre_block_balance_updates={
1048
+ 1: {
1049
+ "unconfirmed_wallet_balance": -1 * tx_amount2,
1050
+ "<=#spendable_balance": -1 * tx_amount2,
1051
+ "<=#max_send_amount": -1 * tx_amount2,
1052
+ ">=#pending_change": 1, # any amount increase
1053
+ "pending_coin_removal_count": 1,
1054
+ }
1055
+ },
1056
+ post_block_balance_updates={
1057
+ 1: {
1058
+ "confirmed_wallet_balance": -1 * tx_amount2,
1059
+ ">=#spendable_balance": 1, # any amount increase
1060
+ ">=#max_send_amount": 1, # any amount increase
1061
+ "<=#pending_change": -1, # any amount decrease
1062
+ "pending_coin_removal_count": -1,
1063
+ }
1064
+ },
1065
+ ),
1066
+ WalletStateTransition(
1067
+ pre_block_balance_updates={},
1068
+ post_block_balance_updates={},
1069
+ ),
1070
+ ]
1071
+ )
1072
+
1073
+ # Check merkle coins
1074
+ await time_out_assert(20, wsm_1.coin_store.count_small_unspent, 2, 1000, CoinType.CLAWBACK)
1075
+ await time_out_assert(20, wsm_2.coin_store.count_small_unspent, 1, 1000, CoinType.CLAWBACK)
1076
+ # clawback merkle coin
1077
+ resp = await api_1.spend_clawback_coins({"coin_ids": [clawback_coin_id_1.hex()], "fee": 0})
1078
+ assert resp["success"]
1079
+ assert len(resp["transaction_ids"]) == 1
1080
+ resp = await api_1.spend_clawback_coins({"coin_ids": [clawback_coin_id_2.hex()], "fee": 0})
1081
+ assert resp["success"]
1082
+ assert len(resp["transaction_ids"]) == 1
1083
+
1084
+ await wallet_environments.process_pending_states(
1085
+ [
1086
+ WalletStateTransition(
1087
+ pre_block_balance_updates={
1088
+ 1: {
1089
+ "unconfirmed_wallet_balance": tx_amount + tx_amount2,
1090
+ "pending_change": tx_amount + tx_amount2,
1091
+ "pending_coin_removal_count": 2,
1092
+ }
1093
+ },
1094
+ post_block_balance_updates={
1095
+ 1: {
1096
+ "confirmed_wallet_balance": tx_amount + tx_amount2,
1097
+ "max_send_amount": tx_amount + tx_amount2,
1098
+ "spendable_balance": tx_amount + tx_amount2,
1099
+ "pending_change": -1 * (tx_amount + tx_amount2),
1100
+ "unspent_coin_count": 2,
1101
+ "pending_coin_removal_count": -2,
1102
+ }
1103
+ },
1104
+ ),
1105
+ WalletStateTransition(
1106
+ pre_block_balance_updates={},
1107
+ post_block_balance_updates={},
1108
+ ),
1109
+ ]
1110
+ )
1111
+
1112
+ await time_out_assert(20, wsm_1.coin_store.count_small_unspent, 0, 1000, CoinType.CLAWBACK)
1113
+ await time_out_assert(20, wsm_2.coin_store.count_small_unspent, 0, 1000, CoinType.CLAWBACK)
1114
+
1115
+ before_txs: dict[str, dict[TransactionType, int]] = {"sender": {}, "recipient": {}}
1116
+ before_txs["sender"][
1117
+ TransactionType.INCOMING_CLAWBACK_SEND
1118
+ ] = await wsm_1.tx_store.get_transaction_count_for_wallet(
1119
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.INCOMING_CLAWBACK_SEND])
1120
+ )
1121
+ before_txs["sender"][TransactionType.OUTGOING_CLAWBACK] = await wsm_1.tx_store.get_transaction_count_for_wallet(
1122
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.OUTGOING_CLAWBACK])
1123
+ )
1124
+ before_txs["sender"][TransactionType.OUTGOING_TX] = await wsm_1.tx_store.get_transaction_count_for_wallet(
1125
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.OUTGOING_TX])
1126
+ )
1127
+ before_txs["sender"][TransactionType.INCOMING_TX] = await wsm_1.tx_store.get_transaction_count_for_wallet(
1128
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.INCOMING_TX])
1129
+ )
1130
+ before_txs["sender"][TransactionType.COINBASE_REWARD] = await wsm_1.tx_store.get_transaction_count_for_wallet(
1131
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.COINBASE_REWARD])
1132
+ )
1133
+ before_txs["recipient"][
1134
+ TransactionType.INCOMING_CLAWBACK_RECEIVE
1135
+ ] = await wsm_2.tx_store.get_transaction_count_for_wallet(
1136
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.INCOMING_CLAWBACK_RECEIVE])
1137
+ )
1138
+ # Resync start
1139
+ env_1.node._close()
1140
+ await env_1.node._await_closed()
1141
+ env_2.node._close()
1142
+ await env_2.node._await_closed()
1143
+ env_1.node.config["database_path"] = "wallet/db/blockchain_wallet_v2_test1_CHALLENGE_KEY.sqlite"
1144
+ env_2.node.config["database_path"] = "wallet/db/blockchain_wallet_v2_test2_CHALLENGE_KEY.sqlite"
1145
+
1146
+ # use second node to start the same wallet, reusing config and db
1147
+ await env_1.node._start()
1148
+ await env_1.peer_server.start_client(PeerInfo(self_hostname, full_node_api.full_node.server.get_port()), None)
1149
+ await env_2.node._start()
1150
+ await env_2.peer_server.start_client(PeerInfo(self_hostname, full_node_api.full_node.server.get_port()), None)
1151
+
1152
+ await wallet_environments.process_pending_states(
1153
+ [
1154
+ WalletStateTransition(),
1155
+ WalletStateTransition(),
1156
+ ]
1157
+ )
1158
+
1159
+ wsm_1 = env_1.node.wallet_state_manager
1160
+ wsm_2 = env_2.node.wallet_state_manager
1161
+
1162
+ after_txs: dict[str, dict[TransactionType, int]] = {"sender": {}, "recipient": {}}
1163
+ after_txs["sender"][
1164
+ TransactionType.INCOMING_CLAWBACK_SEND
1165
+ ] = await wsm_1.tx_store.get_transaction_count_for_wallet(
1166
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.INCOMING_CLAWBACK_SEND])
1167
+ )
1168
+ after_txs["sender"][TransactionType.OUTGOING_CLAWBACK] = await wsm_1.tx_store.get_transaction_count_for_wallet(
1169
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.OUTGOING_CLAWBACK])
1170
+ )
1171
+ after_txs["sender"][TransactionType.OUTGOING_TX] = await wsm_1.tx_store.get_transaction_count_for_wallet(
1172
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.OUTGOING_TX])
1173
+ )
1174
+ after_txs["sender"][TransactionType.INCOMING_TX] = await wsm_1.tx_store.get_transaction_count_for_wallet(
1175
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.INCOMING_TX])
1176
+ )
1177
+ after_txs["sender"][TransactionType.COINBASE_REWARD] = await wsm_1.tx_store.get_transaction_count_for_wallet(
1178
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.COINBASE_REWARD])
1179
+ )
1180
+ after_txs["recipient"][
1181
+ TransactionType.INCOMING_CLAWBACK_RECEIVE
1182
+ ] = await wsm_2.tx_store.get_transaction_count_for_wallet(
1183
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.INCOMING_CLAWBACK_RECEIVE])
1184
+ )
1185
+ # Check clawback
1186
+ clawback_tx_1 = await wsm_1.tx_store.get_transaction_record(clawback_coin_id_1)
1187
+ clawback_tx_2 = await wsm_1.tx_store.get_transaction_record(clawback_coin_id_2)
1188
+ assert clawback_tx_1 is not None
1189
+ assert clawback_tx_1.confirmed
1190
+ assert clawback_tx_2 is not None
1191
+ assert clawback_tx_2.confirmed
1192
+ outgoing_clawback_txs = await wsm_1.tx_store.get_transactions_between(
1193
+ 1, 0, 100, type_filter=TransactionTypeFilter.include([TransactionType.OUTGOING_CLAWBACK])
1194
+ )
1195
+ assert len(outgoing_clawback_txs) == 2
1196
+ assert outgoing_clawback_txs[0].confirmed
1197
+ assert outgoing_clawback_txs[1].confirmed
1198
+
1199
+ # transactions should be the same
1200
+
1201
+ assert (
1202
+ before_txs["sender"][TransactionType.OUTGOING_CLAWBACK]
1203
+ == after_txs["sender"][TransactionType.OUTGOING_CLAWBACK]
1204
+ )
1205
+ assert before_txs["sender"] == after_txs["sender"]
1206
+ assert before_txs["recipient"] == after_txs["recipient"]
1207
+
1208
+ @pytest.mark.parametrize(
1209
+ "wallet_environments",
1210
+ [{"num_environments": 1, "blocks_needed": [3]}],
1211
+ indirect=True,
1212
+ )
1213
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
1214
+ @pytest.mark.anyio
1215
+ async def test_wallet_coinbase_reorg(self, wallet_environments: WalletTestFramework) -> None:
1216
+ full_node_api = wallet_environments.full_node
1217
+ env = wallet_environments.environments[0]
1218
+ wallet = env.xch_wallet
1219
+
1220
+ peak = full_node_api.full_node.blockchain.get_peak()
1221
+ assert peak is not None
1222
+ permanent_height = peak.height # The height of the blocks we will not reorg
1223
+
1224
+ extra_blocks = 2
1225
+ await full_node_api.farm_blocks_to_wallet(count=extra_blocks, wallet=wallet)
1226
+ await full_node_api.wait_for_wallet_synced(wallet_node=env.node, timeout=5)
1227
+ await env.change_balances(
1228
+ {
1229
+ 1: {
1230
+ "confirmed_wallet_balance": 2_000_000_000_000 * extra_blocks,
1231
+ "unconfirmed_wallet_balance": 2_000_000_000_000 * extra_blocks,
1232
+ "max_send_amount": 2_000_000_000_000 * extra_blocks,
1233
+ "spendable_balance": 2_000_000_000_000 * extra_blocks,
1234
+ "unspent_coin_count": 4,
1235
+ }
1236
+ }
1237
+ )
1238
+
1239
+ await full_node_api.reorg_from_index_to_new_index(
1240
+ ReorgProtocol(
1241
+ uint32(permanent_height), uint32(permanent_height + extra_blocks + 6), bytes32(32 * b"0"), None
1242
+ )
1243
+ )
1244
+
1245
+ await full_node_api.wait_for_wallet_synced(wallet_node=env.node, timeout=5)
1246
+
1247
+ await env.change_balances(
1248
+ {
1249
+ 1: {
1250
+ "confirmed_wallet_balance": -2_000_000_000_000 * extra_blocks,
1251
+ "unconfirmed_wallet_balance": -2_000_000_000_000 * extra_blocks,
1252
+ "max_send_amount": -2_000_000_000_000 * extra_blocks,
1253
+ "spendable_balance": -2_000_000_000_000 * extra_blocks,
1254
+ "unspent_coin_count": -4,
1255
+ }
1256
+ }
1257
+ )
1258
+
1259
+ @pytest.mark.parametrize("trusted", [True, False])
1260
+ @pytest.mark.anyio
1261
+ async def test_wallet_send_to_three_peers(
1262
+ self,
1263
+ three_sim_two_wallets: tuple[list[FullNodeSimulator], list[tuple[WalletNode, ChiaServer]], BlockTools],
1264
+ trusted: bool,
1265
+ self_hostname: str,
1266
+ ) -> None:
1267
+ num_blocks = 10
1268
+ full_nodes, wallets, _ = three_sim_two_wallets
1269
+
1270
+ wallet_0, wallet_server_0 = wallets[0]
1271
+
1272
+ full_node_api_0 = full_nodes[0]
1273
+ full_node_api_1 = full_nodes[1]
1274
+ full_node_api_2 = full_nodes[2]
1275
+
1276
+ full_node_0 = full_node_api_0.full_node
1277
+ full_node_1 = full_node_api_1.full_node
1278
+ full_node_2 = full_node_api_2.full_node
1279
+
1280
+ server_0 = full_node_0.server
1281
+ server_1 = full_node_1.server
1282
+ server_2 = full_node_2.server
1283
+
1284
+ if trusted:
1285
+ wallet_0.config["trusted_peers"] = {
1286
+ server_0.node_id.hex(): server_0.node_id.hex(),
1287
+ server_1.node_id.hex(): server_1.node_id.hex(),
1288
+ server_2.node_id.hex(): server_2.node_id.hex(),
1289
+ }
1290
+
1291
+ else:
1292
+ wallet_0.config["trusted_peers"] = {}
1293
+
1294
+ # wallet0 <-> sever0
1295
+ await wallet_server_0.start_client(PeerInfo(self_hostname, server_0.get_port()), None)
1296
+
1297
+ await full_node_api_0.farm_blocks_to_wallet(count=num_blocks, wallet=wallet_0.wallet_state_manager.main_wallet)
1298
+
1299
+ all_blocks = await full_node_api_0.get_all_full_blocks()
1300
+
1301
+ for block in all_blocks:
1302
+ await full_node_1.add_block(block)
1303
+ await full_node_2.add_block(block)
1304
+
1305
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1306
+ await wallet_0.wallet_state_manager.main_wallet.generate_signed_transaction(
1307
+ uint64(10),
1308
+ bytes32(32 * b"0"),
1309
+ action_scope,
1310
+ uint64(0),
1311
+ )
1312
+ await full_node_api_0.wait_transaction_records_entered_mempool(records=action_scope.side_effects.transactions)
1313
+
1314
+ # wallet0 <-> sever1
1315
+ await wallet_server_0.start_client(PeerInfo(self_hostname, server_1.get_port()), wallet_0.on_connect)
1316
+ await full_node_api_1.wait_transaction_records_entered_mempool(records=action_scope.side_effects.transactions)
1317
+
1318
+ # wallet0 <-> sever2
1319
+ await wallet_server_0.start_client(PeerInfo(self_hostname, server_2.get_port()), wallet_0.on_connect)
1320
+ await full_node_api_2.wait_transaction_records_entered_mempool(records=action_scope.side_effects.transactions)
1321
+
1322
+ @pytest.mark.parametrize(
1323
+ "wallet_environments",
1324
+ [{"num_environments": 2, "blocks_needed": [1, 1]}],
1325
+ indirect=True,
1326
+ )
1327
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
1328
+ @pytest.mark.anyio
1329
+ async def test_wallet_make_transaction_hop(self, wallet_environments: WalletTestFramework) -> None:
1330
+ env_0 = wallet_environments.environments[0]
1331
+ env_1 = wallet_environments.environments[1]
1332
+ wallet_0 = env_0.xch_wallet
1333
+ wallet_1 = env_1.xch_wallet
1334
+
1335
+ tx_amount = 10
1336
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1337
+ await wallet_0.generate_signed_transaction(
1338
+ uint64(tx_amount),
1339
+ await wallet_1.get_puzzle_hash(False),
1340
+ action_scope,
1341
+ uint64(0),
1342
+ )
1343
+
1344
+ await wallet_environments.process_pending_states(
1345
+ [
1346
+ WalletStateTransition(
1347
+ pre_block_balance_updates={
1348
+ 1: {
1349
+ "unconfirmed_wallet_balance": -1 * tx_amount,
1350
+ "<=#spendable_balance": -1 * tx_amount,
1351
+ "<=#max_send_amount": -1 * tx_amount,
1352
+ ">=#pending_change": 1, # any amount increase
1353
+ "pending_coin_removal_count": 1,
1354
+ }
1355
+ },
1356
+ post_block_balance_updates={
1357
+ 1: {
1358
+ "confirmed_wallet_balance": -1 * tx_amount,
1359
+ ">=#spendable_balance": 1, # any amount increase
1360
+ ">=#max_send_amount": 1, # any amount increase
1361
+ "<=#pending_change": -1, # any amount decrease
1362
+ "pending_coin_removal_count": -1,
1363
+ }
1364
+ },
1365
+ ),
1366
+ WalletStateTransition(
1367
+ pre_block_balance_updates={},
1368
+ post_block_balance_updates={
1369
+ 1: {
1370
+ "confirmed_wallet_balance": tx_amount,
1371
+ "unconfirmed_wallet_balance": tx_amount,
1372
+ "spendable_balance": tx_amount,
1373
+ "max_send_amount": tx_amount,
1374
+ "unspent_coin_count": 1,
1375
+ }
1376
+ },
1377
+ ),
1378
+ ]
1379
+ )
1380
+
1381
+ tx_amount = 5
1382
+ async with wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1383
+ await wallet_1.generate_signed_transaction(
1384
+ uint64(tx_amount), await wallet_0.get_puzzle_hash(False), action_scope, uint64(0)
1385
+ )
1386
+
1387
+ await wallet_environments.process_pending_states(
1388
+ [
1389
+ WalletStateTransition(
1390
+ pre_block_balance_updates={},
1391
+ post_block_balance_updates={
1392
+ 1: {
1393
+ "confirmed_wallet_balance": tx_amount,
1394
+ "unconfirmed_wallet_balance": tx_amount,
1395
+ "spendable_balance": tx_amount,
1396
+ "max_send_amount": tx_amount,
1397
+ "unspent_coin_count": 1,
1398
+ }
1399
+ },
1400
+ ),
1401
+ WalletStateTransition(
1402
+ pre_block_balance_updates={
1403
+ 1: {
1404
+ "unconfirmed_wallet_balance": -1 * tx_amount,
1405
+ "<=#spendable_balance": -1 * tx_amount,
1406
+ "<=#max_send_amount": -1 * tx_amount,
1407
+ ">=#pending_change": 1, # any amount increase
1408
+ "pending_coin_removal_count": 1,
1409
+ }
1410
+ },
1411
+ post_block_balance_updates={
1412
+ 1: {
1413
+ "confirmed_wallet_balance": -1 * tx_amount,
1414
+ ">=#spendable_balance": 1, # any amount increase
1415
+ ">=#max_send_amount": 1, # any amount increase
1416
+ "<=#pending_change": -1, # any amount decrease
1417
+ "pending_coin_removal_count": -1,
1418
+ }
1419
+ },
1420
+ ),
1421
+ ]
1422
+ )
1423
+
1424
+ @pytest.mark.parametrize(
1425
+ "wallet_environments",
1426
+ [{"num_environments": 2, "blocks_needed": [1, 1]}],
1427
+ indirect=True,
1428
+ )
1429
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
1430
+ @pytest.mark.anyio
1431
+ async def test_wallet_make_transaction_with_fee(self, wallet_environments: WalletTestFramework) -> None:
1432
+ env_0 = wallet_environments.environments[0]
1433
+ env_1 = wallet_environments.environments[1]
1434
+ wallet_0 = env_0.xch_wallet
1435
+ wallet_1 = env_1.xch_wallet
1436
+
1437
+ tx_amount = 1_750_000_000_000 # ensures we grab both coins
1438
+ tx_fee = 10
1439
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1440
+ await wallet_0.generate_signed_transaction(
1441
+ uint64(tx_amount),
1442
+ await wallet_1.get_new_puzzlehash(),
1443
+ action_scope,
1444
+ uint64(tx_fee),
1445
+ )
1446
+ [tx] = action_scope.side_effects.transactions
1447
+ assert tx.spend_bundle is not None
1448
+
1449
+ fees = estimate_fees(tx.spend_bundle)
1450
+ assert fees == tx_fee
1451
+
1452
+ await wallet_environments.process_pending_states(
1453
+ [
1454
+ WalletStateTransition(
1455
+ pre_block_balance_updates={
1456
+ 1: {
1457
+ "unconfirmed_wallet_balance": -1 * tx_amount - tx_fee,
1458
+ "<=#spendable_balance": -1 * tx_amount - tx_fee,
1459
+ "<=#max_send_amount": -1 * tx_amount - tx_fee,
1460
+ ">=#pending_change": 1, # any amount increase
1461
+ "pending_coin_removal_count": 2,
1462
+ }
1463
+ },
1464
+ post_block_balance_updates={
1465
+ 1: {
1466
+ "confirmed_wallet_balance": -1 * tx_amount - tx_fee,
1467
+ ">=#spendable_balance": 1, # any amount increase
1468
+ ">=#max_send_amount": 1, # any amount increase
1469
+ "<=#pending_change": -1, # any amount decrease
1470
+ "pending_coin_removal_count": -2,
1471
+ "unspent_coin_count": -1,
1472
+ }
1473
+ },
1474
+ ),
1475
+ WalletStateTransition(
1476
+ pre_block_balance_updates={},
1477
+ post_block_balance_updates={
1478
+ 1: {
1479
+ "confirmed_wallet_balance": tx_amount,
1480
+ "unconfirmed_wallet_balance": tx_amount,
1481
+ "spendable_balance": tx_amount,
1482
+ "max_send_amount": tx_amount,
1483
+ "unspent_coin_count": 1,
1484
+ }
1485
+ },
1486
+ ),
1487
+ ]
1488
+ )
1489
+
1490
+ @pytest.mark.parametrize(
1491
+ "wallet_environments",
1492
+ [{"num_environments": 2, "blocks_needed": [1, 1]}],
1493
+ indirect=True,
1494
+ )
1495
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
1496
+ @pytest.mark.anyio
1497
+ async def test_wallet_make_transaction_with_memo(self, wallet_environments: WalletTestFramework) -> None:
1498
+ env_0 = wallet_environments.environments[0]
1499
+ env_1 = wallet_environments.environments[1]
1500
+ wallet_0 = env_0.xch_wallet
1501
+ wallet_1 = env_1.xch_wallet
1502
+
1503
+ tx_amount = 1_750_000_000_000 # ensures we grab both coins
1504
+ tx_fee = 10
1505
+ ph_2 = await wallet_1.get_new_puzzlehash()
1506
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1507
+ await wallet_0.generate_signed_transaction(
1508
+ uint64(tx_amount), ph_2, action_scope, uint64(tx_fee), memos=[ph_2]
1509
+ )
1510
+ [tx] = action_scope.side_effects.transactions
1511
+ assert tx.spend_bundle is not None
1512
+
1513
+ fees = estimate_fees(tx.spend_bundle)
1514
+ assert fees == tx_fee
1515
+
1516
+ memos = await env_0.rpc_client.get_transaction_memo(GetTransactionMemo(transaction_id=tx.name))
1517
+ assert len(memos.coins_with_memos) == 1
1518
+ assert memos.coins_with_memos[0].memos[0] == ph_2
1519
+
1520
+ await wallet_environments.process_pending_states(
1521
+ [
1522
+ WalletStateTransition(
1523
+ pre_block_balance_updates={
1524
+ 1: {
1525
+ "unconfirmed_wallet_balance": -1 * tx_amount - tx_fee,
1526
+ "<=#spendable_balance": -1 * tx_amount - tx_fee,
1527
+ "<=#max_send_amount": -1 * tx_amount - tx_fee,
1528
+ ">=#pending_change": 1, # any amount increase
1529
+ "pending_coin_removal_count": 2,
1530
+ }
1531
+ },
1532
+ post_block_balance_updates={
1533
+ 1: {
1534
+ "confirmed_wallet_balance": -1 * tx_amount - tx_fee,
1535
+ ">=#spendable_balance": 1, # any amount increase
1536
+ ">=#max_send_amount": 1, # any amount increase
1537
+ "<=#pending_change": -1, # any amount decrease
1538
+ "pending_coin_removal_count": -2,
1539
+ "unspent_coin_count": -1,
1540
+ }
1541
+ },
1542
+ ),
1543
+ WalletStateTransition(
1544
+ pre_block_balance_updates={},
1545
+ post_block_balance_updates={
1546
+ 1: {
1547
+ "confirmed_wallet_balance": tx_amount,
1548
+ "unconfirmed_wallet_balance": tx_amount,
1549
+ "spendable_balance": tx_amount,
1550
+ "max_send_amount": tx_amount,
1551
+ "unspent_coin_count": 1,
1552
+ }
1553
+ },
1554
+ ),
1555
+ ]
1556
+ )
1557
+
1558
+ tx_id = None
1559
+ for coin in tx.additions:
1560
+ if coin.amount == tx_amount:
1561
+ tx_id = coin.name()
1562
+ assert tx_id is not None
1563
+ memos = await env_1.rpc_client.get_transaction_memo(GetTransactionMemo(transaction_id=tx_id))
1564
+ assert len(memos.coins_with_memos) == 1
1565
+ assert memos.coins_with_memos[0].memos[0] == ph_2
1566
+ # test json serialization
1567
+ assert memos.to_json_dict() == {
1568
+ tx_id.hex(): {memos.coins_with_memos[0].coin_id.hex(): [memos.coins_with_memos[0].memos[0].hex()]}
1569
+ }
1570
+
1571
+ @pytest.mark.parametrize(
1572
+ "wallet_environments",
1573
+ [{"num_environments": 1, "blocks_needed": [1], "trusted": True, "reuse_puzhash": True}],
1574
+ indirect=True,
1575
+ )
1576
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
1577
+ @pytest.mark.anyio
1578
+ async def test_wallet_create_hit_max_send_amount(self, wallet_environments: WalletTestFramework) -> None:
1579
+ env = wallet_environments.environments[0]
1580
+ wallet = env.xch_wallet
1581
+
1582
+ ph = await wallet.get_puzzle_hash(False)
1583
+ primaries = [Payment(ph, uint64(1000000000 + i)) for i in range(int(wallet.max_send_quantity) + 1)]
1584
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1585
+ await wallet.generate_signed_transaction(uint64(1), ph, action_scope, uint64(0), primaries=primaries)
1586
+
1587
+ await wallet_environments.process_pending_states(
1588
+ [
1589
+ WalletStateTransition(
1590
+ pre_block_balance_updates={
1591
+ 1: {
1592
+ # tx sent to ourselves
1593
+ "unconfirmed_wallet_balance": 0,
1594
+ "<=#spendable_balance": 0,
1595
+ "<=#max_send_amount": 0,
1596
+ ">=#pending_change": 1, # any amount increase
1597
+ "pending_coin_removal_count": 1,
1598
+ }
1599
+ },
1600
+ post_block_balance_updates={
1601
+ 1: {
1602
+ "confirmed_wallet_balance": 0,
1603
+ ">=#spendable_balance": 1, # any amount increase
1604
+ ">=#max_send_amount": 1, # any amount increase
1605
+ "<=#pending_change": -1, # any amount decrease
1606
+ "pending_coin_removal_count": -1,
1607
+ "unspent_coin_count": len(primaries) + 1,
1608
+ }
1609
+ },
1610
+ ),
1611
+ ]
1612
+ )
1613
+
1614
+ max_sent_amount = await wallet.get_max_send_amount()
1615
+ assert max_sent_amount < (await wallet.get_spendable_balance())
1616
+
1617
+ # 1) Generate transaction that is under the limit
1618
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=False) as action_scope:
1619
+ await wallet.generate_signed_transaction(
1620
+ uint64(max_sent_amount - 1),
1621
+ ph,
1622
+ action_scope,
1623
+ uint64(0),
1624
+ )
1625
+
1626
+ assert action_scope.side_effects.transactions[0].amount == uint64(max_sent_amount - 1)
1627
+
1628
+ # 2) Generate transaction that is equal to limit
1629
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=False) as action_scope:
1630
+ await wallet.generate_signed_transaction(
1631
+ uint64(max_sent_amount),
1632
+ ph,
1633
+ action_scope,
1634
+ uint64(0),
1635
+ )
1636
+
1637
+ assert action_scope.side_effects.transactions[0].amount == uint64(max_sent_amount)
1638
+
1639
+ # 3) Generate transaction that is greater than limit
1640
+ with pytest.raises(
1641
+ ValueError,
1642
+ match=f"Transaction for {max_sent_amount + 1} is greater than max spendable balance in a block of "
1643
+ f"{max_sent_amount}. There may be other transactions pending or our minimum coin amount is too high.",
1644
+ ):
1645
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=False) as action_scope:
1646
+ await wallet.generate_signed_transaction(
1647
+ uint64(max_sent_amount + 1),
1648
+ ph,
1649
+ action_scope,
1650
+ uint64(0),
1651
+ )
1652
+
1653
+ @pytest.mark.parametrize(
1654
+ "wallet_environments",
1655
+ [{"num_environments": 1, "blocks_needed": [2], "trusted": True, "reuse_puzhash": True}],
1656
+ indirect=True,
1657
+ )
1658
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
1659
+ @pytest.mark.anyio
1660
+ async def test_wallet_prevent_fee_theft(self, wallet_environments: WalletTestFramework) -> None:
1661
+ env = wallet_environments.environments[0]
1662
+ wallet = env.xch_wallet
1663
+
1664
+ tx_amount = 1_750_000_000_000
1665
+ tx_fee = 2_000_000_000_000
1666
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=False) as action_scope:
1667
+ await wallet.generate_signed_transaction(
1668
+ uint64(tx_amount),
1669
+ bytes32.zeros,
1670
+ action_scope,
1671
+ uint64(tx_fee),
1672
+ )
1673
+ [tx] = action_scope.side_effects.transactions
1674
+ assert tx.spend_bundle is not None
1675
+
1676
+ stolen_cs: Optional[CoinSpend] = None
1677
+ # extract coin_spend from generated spend_bundle
1678
+ for cs in tx.spend_bundle.coin_spends:
1679
+ if compute_additions(cs) == []:
1680
+ stolen_cs = cs
1681
+
1682
+ assert stolen_cs is not None
1683
+
1684
+ # get a legit signature
1685
+ stolen_sb, _ = await wallet.wallet_state_manager.sign_bundle([stolen_cs])
1686
+ name = stolen_sb.name()
1687
+ stolen_tx = TransactionRecord(
1688
+ confirmed_at_height=uint32(0),
1689
+ created_at_time=uint64(0),
1690
+ to_puzzle_hash=bytes32(32 * b"0"),
1691
+ amount=uint64(0),
1692
+ fee_amount=uint64(0),
1693
+ confirmed=False,
1694
+ sent=uint32(0),
1695
+ spend_bundle=stolen_sb,
1696
+ additions=[],
1697
+ removals=[],
1698
+ wallet_id=wallet.id(),
1699
+ sent_to=[],
1700
+ trade_id=None,
1701
+ type=uint32(TransactionType.OUTGOING_TX.value),
1702
+ name=name,
1703
+ memos=[],
1704
+ valid_times=ConditionValidTimes(),
1705
+ )
1706
+ [stolen_tx] = await wallet.wallet_state_manager.add_pending_transactions([stolen_tx])
1707
+
1708
+ async def transaction_has_failed(tx_id: bytes32) -> bool:
1709
+ tx = await wallet.wallet_state_manager.tx_store.get_transaction_record(tx_id)
1710
+ assert tx is not None
1711
+ return any(error_str == Err.ASSERT_ANNOUNCE_CONSUMED_FAILED.name for _, _, error_str in tx.sent_to)
1712
+
1713
+ await time_out_assert(10, transaction_has_failed, True, stolen_tx.name)
1714
+
1715
+ @pytest.mark.parametrize(
1716
+ "wallet_environments",
1717
+ [{"num_environments": 2, "blocks_needed": [4, 1]}],
1718
+ indirect=True,
1719
+ )
1720
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
1721
+ @pytest.mark.anyio
1722
+ async def test_wallet_tx_reorg(self, wallet_environments: WalletTestFramework) -> None:
1723
+ full_node_api = wallet_environments.full_node
1724
+ env = wallet_environments.environments[0]
1725
+ env_2 = wallet_environments.environments[1]
1726
+ wsm = env.wallet_state_manager
1727
+ wallet = env.xch_wallet
1728
+ wallet_2 = env_2.xch_wallet
1729
+
1730
+ # Ensure that we use a coin that we will not reorg out
1731
+ tx_amount = 1000
1732
+ async with wallet.wallet_state_manager.new_action_scope(
1733
+ wallet_environments.tx_config, push=False
1734
+ ) as action_scope:
1735
+ coins = await wallet.select_coins(amount=uint64(tx_amount), action_scope=action_scope)
1736
+ coin = next(iter(coins))
1737
+
1738
+ reorg_height = full_node_api.full_node.blockchain.get_peak_height()
1739
+ assert reorg_height is not None
1740
+ await full_node_api.farm_blocks_to_puzzlehash(count=3)
1741
+
1742
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1743
+ await wallet.generate_signed_transaction(
1744
+ uint64(tx_amount), await wallet_2.get_puzzle_hash(False), action_scope, coins={coin}
1745
+ )
1746
+
1747
+ await wallet_environments.process_pending_states(
1748
+ [
1749
+ WalletStateTransition(
1750
+ pre_block_balance_updates={
1751
+ 1: {
1752
+ "unconfirmed_wallet_balance": -1 * tx_amount,
1753
+ "<=#spendable_balance": -1 * tx_amount,
1754
+ "<=#max_send_amount": -1 * tx_amount,
1755
+ ">=#pending_change": 1, # any amount increase
1756
+ "pending_coin_removal_count": 1,
1757
+ }
1758
+ },
1759
+ post_block_balance_updates={
1760
+ 1: {
1761
+ "confirmed_wallet_balance": -1 * tx_amount,
1762
+ ">=#spendable_balance": 1, # any amount increase
1763
+ ">=#max_send_amount": 1, # any amount increase
1764
+ "<=#pending_change": -1, # any amount decrease
1765
+ "pending_coin_removal_count": -1,
1766
+ }
1767
+ },
1768
+ ),
1769
+ WalletStateTransition(
1770
+ pre_block_balance_updates={},
1771
+ post_block_balance_updates={
1772
+ 1: {
1773
+ "confirmed_wallet_balance": tx_amount,
1774
+ "unconfirmed_wallet_balance": tx_amount,
1775
+ "spendable_balance": tx_amount,
1776
+ "max_send_amount": tx_amount,
1777
+ "unspent_coin_count": 1,
1778
+ }
1779
+ },
1780
+ ),
1781
+ ]
1782
+ )
1783
+
1784
+ peak = full_node_api.full_node.blockchain.get_peak()
1785
+ assert peak is not None
1786
+ peak_height = peak.height
1787
+ assert peak_height is not None
1788
+
1789
+ target_height_after_reorg = peak_height + 3
1790
+ # Perform a reorg, which will revert the transaction in the full node and wallet, and cause wallet to resubmit
1791
+ await full_node_api.reorg_from_index_to_new_index(
1792
+ ReorgProtocol(uint32(reorg_height - 1), uint32(target_height_after_reorg), bytes32(32 * b"0"), None)
1793
+ )
1794
+
1795
+ await time_out_assert(20, full_node_api.full_node.blockchain.get_peak_height, target_height_after_reorg)
1796
+
1797
+ await wallet_environments.process_pending_states(
1798
+ [
1799
+ WalletStateTransition(
1800
+ pre_block_balance_updates={
1801
+ 1: {
1802
+ "confirmed_wallet_balance": tx_amount,
1803
+ "unconfirmed_wallet_balance": 0,
1804
+ "<=#spendable_balance": -1, # any amount decrease
1805
+ "<=#max_send_amount": -1, # any amount decrease
1806
+ ">=#pending_change": 1, # any amount increase
1807
+ "pending_coin_removal_count": 1,
1808
+ }
1809
+ },
1810
+ post_block_balance_updates={
1811
+ 1: {
1812
+ "confirmed_wallet_balance": -1 * tx_amount,
1813
+ ">=#spendable_balance": -1, # any amount increase
1814
+ ">=#max_send_amount": -1, # any amount increase
1815
+ "<=#pending_change": -1, # any amount decrease
1816
+ "pending_coin_removal_count": -1,
1817
+ }
1818
+ },
1819
+ ),
1820
+ WalletStateTransition(
1821
+ pre_block_balance_updates={
1822
+ 1: {
1823
+ "confirmed_wallet_balance": -1 * tx_amount,
1824
+ "unconfirmed_wallet_balance": -1 * tx_amount,
1825
+ "spendable_balance": -1 * tx_amount,
1826
+ "max_send_amount": -1 * tx_amount,
1827
+ "unspent_coin_count": -1,
1828
+ }
1829
+ },
1830
+ post_block_balance_updates={
1831
+ 1: {
1832
+ "confirmed_wallet_balance": tx_amount,
1833
+ "unconfirmed_wallet_balance": tx_amount,
1834
+ "spendable_balance": tx_amount,
1835
+ "max_send_amount": tx_amount,
1836
+ "unspent_coin_count": 1,
1837
+ }
1838
+ },
1839
+ ),
1840
+ ]
1841
+ )
1842
+
1843
+ unconfirmed = await wsm.tx_store.get_unconfirmed_for_wallet(int(wallet.id()))
1844
+ assert len(unconfirmed) == 0
1845
+ [tx] = action_scope.side_effects.transactions
1846
+ tx_record = await wsm.tx_store.get_transaction_record(tx.name)
1847
+ assert tx_record is not None
1848
+ removed = tx_record.removals[0]
1849
+ added = tx_record.additions[0]
1850
+ added_1 = tx_record.additions[1]
1851
+ wallet_coin_record_rem = await wsm.coin_store.get_coin_record(removed.name())
1852
+ assert wallet_coin_record_rem is not None
1853
+ assert wallet_coin_record_rem.spent
1854
+
1855
+ coin_record_full_node = await full_node_api.full_node.coin_store.get_coin_record(removed.name())
1856
+ assert coin_record_full_node is not None
1857
+ assert coin_record_full_node.spent
1858
+ add_1_coin_record_full_node = await full_node_api.full_node.coin_store.get_coin_record(added.name())
1859
+ assert add_1_coin_record_full_node is not None
1860
+ assert add_1_coin_record_full_node.confirmed_block_index > 0
1861
+ add_2_coin_record_full_node = await full_node_api.full_node.coin_store.get_coin_record(added_1.name())
1862
+ assert add_2_coin_record_full_node is not None
1863
+ assert add_2_coin_record_full_node.confirmed_block_index > 0
1864
+
1865
+ @pytest.mark.parametrize(
1866
+ "wallet_environments",
1867
+ [
1868
+ {
1869
+ "num_environments": 1,
1870
+ "blocks_needed": [1],
1871
+ "trusted": True,
1872
+ "reuse_puzhash": False,
1873
+ "config_overrides": {"initial_num_public_keys": 100},
1874
+ }
1875
+ ],
1876
+ indirect=True,
1877
+ )
1878
+ @pytest.mark.anyio
1879
+ async def test_address_sliding_window(self, wallet_environments: WalletTestFramework) -> None:
1880
+ full_node_api = wallet_environments.full_node
1881
+ env = wallet_environments.environments[0]
1882
+ wallet = env.xch_wallet
1883
+
1884
+ peak = full_node_api.full_node.blockchain.get_peak_height()
1885
+ assert peak is not None
1886
+
1887
+ puzzle_hashes = []
1888
+ for i in range(211):
1889
+ pubkey = master_sk_to_wallet_sk(wallet.wallet_state_manager.get_master_private_key(), uint32(i)).get_g1()
1890
+ puzzle: Program = wallet.puzzle_for_pk(pubkey)
1891
+ puzzle_hash: bytes32 = puzzle.get_tree_hash()
1892
+ puzzle_hashes.append(puzzle_hash)
1893
+
1894
+ await full_node_api.farm_blocks_to_puzzlehash(count=1, farm_to=puzzle_hashes[0])
1895
+ await full_node_api.farm_blocks_to_puzzlehash(count=1, farm_to=puzzle_hashes[210])
1896
+ await full_node_api.farm_blocks_to_puzzlehash(
1897
+ count=1,
1898
+ farm_to=puzzle_hashes[114],
1899
+ guarantee_transaction_blocks=True,
1900
+ )
1901
+
1902
+ await full_node_api.wait_for_wallet_synced(env.node, peak_height=uint32(peak + 3))
1903
+ await env.change_balances(
1904
+ {
1905
+ 1: {
1906
+ "confirmed_wallet_balance": 2_000_000_000_000,
1907
+ "unconfirmed_wallet_balance": 2_000_000_000_000,
1908
+ "spendable_balance": 2_000_000_000_000,
1909
+ "max_send_amount": 2_000_000_000_000,
1910
+ "unspent_coin_count": 2,
1911
+ }
1912
+ }
1913
+ )
1914
+
1915
+ await full_node_api.farm_blocks_to_puzzlehash(
1916
+ count=1,
1917
+ farm_to=puzzle_hashes[50],
1918
+ guarantee_transaction_blocks=True,
1919
+ )
1920
+ await full_node_api.farm_blocks_to_puzzlehash(
1921
+ count=1,
1922
+ guarantee_transaction_blocks=True,
1923
+ )
1924
+
1925
+ await full_node_api.wait_for_wallet_synced(env.node, peak_height=uint32(peak + 5))
1926
+ await env.change_balances(
1927
+ {
1928
+ 1: {
1929
+ "confirmed_wallet_balance": 6_000_000_000_000,
1930
+ "unconfirmed_wallet_balance": 6_000_000_000_000,
1931
+ "spendable_balance": 6_000_000_000_000,
1932
+ "max_send_amount": 6_000_000_000_000,
1933
+ "unspent_coin_count": 6,
1934
+ }
1935
+ }
1936
+ )
1937
+
1938
+ await full_node_api.farm_blocks_to_puzzlehash(count=1, farm_to=puzzle_hashes[113])
1939
+ await full_node_api.farm_blocks_to_puzzlehash(
1940
+ count=1,
1941
+ farm_to=puzzle_hashes[209],
1942
+ guarantee_transaction_blocks=True,
1943
+ )
1944
+ await full_node_api.farm_blocks_to_puzzlehash(count=1, guarantee_transaction_blocks=True)
1945
+
1946
+ await full_node_api.wait_for_wallet_synced(env.node, peak_height=uint32(peak + 8))
1947
+ await env.change_balances(
1948
+ {
1949
+ 1: {
1950
+ "confirmed_wallet_balance": 4_000_000_000_000,
1951
+ "unconfirmed_wallet_balance": 4_000_000_000_000,
1952
+ "spendable_balance": 4_000_000_000_000,
1953
+ "max_send_amount": 4_000_000_000_000,
1954
+ "unspent_coin_count": 4,
1955
+ }
1956
+ }
1957
+ )
1958
+
1959
+ @pytest.mark.parametrize(
1960
+ "wallet_environments",
1961
+ [{"num_environments": 1, "blocks_needed": [1]}],
1962
+ indirect=True,
1963
+ )
1964
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
1965
+ @pytest.mark.anyio
1966
+ async def test_sign_message(self, wallet_environments: WalletTestFramework) -> None:
1967
+ env = wallet_environments.environments[0]
1968
+ api_0 = env.rpc_api
1969
+
1970
+ # Test general string
1971
+ message = "Hello World"
1972
+ ph = await env.xch_wallet.get_puzzle_hash(False)
1973
+ response = await api_0.sign_message_by_address({"address": encode_puzzle_hash(ph, "xch"), "message": message})
1974
+ puzzle: Program = Program.to((CHIP_0002_SIGN_MESSAGE_PREFIX, message))
1975
+
1976
+ assert AugSchemeMPL.verify(
1977
+ G1Element.from_bytes(bytes.fromhex(response["pubkey"])),
1978
+ puzzle.get_tree_hash(),
1979
+ G2Element.from_bytes(bytes.fromhex(response["signature"])),
1980
+ )
1981
+ # Test hex string
1982
+ message = "0123456789ABCDEF"
1983
+ response = await api_0.sign_message_by_address(
1984
+ {"address": encode_puzzle_hash(ph, "xch"), "message": message, "is_hex": True}
1985
+ )
1986
+ puzzle = Program.to((CHIP_0002_SIGN_MESSAGE_PREFIX, bytes.fromhex(message)))
1987
+
1988
+ assert AugSchemeMPL.verify(
1989
+ G1Element.from_bytes(bytes.fromhex(response["pubkey"])),
1990
+ puzzle.get_tree_hash(),
1991
+ G2Element.from_bytes(bytes.fromhex(response["signature"])),
1992
+ )
1993
+ # Test informal input
1994
+ message = "0123456789ABCDEF"
1995
+ response = await api_0.sign_message_by_address(
1996
+ {"address": encode_puzzle_hash(ph, "xch"), "message": message, "is_hex": "true", "safe_mode": "true"}
1997
+ )
1998
+ puzzle = Program.to((CHIP_0002_SIGN_MESSAGE_PREFIX, bytes.fromhex(message)))
1999
+
2000
+ assert AugSchemeMPL.verify(
2001
+ G1Element.from_bytes(bytes.fromhex(response["pubkey"])),
2002
+ puzzle.get_tree_hash(),
2003
+ G2Element.from_bytes(bytes.fromhex(response["signature"])),
2004
+ )
2005
+ # Test BLS sign string
2006
+ message = "Hello World"
2007
+ response = await api_0.sign_message_by_address(
2008
+ {"address": encode_puzzle_hash(ph, "xch"), "message": message, "is_hex": False, "safe_mode": False}
2009
+ )
2010
+
2011
+ assert AugSchemeMPL.verify(
2012
+ G1Element.from_bytes(bytes.fromhex(response["pubkey"])),
2013
+ bytes(message, "utf-8"),
2014
+ G2Element.from_bytes(bytes.fromhex(response["signature"])),
2015
+ )
2016
+ # Test BLS sign hex
2017
+ message = "0123456789ABCDEF"
2018
+ response = await api_0.sign_message_by_address(
2019
+ {"address": encode_puzzle_hash(ph, "xch"), "message": message, "is_hex": True, "safe_mode": False}
2020
+ )
2021
+
2022
+ assert AugSchemeMPL.verify(
2023
+ G1Element.from_bytes(bytes.fromhex(response["pubkey"])),
2024
+ bytes.fromhex(message),
2025
+ G2Element.from_bytes(bytes.fromhex(response["signature"])),
2026
+ )
2027
+
2028
+ @pytest.mark.parametrize(
2029
+ "wallet_environments",
2030
+ [{"num_environments": 1, "blocks_needed": [2]}],
2031
+ indirect=True,
2032
+ )
2033
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2034
+ @pytest.mark.anyio
2035
+ async def test_wallet_transaction_options(self, wallet_environments: WalletTestFramework) -> None:
2036
+ env = wallet_environments.environments[0]
2037
+ wallet = env.xch_wallet
2038
+
2039
+ AMOUNT_TO_SEND = 4000000000000
2040
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2041
+ coins = await wallet.select_coins(uint64(AMOUNT_TO_SEND), action_scope)
2042
+ coin_list = list(coins)
2043
+ await wallet.generate_signed_transaction(
2044
+ uint64(AMOUNT_TO_SEND),
2045
+ bytes32.zeros,
2046
+ action_scope,
2047
+ uint64(0),
2048
+ coins=coins,
2049
+ origin_id=coin_list[2].name(),
2050
+ )
2051
+ [tx] = action_scope.side_effects.transactions
2052
+ assert tx.spend_bundle is not None
2053
+ paid_coin = next(coin for coin in tx.spend_bundle.additions() if coin.amount == AMOUNT_TO_SEND)
2054
+ assert paid_coin.parent_coin_info == coin_list[2].name()
2055
+ [tx] = await wallet.wallet_state_manager.add_pending_transactions([tx])
2056
+
2057
+ await wallet_environments.process_pending_states(
2058
+ [
2059
+ WalletStateTransition(
2060
+ pre_block_balance_updates={
2061
+ 1: {
2062
+ "unconfirmed_wallet_balance": -1 * AMOUNT_TO_SEND,
2063
+ "spendable_balance": -1 * AMOUNT_TO_SEND, # used exact amount
2064
+ "max_send_amount": -1 * AMOUNT_TO_SEND, # used exact amount
2065
+ "pending_change": 0, # used exact amount
2066
+ "pending_coin_removal_count": len(coins),
2067
+ }
2068
+ },
2069
+ post_block_balance_updates={
2070
+ 1: {
2071
+ "confirmed_wallet_balance": -1 * AMOUNT_TO_SEND,
2072
+ "spendable_balance": 0, # used exact amount
2073
+ "max_send_amount": 0, # used exact amount
2074
+ "pending_change": 0, # used exact amount
2075
+ "unspent_coin_count": -len(coins),
2076
+ "pending_coin_removal_count": -len(coins),
2077
+ }
2078
+ },
2079
+ )
2080
+ ]
2081
+ )
2082
+
2083
+
2084
+ def test_get_wallet_db_path_v2_r1() -> None:
2085
+ root_path: Path = Path("/x/y/z/.chia/mainnet").resolve()
2086
+ config: dict[str, Any] = {
2087
+ "database_path": "wallet/db/blockchain_wallet_v2_r1_CHALLENGE_KEY.sqlite",
2088
+ "selected_network": "mainnet",
2089
+ }
2090
+ fingerprint: str = "1234567890"
2091
+ wallet_db_path: Path = get_wallet_db_path(root_path, config, fingerprint)
2092
+
2093
+ assert wallet_db_path == root_path.joinpath("wallet/db/blockchain_wallet_v2_r1_mainnet_1234567890.sqlite")
2094
+
2095
+
2096
+ def test_get_wallet_db_path_v2() -> None:
2097
+ root_path: Path = Path("/x/y/z/.chia/mainnet").resolve()
2098
+ config: dict[str, Any] = {
2099
+ "database_path": "wallet/db/blockchain_wallet_v2_CHALLENGE_KEY.sqlite",
2100
+ "selected_network": "mainnet",
2101
+ }
2102
+ fingerprint: str = "1234567890"
2103
+ wallet_db_path: Path = get_wallet_db_path(root_path, config, fingerprint)
2104
+
2105
+ assert wallet_db_path == root_path.joinpath("wallet/db/blockchain_wallet_v2_r1_mainnet_1234567890.sqlite")
2106
+
2107
+
2108
+ def test_get_wallet_db_path_v1() -> None:
2109
+ root_path: Path = Path("/x/y/z/.chia/mainnet").resolve()
2110
+ config: dict[str, Any] = {
2111
+ "database_path": "wallet/db/blockchain_wallet_v1_CHALLENGE_KEY.sqlite",
2112
+ "selected_network": "mainnet",
2113
+ }
2114
+ fingerprint: str = "1234567890"
2115
+ wallet_db_path: Path = get_wallet_db_path(root_path, config, fingerprint)
2116
+
2117
+ assert wallet_db_path == root_path.joinpath("wallet/db/blockchain_wallet_v2_r1_mainnet_1234567890.sqlite")
2118
+
2119
+
2120
+ def test_get_wallet_db_path_testnet() -> None:
2121
+ root_path: Path = Path("/x/y/z/.chia/testnet").resolve()
2122
+ config: dict[str, Any] = {
2123
+ "database_path": "wallet/db/blockchain_wallet_v2_CHALLENGE_KEY.sqlite",
2124
+ "selected_network": "testnet",
2125
+ }
2126
+ fingerprint: str = "1234567890"
2127
+ wallet_db_path: Path = get_wallet_db_path(root_path, config, fingerprint)
2128
+
2129
+ assert wallet_db_path == root_path.joinpath("wallet/db/blockchain_wallet_v2_r1_testnet_1234567890.sqlite")
2130
+
2131
+
2132
+ @pytest.mark.anyio
2133
+ async def test_wallet_has_no_server(
2134
+ simulator_and_wallet: tuple[list[FullNodeSimulator], list[tuple[WalletNode, ChiaServer]], BlockTools],
2135
+ ) -> None:
2136
+ _full_nodes, wallets, _bt = simulator_and_wallet
2137
+ _wallet_node, wallet_server = wallets[0]
2138
+
2139
+ assert wallet_server.webserver is None