chia-blockchain 2.5.4rc2__py3-none-any.whl → 2.5.5rc1__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 (453) hide show
  1. chia/_tests/blockchain/blockchain_test_utils.py +2 -3
  2. chia/_tests/blockchain/test_augmented_chain.py +2 -3
  3. chia/_tests/blockchain/test_blockchain.py +261 -44
  4. chia/_tests/blockchain/test_blockchain_transactions.py +4 -3
  5. chia/_tests/blockchain/test_build_chains.py +197 -1
  6. chia/_tests/blockchain/test_get_block_generator.py +1 -1
  7. chia/_tests/blockchain/test_lookup_fork_chain.py +1 -1
  8. chia/_tests/clvm/benchmark_costs.py +1 -1
  9. chia/_tests/clvm/coin_store.py +3 -4
  10. chia/_tests/clvm/test_message_conditions.py +2 -2
  11. chia/_tests/clvm/test_puzzle_compression.py +2 -3
  12. chia/_tests/clvm/test_puzzles.py +1 -2
  13. chia/_tests/clvm/test_singletons.py +2 -3
  14. chia/_tests/clvm/test_spend_sim.py +7 -7
  15. chia/_tests/cmds/cmd_test_utils.py +30 -25
  16. chia/_tests/cmds/test_dev_gh.py +1 -1
  17. chia/_tests/cmds/test_farm_cmd.py +1 -1
  18. chia/_tests/cmds/test_show.py +1 -2
  19. chia/_tests/cmds/wallet/test_did.py +101 -56
  20. chia/_tests/cmds/wallet/test_nft.py +109 -84
  21. chia/_tests/cmds/wallet/test_notifications.py +1 -1
  22. chia/_tests/cmds/wallet/test_offer.toffer +1 -1
  23. chia/_tests/cmds/wallet/test_vcs.py +8 -8
  24. chia/_tests/cmds/wallet/test_wallet.py +100 -46
  25. chia/_tests/conftest.py +31 -20
  26. chia/_tests/connection_utils.py +1 -1
  27. chia/_tests/core/consensus/stores/__init__.py +0 -0
  28. chia/_tests/core/consensus/stores/test_coin_store_protocol.py +40 -0
  29. chia/_tests/core/consensus/test_block_creation.py +2 -31
  30. chia/_tests/core/consensus/test_pot_iterations.py +38 -3
  31. chia/_tests/core/custom_types/test_proof_of_space.py +154 -26
  32. chia/_tests/core/custom_types/test_spend_bundle.py +2 -3
  33. chia/_tests/core/daemon/test_daemon.py +80 -0
  34. chia/_tests/core/data_layer/test_data_layer.py +1 -1
  35. chia/_tests/core/data_layer/test_data_layer_util.py +1 -1
  36. chia/_tests/core/data_layer/test_data_rpc.py +14 -10
  37. chia/_tests/core/data_layer/test_data_store.py +5 -5
  38. chia/_tests/core/farmer/test_farmer_api.py +2 -2
  39. chia/_tests/core/full_node/full_sync/test_full_sync.py +446 -406
  40. chia/_tests/core/full_node/ram_db.py +3 -1
  41. chia/_tests/core/full_node/stores/test_block_store.py +28 -16
  42. chia/_tests/core/full_node/stores/test_coin_store.py +277 -185
  43. chia/_tests/core/full_node/stores/test_full_node_store.py +11 -4
  44. chia/_tests/core/full_node/stores/test_hint_store.py +2 -2
  45. chia/_tests/core/full_node/test_address_manager.py +200 -27
  46. chia/_tests/core/full_node/test_block_height_map.py +2 -2
  47. chia/_tests/core/full_node/test_conditions.py +7 -6
  48. chia/_tests/core/full_node/test_full_node.py +456 -40
  49. chia/_tests/core/full_node/test_generator_tools.py +32 -2
  50. chia/_tests/core/full_node/test_hint_management.py +1 -1
  51. chia/_tests/core/full_node/test_node_load.py +20 -21
  52. chia/_tests/core/full_node/test_performance.py +3 -4
  53. chia/_tests/core/full_node/test_prev_tx_block.py +43 -0
  54. chia/_tests/core/full_node/test_subscriptions.py +1 -2
  55. chia/_tests/core/full_node/test_transactions.py +9 -5
  56. chia/_tests/core/full_node/test_tx_processing_queue.py +1 -2
  57. chia/_tests/core/large_block.py +1 -2
  58. chia/_tests/core/make_block_generator.py +3 -4
  59. chia/_tests/core/mempool/test_mempool.py +36 -86
  60. chia/_tests/core/mempool/test_mempool_fee_estimator.py +1 -1
  61. chia/_tests/core/mempool/test_mempool_item_queries.py +1 -3
  62. chia/_tests/core/mempool/test_mempool_manager.py +421 -69
  63. chia/_tests/core/mempool/test_mempool_performance.py +3 -2
  64. chia/_tests/core/mempool/test_singleton_fast_forward.py +60 -131
  65. chia/_tests/core/server/flood.py +1 -1
  66. chia/_tests/core/server/test_dos.py +1 -1
  67. chia/_tests/core/server/test_node_discovery.py +41 -27
  68. chia/_tests/core/server/test_rate_limits.py +1 -1
  69. chia/_tests/core/server/test_server.py +1 -1
  70. chia/_tests/core/services/test_services.py +5 -5
  71. chia/_tests/core/ssl/test_ssl.py +1 -1
  72. chia/_tests/core/test_cost_calculation.py +6 -6
  73. chia/_tests/core/test_crawler.py +2 -2
  74. chia/_tests/core/test_crawler_rpc.py +1 -1
  75. chia/_tests/core/test_db_conversion.py +3 -1
  76. chia/_tests/core/test_db_validation.py +5 -3
  77. chia/_tests/core/test_farmer_harvester_rpc.py +15 -15
  78. chia/_tests/core/test_filter.py +4 -1
  79. chia/_tests/core/test_full_node_rpc.py +99 -82
  80. chia/_tests/core/test_program.py +2 -2
  81. chia/_tests/core/util/test_block_cache.py +1 -1
  82. chia/_tests/core/util/test_keychain.py +2 -2
  83. chia/_tests/core/util/test_lockfile.py +1 -1
  84. chia/_tests/core/util/test_log_exceptions.py +5 -5
  85. chia/_tests/core/util/test_streamable.py +81 -22
  86. chia/_tests/db/test_db_wrapper.py +1 -3
  87. chia/_tests/environments/wallet.py +5 -5
  88. chia/_tests/farmer_harvester/test_farmer.py +9 -7
  89. chia/_tests/farmer_harvester/test_farmer_harvester.py +11 -4
  90. chia/_tests/farmer_harvester/test_filter_prefix_bits.py +6 -5
  91. chia/_tests/farmer_harvester/test_third_party_harvesters.py +15 -9
  92. chia/_tests/fee_estimation/test_fee_estimation_integration.py +1 -2
  93. chia/_tests/fee_estimation/test_fee_estimation_rpc.py +7 -5
  94. chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +1 -1
  95. chia/_tests/generator/test_compression.py +1 -2
  96. chia/_tests/generator/test_rom.py +8 -4
  97. chia/_tests/plot_sync/test_plot_sync.py +3 -3
  98. chia/_tests/plot_sync/test_receiver.py +3 -3
  99. chia/_tests/plot_sync/test_sender.py +1 -1
  100. chia/_tests/plot_sync/test_sync_simulated.py +3 -3
  101. chia/_tests/plot_sync/util.py +2 -2
  102. chia/_tests/pools/test_pool_cmdline.py +48 -21
  103. chia/_tests/pools/test_pool_puzzles_lifecycle.py +2 -3
  104. chia/_tests/pools/test_pool_rpc.py +237 -105
  105. chia/_tests/pools/test_pool_wallet.py +11 -2
  106. chia/_tests/pools/test_wallet_pool_store.py +5 -4
  107. chia/_tests/rpc/test_rpc_client.py +1 -1
  108. chia/_tests/simulation/test_simulation.py +13 -8
  109. chia/_tests/simulation/test_simulator.py +2 -2
  110. chia/_tests/timelord/test_new_peak.py +191 -47
  111. chia/_tests/timelord/test_timelord.py +1 -1
  112. chia/_tests/tools/test_full_sync.py +0 -2
  113. chia/_tests/tools/test_run_block.py +3 -1
  114. chia/_tests/util/benchmark_cost.py +3 -3
  115. chia/_tests/util/benchmarks.py +2 -2
  116. chia/_tests/util/blockchain.py +11 -5
  117. chia/_tests/util/blockchain_mock.py +1 -4
  118. chia/_tests/util/coin_store.py +29 -0
  119. chia/_tests/util/constants.py +2 -18
  120. chia/_tests/util/full_sync.py +3 -3
  121. chia/_tests/util/generator_tools_testing.py +2 -3
  122. chia/_tests/util/key_tool.py +2 -3
  123. chia/_tests/util/misc.py +33 -31
  124. chia/_tests/util/network_protocol_data.py +19 -17
  125. chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
  126. chia/_tests/util/protocol_messages_json.py +3 -1
  127. chia/_tests/util/run_block.py +2 -2
  128. chia/_tests/util/setup_nodes.py +7 -7
  129. chia/_tests/util/spend_sim.py +47 -55
  130. chia/_tests/util/test_condition_tools.py +5 -4
  131. chia/_tests/util/test_config.py +2 -2
  132. chia/_tests/util/test_dump_keyring.py +1 -1
  133. chia/_tests/util/test_full_block_utils.py +12 -14
  134. chia/_tests/util/test_misc.py +2 -2
  135. chia/_tests/util/test_paginator.py +4 -4
  136. chia/_tests/util/test_priority_mutex.py +2 -2
  137. chia/_tests/util/test_replace_str_to_bytes.py +15 -5
  138. chia/_tests/util/test_ssl_check.py +1 -1
  139. chia/_tests/util/test_testnet_overrides.py +13 -3
  140. chia/_tests/util/time_out_assert.py +4 -2
  141. chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +1 -1
  142. chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +1 -2
  143. chia/_tests/wallet/cat_wallet/test_cat_wallet.py +352 -432
  144. chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +3 -6
  145. chia/_tests/wallet/cat_wallet/test_trades.py +53 -77
  146. chia/_tests/wallet/clawback/test_clawback_decorator.py +3 -1
  147. chia/_tests/wallet/clawback/test_clawback_lifecycle.py +3 -3
  148. chia/_tests/wallet/clawback/test_clawback_metadata.py +4 -2
  149. chia/_tests/wallet/conftest.py +11 -12
  150. chia/_tests/wallet/db_wallet/test_db_graftroot.py +11 -4
  151. chia/_tests/wallet/db_wallet/test_dl_offers.py +433 -130
  152. chia/_tests/wallet/db_wallet/test_dl_wallet.py +3 -3
  153. chia/_tests/wallet/did_wallet/test_did.py +2132 -2000
  154. chia/_tests/wallet/nft_wallet/config.py +1 -1
  155. chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +1610 -742
  156. chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +486 -907
  157. chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +4 -4
  158. chia/_tests/wallet/nft_wallet/test_nft_wallet.py +517 -294
  159. chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +133 -62
  160. chia/_tests/wallet/rpc/test_wallet_rpc.py +305 -184
  161. chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +10 -6
  162. chia/_tests/wallet/sync/test_wallet_sync.py +89 -60
  163. chia/_tests/wallet/test_clvm_casts.py +88 -0
  164. chia/_tests/wallet/test_coin_management.py +1 -1
  165. chia/_tests/wallet/test_coin_selection.py +1 -1
  166. chia/_tests/wallet/test_conditions.py +1 -1
  167. chia/_tests/wallet/test_new_wallet_protocol.py +13 -11
  168. chia/_tests/wallet/test_notifications.py +5 -3
  169. chia/_tests/wallet/test_sign_coin_spends.py +6 -6
  170. chia/_tests/wallet/test_signer_protocol.py +13 -12
  171. chia/_tests/wallet/test_singleton.py +1 -1
  172. chia/_tests/wallet/test_singleton_lifecycle_fast.py +5 -7
  173. chia/_tests/wallet/test_util.py +2 -2
  174. chia/_tests/wallet/test_wallet.py +108 -29
  175. chia/_tests/wallet/test_wallet_action_scope.py +9 -2
  176. chia/_tests/wallet/test_wallet_blockchain.py +2 -3
  177. chia/_tests/wallet/test_wallet_key_val_store.py +1 -2
  178. chia/_tests/wallet/test_wallet_node.py +2 -4
  179. chia/_tests/wallet/test_wallet_retry.py +4 -2
  180. chia/_tests/wallet/test_wallet_state_manager.py +191 -5
  181. chia/_tests/wallet/test_wallet_test_framework.py +1 -1
  182. chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +8 -8
  183. chia/_tests/wallet/vc_wallet/test_vc_wallet.py +29 -12
  184. chia/_tests/wallet/wallet_block_tools.py +6 -6
  185. chia/_tests/weight_proof/test_weight_proof.py +10 -48
  186. chia/apis.py +1 -1
  187. chia/cmds/beta.py +1 -1
  188. chia/cmds/chia.py +9 -9
  189. chia/cmds/cmd_classes.py +12 -11
  190. chia/cmds/cmd_helpers.py +1 -1
  191. chia/cmds/cmds_util.py +12 -9
  192. chia/cmds/coin_funcs.py +2 -2
  193. chia/cmds/configure.py +2 -2
  194. chia/cmds/data.py +0 -2
  195. chia/cmds/data_funcs.py +1 -1
  196. chia/cmds/db_validate_func.py +1 -2
  197. chia/cmds/dev/__init__.py +0 -0
  198. chia/cmds/dev/data.py +273 -0
  199. chia/cmds/{gh.py → dev/gh.py} +5 -5
  200. chia/cmds/dev/main.py +22 -0
  201. chia/cmds/dev/mempool.py +78 -0
  202. chia/cmds/dev/mempool_funcs.py +63 -0
  203. chia/cmds/farm_funcs.py +5 -4
  204. chia/cmds/init_funcs.py +11 -11
  205. chia/cmds/keys.py +2 -2
  206. chia/cmds/keys_funcs.py +4 -4
  207. chia/cmds/netspace_funcs.py +1 -1
  208. chia/cmds/peer_funcs.py +2 -2
  209. chia/cmds/plotnft_funcs.py +72 -26
  210. chia/cmds/rpc.py +1 -1
  211. chia/cmds/show_funcs.py +5 -5
  212. chia/cmds/signer.py +8 -7
  213. chia/cmds/sim_funcs.py +8 -9
  214. chia/cmds/wallet.py +2 -2
  215. chia/cmds/wallet_funcs.py +165 -131
  216. chia/{util → consensus}/augmented_chain.py +1 -2
  217. chia/consensus/block_body_validation.py +54 -40
  218. chia/consensus/block_creation.py +42 -76
  219. chia/consensus/block_header_validation.py +32 -26
  220. chia/consensus/block_record.py +0 -3
  221. chia/consensus/blockchain.py +23 -32
  222. chia/consensus/blockchain_interface.py +1 -5
  223. chia/consensus/check_time_locks.py +57 -0
  224. chia/consensus/coin_store_protocol.py +151 -0
  225. chia/consensus/coinbase.py +0 -6
  226. chia/consensus/condition_costs.py +4 -0
  227. chia/{util → consensus}/condition_tools.py +4 -5
  228. chia/consensus/cost_calculator.py +1 -1
  229. chia/consensus/default_constants.py +32 -9
  230. chia/consensus/deficit.py +1 -3
  231. chia/consensus/difficulty_adjustment.py +1 -2
  232. chia/consensus/find_fork_point.py +1 -3
  233. chia/consensus/full_block_to_block_record.py +1 -6
  234. chia/{util → consensus}/generator_tools.py +1 -3
  235. chia/consensus/get_block_challenge.py +30 -7
  236. chia/consensus/make_sub_epoch_summary.py +1 -5
  237. chia/consensus/multiprocess_validation.py +21 -20
  238. chia/consensus/pot_iterations.py +74 -13
  239. chia/{util → consensus}/prev_transaction_block.py +1 -1
  240. chia/consensus/vdf_info_computation.py +1 -3
  241. chia/daemon/keychain_proxy.py +5 -5
  242. chia/daemon/server.py +22 -5
  243. chia/data_layer/data_layer.py +92 -51
  244. chia/{rpc → data_layer}/data_layer_rpc_api.py +1 -1
  245. chia/{rpc → data_layer}/data_layer_rpc_util.py +3 -6
  246. chia/data_layer/data_layer_util.py +4 -6
  247. chia/data_layer/data_layer_wallet.py +42 -69
  248. chia/data_layer/dl_wallet_store.py +12 -6
  249. chia/data_layer/download_data.py +3 -3
  250. chia/data_layer/s3_plugin_service.py +0 -1
  251. chia/farmer/farmer.py +3 -4
  252. chia/farmer/farmer_api.py +11 -7
  253. chia/{rpc → farmer}/farmer_rpc_client.py +1 -1
  254. chia/full_node/block_height_map.py +7 -6
  255. chia/full_node/block_store.py +5 -7
  256. chia/full_node/bundle_tools.py +1 -2
  257. chia/full_node/coin_store.py +143 -124
  258. chia/{types → full_node}/eligible_coin_spends.py +39 -70
  259. chia/full_node/fee_estimator.py +1 -1
  260. chia/full_node/fee_estimator_interface.py +0 -8
  261. chia/full_node/fee_tracker.py +25 -25
  262. chia/full_node/full_node.py +70 -53
  263. chia/full_node/full_node_api.py +57 -40
  264. chia/{rpc → full_node}/full_node_rpc_api.py +87 -8
  265. chia/{rpc → full_node}/full_node_rpc_client.py +7 -6
  266. chia/full_node/full_node_store.py +23 -8
  267. chia/full_node/mempool.py +206 -53
  268. chia/full_node/mempool_check_conditions.py +20 -63
  269. chia/full_node/mempool_manager.py +26 -40
  270. chia/full_node/subscriptions.py +1 -3
  271. chia/full_node/tx_processing_queue.py +50 -3
  272. chia/full_node/weight_proof.py +46 -37
  273. chia/harvester/harvester.py +1 -1
  274. chia/harvester/harvester_api.py +22 -7
  275. chia/introducer/introducer.py +1 -1
  276. chia/introducer/introducer_api.py +1 -1
  277. chia/plot_sync/exceptions.py +1 -1
  278. chia/plot_sync/receiver.py +1 -1
  279. chia/plot_sync/sender.py +2 -2
  280. chia/pools/pool_puzzles.py +13 -18
  281. chia/pools/pool_wallet.py +23 -46
  282. chia/protocols/farmer_protocol.py +11 -3
  283. chia/protocols/full_node_protocol.py +1 -4
  284. chia/protocols/harvester_protocol.py +3 -3
  285. chia/protocols/pool_protocol.py +1 -2
  286. chia/protocols/shared_protocol.py +3 -3
  287. chia/protocols/timelord_protocol.py +1 -3
  288. chia/protocols/wallet_protocol.py +3 -3
  289. chia/rpc/rpc_client.py +7 -8
  290. chia/rpc/rpc_server.py +3 -3
  291. chia/rpc/util.py +3 -1
  292. chia/seeder/crawler.py +1 -1
  293. chia/seeder/crawler_api.py +1 -1
  294. chia/seeder/dns_server.py +2 -0
  295. chia/seeder/start_crawler.py +3 -3
  296. chia/server/address_manager.py +286 -38
  297. chia/server/address_manager_store.py +0 -215
  298. chia/{types → server}/aliases.py +7 -7
  299. chia/server/api_protocol.py +1 -1
  300. chia/server/chia_policy.py +1 -1
  301. chia/server/node_discovery.py +76 -113
  302. chia/server/rate_limits.py +1 -1
  303. chia/server/resolve_peer_info.py +43 -0
  304. chia/server/server.py +5 -5
  305. chia/server/start_data_layer.py +4 -4
  306. chia/server/start_farmer.py +5 -4
  307. chia/server/start_full_node.py +5 -4
  308. chia/server/start_harvester.py +7 -5
  309. chia/server/start_introducer.py +2 -2
  310. chia/server/start_service.py +1 -1
  311. chia/server/start_timelord.py +7 -5
  312. chia/server/start_wallet.py +7 -5
  313. chia/server/ws_connection.py +1 -1
  314. chia/simulator/add_blocks_in_batches.py +2 -2
  315. chia/simulator/block_tools.py +245 -201
  316. chia/simulator/full_node_simulator.py +38 -10
  317. chia/simulator/setup_services.py +12 -12
  318. chia/simulator/simulator_full_node_rpc_api.py +2 -2
  319. chia/simulator/simulator_full_node_rpc_client.py +2 -2
  320. chia/simulator/simulator_test_tools.py +2 -2
  321. chia/simulator/start_simulator.py +1 -1
  322. chia/simulator/wallet_tools.py +10 -18
  323. chia/ssl/create_ssl.py +1 -1
  324. chia/timelord/iters_from_block.py +14 -14
  325. chia/timelord/timelord.py +15 -11
  326. chia/timelord/timelord_api.py +14 -2
  327. chia/timelord/timelord_state.py +20 -14
  328. chia/types/blockchain_format/program.py +53 -10
  329. chia/types/blockchain_format/proof_of_space.py +73 -19
  330. chia/types/coin_spend.py +3 -56
  331. chia/types/generator_types.py +28 -0
  332. chia/types/internal_mempool_item.py +1 -2
  333. chia/types/mempool_item.py +12 -7
  334. chia/types/unfinished_header_block.py +1 -2
  335. chia/types/validation_state.py +1 -2
  336. chia/types/weight_proof.py +1 -3
  337. chia/util/action_scope.py +3 -3
  338. chia/util/block_cache.py +1 -2
  339. chia/util/byte_types.py +1 -1
  340. chia/util/casts.py +21 -0
  341. chia/util/config.py +0 -37
  342. chia/util/db_wrapper.py +8 -1
  343. chia/util/errors.py +3 -2
  344. chia/util/initial-config.yaml +21 -5
  345. chia/util/keychain.py +6 -7
  346. chia/util/keyring_wrapper.py +5 -5
  347. chia/util/limited_semaphore.py +1 -1
  348. chia/util/priority_mutex.py +1 -1
  349. chia/util/streamable.py +63 -5
  350. chia/util/task_timing.py +1 -1
  351. chia/util/virtual_project_analysis.py +1 -1
  352. chia/wallet/cat_wallet/cat_info.py +7 -3
  353. chia/wallet/cat_wallet/cat_outer_puzzle.py +9 -5
  354. chia/wallet/cat_wallet/cat_utils.py +1 -1
  355. chia/wallet/cat_wallet/cat_wallet.py +44 -36
  356. chia/wallet/cat_wallet/lineage_store.py +7 -0
  357. chia/wallet/cat_wallet/r_cat_wallet.py +273 -0
  358. chia/wallet/conditions.py +5 -10
  359. chia/wallet/db_wallet/db_wallet_puzzles.py +4 -4
  360. chia/wallet/derivation_record.py +33 -0
  361. chia/wallet/derive_keys.py +3 -3
  362. chia/wallet/did_wallet/did_info.py +12 -3
  363. chia/wallet/did_wallet/did_wallet.py +132 -101
  364. chia/wallet/did_wallet/did_wallet_puzzles.py +9 -9
  365. chia/wallet/driver_protocol.py +3 -1
  366. chia/{types/spend_bundle.py → wallet/estimate_fees.py} +2 -7
  367. chia/wallet/nft_wallet/metadata_outer_puzzle.py +5 -3
  368. chia/wallet/nft_wallet/nft_puzzle_utils.py +1 -1
  369. chia/wallet/nft_wallet/nft_wallet.py +69 -112
  370. chia/wallet/nft_wallet/ownership_outer_puzzle.py +5 -3
  371. chia/wallet/nft_wallet/singleton_outer_puzzle.py +6 -4
  372. chia/wallet/nft_wallet/transfer_program_puzzle.py +4 -2
  373. chia/wallet/nft_wallet/uncurry_nft.py +4 -6
  374. chia/wallet/notification_manager.py +2 -3
  375. chia/wallet/outer_puzzles.py +7 -2
  376. chia/wallet/puzzle_drivers.py +1 -1
  377. chia/wallet/puzzles/clawback/drivers.py +5 -4
  378. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +1 -1
  379. chia/wallet/puzzles/singleton_top_layer.py +2 -1
  380. chia/wallet/puzzles/singleton_top_layer_v1_1.py +2 -1
  381. chia/wallet/puzzles/tails.py +1 -3
  382. chia/wallet/signer_protocol.py +5 -6
  383. chia/wallet/singleton.py +5 -4
  384. chia/wallet/singleton_record.py +1 -1
  385. chia/wallet/trade_manager.py +18 -20
  386. chia/wallet/trade_record.py +3 -6
  387. chia/wallet/trading/offer.py +12 -13
  388. chia/wallet/uncurried_puzzle.py +2 -2
  389. chia/wallet/util/compute_additions.py +58 -0
  390. chia/wallet/util/compute_hints.py +3 -3
  391. chia/wallet/util/compute_memos.py +4 -4
  392. chia/wallet/util/curry_and_treehash.py +2 -1
  393. chia/wallet/util/debug_spend_bundle.py +1 -1
  394. chia/wallet/util/merkle_tree.py +1 -1
  395. chia/wallet/util/peer_request_cache.py +1 -2
  396. chia/wallet/util/tx_config.py +3 -8
  397. chia/wallet/util/wallet_sync_utils.py +10 -5
  398. chia/wallet/util/wallet_types.py +1 -0
  399. chia/wallet/vc_wallet/cr_cat_drivers.py +17 -18
  400. chia/wallet/vc_wallet/cr_cat_wallet.py +30 -28
  401. chia/wallet/vc_wallet/cr_outer_puzzle.py +5 -3
  402. chia/wallet/vc_wallet/vc_drivers.py +50 -8
  403. chia/wallet/vc_wallet/vc_store.py +3 -5
  404. chia/wallet/vc_wallet/vc_wallet.py +15 -22
  405. chia/wallet/wallet.py +36 -46
  406. chia/wallet/wallet_action_scope.py +73 -4
  407. chia/wallet/wallet_blockchain.py +1 -3
  408. chia/wallet/wallet_interested_store.py +1 -1
  409. chia/wallet/wallet_nft_store.py +3 -3
  410. chia/wallet/wallet_node.py +17 -16
  411. chia/wallet/wallet_node_api.py +4 -5
  412. chia/wallet/wallet_pool_store.py +1 -1
  413. chia/wallet/wallet_protocol.py +2 -0
  414. chia/wallet/wallet_puzzle_store.py +1 -1
  415. chia/{rpc → wallet}/wallet_request_types.py +670 -81
  416. chia/{rpc → wallet}/wallet_rpc_api.py +735 -766
  417. chia/{rpc → wallet}/wallet_rpc_client.py +268 -420
  418. chia/wallet/wallet_singleton_store.py +8 -7
  419. chia/wallet/wallet_spend_bundle.py +4 -3
  420. chia/wallet/wallet_state_manager.py +320 -191
  421. chia/wallet/wallet_weight_proof_handler.py +1 -2
  422. chia/wallet/wsm_apis.py +98 -0
  423. {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5rc1.dist-info}/METADATA +7 -7
  424. {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5rc1.dist-info}/RECORD +443 -436
  425. mozilla-ca/cacert.pem +3 -165
  426. chia/_tests/fee_estimation/test_mempoolitem_height_added.py +0 -145
  427. chia/cmds/dev.py +0 -18
  428. chia/types/blockchain_format/slots.py +0 -9
  429. chia/types/blockchain_format/sub_epoch_summary.py +0 -5
  430. chia/types/end_of_slot_bundle.py +0 -5
  431. chia/types/full_block.py +0 -5
  432. chia/types/header_block.py +0 -5
  433. chia/types/spend_bundle_conditions.py +0 -7
  434. chia/types/transaction_queue_entry.py +0 -56
  435. chia/types/unfinished_block.py +0 -5
  436. /chia/cmds/{installers.py → dev/installers.py} +0 -0
  437. /chia/cmds/{sim.py → dev/sim.py} +0 -0
  438. /chia/{util → cmds}/dump_keyring.py +0 -0
  439. /chia/{full_node → consensus}/signage_point.py +0 -0
  440. /chia/{rpc → data_layer}/data_layer_rpc_client.py +0 -0
  441. /chia/{rpc → farmer}/farmer_rpc_api.py +0 -0
  442. /chia/{util → full_node}/full_block_utils.py +0 -0
  443. /chia/{rpc → harvester}/harvester_rpc_api.py +0 -0
  444. /chia/{rpc → harvester}/harvester_rpc_client.py +0 -0
  445. /chia/{full_node → protocols}/fee_estimate.py +0 -0
  446. /chia/{server → protocols}/outbound_message.py +0 -0
  447. /chia/{rpc → seeder}/crawler_rpc_api.py +0 -0
  448. /chia/{util → simulator}/vdf_prover.py +0 -0
  449. /chia/{util → ssl}/ssl_check.py +0 -0
  450. /chia/{rpc → timelord}/timelord_rpc_api.py +0 -0
  451. {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5rc1.dist-info}/LICENSE +0 -0
  452. {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5rc1.dist-info}/WHEEL +0 -0
  453. {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5rc1.dist-info}/entry_points.txt +0 -0
@@ -10,15 +10,16 @@ import traceback
10
10
  from collections.abc import AsyncIterator
11
11
  from contextlib import asynccontextmanager
12
12
  from pathlib import Path
13
- from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, Union
13
+ from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, cast
14
14
 
15
15
  import aiosqlite
16
- from chia_rs import AugSchemeMPL, ConsensusConstants, G1Element, G2Element, PrivateKey
16
+ from chia_rs import AugSchemeMPL, CoinSpend, CoinState, ConsensusConstants, G1Element, G2Element, PrivateKey
17
17
  from chia_rs.sized_bytes import bytes32
18
18
  from chia_rs.sized_ints import uint16, uint32, uint64, uint128
19
19
 
20
20
  from chia.consensus.block_rewards import calculate_base_farmer_reward, calculate_pool_reward
21
21
  from chia.consensus.coinbase import farmer_parent_id, pool_parent_id
22
+ from chia.consensus.condition_tools import conditions_dict_for_solution, pkm_pairs_for_conditions_dict
22
23
  from chia.data_layer.data_layer_wallet import DataLayerWallet
23
24
  from chia.data_layer.dl_wallet_store import DataLayerStore
24
25
  from chia.data_layer.singleton_record import SingletonRecord
@@ -27,20 +28,17 @@ from chia.pools.pool_puzzles import (
27
28
  solution_to_pool_state,
28
29
  )
29
30
  from chia.pools.pool_wallet import PoolWallet
30
- from chia.protocols.wallet_protocol import CoinState
31
+ from chia.protocols.outbound_message import NodeType
31
32
  from chia.rpc.rpc_server import StateChangedProtocol
32
- from chia.server.outbound_message import NodeType
33
33
  from chia.server.server import ChiaServer
34
34
  from chia.server.ws_connection import WSChiaConnection
35
35
  from chia.types.blockchain_format.coin import Coin
36
- from chia.types.blockchain_format.program import Program
36
+ from chia.types.blockchain_format.program import NIL, Program
37
37
  from chia.types.coin_record import CoinRecord
38
- from chia.types.coin_spend import CoinSpend, compute_additions
39
38
  from chia.types.mempool_inclusion_status import MempoolInclusionStatus
40
39
  from chia.util.bech32m import encode_puzzle_hash
41
- from chia.util.condition_tools import conditions_dict_for_solution, pkm_pairs_for_conditions_dict
42
40
  from chia.util.db_synchronous import db_synchronous_on
43
- from chia.util.db_wrapper import DBWrapper2
41
+ from chia.util.db_wrapper import DBWrapper2, PurposefulAbort
44
42
  from chia.util.errors import Err
45
43
  from chia.util.hash import std_hash
46
44
  from chia.util.lru_cache import LRUCache
@@ -50,6 +48,7 @@ from chia.wallet.cat_wallet.cat_constants import DEFAULT_CATS
50
48
  from chia.wallet.cat_wallet.cat_info import CATCoinData, CATInfo, CRCATInfo
51
49
  from chia.wallet.cat_wallet.cat_utils import CAT_MOD, CAT_MOD_HASH, construct_cat_puzzle, match_cat_puzzle
52
50
  from chia.wallet.cat_wallet.cat_wallet import CATWallet
51
+ from chia.wallet.cat_wallet.r_cat_wallet import RCATWallet
53
52
  from chia.wallet.conditions import (
54
53
  AssertCoinAnnouncement,
55
54
  Condition,
@@ -101,6 +100,7 @@ from chia.wallet.trading.trade_status import TradeStatus
101
100
  from chia.wallet.transaction_record import LightTransactionRecord, TransactionRecord
102
101
  from chia.wallet.uncurried_puzzle import uncurry_puzzle
103
102
  from chia.wallet.util.address_type import AddressType
103
+ from chia.wallet.util.compute_additions import compute_additions
104
104
  from chia.wallet.util.compute_hints import compute_spend_hints_and_additions
105
105
  from chia.wallet.util.compute_memos import compute_memos
106
106
  from chia.wallet.util.curry_and_treehash import NIL_TREEHASH
@@ -116,7 +116,7 @@ from chia.wallet.util.wallet_sync_utils import (
116
116
  from chia.wallet.util.wallet_types import CoinType, WalletIdentifier, WalletType
117
117
  from chia.wallet.vc_wallet.cr_cat_drivers import CRCAT, ProofsChecker, construct_pending_approval_state
118
118
  from chia.wallet.vc_wallet.cr_cat_wallet import CRCATWallet
119
- from chia.wallet.vc_wallet.vc_drivers import VerifiedCredential
119
+ from chia.wallet.vc_wallet.vc_drivers import VerifiedCredential, match_revocation_layer
120
120
  from chia.wallet.vc_wallet.vc_store import VCStore
121
121
  from chia.wallet.vc_wallet.vc_wallet import VCWallet
122
122
  from chia.wallet.wallet import Wallet
@@ -134,6 +134,7 @@ from chia.wallet.wallet_retry_store import WalletRetryStore
134
134
  from chia.wallet.wallet_spend_bundle import WalletSpendBundle
135
135
  from chia.wallet.wallet_transaction_store import WalletTransactionStore
136
136
  from chia.wallet.wallet_user_store import WalletUserStore
137
+ from chia.wallet.wsm_apis import CreateMorePuzzleHashesResult, GetUnusedDerivationRecordResult
137
138
 
138
139
  TWalletType = TypeVar("TWalletType", bound=WalletProtocol[Any])
139
140
 
@@ -327,6 +328,12 @@ class WalletStateManager:
327
328
  self.main_wallet,
328
329
  wallet_info,
329
330
  )
331
+ elif wallet_type == WalletType.RCAT:
332
+ wallet = await RCATWallet.create(
333
+ self,
334
+ self.main_wallet,
335
+ wallet_info,
336
+ )
330
337
  if wallet is not None:
331
338
  self.wallets[wallet_info.id] = wallet
332
339
 
@@ -368,130 +375,167 @@ class WalletStateManager:
368
375
 
369
376
  return wallet
370
377
 
378
+ @asynccontextmanager
379
+ async def puzzle_hash_db_writer(self) -> AsyncIterator[None]:
380
+ async with self.db_wrapper.writer():
381
+ old_cache = self.puzzle_store.last_wallet_derivation_index.copy()
382
+ try:
383
+ yield
384
+ except Exception:
385
+ self.puzzle_store.last_wallet_derivation_index = old_cache
386
+ raise
387
+
371
388
  async def create_more_puzzle_hashes(
372
389
  self,
373
390
  from_zero: bool = False,
374
391
  mark_existing_as_used: bool = True,
375
392
  up_to_index: Optional[uint32] = None,
376
393
  num_additional_phs: Optional[int] = None,
377
- ) -> None:
394
+ previous_result: Optional[CreateMorePuzzleHashesResult] = None,
395
+ _commit_previous_result: bool = True,
396
+ ) -> CreateMorePuzzleHashesResult:
378
397
  """
379
398
  For all wallets in the user store, generates the first few puzzle hashes so
380
399
  that we can restore the wallet from only the private keys.
381
400
  """
382
- targets = list(self.wallets.keys())
383
- self.log.debug("Target wallets to generate puzzle hashes for: %s", repr(targets))
384
- unused: Optional[uint32] = (
385
- uint32(up_to_index + 1) if up_to_index is not None else await self.puzzle_store.get_unused_derivation_path()
386
- )
387
- if unused is None:
388
- # This handles the case where the database has entries but they have all been used
389
- unused = await self.puzzle_store.get_last_derivation_path()
390
- self.log.debug("Tried finding unused: %s", unused)
391
- if unused is None:
392
- # This handles the case where the database is empty
393
- unused = uint32(0)
401
+ try:
402
+ async with self.puzzle_hash_db_writer():
403
+ if previous_result is not None:
404
+ if previous_result.mark_existing_as_used is not mark_existing_as_used:
405
+ raise ValueError(
406
+ "Called `create_more_puzzle_hashes` with a previous result and different configuration"
407
+ )
408
+ if _commit_previous_result:
409
+ await previous_result.commit(self)
410
+ targets = list(self.wallets.keys())
411
+ self.log.debug("Target wallets to generate puzzle hashes for: %s", repr(targets))
412
+ unused: Optional[uint32] = (
413
+ up_to_index if up_to_index is not None else await self.puzzle_store.get_unused_derivation_path()
414
+ )
415
+ if unused is None:
416
+ # This handles the case where the database has entries but they have all been used
417
+ unused = await self.puzzle_store.get_last_derivation_path()
418
+ self.log.debug("Tried finding unused: %s", unused)
419
+ if unused is None:
420
+ # This handles the case where the database is empty
421
+ unused = uint32(0)
422
+ else:
423
+ # The first unused will be the one after the last used one we got above
424
+ unused = uint32(unused + 1)
425
+
426
+ self.log.debug(f"Requested to generate puzzle hashes to at least index {unused}")
427
+ start_t = time.time()
428
+ to_generate = num_additional_phs if num_additional_phs is not None else self.initial_num_public_keys
429
+
430
+ # iterate all wallets that need derived keys and establish the start
431
+ # index for all of them
432
+ start_index_by_wallet: dict[uint32, int] = {}
433
+ last_index = unused + to_generate
434
+ for wallet_id in targets:
435
+ target_wallet = self.wallets[wallet_id]
436
+ if not target_wallet.require_derivation_paths():
437
+ self.log.debug("Skipping wallet %s as no derivation paths required", wallet_id)
438
+ continue
439
+ if from_zero:
440
+ start_index_by_wallet[wallet_id] = 0
441
+ continue
442
+ last: Optional[uint32] = await self.puzzle_store.get_last_derivation_path_for_wallet(wallet_id)
443
+ if last is not None:
444
+ if last >= last_index:
445
+ self.log.debug(f"Nothing to create for for wallet_id: {wallet_id}, index: {last_index}")
446
+ continue
447
+ start_index_by_wallet[wallet_id] = last
448
+ else:
449
+ start_index_by_wallet[wallet_id] = 0
450
+
451
+ if len(start_index_by_wallet) == 0:
452
+ raise PurposefulAbort(
453
+ CreateMorePuzzleHashesResult(
454
+ derivation_paths=[] if previous_result is None else previous_result.derivation_paths,
455
+ mark_existing_as_used=mark_existing_as_used,
456
+ unused=unused,
457
+ new_unhardened_keys=False,
458
+ last_index=last_index,
459
+ )
460
+ )
394
461
 
395
- self.log.debug(f"Requested to generate puzzle hashes to at least index {unused}")
396
- start_t = time.time()
397
- to_generate = num_additional_phs if num_additional_phs is not None else self.initial_num_public_keys
398
-
399
- # iterate all wallets that need derived keys and establish the start
400
- # index for all of them
401
- start_index_by_wallet: dict[uint32, int] = {}
402
- last_index = unused + to_generate
403
- for wallet_id in targets:
404
- target_wallet = self.wallets[wallet_id]
405
- if not target_wallet.require_derivation_paths():
406
- self.log.debug("Skipping wallet %s as no derivation paths required", wallet_id)
407
- continue
408
- if from_zero:
409
- start_index_by_wallet[wallet_id] = 0
410
- continue
411
- last: Optional[uint32] = await self.puzzle_store.get_last_derivation_path_for_wallet(wallet_id)
412
- if last is not None:
413
- if last + 1 >= last_index:
414
- self.log.debug(f"Nothing to create for for wallet_id: {wallet_id}, index: {last_index}")
415
- continue
416
- start_index_by_wallet[wallet_id] = last + 1
417
- else:
418
- start_index_by_wallet[wallet_id] = 0
462
+ lowest_start_index = min(start_index_by_wallet.values())
419
463
 
420
- if len(start_index_by_wallet) == 0:
421
- return
464
+ # now derive the keysfrom lowest_start_index to last_index
465
+ # these maps derivation index to public key
466
+ hardened_keys: dict[int, G1Element] = {}
467
+ unhardened_keys: dict[int, G1Element] = {}
422
468
 
423
- lowest_start_index = min(start_index_by_wallet.values())
424
-
425
- # now derive the keysfrom lowest_start_index to last_index
426
- # these maps derivation index to public key
427
- hardened_keys: dict[int, G1Element] = {}
428
- unhardened_keys: dict[int, G1Element] = {}
429
-
430
- if self.private_key is not None:
431
- # Hardened
432
- intermediate_sk = master_sk_to_wallet_sk_intermediate(self.private_key)
433
- for index in range(lowest_start_index, last_index):
434
- hardened_keys[index] = _derive_path(intermediate_sk, [index]).get_g1()
435
-
436
- # Unhardened
437
- intermediate_pk_un = master_pk_to_wallet_pk_unhardened_intermediate(self.root_pubkey)
438
- for index in range(lowest_start_index, last_index):
439
- unhardened_keys[index] = _derive_pk_unhardened(intermediate_pk_un, [index])
440
-
441
- for wallet_id, start_index in start_index_by_wallet.items():
442
- target_wallet = self.wallets[wallet_id]
443
- assert target_wallet.type() != WalletType.POOLING_WALLET
444
- assert start_index < last_index
445
-
446
- derivation_paths: list[DerivationRecord] = []
447
- creating_msg = f"Creating puzzle hashes from {start_index} to {last_index - 1} for wallet_id: {wallet_id}"
448
- self.log.info(f"Start: {creating_msg}")
449
- for index in range(start_index, last_index):
450
- pubkey: Optional[G1Element] = hardened_keys.get(index)
451
- if pubkey is not None:
469
+ if self.private_key is not None:
452
470
  # Hardened
453
- puzzlehash: bytes32 = target_wallet.puzzle_hash_for_pk(pubkey)
454
- self.log.debug(f"Puzzle at index {index} wallet ID {wallet_id} puzzle hash {puzzlehash.hex()}")
455
- derivation_paths.append(
456
- DerivationRecord(
457
- uint32(index),
458
- puzzlehash,
459
- pubkey,
460
- target_wallet.type(),
461
- uint32(target_wallet.id()),
462
- True,
463
- )
464
- )
471
+ intermediate_sk = master_sk_to_wallet_sk_intermediate(self.private_key)
472
+ for index in range(lowest_start_index, last_index + 1):
473
+ hardened_keys[index] = _derive_path(intermediate_sk, [index]).get_g1()
474
+
465
475
  # Unhardened
466
- pubkey = unhardened_keys.get(index)
467
- assert pubkey is not None
468
- puzzlehash_unhardened: bytes32 = target_wallet.puzzle_hash_for_pk(pubkey)
469
- self.log.debug(
470
- f"Puzzle at index {index} wallet ID {wallet_id} puzzle hash {puzzlehash_unhardened.hex()}"
476
+ intermediate_pk_un = master_pk_to_wallet_pk_unhardened_intermediate(self.root_pubkey)
477
+ for index in range(lowest_start_index, last_index + 1):
478
+ unhardened_keys[index] = _derive_pk_unhardened(intermediate_pk_un, [index])
479
+
480
+ derivation_paths: list[DerivationRecord] = (
481
+ [] if previous_result is None else previous_result.derivation_paths
471
482
  )
472
- derivation_paths.append(
473
- DerivationRecord(
474
- uint32(index),
475
- puzzlehash_unhardened,
476
- pubkey,
477
- target_wallet.type(),
478
- uint32(target_wallet.id()),
479
- False,
483
+ for wallet_id, start_index in start_index_by_wallet.items():
484
+ target_wallet = self.wallets[wallet_id]
485
+ assert target_wallet.type() != WalletType.POOLING_WALLET
486
+ assert start_index < last_index
487
+
488
+ creating_msg = (
489
+ f"Creating puzzle hashes from {start_index} to {last_index} for wallet_id: {wallet_id}"
480
490
  )
481
- )
482
- self.log.info(f"Done: {creating_msg} Time: {time.time() - start_t} seconds")
483
- if len(derivation_paths) > 0:
484
- await self.puzzle_store.add_derivation_paths(derivation_paths)
485
- if wallet_id == self.main_wallet.id():
486
- await self.wallet_node.new_peak_queue.subscribe_to_puzzle_hashes(
487
- [record.puzzle_hash for record in derivation_paths]
491
+ self.log.info(f"Start: {creating_msg}")
492
+ for index in range(start_index, last_index + 1):
493
+ pubkey: Optional[G1Element] = hardened_keys.get(index)
494
+ if pubkey is not None:
495
+ # Hardened
496
+ puzzlehash: bytes32 = target_wallet.puzzle_hash_for_pk(pubkey)
497
+ self.log.debug(
498
+ f"Puzzle at index {index} wallet ID {wallet_id} puzzle hash {puzzlehash.hex()}"
499
+ )
500
+ derivation_paths.append(
501
+ DerivationRecord(
502
+ uint32(index),
503
+ puzzlehash,
504
+ pubkey,
505
+ target_wallet.type(),
506
+ uint32(target_wallet.id()),
507
+ True,
508
+ )
509
+ )
510
+ # Unhardened
511
+ pubkey = unhardened_keys.get(index)
512
+ assert pubkey is not None
513
+ puzzlehash_unhardened: bytes32 = target_wallet.puzzle_hash_for_pk(pubkey)
514
+ self.log.debug(
515
+ f"Puzzle at index {index} wallet ID {wallet_id} puzzle hash {puzzlehash_unhardened.hex()}"
516
+ )
517
+ derivation_paths.append(
518
+ DerivationRecord(
519
+ uint32(index),
520
+ puzzlehash_unhardened,
521
+ pubkey,
522
+ target_wallet.type(),
523
+ uint32(target_wallet.id()),
524
+ False,
525
+ )
526
+ )
527
+ self.log.info(f"Done: {creating_msg} Time: {time.time() - start_t} seconds")
528
+ raise PurposefulAbort(
529
+ CreateMorePuzzleHashesResult(
530
+ derivation_paths=derivation_paths,
531
+ mark_existing_as_used=mark_existing_as_used,
532
+ unused=unused,
533
+ new_unhardened_keys=(len(hardened_keys) > 0),
534
+ last_index=last_index,
488
535
  )
489
- if len(unhardened_keys) > 0:
490
- self.state_changed("new_derivation_index", data_object={"index": last_index - 1})
491
- # By default, we'll mark previously generated unused puzzle hashes as used if we have new paths
492
- if mark_existing_as_used and unused > 0 and len(unhardened_keys) > 0:
493
- self.log.info(f"Updating last used derivation index: {unused - 1}")
494
- await self.puzzle_store.set_used_up_to(uint32(unused - 1))
536
+ )
537
+ except PurposefulAbort as e:
538
+ return cast(CreateMorePuzzleHashesResult, e.obj)
495
539
 
496
540
  async def update_wallet_puzzle_hashes(self, wallet_id: uint32) -> None:
497
541
  derivation_paths: list[DerivationRecord] = []
@@ -522,35 +566,64 @@ class WalletStateManager:
522
566
  )
523
567
  await self.puzzle_store.add_derivation_paths(derivation_paths)
524
568
 
525
- async def get_unused_derivation_record(self, wallet_id: uint32, *, hardened: bool = False) -> DerivationRecord:
569
+ async def _get_unused_derivation_record(
570
+ self,
571
+ wallet_id: uint32,
572
+ *,
573
+ hardened: bool = False,
574
+ previous_result: Optional[GetUnusedDerivationRecordResult] = None,
575
+ ) -> GetUnusedDerivationRecordResult:
526
576
  """
527
577
  Creates a puzzle hash for the given wallet, and then makes more puzzle hashes
528
578
  for every wallet to ensure we always have more in the database. Never reusue the
529
579
  same public key more than once (for privacy).
530
580
  """
531
- async with self.puzzle_store.lock:
532
- # If we have no unused public keys, we will create new ones
533
- unused: Optional[uint32] = await self.puzzle_store.get_unused_derivation_path()
534
- if unused is None:
535
- self.log.debug("No unused paths, generate more ")
536
- await self.create_more_puzzle_hashes()
537
- # Now we must have unused public keys
538
- unused = await self.puzzle_store.get_unused_derivation_path()
539
- assert unused is not None
540
-
541
- self.log.debug("Fetching derivation record for: %s %s %s", unused, wallet_id, hardened)
542
- record: Optional[DerivationRecord] = await self.puzzle_store.get_derivation_record(
543
- unused, wallet_id, hardened
544
- )
545
- if record is None:
546
- raise ValueError(f"Missing derivation '{unused}' for wallet id '{wallet_id}' (hardened={hardened})")
581
+ try:
582
+ async with self.puzzle_hash_db_writer():
583
+ if previous_result is not None:
584
+ await previous_result.commit(self)
585
+ create_more_puzzle_hashes_result: Optional[CreateMorePuzzleHashesResult] = (
586
+ previous_result.create_more_puzzle_hashes_result
587
+ )
588
+ else:
589
+ create_more_puzzle_hashes_result = None
590
+ # If we have no unused public keys, we will create new ones
591
+ unused: Optional[uint32] = await self.puzzle_store.get_unused_derivation_path()
592
+ if unused is None:
593
+ self.log.debug("No unused paths, generate more ")
594
+ create_more_puzzle_hashes_result = await self.create_more_puzzle_hashes(
595
+ previous_result=create_more_puzzle_hashes_result, _commit_previous_result=False
596
+ )
597
+ await create_more_puzzle_hashes_result.commit(self)
598
+ # Now we must have unused public keys
599
+ unused = await self.puzzle_store.get_unused_derivation_path()
600
+ assert unused is not None
601
+
602
+ self.log.debug("Fetching derivation record for: %s %s %s", unused, wallet_id, hardened)
603
+ record: Optional[DerivationRecord] = await self.puzzle_store.get_derivation_record(
604
+ unused, wallet_id, hardened
605
+ )
606
+ if record is None:
607
+ raise ValueError(f"Missing derivation '{unused}' for wallet id '{wallet_id}' (hardened={hardened})")
608
+
609
+ # Set this key to used so we never use it again
610
+ await self.puzzle_store.set_used_up_to(record.index)
547
611
 
548
- # Set this key to used so we never use it again
549
- await self.puzzle_store.set_used_up_to(record.index)
612
+ # Create more puzzle hashes / keys
613
+ create_more_puzzle_hashes_result = await self.create_more_puzzle_hashes(
614
+ previous_result=create_more_puzzle_hashes_result,
615
+ up_to_index=record.index,
616
+ _commit_previous_result=False,
617
+ )
618
+ await create_more_puzzle_hashes_result.commit(self)
619
+ raise PurposefulAbort(GetUnusedDerivationRecordResult(record, create_more_puzzle_hashes_result))
620
+ except PurposefulAbort as e:
621
+ return cast(GetUnusedDerivationRecordResult, e.obj)
550
622
 
551
- # Create more puzzle hashes / keys
552
- await self.create_more_puzzle_hashes()
553
- return record
623
+ async def get_unused_derivation_record(self, wallet_id: uint32, *, hardened: bool = False) -> DerivationRecord:
624
+ result = await self._get_unused_derivation_record(wallet_id, hardened=hardened)
625
+ await result.commit(self)
626
+ return result.record
554
627
 
555
628
  async def get_current_derivation_record_for_wallet(self, wallet_id: uint32) -> Optional[DerivationRecord]:
556
629
  async with self.puzzle_store.lock:
@@ -810,7 +883,7 @@ class WalletStateManager:
810
883
  p2_puzzle, recovery_list_hash, num_verification, singleton_struct, metadata = did_curried_args
811
884
  did_data: DIDCoinData = DIDCoinData(
812
885
  p2_puzzle,
813
- bytes32(recovery_list_hash.as_atom()),
886
+ bytes32(recovery_list_hash.as_atom()) if recovery_list_hash != Program.to(None) else None,
814
887
  uint16(num_verification.as_int()),
815
888
  singleton_struct,
816
889
  metadata,
@@ -834,32 +907,35 @@ class WalletStateManager:
834
907
 
835
908
  return None, None
836
909
 
837
- async def auto_claim_coins(self) -> None:
838
- # Get unspent clawback coin
839
- current_timestamp = self.blockchain.get_latest_timestamp()
840
- clawback_coins: dict[Coin, ClawbackMetadata] = {}
841
- tx_fee = uint64(self.config.get("auto_claim", {}).get("tx_fee", 0))
842
- assert self.wallet_node.logged_in_fingerprint is not None
910
+ @property
911
+ def tx_config(self) -> TXConfig:
843
912
  tx_config_loader: TXConfigLoader = TXConfigLoader.from_json_dict(self.config.get("auto_claim", {}))
844
913
  if tx_config_loader.min_coin_amount is None:
845
914
  tx_config_loader = tx_config_loader.override(
846
915
  min_coin_amount=self.config.get("auto_claim", {}).get("min_amount"),
847
916
  )
848
- tx_config: TXConfig = tx_config_loader.autofill(
917
+ assert self.wallet_node.logged_in_fingerprint is not None
918
+ return tx_config_loader.autofill(
849
919
  constants=self.constants,
850
920
  config=self.config,
851
921
  logged_in_fingerprint=self.wallet_node.logged_in_fingerprint,
852
922
  )
923
+
924
+ async def auto_claim_coins(self) -> None:
925
+ # Get unspent clawback coin
926
+ current_timestamp = self.blockchain.get_latest_timestamp()
927
+ clawback_coins: dict[Coin, ClawbackMetadata] = {}
928
+ tx_fee = uint64(self.config.get("auto_claim", {}).get("tx_fee", 0))
853
929
  unspent_coins = await self.coin_store.get_coin_records(
854
930
  coin_type=CoinType.CLAWBACK,
855
931
  wallet_type=WalletType.STANDARD_WALLET,
856
932
  spent_range=UInt32Range(stop=uint32(0)),
857
933
  amount_range=UInt64Range(
858
- start=tx_config.coin_selection_config.min_coin_amount,
859
- stop=tx_config.coin_selection_config.max_coin_amount,
934
+ start=self.tx_config.coin_selection_config.min_coin_amount,
935
+ stop=self.tx_config.coin_selection_config.max_coin_amount,
860
936
  ),
861
937
  )
862
- async with self.new_action_scope(tx_config, push=True) as action_scope:
938
+ async with self.new_action_scope(self.tx_config, push=True) as action_scope:
863
939
  for coin in unspent_coins.records:
864
940
  try:
865
941
  metadata: MetadataTypes = coin.parsed_metadata()
@@ -1058,19 +1134,28 @@ class WalletStateManager:
1058
1134
  our_inner_puzzle: Program = self.main_wallet.puzzle_for_pk(derivation_record.pubkey)
1059
1135
  asset_id: bytes32 = parent_data.tail_program_hash
1060
1136
  cat_puzzle = construct_cat_puzzle(CAT_MOD, asset_id, our_inner_puzzle, CAT_MOD_HASH)
1061
- is_crcat: bool = False
1137
+ wallet_type: type[CATWallet] = CATWallet
1062
1138
  if cat_puzzle.get_tree_hash() != coin_state.coin.puzzle_hash:
1063
- # Check if it is a CRCAT
1064
- if CRCAT.is_cr_cat(uncurry_puzzle(coin_spend.puzzle_reveal)):
1065
- is_crcat = True
1139
+ # Check if it is a special type of CAT
1140
+ uncurried_puzzle_reveal = uncurry_puzzle(coin_spend.puzzle_reveal)
1141
+ if uncurried_puzzle_reveal.mod != CAT_MOD:
1142
+ return None
1143
+ revocation_layer_match = match_revocation_layer(uncurry_puzzle(uncurried_puzzle_reveal.args.at("rrf")))
1144
+ if revocation_layer_match is not None:
1145
+ wallet_type = RCATWallet
1066
1146
  else:
1067
- return None # pragma: no cover
1068
- if is_crcat:
1069
- # Since CRCAT wallet doesn't have derivation path, every CRCAT will go through this code path
1070
- crcat: CRCAT = next(
1071
- crc for crc in CRCAT.get_next_from_coin_spend(coin_spend) if crc.coin == coin_state.coin
1072
- )
1147
+ try:
1148
+ next_crcats = CRCAT.get_next_from_coin_spend(coin_spend)
1073
1149
 
1150
+ except ValueError:
1151
+ return None
1152
+
1153
+ crcat = next(crc for crc in next_crcats if crc.coin == coin_state.coin)
1154
+
1155
+ wallet_type = CRCATWallet
1156
+ if wallet_type is CRCATWallet:
1157
+ assert crcat # mypy doesn't get the semantics
1158
+ # Since CRCAT wallet doesn't have derivation path, every CRCAT will go through this code path
1074
1159
  # Make sure we control the inner puzzle or we control it if it's wrapped in the pending state
1075
1160
  if (
1076
1161
  await self.puzzle_store.get_derivation_record_for_puzzle_hash(crcat.inner_puzzle_hash) is None
@@ -1089,30 +1174,53 @@ class WalletStateManager:
1089
1174
  if crcat_info.limitations_program_hash == asset_id:
1090
1175
  return WalletIdentifier(wallet_info.id, WalletType(wallet_info.type))
1091
1176
 
1092
- # We didn't find a matching CR-CAT wallet, but maybe we have a matching CAT wallet that we can convert
1177
+ if wallet_type in {CRCATWallet, RCATWallet}:
1178
+ # We didn't find a matching alt-CAT wallet, but maybe we have a matching CAT wallet that we can convert
1093
1179
  for wallet_info in await self.get_all_wallet_info_entries(wallet_type=WalletType.CAT):
1094
1180
  cat_info: CATInfo = CATInfo.from_bytes(bytes.fromhex(wallet_info.data))
1095
1181
  found_cat_wallet = self.wallets[wallet_info.id]
1096
1182
  assert isinstance(found_cat_wallet, CATWallet)
1097
- if cat_info.limitations_program_hash == crcat.tail_hash:
1098
- await CRCATWallet.convert_to_cr(
1099
- found_cat_wallet,
1100
- crcat.authorized_providers,
1101
- ProofsChecker.from_program(uncurry_puzzle(crcat.proofs_checker)),
1102
- )
1103
- self.state_changed("converted cat wallet to cr", wallet_info.id)
1104
- return WalletIdentifier(wallet_info.id, WalletType(WalletType.CRCAT))
1183
+ if cat_info.limitations_program_hash == asset_id:
1184
+ if wallet_type is CRCATWallet:
1185
+ assert crcat # again, mypy isn't this smart
1186
+ await CRCATWallet.convert_to_cr(
1187
+ found_cat_wallet,
1188
+ crcat.authorized_providers,
1189
+ ProofsChecker.from_program(uncurry_puzzle(crcat.proofs_checker)),
1190
+ )
1191
+ self.state_changed("converted cat wallet to cr", wallet_info.id)
1192
+ return WalletIdentifier(wallet_info.id, WalletType(WalletType.CRCAT))
1193
+ elif wallet_type is RCATWallet:
1194
+ success = await RCATWallet.convert_to_revocable(
1195
+ found_cat_wallet,
1196
+ # too complicated for mypy but semantics guarantee this not to be None
1197
+ hidden_puzzle_hash=revocation_layer_match[0], # type: ignore[index]
1198
+ )
1199
+ if success:
1200
+ self.state_changed("converted cat wallet to revocable", wallet_info.id)
1201
+ return WalletIdentifier(wallet_info.id, WalletType(WalletType.CRCAT))
1202
+ else:
1203
+ return None
1204
+
1105
1205
  if parent_data.tail_program_hash.hex() in self.default_cats or self.config.get(
1106
1206
  "automatically_add_unknown_cats", False
1107
1207
  ):
1108
- if is_crcat:
1109
- cat_wallet: Union[CATWallet, CRCATWallet] = await CRCATWallet.get_or_create_wallet_for_cat(
1208
+ if wallet_type is CRCATWallet:
1209
+ cat_wallet: CATWallet = await CRCATWallet.get_or_create_wallet_for_cat(
1110
1210
  self,
1111
1211
  self.main_wallet,
1112
1212
  crcat.tail_hash.hex(),
1113
1213
  authorized_providers=crcat.authorized_providers,
1114
1214
  proofs_checker=ProofsChecker.from_program(uncurry_puzzle(crcat.proofs_checker)),
1115
1215
  )
1216
+ elif wallet_type is RCATWallet:
1217
+ cat_wallet = await RCATWallet.get_or_create_wallet_for_cat(
1218
+ self,
1219
+ self.main_wallet,
1220
+ parent_data.tail_program_hash.hex(),
1221
+ # too complicated for mypy but semantics guarantee this not to be None
1222
+ hidden_puzzle_hash=revocation_layer_match[0], # type: ignore[index]
1223
+ )
1116
1224
  else:
1117
1225
  cat_wallet = await CATWallet.get_or_create_wallet_for_cat(
1118
1226
  self, self.main_wallet, parent_data.tail_program_hash.hex()
@@ -1198,11 +1306,23 @@ class WalletStateManager:
1198
1306
  parent_data.singleton_struct,
1199
1307
  parent_data.metadata,
1200
1308
  )
1309
+ alt_did_puzzle_empty_recovery = DID_INNERPUZ_MOD.curry(
1310
+ our_inner_puzzle,
1311
+ NIL,
1312
+ uint64(0),
1313
+ parent_data.singleton_struct,
1314
+ parent_data.metadata,
1315
+ )
1316
+
1201
1317
  full_puzzle_empty_recovery = create_singleton_puzzle(did_puzzle_empty_recovery, launch_id)
1318
+ alt_full_puzzle_empty_recovery = create_singleton_puzzle(alt_did_puzzle_empty_recovery, launch_id)
1202
1319
  if full_puzzle.get_tree_hash() != coin_state.coin.puzzle_hash:
1203
1320
  if full_puzzle_empty_recovery.get_tree_hash() == coin_state.coin.puzzle_hash:
1204
1321
  did_puzzle = did_puzzle_empty_recovery
1205
1322
  self.log.info("DID recovery list was reset by the previous owner.")
1323
+ elif alt_full_puzzle_empty_recovery.get_tree_hash() == coin_state.coin.puzzle_hash:
1324
+ did_puzzle = alt_did_puzzle_empty_recovery
1325
+ self.log.info("DID recovery list was reset by the previous owner.")
1206
1326
  else:
1207
1327
  self.log.error("DID puzzle hash doesn't match, please check curried parameters.")
1208
1328
  return None
@@ -1256,7 +1376,7 @@ class WalletStateManager:
1256
1376
  raise ValueError("Couldn't get minter DID for NFT")
1257
1377
  if not eve_uncurried_nft.supports_did:
1258
1378
  return None
1259
- minter_did = get_new_owner_did(eve_uncurried_nft, eve_coin_spend.solution.to_program())
1379
+ minter_did = get_new_owner_did(eve_uncurried_nft, Program.from_serialized(eve_coin_spend.solution))
1260
1380
  if minter_did == b"":
1261
1381
  minter_did = None
1262
1382
  if minter_did is None:
@@ -1307,7 +1427,7 @@ class WalletStateManager:
1307
1427
  nft_data.parent_coin_spend.solution,
1308
1428
  )
1309
1429
  if uncurried_nft.supports_did:
1310
- _new_did_id = get_new_owner_did(uncurried_nft, nft_data.parent_coin_spend.solution.to_program())
1430
+ _new_did_id = get_new_owner_did(uncurried_nft, Program.from_serialized(nft_data.parent_coin_spend.solution))
1311
1431
  old_did_id = uncurried_nft.owner_did
1312
1432
  if _new_did_id is None:
1313
1433
  new_did_id = old_did_id
@@ -1810,9 +1930,10 @@ class WalletStateManager:
1810
1930
 
1811
1931
  while curr_coin_state.spent_height is not None:
1812
1932
  cs: CoinSpend = await fetch_coin_spend_for_coin_state(curr_coin_state, peer)
1813
- success = await singleton_wallet.apply_state_transition(
1814
- cs, uint32(curr_coin_state.spent_height)
1815
- )
1933
+ async with self.new_action_scope(self.tx_config, push=True) as action_scope:
1934
+ success = await singleton_wallet.apply_state_transition(
1935
+ cs, uint32(curr_coin_state.spent_height), action_scope
1936
+ )
1816
1937
  if not success:
1817
1938
  break
1818
1939
  new_singleton_coin = get_most_recent_singleton_coin_from_coin_spend(cs)
@@ -1901,14 +2022,16 @@ class WalletStateManager:
1901
2022
  self.log.debug("solution_to_pool_state returned None, ignore and continue")
1902
2023
  continue
1903
2024
 
1904
- pool_wallet = await PoolWallet.create(
1905
- self,
1906
- self.main_wallet,
1907
- child.coin.name(),
1908
- [launcher_spend],
1909
- uint32(child.spent_height),
1910
- name="pool_wallet",
1911
- )
2025
+ async with self.new_action_scope(self.tx_config, push=True) as action_scope:
2026
+ pool_wallet = await PoolWallet.create(
2027
+ self,
2028
+ action_scope,
2029
+ self.main_wallet,
2030
+ child.coin.name(),
2031
+ [launcher_spend],
2032
+ uint32(child.spent_height),
2033
+ name="pool_wallet",
2034
+ )
1912
2035
  launcher_spend_additions = compute_additions(launcher_spend)
1913
2036
  assert len(launcher_spend_additions) == 1
1914
2037
  coin_added = launcher_spend_additions[0]
@@ -1971,7 +2094,7 @@ class WalletStateManager:
1971
2094
  ):
1972
2095
  # Optimization to avoid the computation below. Any coin that has a different amount is not a pool reward
1973
2096
  return False
1974
- for i in range(0, 30):
2097
+ for i in range(30):
1975
2098
  try_height = created_height - i
1976
2099
  if try_height < 0:
1977
2100
  break
@@ -1984,7 +2107,7 @@ class WalletStateManager:
1984
2107
  if coin.amount < calculate_base_farmer_reward(created_height):
1985
2108
  # Optimization to avoid the computation below. Any coin less than this base amount cannot be farmer reward
1986
2109
  return False
1987
- for i in range(0, 30):
2110
+ for i in range(30):
1988
2111
  try_height = created_height - i
1989
2112
  if try_height < 0:
1990
2113
  break
@@ -2107,7 +2230,8 @@ class WalletStateManager:
2107
2230
 
2108
2231
  await self.wallets[wallet_id].coin_added(coin, height, peer, coin_data)
2109
2232
 
2110
- await self.create_more_puzzle_hashes()
2233
+ result = await self.create_more_puzzle_hashes()
2234
+ await result.commit(self)
2111
2235
 
2112
2236
  async def add_pending_transactions(
2113
2237
  self,
@@ -2300,7 +2424,8 @@ class WalletStateManager:
2300
2424
  for wallet_id, wallet in self.wallets.items():
2301
2425
  if wallet.type() == WalletType.POOLING_WALLET.value:
2302
2426
  assert isinstance(wallet, PoolWallet)
2303
- remove: bool = await wallet.rewind(height)
2427
+ async with self.new_action_scope(self.tx_config, push=True) as action_scope:
2428
+ remove: bool = await wallet.rewind(height, action_scope)
2304
2429
  if remove:
2305
2430
  remove_ids.append(wallet_id)
2306
2431
  for wallet_id in remove_ids:
@@ -2320,7 +2445,7 @@ class WalletStateManager:
2320
2445
 
2321
2446
  async def get_wallet_for_asset_id(self, asset_id: str) -> Optional[WalletProtocol[Any]]:
2322
2447
  for wallet_id, wallet in self.wallets.items():
2323
- if wallet.type() in {WalletType.CAT, WalletType.CRCAT}:
2448
+ if wallet.type() in {WalletType.CAT, WalletType.CRCAT, WalletType.RCAT}:
2324
2449
  assert isinstance(wallet, CATWallet)
2325
2450
  if wallet.get_asset_id() == asset_id:
2326
2451
  return wallet
@@ -2352,12 +2477,14 @@ class WalletStateManager:
2352
2477
  name,
2353
2478
  potential_subclasses={
2354
2479
  AssetType.CR: CRCATWallet,
2480
+ AssetType.REVOCATION_LAYER: RCATWallet,
2355
2481
  },
2356
2482
  )
2357
2483
 
2358
2484
  async def add_new_wallet(self, wallet: WalletProtocol[Any]) -> None:
2359
2485
  self.wallets[wallet.id()] = wallet
2360
- await self.create_more_puzzle_hashes()
2486
+ result = await self.create_more_puzzle_hashes()
2487
+ await result.commit(self)
2361
2488
  self.state_changed("wallet_created")
2362
2489
 
2363
2490
  async def get_spendable_coins_for_wallet(
@@ -2439,7 +2566,7 @@ class WalletStateManager:
2439
2566
  async def convert_puzzle_hash(self, wallet_id: uint32, puzzle_hash: bytes32) -> bytes32:
2440
2567
  wallet = self.wallets[wallet_id]
2441
2568
  # This should be general to wallets but for right now this is just for CATs so we'll add this if
2442
- if wallet.type() in {WalletType.CAT.value, WalletType.CRCAT.value}:
2569
+ if wallet.type() in {WalletType.CAT.value, WalletType.CRCAT.value, WalletType.RCAT.value}:
2443
2570
  assert isinstance(wallet, CATWallet)
2444
2571
  return await wallet.convert_puzzle_hash(puzzle_hash)
2445
2572
 
@@ -2485,8 +2612,8 @@ class WalletStateManager:
2485
2612
  _coin_spend = coin_spend.as_coin_spend()
2486
2613
  # Get AGG_SIG conditions
2487
2614
  conditions_dict = conditions_dict_for_solution(
2488
- _coin_spend.puzzle_reveal.to_program(),
2489
- _coin_spend.solution.to_program(),
2615
+ Program.from_serialized(_coin_spend.puzzle_reveal),
2616
+ Program.from_serialized(_coin_spend.solution),
2490
2617
  self.constants.MAX_BLOCK_COST_CLVM,
2491
2618
  )
2492
2619
  # Create signature
@@ -2625,6 +2752,7 @@ class WalletStateManager:
2625
2752
  sign: Optional[bool] = None,
2626
2753
  additional_signing_responses: list[SigningResponse] = [],
2627
2754
  extra_spends: list[WalletSpendBundle] = [],
2755
+ puzzle_for_pk: Optional[Callable[[G1Element], Program]] = None,
2628
2756
  ) -> AsyncIterator[WalletActionScope]:
2629
2757
  async with new_wallet_action_scope(
2630
2758
  self,
@@ -2634,6 +2762,7 @@ class WalletStateManager:
2634
2762
  sign=sign,
2635
2763
  additional_signing_responses=additional_signing_responses,
2636
2764
  extra_spends=extra_spends,
2765
+ puzzle_for_pk=puzzle_for_pk,
2637
2766
  ) as action_scope:
2638
2767
  yield action_scope
2639
2768