chia-blockchain 2.5.4rc2__py3-none-any.whl → 2.5.5__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 +529 -69
  63. chia/_tests/core/mempool/test_mempool_performance.py +3 -2
  64. chia/_tests/core/mempool/test_singleton_fast_forward.py +61 -132
  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 +495 -265
  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 +153 -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 +47 -45
  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 +274 -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.5.dist-info}/METADATA +7 -7
  424. {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5.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.5.dist-info}/LICENSE +0 -0
  452. {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5.dist-info}/WHEEL +0 -0
  453. {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5.dist-info}/entry_points.txt +0 -0
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import dataclasses
4
4
  import json
5
+ from typing import Any, Optional, Union
5
6
 
6
7
  import pytest
7
8
  from chia_rs import AugSchemeMPL, G1Element, G2Element
@@ -12,8 +13,7 @@ from chia._tests.conftest import ConsensusMode
12
13
  from chia._tests.environments.wallet import WalletStateTransition, WalletTestFramework
13
14
  from chia._tests.util.setup_nodes import OldSimulatorsAndWallets
14
15
  from chia._tests.util.time_out_assert import time_out_assert
15
- from chia.rpc.wallet_request_types import DIDGetCurrentCoinInfo, DIDGetRecoveryInfo
16
- from chia.rpc.wallet_rpc_api import WalletRpcApi
16
+ from chia.consensus.condition_tools import conditions_dict_for_solution
17
17
  from chia.server.server import ChiaServer
18
18
  from chia.simulator.block_tools import BlockTools
19
19
  from chia.simulator.full_node_simulator import FullNodeSimulator
@@ -23,13 +23,23 @@ from chia.types.condition_opcodes import ConditionOpcode
23
23
  from chia.types.peer_info import PeerInfo
24
24
  from chia.types.signing_mode import CHIP_0002_SIGN_MESSAGE_PREFIX
25
25
  from chia.util.bech32m import decode_puzzle_hash, encode_puzzle_hash
26
- from chia.util.condition_tools import conditions_dict_for_solution
27
26
  from chia.wallet.did_wallet.did_wallet import DIDWallet
28
- from chia.wallet.singleton import create_singleton_puzzle
27
+ from chia.wallet.did_wallet.did_wallet_puzzles import (
28
+ DID_INNERPUZ_MOD,
29
+ )
30
+ from chia.wallet.singleton import (
31
+ SINGLETON_LAUNCHER_PUZZLE_HASH,
32
+ SINGLETON_TOP_LAYER_MOD_HASH,
33
+ create_singleton_puzzle,
34
+ )
29
35
  from chia.wallet.util.address_type import AddressType
30
36
  from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
31
37
  from chia.wallet.util.wallet_types import WalletType
38
+ from chia.wallet.wallet import Wallet
39
+ from chia.wallet.wallet_action_scope import WalletActionScope
32
40
  from chia.wallet.wallet_node import WalletNode
41
+ from chia.wallet.wallet_request_types import DIDFindLostDID, DIDGetCurrentCoinInfo, DIDGetInfo, DIDGetRecoveryInfo
42
+ from chia.wallet.wallet_rpc_api import WalletRpcApi
33
43
  from chia.wallet.wallet_spend_bundle import WalletSpendBundle
34
44
 
35
45
 
@@ -41,2185 +51,2297 @@ def get_parent_num(did_wallet: DIDWallet):
41
51
  return len(did_wallet.did_info.parent_info)
42
52
 
43
53
 
44
- class TestDIDWallet:
45
- # TODO: See Issue CHIA-1544
46
- # This test should be ported to WalletTestFramework once we can replace keys in the wallet node
47
- @pytest.mark.parametrize(
48
- "trusted",
49
- [True, False],
50
- )
51
- @pytest.mark.anyio
52
- async def test_creation_from_coin_spend(
53
- self, self_hostname: str, two_nodes_two_wallets_with_same_keys: OldSimulatorsAndWallets, trusted: bool
54
- ) -> None:
55
- """
56
- Verify that DIDWallet.create_new_did_wallet_from_coin_spend() is called after Singleton creation on
57
- the blockchain, and that the wallet is created in the second wallet node.
58
- """
59
- full_nodes, wallets, _ = two_nodes_two_wallets_with_same_keys
60
- full_node_api = full_nodes[0]
61
- full_node_server = full_node_api.server
62
- wallet_node_0, server_0 = wallets[0]
63
- wallet_node_1, server_1 = wallets[1]
64
-
65
- wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
66
- wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
67
-
68
- ph0 = await wallet_0.get_new_puzzlehash()
69
- ph1 = await wallet_1.get_new_puzzlehash()
70
-
71
- sk0 = await wallet_node_0.wallet_state_manager.get_private_key(ph0)
72
- sk1 = await wallet_node_1.wallet_state_manager.get_private_key(ph1)
73
- assert sk0 == sk1
74
-
75
- if trusted:
76
- wallet_node_0.config["trusted_peers"] = {
77
- full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
78
- }
79
- wallet_node_1.config["trusted_peers"] = {
80
- full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
81
- }
54
+ async def make_did_wallet(
55
+ wallet_state_manager: Any,
56
+ wallet: Wallet,
57
+ amount: uint64,
58
+ action_scope: WalletActionScope,
59
+ recovery_list: list[bytes32] = [],
60
+ metadata: dict[str, str] = {},
61
+ fee: uint64 = uint64(0),
62
+ use_alternate_recovery: bool = False,
63
+ ) -> DIDWallet:
64
+ def alt_create_innerpuz(
65
+ p2_puzzle_or_hash: Union[Program, bytes32],
66
+ recovery_list: list[bytes32],
67
+ num_of_backup_ids_needed: uint64,
68
+ launcher_id: bytes32,
69
+ metadata: Program = Program.to([]),
70
+ recovery_list_hash: Optional[Program] = None,
71
+ ) -> Program:
72
+ # override the default of NIL_TREEHASH with NIL to match other wallet implementations
73
+ nil_recovery = Program.to(None)
74
+ singleton_struct = Program.to((SINGLETON_TOP_LAYER_MOD_HASH, (launcher_id, SINGLETON_LAUNCHER_PUZZLE_HASH)))
75
+ return DID_INNERPUZ_MOD.curry(p2_puzzle_or_hash, nil_recovery, 0, singleton_struct, metadata)
76
+
77
+ if use_alternate_recovery:
78
+ with pytest.MonkeyPatch.context() as m:
79
+ m.setattr("chia.wallet.did_wallet.did_wallet_puzzles.create_innerpuz", alt_create_innerpuz)
80
+ did_wallet = await DIDWallet.create_new_did_wallet(
81
+ wallet_state_manager, wallet, uint64(101), action_scope, metadata=metadata, fee=fee
82
+ )
83
+ else:
84
+ did_wallet = await DIDWallet.create_new_did_wallet(
85
+ wallet_state_manager, wallet, amount, action_scope, backups_ids=recovery_list, metadata=metadata, fee=fee
86
+ )
82
87
 
83
- else:
84
- wallet_node_0.config["trusted_peers"] = {}
85
- wallet_node_1.config["trusted_peers"] = {}
86
- await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
87
- await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
88
+ return did_wallet
88
89
 
89
- await full_node_api.farm_blocks_to_wallet(1, wallet_0)
90
- await full_node_api.farm_blocks_to_wallet(1, wallet_1)
91
90
 
92
- # Wallet1 sets up DIDWallet1 without any backup set
93
- async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
94
- did_wallet_0: DIDWallet = await DIDWallet.create_new_did_wallet(
95
- wallet_node_0.wallet_state_manager, wallet_0, uint64(101), action_scope
96
- )
91
+ # TODO: See Issue CHIA-1544
92
+ # This test should be ported to WalletTestFramework once we can replace keys in the wallet node
93
+ @pytest.mark.parametrize(
94
+ "trusted",
95
+ [True, False],
96
+ )
97
+ @pytest.mark.parametrize(
98
+ "use_alternate_recovery",
99
+ [True, False],
100
+ )
101
+ @pytest.mark.anyio
102
+ async def test_creation_from_coin_spend(
103
+ self_hostname: str,
104
+ two_nodes_two_wallets_with_same_keys: OldSimulatorsAndWallets,
105
+ trusted: bool,
106
+ use_alternate_recovery: bool,
107
+ ) -> None:
108
+ """
109
+ Verify that DIDWallet.create_new_did_wallet_from_coin_spend() is called after Singleton creation on
110
+ the blockchain, and that the wallet is created in the second wallet node.
111
+ """
112
+ full_nodes, wallets, _ = two_nodes_two_wallets_with_same_keys
113
+ full_node_api = full_nodes[0]
114
+ full_node_server = full_node_api.server
115
+ wallet_node_0, server_0 = wallets[0]
116
+ wallet_node_1, server_1 = wallets[1]
117
+
118
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
119
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
120
+
121
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
122
+ ph0 = await action_scope.get_puzzle_hash(wallet_0.wallet_state_manager)
123
+ async with wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
124
+ ph1 = await action_scope.get_puzzle_hash(wallet_1.wallet_state_manager)
125
+
126
+ sk0 = await wallet_node_0.wallet_state_manager.get_private_key(ph0)
127
+ sk1 = await wallet_node_1.wallet_state_manager.get_private_key(ph1)
128
+ assert sk0 == sk1
129
+
130
+ if trusted:
131
+ wallet_node_0.config["trusted_peers"] = {
132
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
133
+ }
134
+ wallet_node_1.config["trusted_peers"] = {
135
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
136
+ }
97
137
 
98
- with pytest.raises(RuntimeError):
99
- assert await did_wallet_0.get_coin() == set()
100
- assert await did_wallet_0.get_info_for_recovery() is None
138
+ else:
139
+ wallet_node_0.config["trusted_peers"] = {}
140
+ wallet_node_1.config["trusted_peers"] = {}
141
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
142
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
143
+
144
+ await full_node_api.farm_blocks_to_wallet(1, wallet_0)
145
+ await full_node_api.farm_blocks_to_wallet(1, wallet_1)
146
+
147
+ # Wallet1 sets up DIDWallet1 without any backup set
148
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
149
+ did_wallet_0: DIDWallet = await make_did_wallet(
150
+ wallet_node_0.wallet_state_manager,
151
+ wallet_0,
152
+ uint64(101),
153
+ action_scope,
154
+ use_alternate_recovery=use_alternate_recovery,
155
+ )
101
156
 
102
- await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
103
- await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1])
157
+ with pytest.raises(RuntimeError):
158
+ assert await did_wallet_0.get_coin() == set()
159
+ assert await did_wallet_0.get_info_for_recovery() is None
104
160
 
105
- await time_out_assert(15, did_wallet_0.get_confirmed_balance, 101)
106
- await time_out_assert(15, did_wallet_0.get_unconfirmed_balance, 101)
107
- await time_out_assert(15, did_wallet_0.get_pending_change_balance, 0)
161
+ await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
162
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1])
108
163
 
109
- await full_node_api.farm_blocks_to_wallet(1, wallet_0)
164
+ await time_out_assert(15, did_wallet_0.get_confirmed_balance, 101)
165
+ await time_out_assert(15, did_wallet_0.get_unconfirmed_balance, 101)
166
+ await time_out_assert(15, did_wallet_0.get_pending_change_balance, 0)
110
167
 
111
- #######################
112
- all_node_0_wallets = await wallet_node_0.wallet_state_manager.user_store.get_all_wallet_info_entries()
113
- all_node_1_wallets = await wallet_node_1.wallet_state_manager.user_store.get_all_wallet_info_entries()
114
- assert (
115
- json.loads(all_node_0_wallets[1].data)["current_inner"]
116
- == json.loads(all_node_1_wallets[1].data)["current_inner"]
117
- )
168
+ await full_node_api.farm_blocks_to_wallet(1, wallet_0)
118
169
 
119
- @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
120
- @pytest.mark.parametrize(
121
- "wallet_environments",
122
- [
123
- {
124
- "num_environments": 3,
125
- "blocks_needed": [1, 1, 1],
126
- }
127
- ],
128
- indirect=True,
170
+ #######################
171
+ all_node_0_wallets = await wallet_node_0.wallet_state_manager.user_store.get_all_wallet_info_entries()
172
+ all_node_1_wallets = await wallet_node_1.wallet_state_manager.user_store.get_all_wallet_info_entries()
173
+ assert (
174
+ json.loads(all_node_0_wallets[1].data)["current_inner"]
175
+ == json.loads(all_node_1_wallets[1].data)["current_inner"]
129
176
  )
130
- @pytest.mark.anyio
131
- @pytest.mark.limit_consensus_modes(reason="irrelevant")
132
- async def test_creation_from_backup_file(self, wallet_environments: WalletTestFramework) -> None:
133
- env_0 = wallet_environments.environments[0]
134
- env_1 = wallet_environments.environments[1]
135
- env_2 = wallet_environments.environments[2]
136
-
137
- env_0.wallet_aliases = {
138
- "xch": 1,
139
- "did": 2,
140
- }
141
- env_1.wallet_aliases = {
142
- "xch": 1,
143
- "did": 2,
144
- }
145
- env_2.wallet_aliases = {
146
- "xch": 1,
147
- "did": 2,
148
- }
149
177
 
150
- # Wallet1 sets up DIDWallet1 without any backup set
151
- async with env_0.wallet_state_manager.new_action_scope(
152
- wallet_environments.tx_config, push=True
153
- ) as action_scope:
154
- did_wallet_0: DIDWallet = await DIDWallet.create_new_did_wallet(
155
- env_0.wallet_state_manager, env_0.xch_wallet, uint64(101), action_scope
156
- )
157
178
 
158
- await wallet_environments.process_pending_states(
159
- [
160
- WalletStateTransition(
161
- pre_block_balance_updates={
162
- "xch": {
163
- "unconfirmed_wallet_balance": -101,
164
- "<=#spendable_balance": -101,
165
- "<=#max_send_amount": -101,
166
- ">=#pending_change": 1,
167
- "pending_coin_removal_count": 1,
168
- },
169
- "did": {
170
- "init": True,
171
- "unconfirmed_wallet_balance": 101,
172
- "pending_change": 101,
173
- "pending_coin_removal_count": 1,
174
- },
175
- },
176
- post_block_balance_updates={
177
- "xch": {
178
- "confirmed_wallet_balance": -101,
179
- ">=#spendable_balance": 1,
180
- ">=#max_send_amount": 1,
181
- "<=#pending_change": -1,
182
- "pending_coin_removal_count": -1,
183
- },
184
- "did": {
185
- "confirmed_wallet_balance": 101,
186
- "spendable_balance": 101,
187
- "max_send_amount": 101,
188
- "unspent_coin_count": 1,
189
- "pending_change": -101,
190
- "pending_coin_removal_count": -1,
191
- },
192
- },
193
- ),
194
- WalletStateTransition(
195
- pre_block_balance_updates={},
196
- post_block_balance_updates={},
197
- ),
198
- WalletStateTransition(
199
- pre_block_balance_updates={},
200
- post_block_balance_updates={},
201
- ),
202
- ]
179
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
180
+ @pytest.mark.parametrize(
181
+ "wallet_environments",
182
+ [
183
+ {
184
+ "num_environments": 3,
185
+ "blocks_needed": [1, 1, 1],
186
+ }
187
+ ],
188
+ indirect=True,
189
+ )
190
+ @pytest.mark.parametrize(
191
+ "use_alternate_recovery",
192
+ [True, False],
193
+ )
194
+ @pytest.mark.anyio
195
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
196
+ async def test_creation_from_backup_file(
197
+ wallet_environments: WalletTestFramework, use_alternate_recovery: bool
198
+ ) -> None:
199
+ env_0 = wallet_environments.environments[0]
200
+ env_1 = wallet_environments.environments[1]
201
+ env_2 = wallet_environments.environments[2]
202
+
203
+ env_0.wallet_aliases = {
204
+ "xch": 1,
205
+ "did": 2,
206
+ }
207
+ env_1.wallet_aliases = {
208
+ "xch": 1,
209
+ "did": 2,
210
+ }
211
+ env_2.wallet_aliases = {
212
+ "xch": 1,
213
+ "did": 2,
214
+ }
215
+
216
+ # Wallet1 sets up DIDWallet1 without any backup set
217
+ async with env_0.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
218
+ did_wallet_0: DIDWallet = await make_did_wallet(
219
+ env_0.wallet_state_manager,
220
+ env_0.xch_wallet,
221
+ uint64(101),
222
+ action_scope,
223
+ use_alternate_recovery=use_alternate_recovery,
203
224
  )
204
225
 
205
- # Wallet1 sets up DIDWallet_1 with DIDWallet_0 as backup
206
- backup_ids = [bytes32.from_hexstr(did_wallet_0.get_my_DID())]
207
-
208
- async with env_1.wallet_state_manager.new_action_scope(
209
- wallet_environments.tx_config, push=True
210
- ) as action_scope:
211
- did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
212
- env_1.wallet_state_manager, env_1.xch_wallet, uint64(201), action_scope, backup_ids
213
- )
214
-
215
- await wallet_environments.process_pending_states(
216
- [
217
- WalletStateTransition(
218
- pre_block_balance_updates={},
219
- post_block_balance_updates={},
220
- ),
221
- WalletStateTransition(
222
- pre_block_balance_updates={
223
- "xch": {
224
- "unconfirmed_wallet_balance": -201,
225
- "<=#spendable_balance": -201,
226
- "<=#max_send_amount": -201,
227
- ">=#pending_change": 1,
228
- "pending_coin_removal_count": 1,
229
- },
230
- "did": {
231
- "init": True,
232
- "unconfirmed_wallet_balance": 201,
233
- "pending_change": 201,
234
- "pending_coin_removal_count": 1,
235
- },
226
+ await wallet_environments.process_pending_states(
227
+ [
228
+ WalletStateTransition(
229
+ pre_block_balance_updates={
230
+ "xch": {
231
+ "unconfirmed_wallet_balance": -101,
232
+ "<=#spendable_balance": -101,
233
+ "<=#max_send_amount": -101,
234
+ ">=#pending_change": 1,
235
+ "pending_coin_removal_count": 1,
236
+ },
237
+ "did": {
238
+ "init": True,
239
+ "unconfirmed_wallet_balance": 101,
240
+ "pending_change": 101,
241
+ "pending_coin_removal_count": 1,
236
242
  },
237
- post_block_balance_updates={
238
- "xch": {
239
- "confirmed_wallet_balance": -201,
240
- ">=#spendable_balance": 1,
241
- ">=#max_send_amount": 1,
242
- "<=#pending_change": -1,
243
- "pending_coin_removal_count": -1,
244
- },
245
- "did": {
246
- "confirmed_wallet_balance": 201,
247
- "spendable_balance": 201,
248
- "max_send_amount": 201,
249
- "unspent_coin_count": 1,
250
- "pending_change": -201,
251
- "pending_coin_removal_count": -1,
252
- },
243
+ },
244
+ post_block_balance_updates={
245
+ "xch": {
246
+ "confirmed_wallet_balance": -101,
247
+ ">=#spendable_balance": 1,
248
+ ">=#max_send_amount": 1,
249
+ "<=#pending_change": -1,
250
+ "pending_coin_removal_count": -1,
251
+ },
252
+ "did": {
253
+ "confirmed_wallet_balance": 101,
254
+ "spendable_balance": 101,
255
+ "max_send_amount": 101,
256
+ "unspent_coin_count": 1,
257
+ "pending_change": -101,
258
+ "pending_coin_removal_count": -1,
253
259
  },
254
- ),
255
- WalletStateTransition(
256
- pre_block_balance_updates={},
257
- post_block_balance_updates={},
258
- ),
259
- ]
260
- )
260
+ },
261
+ ),
262
+ WalletStateTransition(
263
+ pre_block_balance_updates={},
264
+ post_block_balance_updates={},
265
+ ),
266
+ WalletStateTransition(
267
+ pre_block_balance_updates={},
268
+ post_block_balance_updates={},
269
+ ),
270
+ ]
271
+ )
261
272
 
262
- backup_data = did_wallet_1.create_backup()
273
+ # Wallet1 sets up DIDWallet_1 with DIDWallet_0 as backup
274
+ backup_ids = [bytes32.from_hexstr(did_wallet_0.get_my_DID())]
263
275
 
264
- # Wallet2 recovers DIDWallet2 to a new set of keys
265
- await env_2.rpc_client.create_new_did_wallet(
266
- uint64(1),
267
- DEFAULT_TX_CONFIG,
268
- type="recovery",
269
- backup_data=backup_data,
276
+ async with env_1.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
277
+ did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
278
+ env_1.wallet_state_manager, env_1.xch_wallet, uint64(201), action_scope, backup_ids
270
279
  )
271
- did_wallet_2 = env_2.wallet_state_manager.get_wallet(id=uint32(2), required_type=DIDWallet)
272
- recovery_info = await env_2.rpc_client.did_get_recovery_info(
273
- DIDGetRecoveryInfo(uint32(env_2.wallet_aliases["did"]))
274
- )
275
- assert recovery_info.wallet_id == env_2.wallet_aliases["did"]
276
- assert recovery_info.backup_dids == backup_ids
277
- current_coin_info_response = await env_0.rpc_client.did_get_current_coin_info(
278
- DIDGetCurrentCoinInfo(uint32(env_0.wallet_aliases["did"]))
279
- )
280
- # TODO: this check is kind of weak, we should research when this endpoint might actually be useful
281
- assert current_coin_info_response.wallet_id == env_0.wallet_aliases["did"]
282
- async with env_0.wallet_state_manager.new_action_scope(
283
- wallet_environments.tx_config, push=True
284
- ) as action_scope:
285
- message_spend_bundle, attest_data = await did_wallet_0.create_attestment(
286
- recovery_info.coin_name, recovery_info.newpuzhash, recovery_info.pubkey, action_scope
287
- )
288
280
 
289
- await wallet_environments.process_pending_states(
290
- [
291
- WalletStateTransition(
292
- pre_block_balance_updates={
293
- "did": {
294
- "spendable_balance": -101,
295
- "pending_change": 101,
296
- "pending_coin_removal_count": 1,
297
- "max_send_amount": -101,
298
- }
299
- },
300
- post_block_balance_updates={
301
- "did": {
302
- "spendable_balance": 101,
303
- "pending_change": -101,
304
- "pending_coin_removal_count": -1,
305
- "max_send_amount": 101,
306
- }
281
+ await wallet_environments.process_pending_states(
282
+ [
283
+ WalletStateTransition(
284
+ pre_block_balance_updates={},
285
+ post_block_balance_updates={},
286
+ ),
287
+ WalletStateTransition(
288
+ pre_block_balance_updates={
289
+ "xch": {
290
+ "unconfirmed_wallet_balance": -201,
291
+ "<=#spendable_balance": -201,
292
+ "<=#max_send_amount": -201,
293
+ ">=#pending_change": 1,
294
+ "pending_coin_removal_count": 1,
295
+ },
296
+ "did": {
297
+ "init": True,
298
+ "unconfirmed_wallet_balance": 201,
299
+ "pending_change": 201,
300
+ "pending_coin_removal_count": 1,
307
301
  },
308
- ),
309
- WalletStateTransition(
310
- pre_block_balance_updates={},
311
- post_block_balance_updates={},
312
- ),
313
- WalletStateTransition(
314
- pre_block_balance_updates={
315
- "did": {
316
- "init": True,
317
- }
302
+ },
303
+ post_block_balance_updates={
304
+ "xch": {
305
+ "confirmed_wallet_balance": -201,
306
+ ">=#spendable_balance": 1,
307
+ ">=#max_send_amount": 1,
308
+ "<=#pending_change": -1,
309
+ "pending_coin_removal_count": -1,
310
+ },
311
+ "did": {
312
+ "confirmed_wallet_balance": 201,
313
+ "spendable_balance": 201,
314
+ "max_send_amount": 201,
315
+ "unspent_coin_count": 1,
316
+ "pending_change": -201,
317
+ "pending_coin_removal_count": -1,
318
318
  },
319
- post_block_balance_updates={},
320
- ),
321
- ]
319
+ },
320
+ ),
321
+ WalletStateTransition(
322
+ pre_block_balance_updates={},
323
+ post_block_balance_updates={},
324
+ ),
325
+ ]
326
+ )
327
+
328
+ backup_data = did_wallet_1.create_backup()
329
+
330
+ # Wallet2 recovers DIDWallet2 to a new set of keys
331
+ await env_2.rpc_client.create_new_did_wallet(
332
+ uint64(1),
333
+ DEFAULT_TX_CONFIG,
334
+ type="recovery",
335
+ backup_data=backup_data,
336
+ )
337
+ did_wallet_2 = env_2.wallet_state_manager.get_wallet(id=uint32(2), required_type=DIDWallet)
338
+ recovery_info = await env_2.rpc_client.did_get_recovery_info(
339
+ DIDGetRecoveryInfo(uint32(env_2.wallet_aliases["did"]))
340
+ )
341
+ assert recovery_info.wallet_id == env_2.wallet_aliases["did"]
342
+ assert recovery_info.backup_dids == backup_ids
343
+ current_coin_info_response = await env_0.rpc_client.did_get_current_coin_info(
344
+ DIDGetCurrentCoinInfo(uint32(env_0.wallet_aliases["did"]))
345
+ )
346
+ # TODO: this check is kind of weak, we should research when this endpoint might actually be useful
347
+ assert current_coin_info_response.wallet_id == env_0.wallet_aliases["did"]
348
+ async with env_0.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
349
+ assert recovery_info.pubkey is not None
350
+ assert recovery_info.newpuzhash is not None
351
+ message_spend_bundle, attest_data = await did_wallet_0.create_attestment(
352
+ recovery_info.coin_name, recovery_info.newpuzhash, recovery_info.pubkey, action_scope
322
353
  )
323
354
 
324
- (
355
+ await wallet_environments.process_pending_states(
356
+ [
357
+ WalletStateTransition(
358
+ pre_block_balance_updates={
359
+ "did": {
360
+ "spendable_balance": -101,
361
+ "pending_change": 101,
362
+ "pending_coin_removal_count": 1,
363
+ "max_send_amount": -101,
364
+ }
365
+ },
366
+ post_block_balance_updates={
367
+ "did": {
368
+ "spendable_balance": 101,
369
+ "pending_change": -101,
370
+ "pending_coin_removal_count": -1,
371
+ "max_send_amount": 101,
372
+ }
373
+ },
374
+ ),
375
+ WalletStateTransition(
376
+ pre_block_balance_updates={},
377
+ post_block_balance_updates={},
378
+ ),
379
+ WalletStateTransition(
380
+ pre_block_balance_updates={
381
+ "did": {
382
+ "init": True,
383
+ }
384
+ },
385
+ post_block_balance_updates={},
386
+ ),
387
+ ]
388
+ )
389
+
390
+ (
391
+ test_info_list,
392
+ test_message_spend_bundle,
393
+ ) = await did_wallet_2.load_attest_files_for_recovery_spend([attest_data])
394
+ assert message_spend_bundle == test_message_spend_bundle
395
+
396
+ async with env_2.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
397
+ assert did_wallet_2.did_info.temp_coin is not None
398
+ await did_wallet_2.recovery_spend(
399
+ did_wallet_2.did_info.temp_coin,
400
+ recovery_info.newpuzhash,
325
401
  test_info_list,
402
+ recovery_info.pubkey,
326
403
  test_message_spend_bundle,
327
- ) = await did_wallet_2.load_attest_files_for_recovery_spend([attest_data])
328
- assert message_spend_bundle == test_message_spend_bundle
404
+ action_scope,
405
+ )
329
406
 
330
- async with env_2.wallet_state_manager.new_action_scope(
331
- wallet_environments.tx_config, push=True
332
- ) as action_scope:
333
- assert did_wallet_2.did_info.temp_coin is not None
334
- await did_wallet_2.recovery_spend(
335
- did_wallet_2.did_info.temp_coin,
336
- recovery_info.newpuzhash,
337
- test_info_list,
338
- recovery_info.pubkey,
339
- test_message_spend_bundle,
340
- action_scope,
341
- )
407
+ await wallet_environments.process_pending_states(
408
+ [
409
+ WalletStateTransition(
410
+ pre_block_balance_updates={},
411
+ post_block_balance_updates={},
412
+ ),
413
+ WalletStateTransition(
414
+ pre_block_balance_updates={},
415
+ post_block_balance_updates={
416
+ "did": {
417
+ "confirmed_wallet_balance": -201,
418
+ "unconfirmed_wallet_balance": -201,
419
+ "spendable_balance": -201,
420
+ "max_send_amount": -201,
421
+ "unspent_coin_count": -1,
422
+ }
423
+ },
424
+ ),
425
+ WalletStateTransition(
426
+ pre_block_balance_updates={
427
+ "did": {
428
+ "unconfirmed_wallet_balance": 201,
429
+ "pending_coin_removal_count": 2,
430
+ }
431
+ },
432
+ post_block_balance_updates={
433
+ "did": {
434
+ "confirmed_wallet_balance": 201,
435
+ "spendable_balance": 201,
436
+ "max_send_amount": 201,
437
+ "unspent_coin_count": 1,
438
+ "pending_coin_removal_count": -2,
439
+ }
440
+ },
441
+ ),
442
+ ]
443
+ )
342
444
 
343
- await wallet_environments.process_pending_states(
344
- [
345
- WalletStateTransition(
346
- pre_block_balance_updates={},
347
- post_block_balance_updates={},
348
- ),
349
- WalletStateTransition(
350
- pre_block_balance_updates={},
351
- post_block_balance_updates={
352
- "did": {
353
- "confirmed_wallet_balance": -201,
354
- "unconfirmed_wallet_balance": -201,
355
- "spendable_balance": -201,
356
- "max_send_amount": -201,
357
- "unspent_coin_count": -1,
358
- }
359
- },
360
- ),
361
- WalletStateTransition(
362
- pre_block_balance_updates={
363
- "did": {
364
- "unconfirmed_wallet_balance": 201,
365
- "pending_coin_removal_count": 2,
366
- }
367
- },
368
- post_block_balance_updates={
369
- "did": {
370
- "confirmed_wallet_balance": 201,
371
- "spendable_balance": 201,
372
- "max_send_amount": 201,
373
- "unspent_coin_count": 1,
374
- "pending_coin_removal_count": -2,
375
- }
376
- },
377
- ),
378
- ]
379
- )
445
+ for wallet in [did_wallet_0, did_wallet_1, did_wallet_2]:
446
+ assert wallet.wallet_state_manager.wallets[wallet.id()] == wallet
380
447
 
381
- for wallet in [did_wallet_0, did_wallet_1, did_wallet_2]:
382
- assert wallet.wallet_state_manager.wallets[wallet.id()] == wallet
448
+ some_ph = bytes32(32 * b"\2")
449
+ async with env_2.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
450
+ await did_wallet_2.create_exit_spend(some_ph, action_scope)
383
451
 
384
- some_ph = bytes32(32 * b"\2")
385
- async with env_2.wallet_state_manager.new_action_scope(
386
- wallet_environments.tx_config, push=True
387
- ) as action_scope:
388
- await did_wallet_2.create_exit_spend(some_ph, action_scope)
452
+ await wallet_environments.process_pending_states(
453
+ [
454
+ WalletStateTransition(
455
+ pre_block_balance_updates={},
456
+ post_block_balance_updates={},
457
+ ),
458
+ WalletStateTransition(
459
+ pre_block_balance_updates={},
460
+ post_block_balance_updates={},
461
+ ),
462
+ WalletStateTransition(
463
+ pre_block_balance_updates={
464
+ "did": {
465
+ "unconfirmed_wallet_balance": -201,
466
+ "spendable_balance": -201,
467
+ "max_send_amount": -201,
468
+ "pending_coin_removal_count": 1,
469
+ }
470
+ },
471
+ post_block_balance_updates={
472
+ "did": {
473
+ "confirmed_wallet_balance": -201,
474
+ "unspent_coin_count": -1,
475
+ "pending_coin_removal_count": -1,
476
+ }
477
+ },
478
+ ),
479
+ ]
480
+ )
389
481
 
390
- await wallet_environments.process_pending_states(
391
- [
392
- WalletStateTransition(
393
- pre_block_balance_updates={},
394
- post_block_balance_updates={},
395
- ),
396
- WalletStateTransition(
397
- pre_block_balance_updates={},
398
- post_block_balance_updates={},
399
- ),
400
- WalletStateTransition(
401
- pre_block_balance_updates={
402
- "did": {
403
- "unconfirmed_wallet_balance": -201,
404
- "spendable_balance": -201,
405
- "max_send_amount": -201,
406
- "pending_coin_removal_count": 1,
407
- }
408
- },
409
- post_block_balance_updates={
410
- "did": {
411
- "confirmed_wallet_balance": -201,
412
- "unspent_coin_count": -1,
413
- "pending_coin_removal_count": -1,
414
- }
415
- },
416
- ),
417
- ]
418
- )
482
+ async def get_coins_with_ph() -> bool:
483
+ coins = await wallet_environments.full_node.full_node.coin_store.get_coin_records_by_puzzle_hash(True, some_ph)
484
+ return len(coins) == 1
419
485
 
420
- async def get_coins_with_ph() -> bool:
421
- coins = await wallet_environments.full_node.full_node.coin_store.get_coin_records_by_puzzle_hash(
422
- True, some_ph
423
- )
424
- return len(coins) == 1
425
-
426
- await time_out_assert(15, get_coins_with_ph, True)
427
-
428
- for wallet in [did_wallet_0, did_wallet_1]:
429
- assert wallet.wallet_state_manager.wallets[wallet.id()] == wallet
430
-
431
- @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
432
- @pytest.mark.parametrize("wallet_environments", [{"num_environments": 2, "blocks_needed": [1, 1]}], indirect=True)
433
- @pytest.mark.anyio
434
- async def test_did_recovery_with_multiple_backup_dids(self, wallet_environments: WalletTestFramework):
435
- env_0 = wallet_environments.environments[0]
436
- env_1 = wallet_environments.environments[1]
437
- wallet_node_0 = env_0.node
438
- wallet_node_1 = env_1.node
439
- wallet_0 = env_0.xch_wallet
440
- wallet_1 = env_1.xch_wallet
441
-
442
- env_0.wallet_aliases = {
443
- "xch": 1,
444
- "did": 2,
445
- }
446
- env_1.wallet_aliases = {
447
- "xch": 1,
448
- "did": 2,
449
- }
486
+ await time_out_assert(15, get_coins_with_ph, True)
450
487
 
451
- async with wallet_0.wallet_state_manager.new_action_scope(
452
- wallet_environments.tx_config, push=True
453
- ) as action_scope:
454
- did_wallet: DIDWallet = await DIDWallet.create_new_did_wallet(
455
- wallet_node_0.wallet_state_manager, wallet_0, uint64(101), action_scope
456
- )
457
- assert did_wallet.get_name() == "Profile 1"
458
- recovery_list = [bytes32.from_hexstr(did_wallet.get_my_DID())]
488
+ for wallet in [did_wallet_0, did_wallet_1]:
489
+ assert wallet.wallet_state_manager.wallets[wallet.id()] == wallet
459
490
 
460
- async with wallet_1.wallet_state_manager.new_action_scope(
461
- wallet_environments.tx_config, push=True
462
- ) as action_scope:
463
- did_wallet_2: DIDWallet = await DIDWallet.create_new_did_wallet(
464
- wallet_node_1.wallet_state_manager, wallet_1, uint64(101), action_scope, recovery_list
465
- )
466
491
 
467
- await wallet_environments.process_pending_states(
468
- [
469
- WalletStateTransition(
470
- pre_block_balance_updates={
471
- "xch": {
472
- "set_remainder": True,
473
- },
474
- "did": {
475
- "init": True,
476
- "unconfirmed_wallet_balance": 101,
477
- "pending_change": 101,
478
- "pending_coin_removal_count": 1,
479
- },
492
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
493
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 2, "blocks_needed": [1, 1]}], indirect=True)
494
+ @pytest.mark.parametrize(
495
+ "use_alternate_recovery",
496
+ [True, False],
497
+ )
498
+ @pytest.mark.anyio
499
+ async def test_did_recovery_with_multiple_backup_dids(
500
+ wallet_environments: WalletTestFramework, use_alternate_recovery: bool
501
+ ) -> None:
502
+ env_0 = wallet_environments.environments[0]
503
+ env_1 = wallet_environments.environments[1]
504
+ wallet_node_0 = env_0.node
505
+ wallet_node_1 = env_1.node
506
+ wallet_0 = env_0.xch_wallet
507
+ wallet_1 = env_1.xch_wallet
508
+
509
+ env_0.wallet_aliases = {
510
+ "xch": 1,
511
+ "did": 2,
512
+ }
513
+ env_1.wallet_aliases = {
514
+ "xch": 1,
515
+ "did": 2,
516
+ }
517
+
518
+ async with wallet_0.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
519
+ did_wallet: DIDWallet = await make_did_wallet(
520
+ wallet_node_0.wallet_state_manager,
521
+ wallet_0,
522
+ uint64(101),
523
+ action_scope,
524
+ use_alternate_recovery=use_alternate_recovery,
525
+ )
526
+ assert did_wallet.get_name() == "Profile 1"
527
+ recovery_list = [bytes32.from_hexstr(did_wallet.get_my_DID())]
528
+
529
+ async with wallet_1.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
530
+ did_wallet_2: DIDWallet = await DIDWallet.create_new_did_wallet(
531
+ wallet_node_1.wallet_state_manager, wallet_1, uint64(101), action_scope, recovery_list
532
+ )
533
+
534
+ await wallet_environments.process_pending_states(
535
+ [
536
+ WalletStateTransition(
537
+ pre_block_balance_updates={
538
+ "xch": {
539
+ "set_remainder": True,
480
540
  },
481
- post_block_balance_updates={
482
- "xch": {
483
- "set_remainder": True,
484
- },
485
- "did": {
486
- "confirmed_wallet_balance": 101,
487
- "spendable_balance": 101,
488
- "max_send_amount": 101,
489
- "unspent_coin_count": 1,
490
- "pending_change": -101,
491
- "pending_coin_removal_count": -1,
492
- },
541
+ "did": {
542
+ "init": True,
543
+ "unconfirmed_wallet_balance": 101,
544
+ "pending_change": 101,
545
+ "pending_coin_removal_count": 1,
493
546
  },
494
- ),
495
- WalletStateTransition(
496
- pre_block_balance_updates={
497
- "xch": {
498
- "set_remainder": True,
499
- },
500
- "did": {
501
- "init": True,
502
- "unconfirmed_wallet_balance": 101,
503
- "pending_change": 101,
504
- "pending_coin_removal_count": 1,
505
- },
547
+ },
548
+ post_block_balance_updates={
549
+ "xch": {
550
+ "set_remainder": True,
506
551
  },
507
- post_block_balance_updates={
508
- "xch": {
509
- "set_remainder": True,
510
- },
511
- "did": {
512
- "confirmed_wallet_balance": 101,
513
- "spendable_balance": 101,
514
- "max_send_amount": 101,
515
- "unspent_coin_count": 1,
516
- "pending_change": -101,
517
- "pending_coin_removal_count": -1,
518
- },
552
+ "did": {
553
+ "confirmed_wallet_balance": 101,
554
+ "spendable_balance": 101,
555
+ "max_send_amount": 101,
556
+ "unspent_coin_count": 1,
557
+ "pending_change": -101,
558
+ "pending_coin_removal_count": -1,
519
559
  },
520
- ),
521
- ]
560
+ },
561
+ ),
562
+ WalletStateTransition(
563
+ pre_block_balance_updates={
564
+ "xch": {
565
+ "set_remainder": True,
566
+ },
567
+ "did": {
568
+ "init": True,
569
+ "unconfirmed_wallet_balance": 101,
570
+ "pending_change": 101,
571
+ "pending_coin_removal_count": 1,
572
+ },
573
+ },
574
+ post_block_balance_updates={
575
+ "xch": {
576
+ "set_remainder": True,
577
+ },
578
+ "did": {
579
+ "confirmed_wallet_balance": 101,
580
+ "spendable_balance": 101,
581
+ "max_send_amount": 101,
582
+ "unspent_coin_count": 1,
583
+ "pending_change": -101,
584
+ "pending_coin_removal_count": -1,
585
+ },
586
+ },
587
+ ),
588
+ ]
589
+ )
590
+ assert did_wallet_2.did_info.backup_ids == recovery_list
591
+
592
+ recovery_list.append(bytes32.from_hexstr(did_wallet_2.get_my_DID()))
593
+
594
+ async with wallet_1.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
595
+ did_wallet_3: DIDWallet = await DIDWallet.create_new_did_wallet(
596
+ wallet_node_1.wallet_state_manager, wallet_1, uint64(201), action_scope, recovery_list
522
597
  )
523
- assert did_wallet_2.did_info.backup_ids == recovery_list
524
598
 
525
- recovery_list.append(bytes32.from_hexstr(did_wallet_2.get_my_DID()))
599
+ env_1.wallet_aliases["did_2"] = 3
526
600
 
527
- async with wallet_1.wallet_state_manager.new_action_scope(
528
- wallet_environments.tx_config, push=True
529
- ) as action_scope:
530
- did_wallet_3: DIDWallet = await DIDWallet.create_new_did_wallet(
531
- wallet_node_1.wallet_state_manager, wallet_1, uint64(201), action_scope, recovery_list
532
- )
533
-
534
- env_1.wallet_aliases["did_2"] = 3
535
-
536
- await wallet_environments.process_pending_states(
537
- [
538
- WalletStateTransition(
539
- pre_block_balance_updates={},
540
- post_block_balance_updates={},
541
- ),
542
- WalletStateTransition(
543
- pre_block_balance_updates={
544
- "xch": {
545
- "set_remainder": True,
546
- },
547
- "did": {
548
- "set_remainder": True,
549
- },
550
- "did_2": {
551
- "init": True,
552
- "unconfirmed_wallet_balance": 201,
553
- "pending_change": 201,
554
- "pending_coin_removal_count": 1,
555
- },
601
+ await wallet_environments.process_pending_states(
602
+ [
603
+ WalletStateTransition(
604
+ pre_block_balance_updates={},
605
+ post_block_balance_updates={},
606
+ ),
607
+ WalletStateTransition(
608
+ pre_block_balance_updates={
609
+ "xch": {
610
+ "set_remainder": True,
556
611
  },
557
- post_block_balance_updates={
558
- "xch": {
559
- "set_remainder": True,
560
- },
561
- "did": {
562
- "set_remainder": True,
563
- },
564
- "did_2": {
565
- "confirmed_wallet_balance": 201,
566
- "spendable_balance": 201,
567
- "max_send_amount": 201,
568
- "unspent_coin_count": 1,
569
- "pending_change": -201,
570
- "pending_coin_removal_count": -1,
571
- },
612
+ "did": {
613
+ "set_remainder": True,
572
614
  },
573
- ),
574
- ]
575
- )
576
- coin = await did_wallet_3.get_coin()
577
-
578
- backup_data = did_wallet_3.create_backup()
615
+ "did_2": {
616
+ "init": True,
617
+ "unconfirmed_wallet_balance": 201,
618
+ "pending_change": 201,
619
+ "pending_coin_removal_count": 1,
620
+ },
621
+ },
622
+ post_block_balance_updates={
623
+ "xch": {
624
+ "set_remainder": True,
625
+ },
626
+ "did": {
627
+ "set_remainder": True,
628
+ },
629
+ "did_2": {
630
+ "confirmed_wallet_balance": 201,
631
+ "spendable_balance": 201,
632
+ "max_send_amount": 201,
633
+ "unspent_coin_count": 1,
634
+ "pending_change": -201,
635
+ "pending_coin_removal_count": -1,
636
+ },
637
+ },
638
+ ),
639
+ ]
640
+ )
641
+ coin = await did_wallet_3.get_coin()
579
642
 
580
- async with wallet_node_0.wallet_state_manager.lock:
581
- did_wallet_4 = await DIDWallet.create_new_did_wallet_from_recovery(
582
- wallet_node_0.wallet_state_manager,
583
- wallet_0,
584
- backup_data,
585
- )
586
- assert did_wallet_4.get_name() == "Profile 2"
587
- env_0.wallet_aliases["did_2"] = 3
643
+ backup_data = did_wallet_3.create_backup()
588
644
 
589
- pubkey = (
590
- await did_wallet_4.wallet_state_manager.get_unused_derivation_record(did_wallet_2.wallet_info.id)
591
- ).pubkey
592
- new_ph = did_wallet_4.did_info.temp_puzhash
593
- async with did_wallet.wallet_state_manager.new_action_scope(
594
- wallet_environments.tx_config, push=True
595
- ) as action_scope:
596
- message_spend_bundle, attest1 = await did_wallet.create_attestment(
597
- coin.name(), new_ph, pubkey, action_scope
598
- )
645
+ async with wallet_node_0.wallet_state_manager.lock:
646
+ did_wallet_4 = await DIDWallet.create_new_did_wallet_from_recovery(
647
+ wallet_node_0.wallet_state_manager,
648
+ wallet_0,
649
+ backup_data,
650
+ )
651
+ assert did_wallet_4.get_name() == "Profile 2"
652
+ env_0.wallet_aliases["did_2"] = 3
653
+
654
+ pubkey = (await did_wallet_4.wallet_state_manager.get_unused_derivation_record(did_wallet_2.wallet_info.id)).pubkey
655
+ new_ph = did_wallet_4.did_info.temp_puzhash
656
+ async with did_wallet.wallet_state_manager.new_action_scope(
657
+ wallet_environments.tx_config, push=True
658
+ ) as action_scope:
659
+ message_spend_bundle, attest1 = await did_wallet.create_attestment(coin.name(), new_ph, pubkey, action_scope)
660
+
661
+ async with did_wallet_2.wallet_state_manager.new_action_scope(
662
+ wallet_environments.tx_config, push=True
663
+ ) as action_scope_2:
664
+ message_spend_bundle2, attest2 = await did_wallet_2.create_attestment(
665
+ coin.name(), new_ph, pubkey, action_scope_2
666
+ )
599
667
 
600
- async with did_wallet_2.wallet_state_manager.new_action_scope(
601
- wallet_environments.tx_config, push=True
602
- ) as action_scope_2:
603
- message_spend_bundle2, attest2 = await did_wallet_2.create_attestment(
604
- coin.name(), new_ph, pubkey, action_scope_2
605
- )
668
+ message_spend_bundle = message_spend_bundle.aggregate([message_spend_bundle, message_spend_bundle2])
606
669
 
607
- message_spend_bundle = message_spend_bundle.aggregate([message_spend_bundle, message_spend_bundle2])
670
+ (
671
+ test_info_list,
672
+ test_message_spend_bundle,
673
+ ) = await did_wallet_4.load_attest_files_for_recovery_spend([attest1, attest2])
674
+ assert message_spend_bundle == test_message_spend_bundle
608
675
 
609
- (
610
- test_info_list,
611
- test_message_spend_bundle,
612
- ) = await did_wallet_4.load_attest_files_for_recovery_spend([attest1, attest2])
613
- assert message_spend_bundle == test_message_spend_bundle
614
-
615
- await wallet_environments.process_pending_states(
616
- [
617
- WalletStateTransition(
618
- pre_block_balance_updates={
619
- "did": {
620
- "spendable_balance": -101,
621
- "pending_change": 101,
622
- "max_send_amount": -101,
623
- "pending_coin_removal_count": 1,
624
- "set_remainder": True,
625
- },
626
- "did_2": {
627
- "init": True,
628
- "unconfirmed_wallet_balance": 0,
629
- "pending_change": 0,
630
- "pending_coin_removal_count": 0,
631
- },
676
+ await wallet_environments.process_pending_states(
677
+ [
678
+ WalletStateTransition(
679
+ pre_block_balance_updates={
680
+ "did": {
681
+ "spendable_balance": -101,
682
+ "pending_change": 101,
683
+ "max_send_amount": -101,
684
+ "pending_coin_removal_count": 1,
685
+ "set_remainder": True,
686
+ },
687
+ "did_2": {
688
+ "init": True,
689
+ "unconfirmed_wallet_balance": 0,
690
+ "pending_change": 0,
691
+ "pending_coin_removal_count": 0,
632
692
  },
633
- post_block_balance_updates={
634
- "did": {
635
- "spendable_balance": 101,
636
- "pending_change": -101,
637
- "max_send_amount": 101,
638
- "pending_coin_removal_count": -1,
639
- },
640
- "did_2": {
641
- "confirmed_wallet_balance": 0,
642
- "spendable_balance": 0,
643
- "max_send_amount": 0,
644
- "unspent_coin_count": 0,
645
- "pending_change": 0,
646
- "pending_coin_removal_count": 0,
647
- },
693
+ },
694
+ post_block_balance_updates={
695
+ "did": {
696
+ "spendable_balance": 101,
697
+ "pending_change": -101,
698
+ "max_send_amount": 101,
699
+ "pending_coin_removal_count": -1,
700
+ },
701
+ "did_2": {
702
+ "confirmed_wallet_balance": 0,
703
+ "spendable_balance": 0,
704
+ "max_send_amount": 0,
705
+ "unspent_coin_count": 0,
706
+ "pending_change": 0,
707
+ "pending_coin_removal_count": 0,
648
708
  },
649
- ),
650
- WalletStateTransition(
651
- pre_block_balance_updates={
652
- "did": {
653
- "spendable_balance": -101,
654
- "pending_change": 101,
655
- "max_send_amount": -101,
656
- "pending_coin_removal_count": 1,
657
- "set_remainder": True,
658
- },
709
+ },
710
+ ),
711
+ WalletStateTransition(
712
+ pre_block_balance_updates={
713
+ "did": {
714
+ "spendable_balance": -101,
715
+ "pending_change": 101,
716
+ "max_send_amount": -101,
717
+ "pending_coin_removal_count": 1,
718
+ "set_remainder": True,
659
719
  },
660
- post_block_balance_updates={
661
- "did": {
662
- "spendable_balance": 101,
663
- "pending_change": -101,
664
- "max_send_amount": 101,
665
- "pending_coin_removal_count": -1,
666
- },
720
+ },
721
+ post_block_balance_updates={
722
+ "did": {
723
+ "spendable_balance": 101,
724
+ "pending_change": -101,
725
+ "max_send_amount": 101,
726
+ "pending_coin_removal_count": -1,
667
727
  },
668
- ),
669
- ]
670
- )
728
+ },
729
+ ),
730
+ ]
731
+ )
671
732
 
672
- async with did_wallet_4.wallet_state_manager.new_action_scope(
673
- wallet_environments.tx_config, push=True
674
- ) as action_scope:
675
- await did_wallet_4.recovery_spend(coin, new_ph, test_info_list, pubkey, message_spend_bundle, action_scope)
733
+ async with did_wallet_4.wallet_state_manager.new_action_scope(
734
+ wallet_environments.tx_config, push=True
735
+ ) as action_scope:
736
+ await did_wallet_4.recovery_spend(coin, new_ph, test_info_list, pubkey, message_spend_bundle, action_scope)
676
737
 
677
- await wallet_environments.process_pending_states(
678
- [
679
- WalletStateTransition(
680
- pre_block_balance_updates={
681
- "did_2": {
682
- "unconfirmed_wallet_balance": 201,
683
- "pending_change": 0,
684
- "pending_coin_removal_count": 3,
685
- },
738
+ await wallet_environments.process_pending_states(
739
+ [
740
+ WalletStateTransition(
741
+ pre_block_balance_updates={
742
+ "did_2": {
743
+ "unconfirmed_wallet_balance": 201,
744
+ "pending_change": 0,
745
+ "pending_coin_removal_count": 3,
686
746
  },
687
- post_block_balance_updates={
688
- "did_2": {
689
- "confirmed_wallet_balance": 201,
690
- "spendable_balance": 201,
691
- "max_send_amount": 201,
692
- "unspent_coin_count": 1,
693
- "pending_change": 0,
694
- "pending_coin_removal_count": -3,
695
- },
747
+ },
748
+ post_block_balance_updates={
749
+ "did_2": {
750
+ "confirmed_wallet_balance": 201,
751
+ "spendable_balance": 201,
752
+ "max_send_amount": 201,
753
+ "unspent_coin_count": 1,
754
+ "pending_change": 0,
755
+ "pending_coin_removal_count": -3,
696
756
  },
697
- ),
698
- WalletStateTransition(
699
- pre_block_balance_updates={
700
- "did_2": {
701
- "unconfirmed_wallet_balance": 0, # TODO: fix pre-block balances for recovery
702
- "spendable_balance": 0,
703
- "pending_change": 0,
704
- "max_send_amount": 0,
705
- "pending_coin_removal_count": 0,
706
- "set_remainder": True,
707
- },
757
+ },
758
+ ),
759
+ WalletStateTransition(
760
+ pre_block_balance_updates={
761
+ "did_2": {
762
+ "unconfirmed_wallet_balance": 0, # TODO: fix pre-block balances for recovery
763
+ "spendable_balance": 0,
764
+ "pending_change": 0,
765
+ "max_send_amount": 0,
766
+ "pending_coin_removal_count": 0,
767
+ "set_remainder": True,
708
768
  },
709
- post_block_balance_updates={
710
- "did_2": {
711
- "confirmed_wallet_balance": -201,
712
- "spendable_balance": -201,
713
- "max_send_amount": -201,
714
- "unspent_coin_count": -1,
715
- "set_remainder": True,
716
- },
769
+ },
770
+ post_block_balance_updates={
771
+ "did_2": {
772
+ "confirmed_wallet_balance": -201,
773
+ "spendable_balance": -201,
774
+ "max_send_amount": -201,
775
+ "unspent_coin_count": -1,
776
+ "set_remainder": True,
717
777
  },
718
- ),
719
- ]
720
- )
721
-
722
- for wallet in [did_wallet, did_wallet_2, did_wallet_3, did_wallet_4]:
723
- assert wallet.wallet_state_manager.wallets[wallet.id()] == wallet
724
-
725
- @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
726
- @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
727
- @pytest.mark.anyio
728
- async def test_did_recovery_with_empty_set(self, wallet_environments: WalletTestFramework):
729
- env_0 = wallet_environments.environments[0]
730
- wallet_node_0 = env_0.node
731
- wallet_0 = env_0.xch_wallet
778
+ },
779
+ ),
780
+ ]
781
+ )
732
782
 
733
- env_0.wallet_aliases = {
734
- "xch": 1,
735
- "did": 2,
736
- }
783
+ for wallet in [did_wallet, did_wallet_2, did_wallet_3, did_wallet_4]:
784
+ assert wallet.wallet_state_manager.wallets[wallet.id()] == wallet
737
785
 
738
- ph = await wallet_0.get_new_puzzlehash()
739
786
 
740
- async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
741
- did_wallet: DIDWallet = await DIDWallet.create_new_did_wallet(
742
- wallet_node_0.wallet_state_manager, wallet_0, uint64(101), action_scope
743
- )
787
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
788
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
789
+ @pytest.mark.parametrize(
790
+ "use_alternate_recovery",
791
+ [True, False],
792
+ )
793
+ @pytest.mark.anyio
794
+ async def test_did_recovery_with_empty_set(wallet_environments: WalletTestFramework, use_alternate_recovery: bool):
795
+ env_0 = wallet_environments.environments[0]
796
+ wallet_node_0 = env_0.node
797
+ wallet_0 = env_0.xch_wallet
798
+
799
+ env_0.wallet_aliases = {
800
+ "xch": 1,
801
+ "did": 2,
802
+ }
803
+
804
+ async with wallet_0.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
805
+ ph = await action_scope.get_puzzle_hash(wallet_0.wallet_state_manager)
806
+
807
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
808
+ did_wallet: DIDWallet = await make_did_wallet(
809
+ wallet_node_0.wallet_state_manager,
810
+ wallet_0,
811
+ uint64(101),
812
+ action_scope,
813
+ use_alternate_recovery=use_alternate_recovery,
814
+ )
744
815
 
745
- await wallet_environments.process_pending_states(
746
- [
747
- WalletStateTransition(
748
- pre_block_balance_updates={
749
- "xch": {
750
- "set_remainder": True,
751
- },
752
- "did": {
753
- "init": True,
754
- "unconfirmed_wallet_balance": 101,
755
- "pending_change": 101,
756
- "pending_coin_removal_count": 1,
757
- },
816
+ await wallet_environments.process_pending_states(
817
+ [
818
+ WalletStateTransition(
819
+ pre_block_balance_updates={
820
+ "xch": {
821
+ "set_remainder": True,
758
822
  },
759
- post_block_balance_updates={
760
- "xch": {
761
- "set_remainder": True,
762
- },
763
- "did": {
764
- "confirmed_wallet_balance": 101,
765
- "spendable_balance": 101,
766
- "max_send_amount": 101,
767
- "unspent_coin_count": 1,
768
- "pending_change": -101,
769
- "pending_coin_removal_count": -1,
770
- },
823
+ "did": {
824
+ "init": True,
825
+ "unconfirmed_wallet_balance": 101,
826
+ "pending_change": 101,
827
+ "pending_coin_removal_count": 1,
771
828
  },
772
- ),
773
- ]
774
- )
775
- coin = await did_wallet.get_coin()
776
- info: list[tuple[bytes, bytes, int]] = []
777
- pubkey = (await did_wallet.wallet_state_manager.get_unused_derivation_record(did_wallet.wallet_info.id)).pubkey
778
- with pytest.raises(Exception): # We expect a CLVM 80 error for this test
779
- async with did_wallet.wallet_state_manager.new_action_scope(
780
- wallet_environments.tx_config, push=False
781
- ) as action_scope:
782
- await did_wallet.recovery_spend(
783
- coin,
784
- ph,
785
- info,
786
- pubkey,
787
- WalletSpendBundle([], AugSchemeMPL.aggregate([])),
788
- action_scope,
789
- )
790
-
791
- @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
792
- @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
793
- @pytest.mark.anyio
794
- async def test_did_find_lost_did(self, wallet_environments: WalletTestFramework):
795
- env_0 = wallet_environments.environments[0]
796
- wallet_node_0 = env_0.node
797
- wallet_0 = env_0.xch_wallet
798
- api_0 = env_0.rpc_api
799
-
800
- env_0.wallet_aliases = {
801
- "xch": 1,
802
- "did": 2,
803
- }
804
-
805
- async with wallet_0.wallet_state_manager.new_action_scope(
806
- wallet_environments.tx_config, push=True
829
+ },
830
+ post_block_balance_updates={
831
+ "xch": {
832
+ "set_remainder": True,
833
+ },
834
+ "did": {
835
+ "confirmed_wallet_balance": 101,
836
+ "spendable_balance": 101,
837
+ "max_send_amount": 101,
838
+ "unspent_coin_count": 1,
839
+ "pending_change": -101,
840
+ "pending_coin_removal_count": -1,
841
+ },
842
+ },
843
+ ),
844
+ ]
845
+ )
846
+ coin = await did_wallet.get_coin()
847
+ info: list[tuple[bytes, bytes, int]] = []
848
+ pubkey = (await did_wallet.wallet_state_manager.get_unused_derivation_record(did_wallet.wallet_info.id)).pubkey
849
+ with pytest.raises(Exception): # We expect a CLVM 80 error for this test
850
+ async with did_wallet.wallet_state_manager.new_action_scope(
851
+ wallet_environments.tx_config, push=False
807
852
  ) as action_scope:
808
- did_wallet = await DIDWallet.create_new_did_wallet(
809
- wallet_node_0.wallet_state_manager, wallet_0, uint64(101), action_scope
853
+ await did_wallet.recovery_spend(
854
+ coin,
855
+ ph,
856
+ info,
857
+ pubkey,
858
+ WalletSpendBundle([], AugSchemeMPL.aggregate([])),
859
+ action_scope,
810
860
  )
811
861
 
812
- await wallet_environments.process_pending_states(
813
- [
814
- WalletStateTransition(
815
- pre_block_balance_updates={
816
- "xch": {
817
- "set_remainder": True,
818
- },
819
- "did": {
820
- "init": True,
821
- "unconfirmed_wallet_balance": 101,
822
- "pending_change": 101,
823
- "pending_coin_removal_count": 1,
824
- },
862
+
863
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
864
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
865
+ @pytest.mark.parametrize(
866
+ "use_alternate_recovery",
867
+ [True, False],
868
+ )
869
+ @pytest.mark.anyio
870
+ async def test_did_find_lost_did(wallet_environments: WalletTestFramework, use_alternate_recovery: bool):
871
+ env_0 = wallet_environments.environments[0]
872
+ wallet_node_0 = env_0.node
873
+ wallet_0 = env_0.xch_wallet
874
+
875
+ env_0.wallet_aliases = {
876
+ "xch": 1,
877
+ "did": 2,
878
+ }
879
+
880
+ async with wallet_0.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
881
+ did_wallet_0 = await make_did_wallet(
882
+ wallet_node_0.wallet_state_manager,
883
+ wallet_0,
884
+ uint64(101),
885
+ action_scope,
886
+ use_alternate_recovery=use_alternate_recovery,
887
+ )
888
+
889
+ await wallet_environments.process_pending_states(
890
+ [
891
+ WalletStateTransition(
892
+ pre_block_balance_updates={
893
+ "xch": {
894
+ "set_remainder": True,
825
895
  },
826
- post_block_balance_updates={
827
- "xch": {
828
- "set_remainder": True,
829
- },
830
- "did": {
831
- "confirmed_wallet_balance": 101,
832
- "spendable_balance": 101,
833
- "max_send_amount": 101,
834
- "unspent_coin_count": 1,
835
- "pending_change": -101,
836
- "pending_coin_removal_count": -1,
837
- },
896
+ "did": {
897
+ "init": True,
898
+ "unconfirmed_wallet_balance": 101,
899
+ "pending_change": 101,
900
+ "pending_coin_removal_count": 1,
838
901
  },
839
- ),
840
- ]
841
- )
902
+ },
903
+ post_block_balance_updates={
904
+ "xch": {
905
+ "set_remainder": True,
906
+ },
907
+ "did": {
908
+ "confirmed_wallet_balance": 101,
909
+ "spendable_balance": 101,
910
+ "max_send_amount": 101,
911
+ "unspent_coin_count": 1,
912
+ "pending_change": -101,
913
+ "pending_coin_removal_count": -1,
914
+ },
915
+ },
916
+ ),
917
+ ]
918
+ )
842
919
 
843
- # Delete the coin and wallet
844
- coin = await did_wallet.get_coin()
845
- await wallet_node_0.wallet_state_manager.coin_store.delete_coin_record(coin.name())
846
- await wallet_node_0.wallet_state_manager.delete_wallet(did_wallet.wallet_info.id)
847
- wallet_node_0.wallet_state_manager.wallets.pop(did_wallet.wallet_info.id)
848
- assert len(wallet_node_0.wallet_state_manager.wallets) == 1
849
- # Find lost DID
850
- assert did_wallet.did_info.origin_coin is not None # mypy
851
- resp = await api_0.did_find_lost_did({"coin_id": did_wallet.did_info.origin_coin.name().hex()})
852
- assert resp["success"]
853
- did_wallets = list(
854
- filter(
855
- lambda w: (w.type == WalletType.DECENTRALIZED_ID),
856
- await wallet_node_0.wallet_state_manager.get_all_wallet_info_entries(),
857
- )
920
+ # Delete the coin and wallet
921
+ coin = await did_wallet_0.get_coin()
922
+ await wallet_node_0.wallet_state_manager.coin_store.delete_coin_record(coin.name())
923
+ await wallet_node_0.wallet_state_manager.delete_wallet(did_wallet_0.wallet_info.id)
924
+ wallet_node_0.wallet_state_manager.wallets.pop(did_wallet_0.wallet_info.id)
925
+ assert len(wallet_node_0.wallet_state_manager.wallets) == 1
926
+ # Find lost DID
927
+ assert did_wallet_0.did_info.origin_coin is not None # mypy
928
+ await env_0.rpc_client.find_lost_did(DIDFindLostDID(did_wallet_0.did_info.origin_coin.name().hex()))
929
+ did_wallets = list(
930
+ filter(
931
+ lambda w: (w.type == WalletType.DECENTRALIZED_ID),
932
+ await wallet_node_0.wallet_state_manager.get_all_wallet_info_entries(),
858
933
  )
859
- did_wallet = wallet_node_0.wallet_state_manager.wallets[did_wallets[0].id]
860
- env_0.wallet_aliases["did_found"] = did_wallets[0].id
861
- await env_0.change_balances(
862
- {
863
- "did_found": {
864
- "init": True,
865
- "confirmed_wallet_balance": 101,
866
- "unconfirmed_wallet_balance": 101,
867
- "spendable_balance": 101,
868
- "max_send_amount": 101,
869
- "unspent_coin_count": 1,
870
- }
934
+ )
935
+ did_wallet = wallet_node_0.wallet_state_manager.wallets[did_wallets[0].id]
936
+ assert isinstance(did_wallet, DIDWallet)
937
+ env_0.wallet_aliases["did_found"] = did_wallets[0].id
938
+ await env_0.change_balances(
939
+ {
940
+ "did_found": {
941
+ "init": True,
942
+ "confirmed_wallet_balance": 101,
943
+ "unconfirmed_wallet_balance": 101,
944
+ "spendable_balance": 101,
945
+ "max_send_amount": 101,
946
+ "unspent_coin_count": 1,
871
947
  }
872
- )
873
- await env_0.check_balances()
948
+ }
949
+ )
950
+ await env_0.check_balances()
874
951
 
875
- # Spend DID
876
- recovery_list = [bytes32.fromhex(did_wallet.get_my_DID())]
877
- await did_wallet.update_recovery_list(recovery_list, uint64(1))
878
- assert did_wallet.did_info.backup_ids == recovery_list
879
- async with did_wallet.wallet_state_manager.new_action_scope(
880
- wallet_environments.tx_config, push=True
881
- ) as action_scope:
882
- await did_wallet.create_update_spend(action_scope)
952
+ # Spend DID
953
+ recovery_list = [bytes32.fromhex(did_wallet.get_my_DID())]
954
+ await did_wallet.update_recovery_list(recovery_list, uint64(1))
955
+ assert did_wallet.did_info.backup_ids == recovery_list
956
+ async with did_wallet.wallet_state_manager.new_action_scope(
957
+ wallet_environments.tx_config, push=True
958
+ ) as action_scope:
959
+ await did_wallet.create_update_spend(action_scope)
883
960
 
884
- await wallet_environments.process_pending_states(
885
- [
886
- WalletStateTransition(
887
- pre_block_balance_updates={
888
- "did_found": {
889
- "spendable_balance": -101,
890
- "max_send_amount": -101,
891
- "pending_change": 101,
892
- "pending_coin_removal_count": 1,
893
- },
961
+ await wallet_environments.process_pending_states(
962
+ [
963
+ WalletStateTransition(
964
+ pre_block_balance_updates={
965
+ "did_found": {
966
+ "spendable_balance": -101,
967
+ "max_send_amount": -101,
968
+ "pending_change": 101,
969
+ "pending_coin_removal_count": 1,
894
970
  },
895
- post_block_balance_updates={
896
- "did_found": {
897
- "spendable_balance": 101,
898
- "max_send_amount": 101,
899
- "pending_change": -101,
900
- "pending_coin_removal_count": -1,
901
- },
971
+ },
972
+ post_block_balance_updates={
973
+ "did_found": {
974
+ "spendable_balance": 101,
975
+ "max_send_amount": 101,
976
+ "pending_change": -101,
977
+ "pending_coin_removal_count": -1,
902
978
  },
903
- ),
904
- ]
905
- )
906
-
907
- # Delete the coin and change inner puzzle
908
- coin = await did_wallet.get_coin()
909
- await wallet_node_0.wallet_state_manager.coin_store.delete_coin_record(coin.name())
910
- new_inner_puzzle = await did_wallet.get_did_innerpuz(new=True)
911
- did_wallet.did_info = dataclasses.replace(did_wallet.did_info, current_inner=new_inner_puzzle)
912
- # Recovery the coin
913
- assert did_wallet.did_info.origin_coin is not None # mypy
914
- resp = await api_0.did_find_lost_did({"coin_id": did_wallet.did_info.origin_coin.name().hex()})
915
- assert resp["success"]
916
- found_coin = await did_wallet.get_coin()
917
- assert found_coin == coin
918
- assert did_wallet.did_info.current_inner != new_inner_puzzle
919
-
920
- @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
921
- @pytest.mark.parametrize("wallet_environments", [{"num_environments": 2, "blocks_needed": [1, 1]}], indirect=True)
922
- @pytest.mark.anyio
923
- async def test_did_attest_after_recovery(self, wallet_environments: WalletTestFramework):
924
- env_0 = wallet_environments.environments[0]
925
- env_1 = wallet_environments.environments[1]
926
- wallet_node_0 = env_0.node
927
- wallet_node_1 = env_1.node
928
- wallet_0 = env_0.xch_wallet
929
- wallet_1 = env_1.xch_wallet
930
-
931
- env_0.wallet_aliases = {
932
- "xch": 1,
933
- "did": 2,
934
- }
935
- env_1.wallet_aliases = {
936
- "xch": 1,
937
- "did": 2,
938
- }
979
+ },
980
+ ),
981
+ ]
982
+ )
939
983
 
940
- async with wallet_0.wallet_state_manager.new_action_scope(
984
+ # Delete the coin and change inner puzzle
985
+ coin = await did_wallet.get_coin()
986
+ await wallet_node_0.wallet_state_manager.coin_store.delete_coin_record(coin.name())
987
+ with wallet_environments.new_puzzle_hashes_allowed():
988
+ async with did_wallet.wallet_state_manager.new_action_scope(
941
989
  wallet_environments.tx_config, push=True
942
990
  ) as action_scope:
943
- did_wallet: DIDWallet = await DIDWallet.create_new_did_wallet(
944
- wallet_node_0.wallet_state_manager, wallet_0, uint64(101), action_scope
945
- )
946
- await wallet_environments.process_pending_states(
947
- [
948
- WalletStateTransition(
949
- pre_block_balance_updates={
950
- "xch": {
951
- "set_remainder": True,
952
- },
953
- "did": {
954
- "init": True,
955
- "unconfirmed_wallet_balance": 101,
956
- "pending_change": 101,
957
- "pending_coin_removal_count": 1,
958
- },
991
+ new_inner_puzzle = await did_wallet.get_did_innerpuz(action_scope, override_reuse_puzhash_with=False)
992
+ did_wallet.did_info = dataclasses.replace(did_wallet.did_info, current_inner=new_inner_puzzle)
993
+ # Recovery the coin
994
+ assert did_wallet.did_info.origin_coin is not None # mypy
995
+ await env_0.rpc_client.find_lost_did(DIDFindLostDID(did_wallet.did_info.origin_coin.name().hex()))
996
+ found_coin = await did_wallet.get_coin()
997
+ assert found_coin == coin
998
+ assert did_wallet.did_info.current_inner != new_inner_puzzle
999
+
1000
+
1001
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1002
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 2, "blocks_needed": [1, 1]}], indirect=True)
1003
+ @pytest.mark.parametrize(
1004
+ "use_alternate_recovery",
1005
+ [True, False],
1006
+ )
1007
+ @pytest.mark.anyio
1008
+ async def test_did_attest_after_recovery(wallet_environments: WalletTestFramework, use_alternate_recovery: bool):
1009
+ env_0 = wallet_environments.environments[0]
1010
+ env_1 = wallet_environments.environments[1]
1011
+ wallet_node_0 = env_0.node
1012
+ wallet_node_1 = env_1.node
1013
+ wallet_0 = env_0.xch_wallet
1014
+ wallet_1 = env_1.xch_wallet
1015
+
1016
+ env_0.wallet_aliases = {
1017
+ "xch": 1,
1018
+ "did": 2,
1019
+ }
1020
+ env_1.wallet_aliases = {
1021
+ "xch": 1,
1022
+ "did": 2,
1023
+ }
1024
+
1025
+ async with wallet_0.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1026
+ did_wallet: DIDWallet = await make_did_wallet(
1027
+ wallet_node_0.wallet_state_manager,
1028
+ wallet_0,
1029
+ uint64(101),
1030
+ action_scope,
1031
+ use_alternate_recovery=use_alternate_recovery,
1032
+ )
1033
+ await wallet_environments.process_pending_states(
1034
+ [
1035
+ WalletStateTransition(
1036
+ pre_block_balance_updates={
1037
+ "xch": {
1038
+ "set_remainder": True,
959
1039
  },
960
- post_block_balance_updates={
961
- "xch": {
962
- "set_remainder": True,
963
- },
964
- "did": {
965
- "confirmed_wallet_balance": 101,
966
- "spendable_balance": 101,
967
- "max_send_amount": 101,
968
- "unspent_coin_count": 1,
969
- "pending_change": -101,
970
- "pending_coin_removal_count": -1,
971
- },
1040
+ "did": {
1041
+ "init": True,
1042
+ "unconfirmed_wallet_balance": 101,
1043
+ "pending_change": 101,
1044
+ "pending_coin_removal_count": 1,
972
1045
  },
973
- ),
974
- WalletStateTransition(),
975
- ]
976
- )
1046
+ },
1047
+ post_block_balance_updates={
1048
+ "xch": {
1049
+ "set_remainder": True,
1050
+ },
1051
+ "did": {
1052
+ "confirmed_wallet_balance": 101,
1053
+ "spendable_balance": 101,
1054
+ "max_send_amount": 101,
1055
+ "unspent_coin_count": 1,
1056
+ "pending_change": -101,
1057
+ "pending_coin_removal_count": -1,
1058
+ },
1059
+ },
1060
+ ),
1061
+ WalletStateTransition(),
1062
+ ]
1063
+ )
977
1064
 
978
- await time_out_assert(15, did_wallet.get_confirmed_balance, 101)
979
- await time_out_assert(15, did_wallet.get_unconfirmed_balance, 101)
980
- recovery_list = [bytes32.from_hexstr(did_wallet.get_my_DID())]
1065
+ await time_out_assert(15, did_wallet.get_confirmed_balance, 101)
1066
+ await time_out_assert(15, did_wallet.get_unconfirmed_balance, 101)
1067
+ recovery_list = [bytes32.from_hexstr(did_wallet.get_my_DID())]
981
1068
 
982
- async with wallet_1.wallet_state_manager.new_action_scope(
983
- wallet_environments.tx_config, push=True
984
- ) as action_scope:
985
- did_wallet_2: DIDWallet = await DIDWallet.create_new_did_wallet(
986
- wallet_node_1.wallet_state_manager, wallet_1, uint64(101), action_scope, recovery_list
987
- )
988
- await wallet_environments.process_pending_states(
989
- [
990
- WalletStateTransition(),
991
- WalletStateTransition(
992
- pre_block_balance_updates={
993
- "xch": {
994
- "set_remainder": True,
995
- },
996
- "did": {
997
- "init": True,
998
- "unconfirmed_wallet_balance": 101,
999
- "pending_change": 101,
1000
- "pending_coin_removal_count": 1,
1001
- },
1069
+ async with wallet_1.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1070
+ did_wallet_2: DIDWallet = await DIDWallet.create_new_did_wallet(
1071
+ wallet_node_1.wallet_state_manager, wallet_1, uint64(101), action_scope, recovery_list
1072
+ )
1073
+ await wallet_environments.process_pending_states(
1074
+ [
1075
+ WalletStateTransition(),
1076
+ WalletStateTransition(
1077
+ pre_block_balance_updates={
1078
+ "xch": {
1079
+ "set_remainder": True,
1002
1080
  },
1003
- post_block_balance_updates={
1004
- "xch": {
1005
- "set_remainder": True,
1006
- },
1007
- "did": {
1008
- "confirmed_wallet_balance": 101,
1009
- "spendable_balance": 101,
1010
- "max_send_amount": 101,
1011
- "unspent_coin_count": 1,
1012
- "pending_change": -101,
1013
- "pending_coin_removal_count": -1,
1014
- },
1081
+ "did": {
1082
+ "init": True,
1083
+ "unconfirmed_wallet_balance": 101,
1084
+ "pending_change": 101,
1085
+ "pending_coin_removal_count": 1,
1015
1086
  },
1016
- ),
1017
- ]
1018
- )
1087
+ },
1088
+ post_block_balance_updates={
1089
+ "xch": {
1090
+ "set_remainder": True,
1091
+ },
1092
+ "did": {
1093
+ "confirmed_wallet_balance": 101,
1094
+ "spendable_balance": 101,
1095
+ "max_send_amount": 101,
1096
+ "unspent_coin_count": 1,
1097
+ "pending_change": -101,
1098
+ "pending_coin_removal_count": -1,
1099
+ },
1100
+ },
1101
+ ),
1102
+ ]
1103
+ )
1019
1104
 
1020
- assert did_wallet_2.did_info.backup_ids == recovery_list
1105
+ assert did_wallet_2.did_info.backup_ids == recovery_list
1021
1106
 
1022
- # Update coin with new ID info
1023
- recovery_list = [bytes32.from_hexstr(did_wallet_2.get_my_DID())]
1024
- await did_wallet.update_recovery_list(recovery_list, uint64(1))
1025
- assert did_wallet.did_info.backup_ids == recovery_list
1026
- async with did_wallet.wallet_state_manager.new_action_scope(
1107
+ # Update coin with new ID info
1108
+ recovery_list = [bytes32.from_hexstr(did_wallet_2.get_my_DID())]
1109
+ await did_wallet.update_recovery_list(recovery_list, uint64(1))
1110
+ assert did_wallet.did_info.backup_ids == recovery_list
1111
+ async with did_wallet.wallet_state_manager.new_action_scope(
1112
+ wallet_environments.tx_config, push=True
1113
+ ) as action_scope:
1114
+ await did_wallet.create_update_spend(action_scope)
1115
+
1116
+ await wallet_environments.process_pending_states(
1117
+ [
1118
+ WalletStateTransition(
1119
+ pre_block_balance_updates={
1120
+ "did": {
1121
+ "set_remainder": True,
1122
+ }
1123
+ },
1124
+ post_block_balance_updates={
1125
+ "did": {
1126
+ "set_remainder": True,
1127
+ }
1128
+ },
1129
+ ),
1130
+ WalletStateTransition(),
1131
+ ]
1132
+ )
1133
+
1134
+ # DID Wallet 2 recovers into DID Wallet 3 with new innerpuz
1135
+ backup_data = did_wallet_2.create_backup()
1136
+
1137
+ async with wallet_node_0.wallet_state_manager.lock:
1138
+ did_wallet_3 = await DIDWallet.create_new_did_wallet_from_recovery(
1139
+ wallet_node_0.wallet_state_manager,
1140
+ wallet_0,
1141
+ backup_data,
1142
+ )
1143
+ env_0.wallet_aliases["did_2"] = 3
1144
+ with wallet_environments.new_puzzle_hashes_allowed():
1145
+ async with did_wallet_3.wallet_state_manager.new_action_scope(
1027
1146
  wallet_environments.tx_config, push=True
1028
1147
  ) as action_scope:
1029
- await did_wallet.create_update_spend(action_scope)
1030
-
1031
- await wallet_environments.process_pending_states(
1032
- [
1033
- WalletStateTransition(
1034
- pre_block_balance_updates={
1035
- "did": {
1036
- "set_remainder": True,
1037
- }
1148
+ new_ph = (
1149
+ await did_wallet_3.get_did_innerpuz(action_scope, override_reuse_puzhash_with=False)
1150
+ ).get_tree_hash()
1151
+ coin = await did_wallet_2.get_coin()
1152
+ pubkey = (await did_wallet_3.wallet_state_manager.get_unused_derivation_record(did_wallet_3.wallet_info.id)).pubkey
1153
+
1154
+ async with did_wallet.wallet_state_manager.new_action_scope(
1155
+ wallet_environments.tx_config, push=True
1156
+ ) as action_scope:
1157
+ message_spend_bundle, attest_data = await did_wallet.create_attestment(
1158
+ coin.name(), new_ph, pubkey, action_scope
1159
+ )
1160
+ await wallet_environments.process_pending_states(
1161
+ [
1162
+ WalletStateTransition(
1163
+ pre_block_balance_updates={
1164
+ "did": {
1165
+ "set_remainder": True,
1038
1166
  },
1039
- post_block_balance_updates={
1040
- "did": {
1041
- "set_remainder": True,
1042
- }
1167
+ "did_2": {
1168
+ "init": True,
1169
+ "set_remainder": True,
1043
1170
  },
1044
- ),
1045
- WalletStateTransition(),
1046
- ]
1047
- )
1171
+ },
1172
+ post_block_balance_updates={
1173
+ "did": {
1174
+ "set_remainder": True,
1175
+ },
1176
+ "did_2": {
1177
+ "set_remainder": True,
1178
+ },
1179
+ },
1180
+ ),
1181
+ WalletStateTransition(),
1182
+ ]
1183
+ )
1048
1184
 
1049
- # DID Wallet 2 recovers into DID Wallet 3 with new innerpuz
1050
- backup_data = did_wallet_2.create_backup()
1185
+ (
1186
+ info,
1187
+ message_spend_bundle,
1188
+ ) = await did_wallet_3.load_attest_files_for_recovery_spend([attest_data])
1189
+ async with did_wallet_3.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1190
+ await did_wallet_3.recovery_spend(coin, new_ph, info, pubkey, message_spend_bundle, action_scope)
1191
+ await wallet_environments.process_pending_states(
1192
+ [
1193
+ WalletStateTransition(
1194
+ pre_block_balance_updates={
1195
+ "did_2": {
1196
+ "unconfirmed_wallet_balance": 101,
1197
+ "set_remainder": True,
1198
+ },
1199
+ },
1200
+ post_block_balance_updates={
1201
+ "did_2": {
1202
+ "confirmed_wallet_balance": 101,
1203
+ "set_remainder": True,
1204
+ },
1205
+ },
1206
+ ),
1207
+ WalletStateTransition(
1208
+ pre_block_balance_updates={
1209
+ "did": {
1210
+ "unconfirmed_wallet_balance": 0, # TODO: fix pre-block balances for recovery
1211
+ "set_remainder": True,
1212
+ },
1213
+ },
1214
+ post_block_balance_updates={
1215
+ "did": {
1216
+ "confirmed_wallet_balance": -101,
1217
+ "set_remainder": True,
1218
+ },
1219
+ },
1220
+ ),
1221
+ ]
1222
+ )
1051
1223
 
1052
- async with wallet_node_0.wallet_state_manager.lock:
1053
- did_wallet_3 = await DIDWallet.create_new_did_wallet_from_recovery(
1054
- wallet_node_0.wallet_state_manager,
1055
- wallet_0,
1056
- backup_data,
1057
- )
1058
- env_0.wallet_aliases["did_2"] = 3
1059
- new_ph = await did_wallet_3.get_did_inner_hash(new=True)
1060
- coin = await did_wallet_2.get_coin()
1061
- pubkey = (
1062
- await did_wallet_3.wallet_state_manager.get_unused_derivation_record(did_wallet_3.wallet_info.id)
1063
- ).pubkey
1224
+ # DID Wallet 1 recovery spends into DID Wallet 4
1225
+ backup_data = did_wallet.create_backup()
1064
1226
 
1065
- async with did_wallet.wallet_state_manager.new_action_scope(
1227
+ async with wallet_node_1.wallet_state_manager.lock:
1228
+ did_wallet_4 = await DIDWallet.create_new_did_wallet_from_recovery(
1229
+ wallet_node_1.wallet_state_manager,
1230
+ wallet_1,
1231
+ backup_data,
1232
+ )
1233
+ env_1.wallet_aliases["did_2"] = 3
1234
+ coin = await did_wallet.get_coin()
1235
+ with wallet_environments.new_puzzle_hashes_allowed():
1236
+ async with did_wallet_4.wallet_state_manager.new_action_scope(
1066
1237
  wallet_environments.tx_config, push=True
1067
1238
  ) as action_scope:
1068
- message_spend_bundle, attest_data = await did_wallet.create_attestment(
1069
- coin.name(), new_ph, pubkey, action_scope
1070
- )
1071
- await wallet_environments.process_pending_states(
1072
- [
1073
- WalletStateTransition(
1074
- pre_block_balance_updates={
1075
- "did": {
1076
- "set_remainder": True,
1077
- },
1078
- "did_2": {
1079
- "init": True,
1080
- "set_remainder": True,
1081
- },
1239
+ new_ph = (
1240
+ await did_wallet_4.get_did_innerpuz(action_scope, override_reuse_puzhash_with=False)
1241
+ ).get_tree_hash()
1242
+ pubkey = (await did_wallet_4.wallet_state_manager.get_unused_derivation_record(did_wallet_4.wallet_info.id)).pubkey
1243
+ async with did_wallet_3.wallet_state_manager.new_action_scope(
1244
+ wallet_environments.tx_config, push=True
1245
+ ) as action_scope:
1246
+ message_spend_bundle, attest1 = await did_wallet_3.create_attestment(coin.name(), new_ph, pubkey, action_scope)
1247
+
1248
+ await wallet_environments.process_pending_states(
1249
+ [
1250
+ WalletStateTransition(
1251
+ pre_block_balance_updates={
1252
+ "did_2": {
1253
+ "unconfirmed_wallet_balance": 0,
1254
+ "set_remainder": True,
1255
+ },
1256
+ },
1257
+ post_block_balance_updates={
1258
+ "did_2": {
1259
+ "confirmed_wallet_balance": 0,
1260
+ "set_remainder": True,
1082
1261
  },
1083
- post_block_balance_updates={
1084
- "did": {
1085
- "set_remainder": True,
1086
- },
1087
- "did_2": {
1088
- "set_remainder": True,
1089
- },
1262
+ },
1263
+ ),
1264
+ WalletStateTransition(
1265
+ pre_block_balance_updates={
1266
+ "did_2": {
1267
+ "init": True,
1268
+ "set_remainder": True,
1090
1269
  },
1091
- ),
1092
- WalletStateTransition(),
1093
- ]
1094
- )
1270
+ },
1271
+ post_block_balance_updates={
1272
+ "did_2": {
1273
+ "confirmed_wallet_balance": 0,
1274
+ "set_remainder": True,
1275
+ },
1276
+ },
1277
+ ),
1278
+ ]
1279
+ )
1095
1280
 
1096
- (
1097
- info,
1098
- message_spend_bundle,
1099
- ) = await did_wallet_3.load_attest_files_for_recovery_spend([attest_data])
1100
- async with did_wallet_3.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1101
- await did_wallet_3.recovery_spend(coin, new_ph, info, pubkey, message_spend_bundle, action_scope)
1102
- await wallet_environments.process_pending_states(
1103
- [
1104
- WalletStateTransition(
1105
- pre_block_balance_updates={
1106
- "did_2": {
1107
- "unconfirmed_wallet_balance": 101,
1108
- "set_remainder": True,
1109
- },
1281
+ (
1282
+ test_info_list,
1283
+ test_message_spend_bundle,
1284
+ ) = await did_wallet_4.load_attest_files_for_recovery_spend([attest1])
1285
+ async with did_wallet_4.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1286
+ await did_wallet_4.recovery_spend(coin, new_ph, test_info_list, pubkey, test_message_spend_bundle, action_scope)
1287
+
1288
+ await wallet_environments.process_pending_states(
1289
+ [
1290
+ WalletStateTransition(
1291
+ pre_block_balance_updates={
1292
+ "did": {
1293
+ "set_remainder": True,
1110
1294
  },
1111
- post_block_balance_updates={
1112
- "did_2": {
1113
- "confirmed_wallet_balance": 101,
1114
- "set_remainder": True,
1115
- },
1295
+ },
1296
+ post_block_balance_updates={
1297
+ "did": {
1298
+ "confirmed_wallet_balance": -101,
1299
+ "set_remainder": True,
1116
1300
  },
1117
- ),
1118
- WalletStateTransition(
1119
- pre_block_balance_updates={
1120
- "did": {
1121
- "unconfirmed_wallet_balance": 0, # TODO: fix pre-block balances for recovery
1122
- "set_remainder": True,
1123
- },
1301
+ },
1302
+ ),
1303
+ WalletStateTransition(
1304
+ pre_block_balance_updates={
1305
+ "did_2": {
1306
+ "set_remainder": True,
1124
1307
  },
1125
- post_block_balance_updates={
1126
- "did": {
1127
- "confirmed_wallet_balance": -101,
1128
- "set_remainder": True,
1129
- },
1308
+ },
1309
+ post_block_balance_updates={
1310
+ "did_2": {
1311
+ "confirmed_wallet_balance": 101,
1312
+ "set_remainder": True,
1130
1313
  },
1131
- ),
1132
- ]
1133
- )
1314
+ },
1315
+ ),
1316
+ ]
1317
+ )
1134
1318
 
1135
- # DID Wallet 1 recovery spends into DID Wallet 4
1136
- backup_data = did_wallet.create_backup()
1319
+ for wallet in [did_wallet, did_wallet_3, did_wallet_4]:
1320
+ assert wallet.wallet_state_manager.wallets[wallet.id()] == wallet
1137
1321
 
1138
- async with wallet_node_1.wallet_state_manager.lock:
1139
- did_wallet_4 = await DIDWallet.create_new_did_wallet_from_recovery(
1140
- wallet_node_1.wallet_state_manager,
1141
- wallet_1,
1142
- backup_data,
1143
- )
1144
- env_1.wallet_aliases["did_2"] = 3
1145
- coin = await did_wallet.get_coin()
1146
- new_ph = await did_wallet_4.get_did_inner_hash(new=True)
1147
- pubkey = (
1148
- await did_wallet_4.wallet_state_manager.get_unused_derivation_record(did_wallet_4.wallet_info.id)
1149
- ).pubkey
1150
- async with did_wallet_3.wallet_state_manager.new_action_scope(
1151
- wallet_environments.tx_config, push=True
1152
- ) as action_scope:
1153
- message_spend_bundle, attest1 = await did_wallet_3.create_attestment(
1154
- coin.name(), new_ph, pubkey, action_scope
1155
- )
1156
1322
 
1157
- await wallet_environments.process_pending_states(
1158
- [
1159
- WalletStateTransition(
1160
- pre_block_balance_updates={
1161
- "did_2": {
1162
- "unconfirmed_wallet_balance": 0,
1163
- "set_remainder": True,
1164
- },
1323
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1324
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 2, "blocks_needed": [1, 1]}], indirect=True)
1325
+ @pytest.mark.parametrize(
1326
+ "with_recovery",
1327
+ [True, False],
1328
+ )
1329
+ @pytest.mark.anyio
1330
+ async def test_did_transfer(wallet_environments: WalletTestFramework, with_recovery: bool):
1331
+ env_0 = wallet_environments.environments[0]
1332
+ env_1 = wallet_environments.environments[1]
1333
+ wallet_node_0 = env_0.node
1334
+ wallet_node_1 = env_1.node
1335
+ wallet_0 = env_0.xch_wallet
1336
+ wallet_1 = env_1.xch_wallet
1337
+
1338
+ env_0.wallet_aliases = {
1339
+ "xch": 1,
1340
+ "did": 2,
1341
+ }
1342
+ env_1.wallet_aliases = {
1343
+ "xch": 1,
1344
+ "did": 2,
1345
+ }
1346
+ async with wallet_0.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1347
+ ph = await action_scope.get_puzzle_hash(wallet_0.wallet_state_manager)
1348
+ fee = uint64(1000)
1349
+
1350
+ async with wallet_0.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1351
+ did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
1352
+ wallet_node_0.wallet_state_manager,
1353
+ wallet_0,
1354
+ uint64(101),
1355
+ action_scope,
1356
+ [ph],
1357
+ uint64(1),
1358
+ {"Twitter": "Test", "GitHub": "测试"},
1359
+ fee=fee,
1360
+ )
1361
+ assert did_wallet_1.get_name() == "Profile 1"
1362
+
1363
+ await wallet_environments.process_pending_states(
1364
+ [
1365
+ WalletStateTransition(
1366
+ pre_block_balance_updates={
1367
+ "xch": {
1368
+ "set_remainder": True,
1165
1369
  },
1166
- post_block_balance_updates={
1167
- "did_2": {
1168
- "confirmed_wallet_balance": 0,
1169
- "set_remainder": True,
1170
- },
1370
+ "did": {
1371
+ "init": True,
1372
+ "unconfirmed_wallet_balance": 101,
1373
+ "pending_change": 101,
1374
+ "pending_coin_removal_count": 1,
1171
1375
  },
1172
- ),
1173
- WalletStateTransition(
1174
- pre_block_balance_updates={
1175
- "did_2": {
1176
- "init": True,
1177
- "set_remainder": True,
1178
- },
1376
+ },
1377
+ post_block_balance_updates={
1378
+ "xch": {
1379
+ "set_remainder": True,
1179
1380
  },
1180
- post_block_balance_updates={
1181
- "did_2": {
1182
- "confirmed_wallet_balance": 0,
1183
- "set_remainder": True,
1184
- },
1381
+ "did": {
1382
+ "confirmed_wallet_balance": 101,
1383
+ "spendable_balance": 101,
1384
+ "max_send_amount": 101,
1385
+ "unspent_coin_count": 1,
1386
+ "pending_change": -101,
1387
+ "pending_coin_removal_count": -1,
1185
1388
  },
1186
- ),
1187
- ]
1188
- )
1389
+ },
1390
+ ),
1391
+ WalletStateTransition(),
1392
+ ]
1393
+ )
1189
1394
 
1190
- (
1191
- test_info_list,
1192
- test_message_spend_bundle,
1193
- ) = await did_wallet_4.load_attest_files_for_recovery_spend([attest1])
1194
- async with did_wallet_4.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1195
- await did_wallet_4.recovery_spend(
1196
- coin, new_ph, test_info_list, pubkey, test_message_spend_bundle, action_scope
1197
- )
1395
+ # Transfer DID
1396
+ async with wallet_1.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1397
+ new_puzhash = await action_scope.get_puzzle_hash(wallet_1.wallet_state_manager)
1398
+ async with did_wallet_1.wallet_state_manager.new_action_scope(
1399
+ wallet_environments.tx_config, push=True
1400
+ ) as action_scope:
1401
+ await did_wallet_1.transfer_did(new_puzhash, fee, with_recovery, action_scope)
1198
1402
 
1199
- await wallet_environments.process_pending_states(
1200
- [
1201
- WalletStateTransition(
1202
- pre_block_balance_updates={
1203
- "did": {
1204
- "set_remainder": True,
1205
- },
1403
+ await wallet_environments.process_pending_states(
1404
+ [
1405
+ WalletStateTransition(
1406
+ pre_block_balance_updates={
1407
+ "xch": {
1408
+ "set_remainder": True,
1206
1409
  },
1207
- post_block_balance_updates={
1208
- "did": {
1209
- "confirmed_wallet_balance": -101,
1210
- "set_remainder": True,
1211
- },
1410
+ "did": {
1411
+ "unconfirmed_wallet_balance": -101,
1412
+ "set_remainder": True,
1212
1413
  },
1213
- ),
1214
- WalletStateTransition(
1215
- pre_block_balance_updates={
1216
- "did_2": {
1217
- "set_remainder": True,
1218
- },
1414
+ },
1415
+ post_block_balance_updates={
1416
+ "xch": {
1417
+ "set_remainder": True,
1219
1418
  },
1220
- post_block_balance_updates={
1221
- "did_2": {
1222
- "confirmed_wallet_balance": 101,
1223
- "set_remainder": True,
1224
- },
1419
+ },
1420
+ ),
1421
+ WalletStateTransition(
1422
+ pre_block_balance_updates={},
1423
+ post_block_balance_updates={
1424
+ "did": {
1425
+ "init": True,
1426
+ "confirmed_wallet_balance": 101,
1427
+ "set_remainder": True,
1225
1428
  },
1226
- ),
1227
- ]
1429
+ },
1430
+ ),
1431
+ ]
1432
+ )
1433
+
1434
+ # Get the new DID wallet
1435
+ did_wallets = list(
1436
+ filter(
1437
+ lambda w: (w.type == WalletType.DECENTRALIZED_ID),
1438
+ await wallet_node_1.wallet_state_manager.get_all_wallet_info_entries(),
1228
1439
  )
1440
+ )
1441
+ did_wallet_2 = wallet_node_1.wallet_state_manager.wallets[did_wallets[0].id]
1442
+ assert isinstance(did_wallet_2, DIDWallet) # mypy
1443
+ assert len(wallet_node_0.wallet_state_manager.wallets) == 1
1444
+ assert did_wallet_1.did_info.origin_coin == did_wallet_2.did_info.origin_coin
1445
+ if with_recovery:
1446
+ assert did_wallet_1.did_info.backup_ids[0] == did_wallet_2.did_info.backup_ids[0]
1447
+ assert did_wallet_1.did_info.num_of_backup_ids_needed == did_wallet_2.did_info.num_of_backup_ids_needed
1448
+ metadata = json.loads(did_wallet_2.did_info.metadata)
1449
+ assert metadata["Twitter"] == "Test"
1450
+ assert metadata["GitHub"] == "测试"
1451
+
1452
+ # Test match_hinted_coin
1453
+ assert await did_wallet_2.match_hinted_coin(
1454
+ await did_wallet_2.get_coin(),
1455
+ new_puzhash,
1456
+ )
1229
1457
 
1230
- for wallet in [did_wallet, did_wallet_3, did_wallet_4]:
1231
- assert wallet.wallet_state_manager.wallets[wallet.id()] == wallet
1232
1458
 
1233
- @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1234
- @pytest.mark.parametrize("wallet_environments", [{"num_environments": 2, "blocks_needed": [1, 1]}], indirect=True)
1235
- @pytest.mark.parametrize(
1236
- "with_recovery",
1237
- [True, False],
1238
- )
1239
- @pytest.mark.anyio
1240
- async def test_did_transfer(self, wallet_environments: WalletTestFramework, with_recovery: bool):
1241
- env_0 = wallet_environments.environments[0]
1242
- env_1 = wallet_environments.environments[1]
1243
- wallet_node_0 = env_0.node
1244
- wallet_node_1 = env_1.node
1245
- wallet_0 = env_0.xch_wallet
1246
- wallet_1 = env_1.xch_wallet
1247
-
1248
- env_0.wallet_aliases = {
1249
- "xch": 1,
1250
- "did": 2,
1459
+ @pytest.mark.parametrize(
1460
+ "trusted",
1461
+ [True, False],
1462
+ )
1463
+ @pytest.mark.anyio
1464
+ async def test_did_auto_transfer_limit(
1465
+ self_hostname: str,
1466
+ two_wallet_nodes: tuple[list[FullNodeSimulator], list[tuple[WalletNode, ChiaServer]], BlockTools],
1467
+ trusted: bool,
1468
+ ) -> None:
1469
+ fee = uint64(1000)
1470
+ full_nodes, wallets, _ = two_wallet_nodes
1471
+ full_node_api = full_nodes[0]
1472
+ server_1 = full_node_api.server
1473
+ wallet_node, server_2 = wallets[0]
1474
+ wallet_node_2, server_3 = wallets[1]
1475
+ wallet = wallet_node.wallet_state_manager.main_wallet
1476
+ wallet2 = wallet_node_2.wallet_state_manager.main_wallet
1477
+ api_1 = WalletRpcApi(wallet_node_2)
1478
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1479
+ ph = await action_scope.get_puzzle_hash(wallet.wallet_state_manager)
1480
+
1481
+ if trusted:
1482
+ wallet_node.config["trusted_peers"] = {
1483
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
1251
1484
  }
1252
- env_1.wallet_aliases = {
1253
- "xch": 1,
1254
- "did": 2,
1485
+ wallet_node_2.config["trusted_peers"] = {
1486
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
1255
1487
  }
1256
- ph = await wallet_0.get_new_puzzlehash()
1257
- fee = uint64(1000)
1488
+ else:
1489
+ wallet_node.config["trusted_peers"] = {}
1490
+ wallet_node_2.config["trusted_peers"] = {}
1258
1491
 
1259
- async with wallet_0.wallet_state_manager.new_action_scope(
1260
- wallet_environments.tx_config, push=True
1261
- ) as action_scope:
1492
+ await server_2.start_client(PeerInfo(self_hostname, server_1.get_port()), None)
1493
+ await server_3.start_client(PeerInfo(self_hostname, server_1.get_port()), None)
1494
+ await full_node_api.farm_blocks_to_wallet(1, wallet)
1495
+
1496
+ # Check that we cap out at 10 DID Wallets automatically created upon transfer received
1497
+ for i in range(14):
1498
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1262
1499
  did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
1263
- wallet_node_0.wallet_state_manager,
1264
- wallet_0,
1500
+ wallet_node.wallet_state_manager,
1501
+ wallet,
1265
1502
  uint64(101),
1266
1503
  action_scope,
1267
- [ph],
1504
+ [bytes32(bytes(ph))],
1268
1505
  uint64(1),
1269
1506
  {"Twitter": "Test", "GitHub": "测试"},
1270
1507
  fee=fee,
1271
1508
  )
1272
1509
  assert did_wallet_1.get_name() == "Profile 1"
1273
-
1274
- await wallet_environments.process_pending_states(
1275
- [
1276
- WalletStateTransition(
1277
- pre_block_balance_updates={
1278
- "xch": {
1279
- "set_remainder": True,
1280
- },
1281
- "did": {
1282
- "init": True,
1283
- "unconfirmed_wallet_balance": 101,
1284
- "pending_change": 101,
1285
- "pending_coin_removal_count": 1,
1286
- },
1287
- },
1288
- post_block_balance_updates={
1289
- "xch": {
1290
- "set_remainder": True,
1291
- },
1292
- "did": {
1293
- "confirmed_wallet_balance": 101,
1294
- "spendable_balance": 101,
1295
- "max_send_amount": 101,
1296
- "unspent_coin_count": 1,
1297
- "pending_change": -101,
1298
- "pending_coin_removal_count": -1,
1299
- },
1300
- },
1301
- ),
1302
- WalletStateTransition(),
1303
- ]
1304
- )
1305
-
1510
+ await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
1511
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node, wallet_node_2])
1512
+ await time_out_assert(15, did_wallet_1.get_confirmed_balance, 101)
1513
+ await time_out_assert(15, did_wallet_1.get_unconfirmed_balance, 101)
1306
1514
  # Transfer DID
1307
- new_puzhash = await wallet_1.get_new_puzzlehash()
1308
- async with did_wallet_1.wallet_state_manager.new_action_scope(
1309
- wallet_environments.tx_config, push=True
1310
- ) as action_scope:
1311
- await did_wallet_1.transfer_did(new_puzhash, fee, with_recovery, action_scope)
1515
+ assert did_wallet_1.did_info.origin_coin is not None
1516
+ origin_coin = did_wallet_1.did_info.origin_coin
1517
+ async with wallet2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1518
+ new_puzhash = await action_scope.get_puzzle_hash(wallet2.wallet_state_manager)
1519
+ async with did_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1520
+ await did_wallet_1.transfer_did(new_puzhash, fee, False, action_scope)
1521
+ await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
1522
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node, wallet_node_2])
1523
+ # Check if the DID wallet is created in the wallet2
1312
1524
 
1313
- await wallet_environments.process_pending_states(
1314
- [
1315
- WalletStateTransition(
1316
- pre_block_balance_updates={
1317
- "xch": {
1318
- "set_remainder": True,
1319
- },
1320
- "did": {
1321
- "unconfirmed_wallet_balance": -101,
1322
- "set_remainder": True,
1323
- },
1324
- },
1325
- post_block_balance_updates={
1326
- "xch": {
1327
- "set_remainder": True,
1328
- },
1329
- },
1330
- ),
1331
- WalletStateTransition(
1332
- pre_block_balance_updates={},
1333
- post_block_balance_updates={
1334
- "did": {
1335
- "init": True,
1336
- "confirmed_wallet_balance": 101,
1337
- "set_remainder": True,
1338
- },
1339
- },
1340
- ),
1341
- ]
1525
+ await time_out_assert(
1526
+ 30, get_wallet_num, min(2 + i, 11), wallet_node_2.wallet_state_manager
1527
+ ) # check we haven't made more than 10 DID wallets
1528
+ await time_out_assert(30, get_wallet_num, 1, wallet_node.wallet_state_manager)
1529
+ # Get the new DID wallets
1530
+ did_wallets = list(
1531
+ filter(
1532
+ lambda w: (w.type == WalletType.DECENTRALIZED_ID),
1533
+ await wallet_node_2.wallet_state_manager.get_all_wallet_info_entries(),
1342
1534
  )
1535
+ )
1343
1536
 
1344
- # Get the new DID wallet
1345
- did_wallets = list(
1346
- filter(
1347
- lambda w: (w.type == WalletType.DECENTRALIZED_ID),
1348
- await wallet_node_1.wallet_state_manager.get_all_wallet_info_entries(),
1349
- )
1537
+ assert len(did_wallets) == 10
1538
+ # Test we can use the DID
1539
+ did_wallet_10 = wallet_node_2.wallet_state_manager.get_wallet(id=uint32(did_wallets[9].id), required_type=DIDWallet)
1540
+ # Delete the coin and change inner puzzle
1541
+ coin = await did_wallet_10.get_coin()
1542
+ # origin_coin = did_wallet_10.did_info.origin_coin
1543
+ backup_data = did_wallet_10.create_backup()
1544
+ await wallet_node_2.wallet_state_manager.coin_store.delete_coin_record(coin.name())
1545
+ await time_out_assert(15, did_wallet_10.get_confirmed_balance, 0)
1546
+ await wallet_node_2.wallet_state_manager.user_store.delete_wallet(did_wallet_10.wallet_info.id)
1547
+ wallet_node_2.wallet_state_manager.wallets.pop(did_wallet_10.wallet_info.id)
1548
+ # Recover the coin
1549
+ async with wallet_node_2.wallet_state_manager.lock:
1550
+ did_wallet_10 = await DIDWallet.create_new_did_wallet_from_recovery(
1551
+ wallet_node_2.wallet_state_manager,
1552
+ wallet2,
1553
+ backup_data,
1350
1554
  )
1351
- did_wallet_2 = wallet_node_1.wallet_state_manager.wallets[did_wallets[0].id]
1352
- assert isinstance(did_wallet_2, DIDWallet) # mypy
1353
- assert len(wallet_node_0.wallet_state_manager.wallets) == 1
1354
- assert did_wallet_1.did_info.origin_coin == did_wallet_2.did_info.origin_coin
1355
- if with_recovery:
1356
- assert did_wallet_1.did_info.backup_ids[0] == did_wallet_2.did_info.backup_ids[0]
1357
- assert did_wallet_1.did_info.num_of_backup_ids_needed == did_wallet_2.did_info.num_of_backup_ids_needed
1358
- metadata = json.loads(did_wallet_2.did_info.metadata)
1359
- assert metadata["Twitter"] == "Test"
1360
- assert metadata["GitHub"] == "测试"
1361
-
1362
- # Test match_hinted_coin
1363
- assert await did_wallet_2.match_hinted_coin(
1364
- await did_wallet_2.get_coin(),
1365
- new_puzhash,
1555
+ assert did_wallet_10.did_info.origin_coin is not None
1556
+ await api_1.did_find_lost_did({"coin_id": did_wallet_10.did_info.origin_coin.name().hex()})
1557
+ await time_out_assert(15, did_wallet_10.get_confirmed_balance, 101)
1558
+ await time_out_assert(15, did_wallet_10.get_unconfirmed_balance, 101)
1559
+
1560
+ # Check we can recover an auto-discarded DID
1561
+ did_wallet_9 = wallet_node_2.wallet_state_manager.get_wallet(id=uint32(did_wallets[8].id), required_type=DIDWallet)
1562
+ # Delete the coin and wallet to make space for a auto-discarded DID
1563
+ coin = await did_wallet_9.get_coin()
1564
+ await wallet_node_2.wallet_state_manager.coin_store.delete_coin_record(coin.name())
1565
+ await time_out_assert(15, did_wallet_9.get_confirmed_balance, 0)
1566
+ await wallet_node_2.wallet_state_manager.user_store.delete_wallet(did_wallet_9.wallet_info.id)
1567
+ wallet_node_2.wallet_state_manager.wallets.pop(did_wallet_9.wallet_info.id)
1568
+
1569
+ did_wallets = list(
1570
+ filter(
1571
+ lambda w: (w.type == WalletType.DECENTRALIZED_ID),
1572
+ await wallet_node_2.wallet_state_manager.get_all_wallet_info_entries(),
1366
1573
  )
1367
-
1368
- @pytest.mark.parametrize(
1369
- "trusted",
1370
- [True, False],
1371
1574
  )
1372
- @pytest.mark.anyio
1373
- async def test_did_auto_transfer_limit(
1374
- self,
1375
- self_hostname: str,
1376
- two_wallet_nodes: tuple[list[FullNodeSimulator], list[tuple[WalletNode, ChiaServer]], BlockTools],
1377
- trusted: bool,
1378
- ) -> None:
1379
- fee = uint64(1000)
1380
- full_nodes, wallets, _ = two_wallet_nodes
1381
- full_node_api = full_nodes[0]
1382
- server_1 = full_node_api.server
1383
- wallet_node, server_2 = wallets[0]
1384
- wallet_node_2, server_3 = wallets[1]
1385
- wallet = wallet_node.wallet_state_manager.main_wallet
1386
- wallet2 = wallet_node_2.wallet_state_manager.main_wallet
1387
- api_1 = WalletRpcApi(wallet_node_2)
1388
- ph = await wallet.get_new_puzzlehash()
1389
-
1390
- if trusted:
1391
- wallet_node.config["trusted_peers"] = {
1392
- full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
1393
- }
1394
- wallet_node_2.config["trusted_peers"] = {
1395
- full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
1396
- }
1397
- else:
1398
- wallet_node.config["trusted_peers"] = {}
1399
- wallet_node_2.config["trusted_peers"] = {}
1400
-
1401
- await server_2.start_client(PeerInfo(self_hostname, server_1.get_port()), None)
1402
- await server_3.start_client(PeerInfo(self_hostname, server_1.get_port()), None)
1403
- await full_node_api.farm_blocks_to_wallet(1, wallet)
1404
-
1405
- # Check that we cap out at 10 DID Wallets automatically created upon transfer received
1406
- for i in range(0, 14):
1407
- async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1408
- did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
1409
- wallet_node.wallet_state_manager,
1410
- wallet,
1411
- uint64(101),
1412
- action_scope,
1413
- [bytes32(bytes(ph))],
1414
- uint64(1),
1415
- {"Twitter": "Test", "GitHub": "测试"},
1416
- fee=fee,
1417
- )
1418
- assert did_wallet_1.get_name() == "Profile 1"
1419
- await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
1420
- await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node, wallet_node_2])
1421
- await time_out_assert(15, did_wallet_1.get_confirmed_balance, 101)
1422
- await time_out_assert(15, did_wallet_1.get_unconfirmed_balance, 101)
1423
- # Transfer DID
1424
- assert did_wallet_1.did_info.origin_coin is not None
1425
- origin_coin = did_wallet_1.did_info.origin_coin
1426
- new_puzhash = await wallet2.get_new_puzzlehash()
1427
- async with did_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1428
- await did_wallet_1.transfer_did(new_puzhash, fee, False, action_scope)
1429
- await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
1430
- await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node, wallet_node_2])
1431
- # Check if the DID wallet is created in the wallet2
1432
-
1433
- await time_out_assert(
1434
- 30, get_wallet_num, min(2 + i, 11), wallet_node_2.wallet_state_manager
1435
- ) # check we haven't made more than 10 DID wallets
1436
- await time_out_assert(30, get_wallet_num, 1, wallet_node.wallet_state_manager)
1437
- # Get the new DID wallets
1438
- did_wallets = list(
1439
- filter(
1440
- lambda w: (w.type == WalletType.DECENTRALIZED_ID),
1441
- await wallet_node_2.wallet_state_manager.get_all_wallet_info_entries(),
1442
- )
1575
+ assert len(did_wallets) == 9
1576
+
1577
+ # Try and find lost coin
1578
+ await api_1.did_find_lost_did({"coin_id": origin_coin.name().hex()})
1579
+ did_wallets = list(
1580
+ filter(
1581
+ lambda w: (w.type == WalletType.DECENTRALIZED_ID),
1582
+ await wallet_node_2.wallet_state_manager.get_all_wallet_info_entries(),
1443
1583
  )
1444
-
1445
- assert len(did_wallets) == 10
1446
- # Test we can use the DID
1447
- did_wallet_10 = wallet_node_2.wallet_state_manager.get_wallet(
1448
- id=uint32(did_wallets[9].id), required_type=DIDWallet
1449
- )
1450
- # Delete the coin and change inner puzzle
1451
- coin = await did_wallet_10.get_coin()
1452
- # origin_coin = did_wallet_10.did_info.origin_coin
1453
- backup_data = did_wallet_10.create_backup()
1454
- await wallet_node_2.wallet_state_manager.coin_store.delete_coin_record(coin.name())
1455
- await time_out_assert(15, did_wallet_10.get_confirmed_balance, 0)
1456
- await wallet_node_2.wallet_state_manager.user_store.delete_wallet(did_wallet_10.wallet_info.id)
1457
- wallet_node_2.wallet_state_manager.wallets.pop(did_wallet_10.wallet_info.id)
1458
- # Recover the coin
1459
- async with wallet_node_2.wallet_state_manager.lock:
1460
- did_wallet_10 = await DIDWallet.create_new_did_wallet_from_recovery(
1461
- wallet_node_2.wallet_state_manager,
1462
- wallet2,
1463
- backup_data,
1464
- )
1465
- assert did_wallet_10.did_info.origin_coin is not None
1466
- resp = await api_1.did_find_lost_did({"coin_id": did_wallet_10.did_info.origin_coin.name().hex()})
1467
- assert resp["success"]
1468
- await time_out_assert(15, did_wallet_10.get_confirmed_balance, 101)
1469
- await time_out_assert(15, did_wallet_10.get_unconfirmed_balance, 101)
1470
-
1471
- # Check we can recover an auto-discarded DID
1472
- did_wallet_9 = wallet_node_2.wallet_state_manager.get_wallet(
1473
- id=uint32(did_wallets[8].id), required_type=DIDWallet
1584
+ )
1585
+ assert len(did_wallets) == 10
1586
+
1587
+ # Check we can still manually add new DIDs while at cap
1588
+ await full_node_api.farm_blocks_to_wallet(1, wallet2)
1589
+ async with wallet2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1590
+ ph = await action_scope.get_puzzle_hash(wallet2.wallet_state_manager)
1591
+ did_wallet_11: DIDWallet = await DIDWallet.create_new_did_wallet(
1592
+ wallet_node_2.wallet_state_manager,
1593
+ wallet2,
1594
+ uint64(101),
1595
+ action_scope,
1596
+ [bytes32(bytes(ph))],
1597
+ uint64(1),
1598
+ {"Twitter": "Test", "GitHub": "测试"},
1599
+ fee=fee,
1474
1600
  )
1475
- # Delete the coin and wallet to make space for a auto-discarded DID
1476
- coin = await did_wallet_9.get_coin()
1477
- await wallet_node_2.wallet_state_manager.coin_store.delete_coin_record(coin.name())
1478
- await time_out_assert(15, did_wallet_9.get_confirmed_balance, 0)
1479
- await wallet_node_2.wallet_state_manager.user_store.delete_wallet(did_wallet_9.wallet_info.id)
1480
- wallet_node_2.wallet_state_manager.wallets.pop(did_wallet_9.wallet_info.id)
1481
-
1482
- did_wallets = list(
1483
- filter(
1484
- lambda w: (w.type == WalletType.DECENTRALIZED_ID),
1485
- await wallet_node_2.wallet_state_manager.get_all_wallet_info_entries(),
1486
- )
1601
+ await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
1602
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node, wallet_node_2])
1603
+ await time_out_assert(15, did_wallet_11.get_confirmed_balance, 101)
1604
+ await time_out_assert(15, did_wallet_11.get_unconfirmed_balance, 101)
1605
+
1606
+ did_wallets = list(
1607
+ filter(
1608
+ lambda w: (w.type == WalletType.DECENTRALIZED_ID),
1609
+ await wallet_node_2.wallet_state_manager.get_all_wallet_info_entries(),
1487
1610
  )
1488
- assert len(did_wallets) == 9
1489
-
1490
- # Try and find lost coin
1491
- resp = await api_1.did_find_lost_did({"coin_id": origin_coin.name().hex()})
1492
- did_wallets = list(
1493
- filter(
1494
- lambda w: (w.type == WalletType.DECENTRALIZED_ID),
1495
- await wallet_node_2.wallet_state_manager.get_all_wallet_info_entries(),
1496
- )
1611
+ )
1612
+ assert len(did_wallets) == 11
1613
+
1614
+
1615
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1616
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
1617
+ @pytest.mark.parametrize(
1618
+ "use_alternate_recovery",
1619
+ [True, False],
1620
+ )
1621
+ @pytest.mark.anyio
1622
+ async def test_update_recovery_list(wallet_environments: WalletTestFramework, use_alternate_recovery: bool):
1623
+ env = wallet_environments.environments[0]
1624
+ wallet_node = env.node
1625
+ wallet = env.xch_wallet
1626
+
1627
+ env.wallet_aliases = {
1628
+ "xch": 1,
1629
+ "did": 2,
1630
+ }
1631
+
1632
+ async with wallet.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1633
+ ph = await action_scope.get_puzzle_hash(wallet.wallet_state_manager)
1634
+ did_wallet_1: DIDWallet = await make_did_wallet(
1635
+ wallet_node.wallet_state_manager,
1636
+ wallet,
1637
+ uint64(101),
1638
+ action_scope,
1639
+ use_alternate_recovery=use_alternate_recovery,
1497
1640
  )
1498
- assert len(did_wallets) == 10
1499
1641
 
1500
- # Check we can still manually add new DIDs while at cap
1501
- await full_node_api.farm_blocks_to_wallet(1, wallet2)
1502
- ph = await wallet2.get_new_puzzlehash()
1503
- async with wallet2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1504
- did_wallet_11: DIDWallet = await DIDWallet.create_new_did_wallet(
1505
- wallet_node_2.wallet_state_manager,
1506
- wallet2,
1507
- uint64(101),
1508
- action_scope,
1509
- [bytes32(bytes(ph))],
1510
- uint64(1),
1511
- {"Twitter": "Test", "GitHub": "测试"},
1512
- fee=fee,
1513
- )
1514
- await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
1515
- await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node, wallet_node_2])
1516
- await time_out_assert(15, did_wallet_11.get_confirmed_balance, 101)
1517
- await time_out_assert(15, did_wallet_11.get_unconfirmed_balance, 101)
1642
+ await wallet_environments.process_pending_states(
1643
+ [
1644
+ WalletStateTransition(
1645
+ pre_block_balance_updates={
1646
+ "xch": {
1647
+ "set_remainder": True,
1648
+ },
1649
+ "did": {
1650
+ "init": True,
1651
+ "unconfirmed_wallet_balance": 101,
1652
+ "pending_change": 101,
1653
+ "pending_coin_removal_count": 1,
1654
+ },
1655
+ },
1656
+ post_block_balance_updates={
1657
+ "xch": {
1658
+ "set_remainder": True,
1659
+ },
1660
+ "did": {
1661
+ "confirmed_wallet_balance": 101,
1662
+ "spendable_balance": 101,
1663
+ "max_send_amount": 101,
1664
+ "unspent_coin_count": 1,
1665
+ "pending_change": -101,
1666
+ "pending_coin_removal_count": -1,
1667
+ },
1668
+ },
1669
+ ),
1670
+ ]
1671
+ )
1672
+ await did_wallet_1.update_recovery_list([ph], uint64(1))
1673
+ async with did_wallet_1.wallet_state_manager.new_action_scope(
1674
+ wallet_environments.tx_config, push=True
1675
+ ) as action_scope:
1676
+ await did_wallet_1.create_update_spend(action_scope)
1518
1677
 
1519
- did_wallets = list(
1520
- filter(
1521
- lambda w: (w.type == WalletType.DECENTRALIZED_ID),
1522
- await wallet_node_2.wallet_state_manager.get_all_wallet_info_entries(),
1523
- )
1678
+ await wallet_environments.process_pending_states(
1679
+ [
1680
+ WalletStateTransition(
1681
+ pre_block_balance_updates={
1682
+ "did": {
1683
+ "set_remainder": True,
1684
+ },
1685
+ },
1686
+ post_block_balance_updates={
1687
+ "did": {
1688
+ "set_remainder": True,
1689
+ },
1690
+ },
1691
+ ),
1692
+ ]
1693
+ )
1694
+ assert did_wallet_1.did_info.backup_ids[0] == bytes(ph)
1695
+ assert did_wallet_1.did_info.num_of_backup_ids_needed == 1
1696
+
1697
+
1698
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1699
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 2, "blocks_needed": [1, 1]}], indirect=True)
1700
+ @pytest.mark.parametrize(
1701
+ "use_alternate_recovery",
1702
+ [True, False],
1703
+ )
1704
+ @pytest.mark.anyio
1705
+ async def test_get_info(wallet_environments: WalletTestFramework, use_alternate_recovery: bool):
1706
+ env_0 = wallet_environments.environments[0]
1707
+ env_1 = wallet_environments.environments[1]
1708
+ wallet_node_0 = env_0.node
1709
+ wallet_0 = env_0.xch_wallet
1710
+ wallet_1 = env_1.xch_wallet
1711
+ api_0 = env_0.rpc_client
1712
+
1713
+ env_0.wallet_aliases = {
1714
+ "xch": 1,
1715
+ "did": 2,
1716
+ }
1717
+ env_1.wallet_aliases = {
1718
+ "xch": 1,
1719
+ "did": 2,
1720
+ }
1721
+
1722
+ fee = uint64(1000)
1723
+ did_amount = uint64(101)
1724
+ async with wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1725
+ ph_1 = await action_scope.get_puzzle_hash(wallet_1.wallet_state_manager)
1726
+
1727
+ async with wallet_0.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1728
+ did_wallet_1: DIDWallet = await make_did_wallet(
1729
+ wallet_node_0.wallet_state_manager,
1730
+ wallet_0,
1731
+ did_amount,
1732
+ action_scope,
1733
+ [],
1734
+ metadata={"twitter": "twitter"},
1735
+ fee=fee,
1736
+ use_alternate_recovery=use_alternate_recovery,
1524
1737
  )
1525
- assert len(did_wallets) == 11
1526
-
1527
- @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1528
- @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
1529
- @pytest.mark.anyio
1530
- async def test_update_recovery_list(self, wallet_environments: WalletTestFramework):
1531
- env = wallet_environments.environments[0]
1532
- wallet_node = env.node
1533
- wallet = env.xch_wallet
1534
-
1535
- env.wallet_aliases = {
1536
- "xch": 1,
1537
- "did": 2,
1538
- }
1539
1738
 
1540
- ph = await wallet.get_new_puzzlehash()
1739
+ await wallet_environments.process_pending_states(
1740
+ [
1741
+ WalletStateTransition(
1742
+ pre_block_balance_updates={
1743
+ "xch": {
1744
+ "set_remainder": True,
1745
+ },
1746
+ "did": {
1747
+ "init": True,
1748
+ "unconfirmed_wallet_balance": did_amount,
1749
+ "pending_change": did_amount,
1750
+ "pending_coin_removal_count": 1,
1751
+ },
1752
+ },
1753
+ post_block_balance_updates={
1754
+ "xch": {
1755
+ "set_remainder": True,
1756
+ },
1757
+ "did": {
1758
+ "confirmed_wallet_balance": did_amount,
1759
+ "spendable_balance": did_amount,
1760
+ "max_send_amount": did_amount,
1761
+ "unspent_coin_count": 1,
1762
+ "pending_change": -did_amount,
1763
+ "pending_coin_removal_count": -1,
1764
+ },
1765
+ },
1766
+ ),
1767
+ WalletStateTransition(),
1768
+ ]
1769
+ )
1770
+ assert did_wallet_1.did_info.origin_coin is not None # mypy
1771
+ coin_id_as_bech32 = encode_puzzle_hash(did_wallet_1.did_info.origin_coin.name(), AddressType.DID.value)
1772
+ response = await api_0.get_did_info(DIDGetInfo(did_wallet_1.did_info.origin_coin.name().hex()))
1773
+ response_with_bech32 = await api_0.get_did_info(DIDGetInfo(coin_id_as_bech32))
1774
+ assert response == response_with_bech32
1775
+ assert response.did_id == coin_id_as_bech32
1776
+ assert response.launcher_id == did_wallet_1.did_info.origin_coin.name()
1777
+ assert did_wallet_1.did_info.current_inner is not None # mypy
1778
+ assert response.full_puzzle == create_singleton_puzzle(
1779
+ did_wallet_1.did_info.current_inner, did_wallet_1.did_info.origin_coin.name()
1780
+ )
1781
+ assert response.metadata["twitter"] == "twitter"
1782
+ assert response.latest_coin == (await did_wallet_1.get_coin()).name()
1783
+ assert response.num_verification == 0
1784
+ if use_alternate_recovery:
1785
+ assert response.recovery_list_hash is None
1786
+ else:
1787
+ assert response.recovery_list_hash == Program(Program.to([])).get_tree_hash()
1788
+ assert decode_puzzle_hash(response.p2_address) == response.hints[0]
1789
+
1790
+ # Test non-singleton coin
1791
+ async with wallet_0.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1792
+ coin = (await wallet_0.select_coins(uint64(1), action_scope)).pop()
1793
+ assert coin.amount % 2 == 1
1794
+ coin_id = coin.name()
1795
+ with pytest.raises(ValueError, match="The coin is not a DID."):
1796
+ await api_0.get_did_info(DIDGetInfo(coin_id.hex()))
1797
+
1798
+ # Test multiple odd coins
1799
+ odd_amount = uint64(1)
1800
+ async with wallet_0.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1801
+ async with action_scope.use() as interface:
1802
+ interface.side_effects.selected_coins.append(coin)
1803
+ coin_1 = (await wallet_0.select_coins(odd_amount, action_scope)).pop()
1804
+ assert coin_1.amount % 2 == 0
1805
+ async with wallet_0.wallet_state_manager.new_action_scope(
1806
+ wallet_environments.tx_config.override(excluded_coin_ids=[coin_id]), push=True
1807
+ ) as action_scope:
1808
+ await wallet_0.generate_signed_transaction([odd_amount], [ph_1], action_scope, fee)
1809
+
1810
+ await wallet_environments.process_pending_states(
1811
+ [
1812
+ WalletStateTransition(
1813
+ pre_block_balance_updates={
1814
+ "xch": {
1815
+ "unconfirmed_wallet_balance": -odd_amount - fee,
1816
+ "set_remainder": True,
1817
+ },
1818
+ "did": {
1819
+ "set_remainder": True,
1820
+ },
1821
+ },
1822
+ post_block_balance_updates={
1823
+ "xch": {
1824
+ "confirmed_wallet_balance": -odd_amount - fee,
1825
+ "set_remainder": True,
1826
+ },
1827
+ "did": {
1828
+ "set_remainder": True,
1829
+ },
1830
+ },
1831
+ ),
1832
+ WalletStateTransition(
1833
+ pre_block_balance_updates={
1834
+ "xch": {
1835
+ "unconfirmed_wallet_balance": 0,
1836
+ "set_remainder": True,
1837
+ }
1838
+ },
1839
+ post_block_balance_updates={
1840
+ "xch": {
1841
+ "confirmed_wallet_balance": odd_amount,
1842
+ "set_remainder": True,
1843
+ }
1844
+ },
1845
+ ),
1846
+ ]
1847
+ )
1848
+
1849
+ with pytest.raises(ValueError, match="This is not a singleton, multiple children coins found."):
1850
+ await api_0.get_did_info(DIDGetInfo(coin_1.name().hex()))
1541
1851
 
1542
- async with wallet.wallet_state_manager.new_action_scope(
1543
- wallet_environments.tx_config, push=True
1544
- ) as action_scope:
1545
- did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
1546
- wallet_node.wallet_state_manager, wallet, uint64(101), action_scope, []
1547
- )
1548
1852
 
1549
- await wallet_environments.process_pending_states(
1550
- [
1551
- WalletStateTransition(
1552
- pre_block_balance_updates={
1553
- "xch": {
1554
- "set_remainder": True,
1555
- },
1556
- "did": {
1557
- "init": True,
1558
- "unconfirmed_wallet_balance": 101,
1559
- "pending_change": 101,
1560
- "pending_coin_removal_count": 1,
1561
- },
1853
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1854
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
1855
+ @pytest.mark.parametrize(
1856
+ "use_alternate_recovery",
1857
+ [True, False],
1858
+ )
1859
+ @pytest.mark.anyio
1860
+ async def test_message_spend(wallet_environments: WalletTestFramework, use_alternate_recovery: bool):
1861
+ env = wallet_environments.environments[0]
1862
+ wallet_node = env.node
1863
+ wallet = env.xch_wallet
1864
+ api_0 = env.rpc_api
1865
+
1866
+ env.wallet_aliases = {
1867
+ "xch": 1,
1868
+ "did": 2,
1869
+ }
1870
+
1871
+ fee = uint64(1000)
1872
+
1873
+ async with wallet.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1874
+ did_wallet_1: DIDWallet = await make_did_wallet(
1875
+ wallet_node.wallet_state_manager,
1876
+ wallet,
1877
+ uint64(101),
1878
+ action_scope,
1879
+ [],
1880
+ fee=fee,
1881
+ use_alternate_recovery=use_alternate_recovery,
1882
+ )
1883
+ await wallet_environments.process_pending_states(
1884
+ [
1885
+ WalletStateTransition(
1886
+ pre_block_balance_updates={
1887
+ "xch": {
1888
+ "set_remainder": True,
1562
1889
  },
1563
- post_block_balance_updates={
1564
- "xch": {
1565
- "set_remainder": True,
1566
- },
1567
- "did": {
1568
- "confirmed_wallet_balance": 101,
1569
- "spendable_balance": 101,
1570
- "max_send_amount": 101,
1571
- "unspent_coin_count": 1,
1572
- "pending_change": -101,
1573
- "pending_coin_removal_count": -1,
1574
- },
1890
+ "did": {
1891
+ "init": True,
1892
+ "unconfirmed_wallet_balance": 101,
1893
+ "pending_change": 101,
1894
+ "pending_coin_removal_count": 1,
1575
1895
  },
1576
- ),
1577
- ]
1578
- )
1579
- await did_wallet_1.update_recovery_list([ph], uint64(1))
1580
- async with did_wallet_1.wallet_state_manager.new_action_scope(
1581
- wallet_environments.tx_config, push=True
1582
- ) as action_scope:
1583
- await did_wallet_1.create_update_spend(action_scope)
1584
-
1585
- await wallet_environments.process_pending_states(
1586
- [
1587
- WalletStateTransition(
1588
- pre_block_balance_updates={
1589
- "did": {
1590
- "set_remainder": True,
1591
- },
1896
+ },
1897
+ post_block_balance_updates={
1898
+ "xch": {
1899
+ "set_remainder": True,
1592
1900
  },
1593
- post_block_balance_updates={
1594
- "did": {
1595
- "set_remainder": True,
1596
- },
1901
+ "did": {
1902
+ "confirmed_wallet_balance": 101,
1903
+ "spendable_balance": 101,
1904
+ "max_send_amount": 101,
1905
+ "unspent_coin_count": 1,
1906
+ "pending_change": -101,
1907
+ "pending_coin_removal_count": -1,
1597
1908
  },
1598
- ),
1599
- ]
1600
- )
1601
- assert did_wallet_1.did_info.backup_ids[0] == bytes(ph)
1602
- assert did_wallet_1.did_info.num_of_backup_ids_needed == 1
1603
-
1604
- @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1605
- @pytest.mark.parametrize("wallet_environments", [{"num_environments": 2, "blocks_needed": [1, 1]}], indirect=True)
1606
- @pytest.mark.anyio
1607
- async def test_get_info(self, wallet_environments: WalletTestFramework):
1608
- env_0 = wallet_environments.environments[0]
1609
- env_1 = wallet_environments.environments[1]
1610
- wallet_node_0 = env_0.node
1611
- wallet_0 = env_0.xch_wallet
1612
- wallet_1 = env_1.xch_wallet
1613
- api_0 = env_0.rpc_api
1614
-
1615
- env_0.wallet_aliases = {
1616
- "xch": 1,
1617
- "did": 2,
1618
- }
1619
- env_1.wallet_aliases = {
1620
- "xch": 1,
1621
- "did": 2,
1622
- }
1909
+ },
1910
+ ),
1911
+ ]
1912
+ )
1913
+ response = await api_0.did_message_spend(
1914
+ {"wallet_id": did_wallet_1.wallet_id, "coin_announcements": ["0abc"], "puzzle_announcements": ["0def"]}
1915
+ )
1916
+ spend = response["spend_bundle"].coin_spends[0]
1917
+ conditions = conditions_dict_for_solution(
1918
+ spend.puzzle_reveal, spend.solution, wallet.wallet_state_manager.constants.MAX_BLOCK_COST_CLVM
1919
+ )
1623
1920
 
1624
- fee = uint64(1000)
1625
- did_amount = uint64(101)
1626
- ph_1 = await wallet_1.get_new_puzzlehash()
1921
+ assert len(conditions[ConditionOpcode.CREATE_COIN_ANNOUNCEMENT]) == 1
1922
+ assert conditions[ConditionOpcode.CREATE_COIN_ANNOUNCEMENT][0].vars[0].hex() == "0abc"
1923
+ assert len(conditions[ConditionOpcode.CREATE_PUZZLE_ANNOUNCEMENT]) == 1
1924
+ assert conditions[ConditionOpcode.CREATE_PUZZLE_ANNOUNCEMENT][0].vars[0].hex() == "0def"
1627
1925
 
1628
- async with wallet_0.wallet_state_manager.new_action_scope(
1629
- wallet_environments.tx_config, push=True
1630
- ) as action_scope:
1631
- did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
1632
- wallet_node_0.wallet_state_manager,
1633
- wallet_0,
1634
- did_amount,
1635
- action_scope,
1636
- [],
1637
- metadata={"twitter": "twitter"},
1638
- fee=fee,
1639
- )
1640
1926
 
1641
- await wallet_environments.process_pending_states(
1642
- [
1643
- WalletStateTransition(
1644
- pre_block_balance_updates={
1645
- "xch": {
1646
- "set_remainder": True,
1647
- },
1648
- "did": {
1649
- "init": True,
1650
- "unconfirmed_wallet_balance": did_amount,
1651
- "pending_change": did_amount,
1652
- "pending_coin_removal_count": 1,
1653
- },
1654
- },
1655
- post_block_balance_updates={
1656
- "xch": {
1657
- "set_remainder": True,
1658
- },
1659
- "did": {
1660
- "confirmed_wallet_balance": did_amount,
1661
- "spendable_balance": did_amount,
1662
- "max_send_amount": did_amount,
1663
- "unspent_coin_count": 1,
1664
- "pending_change": -did_amount,
1665
- "pending_coin_removal_count": -1,
1666
- },
1667
- },
1668
- ),
1669
- WalletStateTransition(),
1670
- ]
1671
- )
1672
- assert did_wallet_1.did_info.origin_coin is not None # mypy
1673
- response = await api_0.did_get_info({"coin_id": did_wallet_1.did_info.origin_coin.name().hex()})
1674
- assert response["did_id"] == encode_puzzle_hash(did_wallet_1.did_info.origin_coin.name(), AddressType.DID.value)
1675
- assert response["launcher_id"] == did_wallet_1.did_info.origin_coin.name().hex()
1676
- assert did_wallet_1.did_info.current_inner is not None # mypy
1677
- assert response["full_puzzle"].to_program() == create_singleton_puzzle(
1678
- did_wallet_1.did_info.current_inner, did_wallet_1.did_info.origin_coin.name()
1927
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1928
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
1929
+ @pytest.mark.parametrize(
1930
+ "use_alternate_recovery",
1931
+ [True, False],
1932
+ )
1933
+ @pytest.mark.anyio
1934
+ async def test_update_metadata(wallet_environments: WalletTestFramework, use_alternate_recovery: bool):
1935
+ env = wallet_environments.environments[0]
1936
+ wallet_node = env.node
1937
+ wallet = env.xch_wallet
1938
+
1939
+ env.wallet_aliases = {
1940
+ "xch": 1,
1941
+ "did": 2,
1942
+ }
1943
+
1944
+ fee = uint64(1000)
1945
+ did_amount = uint64(101)
1946
+
1947
+ async with wallet.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1948
+ did_wallet_1: DIDWallet = await make_did_wallet(
1949
+ wallet_node.wallet_state_manager,
1950
+ wallet,
1951
+ did_amount,
1952
+ action_scope,
1953
+ [],
1954
+ fee=fee,
1955
+ use_alternate_recovery=use_alternate_recovery,
1679
1956
  )
1680
- assert response["metadata"]["twitter"] == "twitter"
1681
- assert response["latest_coin"] == (await did_wallet_1.get_coin()).name().hex()
1682
- assert response["num_verification"] == 0
1683
- assert response["recovery_list_hash"] == Program(Program.to([])).get_tree_hash().hex()
1684
- assert decode_puzzle_hash(response["p2_address"]).hex() == response["hints"][0]
1685
-
1686
- # Test non-singleton coin
1687
- async with wallet_0.wallet_state_manager.new_action_scope(
1688
- wallet_environments.tx_config, push=True
1689
- ) as action_scope:
1690
- coin = (await wallet_0.select_coins(uint64(1), action_scope)).pop()
1691
- assert coin.amount % 2 == 1
1692
- coin_id = coin.name()
1693
- response = await api_0.did_get_info({"coin_id": coin_id.hex()})
1694
- assert not response["success"]
1695
-
1696
- # Test multiple odd coins
1697
- odd_amount = uint64(1)
1698
- async with wallet_0.wallet_state_manager.new_action_scope(
1699
- wallet_environments.tx_config, push=True
1700
- ) as action_scope:
1701
- async with action_scope.use() as interface:
1702
- interface.side_effects.selected_coins.append(coin)
1703
- coin_1 = (await wallet_0.select_coins(odd_amount, action_scope)).pop()
1704
- assert coin_1.amount % 2 == 0
1705
- async with wallet_0.wallet_state_manager.new_action_scope(
1706
- wallet_environments.tx_config.override(excluded_coin_ids=[coin_id]), push=True
1707
- ) as action_scope:
1708
- await wallet_0.generate_signed_transaction([odd_amount], [ph_1], action_scope, fee)
1709
1957
 
1710
- await wallet_environments.process_pending_states(
1711
- [
1712
- WalletStateTransition(
1713
- pre_block_balance_updates={
1714
- "xch": {
1715
- "unconfirmed_wallet_balance": -odd_amount - fee,
1716
- "set_remainder": True,
1717
- },
1718
- "did": {
1719
- "set_remainder": True,
1720
- },
1958
+ await wallet_environments.process_pending_states(
1959
+ [
1960
+ WalletStateTransition(
1961
+ pre_block_balance_updates={
1962
+ "xch": {
1963
+ "set_remainder": True,
1721
1964
  },
1722
- post_block_balance_updates={
1723
- "xch": {
1724
- "confirmed_wallet_balance": -odd_amount - fee,
1725
- "set_remainder": True,
1726
- },
1727
- "did": {
1728
- "set_remainder": True,
1729
- },
1965
+ "did": {
1966
+ "init": True,
1967
+ "unconfirmed_wallet_balance": 101,
1968
+ "pending_change": 101,
1969
+ "pending_coin_removal_count": 1,
1730
1970
  },
1731
- ),
1732
- WalletStateTransition(
1733
- pre_block_balance_updates={
1734
- "xch": {
1735
- "unconfirmed_wallet_balance": 0,
1736
- "set_remainder": True,
1737
- }
1971
+ },
1972
+ post_block_balance_updates={
1973
+ "xch": {
1974
+ "set_remainder": True,
1738
1975
  },
1739
- post_block_balance_updates={
1740
- "xch": {
1741
- "confirmed_wallet_balance": odd_amount,
1742
- "set_remainder": True,
1743
- }
1976
+ "did": {
1977
+ "confirmed_wallet_balance": 101,
1978
+ "spendable_balance": 101,
1979
+ "max_send_amount": 101,
1980
+ "unspent_coin_count": 1,
1981
+ "pending_change": -101,
1982
+ "pending_coin_removal_count": -1,
1744
1983
  },
1745
- ),
1746
- ]
1747
- )
1984
+ },
1985
+ ),
1986
+ ]
1987
+ )
1748
1988
 
1749
- with pytest.raises(ValueError):
1750
- await api_0.did_get_info({"coin_id": coin_1.name().hex()})
1751
-
1752
- @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1753
- @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
1754
- @pytest.mark.anyio
1755
- async def test_message_spend(self, wallet_environments: WalletTestFramework):
1756
- env = wallet_environments.environments[0]
1757
- wallet_node = env.node
1758
- wallet = env.xch_wallet
1759
- api_0 = env.rpc_api
1760
-
1761
- env.wallet_aliases = {
1762
- "xch": 1,
1763
- "did": 2,
1764
- }
1989
+ assert did_wallet_1.did_info.current_inner is not None # mypy
1990
+ puzhash = did_wallet_1.did_info.current_inner.get_tree_hash()
1991
+ parent_num = get_parent_num(did_wallet_1)
1765
1992
 
1766
- fee = uint64(1000)
1993
+ bad_metadata = {"Twitter": {"url": "http://www.twitter.com"}}
1994
+ with pytest.raises(ValueError) as e:
1995
+ await did_wallet_1.update_metadata(bad_metadata) # type: ignore
1996
+ assert e.match("Metadata key value pairs must be strings.")
1767
1997
 
1768
- async with wallet.wallet_state_manager.new_action_scope(
1769
- wallet_environments.tx_config, push=True
1770
- ) as action_scope:
1771
- did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
1772
- wallet_node.wallet_state_manager, wallet, uint64(101), action_scope, [], fee=fee
1773
- )
1774
- await wallet_environments.process_pending_states(
1775
- [
1776
- WalletStateTransition(
1777
- pre_block_balance_updates={
1778
- "xch": {
1779
- "set_remainder": True,
1780
- },
1781
- "did": {
1782
- "init": True,
1783
- "unconfirmed_wallet_balance": 101,
1784
- "pending_change": 101,
1785
- "pending_coin_removal_count": 1,
1786
- },
1998
+ metadata = {}
1999
+ metadata["Twitter"] = "http://www.twitter.com"
2000
+ await did_wallet_1.update_metadata(metadata)
2001
+ async with did_wallet_1.wallet_state_manager.new_action_scope(
2002
+ wallet_environments.tx_config, push=True
2003
+ ) as action_scope:
2004
+ await did_wallet_1.create_update_spend(action_scope, fee)
2005
+
2006
+ await wallet_environments.process_pending_states(
2007
+ [
2008
+ WalletStateTransition(
2009
+ pre_block_balance_updates={
2010
+ "xch": {
2011
+ "unconfirmed_wallet_balance": -fee,
2012
+ "set_remainder": True,
1787
2013
  },
1788
- post_block_balance_updates={
1789
- "xch": {
1790
- "set_remainder": True,
1791
- },
1792
- "did": {
1793
- "confirmed_wallet_balance": 101,
1794
- "spendable_balance": 101,
1795
- "max_send_amount": 101,
1796
- "unspent_coin_count": 1,
1797
- "pending_change": -101,
1798
- "pending_coin_removal_count": -1,
1799
- },
2014
+ "did": {
2015
+ "unconfirmed_wallet_balance": 0,
2016
+ "set_remainder": True,
1800
2017
  },
1801
- ),
1802
- ]
1803
- )
1804
- response = await api_0.did_message_spend(
1805
- {"wallet_id": did_wallet_1.wallet_id, "coin_announcements": ["0abc"], "puzzle_announcements": ["0def"]}
1806
- )
1807
- spend = response["spend_bundle"].coin_spends[0]
1808
- conditions = conditions_dict_for_solution(
1809
- spend.puzzle_reveal, spend.solution, wallet.wallet_state_manager.constants.MAX_BLOCK_COST_CLVM
1810
- )
2018
+ },
2019
+ post_block_balance_updates={
2020
+ "xch": {
2021
+ "confirmed_wallet_balance": -fee,
2022
+ "set_remainder": True,
2023
+ },
2024
+ "did": {
2025
+ "confirmed_wallet_balance": 0,
2026
+ "set_remainder": True,
2027
+ },
2028
+ },
2029
+ ),
2030
+ ]
2031
+ )
1811
2032
 
1812
- assert len(conditions[ConditionOpcode.CREATE_COIN_ANNOUNCEMENT]) == 1
1813
- assert conditions[ConditionOpcode.CREATE_COIN_ANNOUNCEMENT][0].vars[0].hex() == "0abc"
1814
- assert len(conditions[ConditionOpcode.CREATE_PUZZLE_ANNOUNCEMENT]) == 1
1815
- assert conditions[ConditionOpcode.CREATE_PUZZLE_ANNOUNCEMENT][0].vars[0].hex() == "0def"
1816
-
1817
- @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1818
- @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
1819
- @pytest.mark.anyio
1820
- async def test_update_metadata(self, wallet_environments: WalletTestFramework):
1821
- env = wallet_environments.environments[0]
1822
- wallet_node = env.node
1823
- wallet = env.xch_wallet
1824
-
1825
- env.wallet_aliases = {
1826
- "xch": 1,
1827
- "did": 2,
1828
- }
2033
+ assert get_parent_num(did_wallet_1) == parent_num + 2
2034
+ assert did_wallet_1.did_info.current_inner is not None # mypy
2035
+ assert puzhash != did_wallet_1.did_info.current_inner.get_tree_hash()
2036
+ assert did_wallet_1.did_info.metadata.find("Twitter") > 0
1829
2037
 
1830
- fee = uint64(1000)
1831
- did_amount = uint64(101)
1832
2038
 
1833
- async with wallet.wallet_state_manager.new_action_scope(
1834
- wallet_environments.tx_config, push=True
1835
- ) as action_scope:
1836
- did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
1837
- wallet_node.wallet_state_manager, wallet, did_amount, action_scope, [], fee=fee
1838
- )
2039
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
2040
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
2041
+ @pytest.mark.anyio
2042
+ async def test_did_sign_message(wallet_environments: WalletTestFramework):
2043
+ env = wallet_environments.environments[0]
2044
+ wallet_node = env.node
2045
+ wallet = env.xch_wallet
2046
+ api_0 = env.rpc_api
2047
+
2048
+ env.wallet_aliases = {
2049
+ "xch": 1,
2050
+ "did": 2,
2051
+ }
2052
+ fee = uint64(1000)
2053
+
2054
+ async with wallet.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
2055
+ ph = await action_scope.get_puzzle_hash(wallet.wallet_state_manager)
2056
+ did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
2057
+ wallet_node.wallet_state_manager,
2058
+ wallet,
2059
+ uint64(101),
2060
+ action_scope,
2061
+ [ph],
2062
+ uint64(1),
2063
+ {"Twitter": "Test", "GitHub": "测试"},
2064
+ fee=fee,
2065
+ )
2066
+ assert did_wallet_1.get_name() == "Profile 1"
1839
2067
 
1840
- await wallet_environments.process_pending_states(
1841
- [
1842
- WalletStateTransition(
1843
- pre_block_balance_updates={
1844
- "xch": {
1845
- "set_remainder": True,
1846
- },
1847
- "did": {
1848
- "init": True,
1849
- "unconfirmed_wallet_balance": 101,
1850
- "pending_change": 101,
1851
- "pending_coin_removal_count": 1,
1852
- },
2068
+ await wallet_environments.process_pending_states(
2069
+ [
2070
+ WalletStateTransition(
2071
+ pre_block_balance_updates={
2072
+ "xch": {
2073
+ "set_remainder": True,
1853
2074
  },
1854
- post_block_balance_updates={
1855
- "xch": {
1856
- "set_remainder": True,
1857
- },
1858
- "did": {
1859
- "confirmed_wallet_balance": 101,
1860
- "spendable_balance": 101,
1861
- "max_send_amount": 101,
1862
- "unspent_coin_count": 1,
1863
- "pending_change": -101,
1864
- "pending_coin_removal_count": -1,
1865
- },
2075
+ "did": {
2076
+ "init": True,
2077
+ "unconfirmed_wallet_balance": 101,
2078
+ "pending_change": 101,
2079
+ "pending_coin_removal_count": 1,
1866
2080
  },
1867
- ),
1868
- ]
1869
- )
2081
+ },
2082
+ post_block_balance_updates={
2083
+ "xch": {
2084
+ "set_remainder": True,
2085
+ },
2086
+ "did": {
2087
+ "confirmed_wallet_balance": 101,
2088
+ "spendable_balance": 101,
2089
+ "max_send_amount": 101,
2090
+ "unspent_coin_count": 1,
2091
+ "pending_change": -101,
2092
+ "pending_coin_removal_count": -1,
2093
+ },
2094
+ },
2095
+ ),
2096
+ ]
2097
+ )
2098
+ # Test general string
2099
+ assert did_wallet_1.did_info.origin_coin is not None # mypy
2100
+ message = "Hello World"
2101
+ assert did_wallet_1.did_info.origin_coin is not None
2102
+ response = await api_0.sign_message_by_id(
2103
+ {
2104
+ "id": encode_puzzle_hash(did_wallet_1.did_info.origin_coin.name(), AddressType.DID.value),
2105
+ "message": message,
2106
+ }
2107
+ )
2108
+ puzzle: Program = Program.to((CHIP_0002_SIGN_MESSAGE_PREFIX, message))
2109
+ assert AugSchemeMPL.verify(
2110
+ G1Element.from_bytes(bytes.fromhex(response["pubkey"])),
2111
+ puzzle.get_tree_hash(),
2112
+ G2Element.from_bytes(bytes.fromhex(response["signature"])),
2113
+ )
2114
+ # Test hex string
2115
+ message = "0123456789ABCDEF"
2116
+ response = await api_0.sign_message_by_id(
2117
+ {
2118
+ "id": encode_puzzle_hash(did_wallet_1.did_info.origin_coin.name(), AddressType.DID.value),
2119
+ "message": message,
2120
+ "is_hex": True,
2121
+ }
2122
+ )
2123
+ puzzle = Program.to((CHIP_0002_SIGN_MESSAGE_PREFIX, bytes.fromhex(message)))
1870
2124
 
1871
- assert did_wallet_1.did_info.current_inner is not None # mypy
1872
- puzhash = did_wallet_1.did_info.current_inner.get_tree_hash()
1873
- parent_num = get_parent_num(did_wallet_1)
2125
+ assert AugSchemeMPL.verify(
2126
+ G1Element.from_bytes(bytes.fromhex(response["pubkey"])),
2127
+ puzzle.get_tree_hash(),
2128
+ G2Element.from_bytes(bytes.fromhex(response["signature"])),
2129
+ )
1874
2130
 
1875
- bad_metadata = {"Twitter": {"url": "http://www.twitter.com"}}
1876
- with pytest.raises(ValueError) as e:
1877
- await did_wallet_1.update_metadata(bad_metadata) # type: ignore
1878
- assert e.match("Metadata key value pairs must be strings.")
2131
+ # Test BLS sign string
2132
+ message = "Hello World"
2133
+ assert did_wallet_1.did_info.origin_coin is not None
2134
+ response = await api_0.sign_message_by_id(
2135
+ {
2136
+ "id": encode_puzzle_hash(did_wallet_1.did_info.origin_coin.name(), AddressType.DID.value),
2137
+ "message": message,
2138
+ "is_hex": "False",
2139
+ "safe_mode": "False",
2140
+ }
2141
+ )
1879
2142
 
1880
- metadata = {}
1881
- metadata["Twitter"] = "http://www.twitter.com"
1882
- await did_wallet_1.update_metadata(metadata)
1883
- async with did_wallet_1.wallet_state_manager.new_action_scope(
1884
- wallet_environments.tx_config, push=True
1885
- ) as action_scope:
1886
- await did_wallet_1.create_update_spend(action_scope, fee)
2143
+ assert AugSchemeMPL.verify(
2144
+ G1Element.from_bytes(bytes.fromhex(response["pubkey"])),
2145
+ bytes(message, "utf-8"),
2146
+ G2Element.from_bytes(bytes.fromhex(response["signature"])),
2147
+ )
2148
+ # Test BLS sign hex
2149
+ message = "0123456789ABCDEF"
2150
+ assert did_wallet_1.did_info.origin_coin is not None
2151
+ response = await api_0.sign_message_by_id(
2152
+ {
2153
+ "id": encode_puzzle_hash(did_wallet_1.did_info.origin_coin.name(), AddressType.DID.value),
2154
+ "message": message,
2155
+ "is_hex": True,
2156
+ "safe_mode": False,
2157
+ }
2158
+ )
1887
2159
 
1888
- await wallet_environments.process_pending_states(
1889
- [
1890
- WalletStateTransition(
1891
- pre_block_balance_updates={
1892
- "xch": {
1893
- "unconfirmed_wallet_balance": -fee,
1894
- "set_remainder": True,
1895
- },
1896
- "did": {
1897
- "unconfirmed_wallet_balance": 0,
1898
- "set_remainder": True,
1899
- },
1900
- },
1901
- post_block_balance_updates={
1902
- "xch": {
1903
- "confirmed_wallet_balance": -fee,
1904
- "set_remainder": True,
1905
- },
1906
- "did": {
1907
- "confirmed_wallet_balance": 0,
1908
- "set_remainder": True,
1909
- },
1910
- },
1911
- ),
1912
- ]
1913
- )
2160
+ assert AugSchemeMPL.verify(
2161
+ G1Element.from_bytes(bytes.fromhex(response["pubkey"])),
2162
+ bytes.fromhex(message),
2163
+ G2Element.from_bytes(bytes.fromhex(response["signature"])),
2164
+ )
1914
2165
 
1915
- assert get_parent_num(did_wallet_1) == parent_num + 2
1916
- assert did_wallet_1.did_info.current_inner is not None # mypy
1917
- assert puzhash != did_wallet_1.did_info.current_inner.get_tree_hash()
1918
- assert did_wallet_1.did_info.metadata.find("Twitter") > 0
1919
-
1920
- @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1921
- @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
1922
- @pytest.mark.anyio
1923
- async def test_did_sign_message(self, wallet_environments: WalletTestFramework):
1924
- env = wallet_environments.environments[0]
1925
- wallet_node = env.node
1926
- wallet = env.xch_wallet
1927
- api_0 = env.rpc_api
1928
-
1929
- env.wallet_aliases = {
1930
- "xch": 1,
1931
- "did": 2,
1932
- }
1933
- fee = uint64(1000)
1934
- ph = await wallet.get_new_puzzlehash()
1935
2166
 
1936
- async with wallet.wallet_state_manager.new_action_scope(
1937
- wallet_environments.tx_config, push=True
1938
- ) as action_scope:
1939
- did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
1940
- wallet_node.wallet_state_manager,
1941
- wallet,
1942
- uint64(101),
1943
- action_scope,
1944
- [ph],
1945
- uint64(1),
1946
- {"Twitter": "Test", "GitHub": "测试"},
1947
- fee=fee,
1948
- )
1949
- assert did_wallet_1.get_name() == "Profile 1"
2167
+ @pytest.mark.parametrize(
2168
+ "trusted",
2169
+ [True, False],
2170
+ )
2171
+ @pytest.mark.anyio
2172
+ async def test_create_did_with_recovery_list(
2173
+ self_hostname: str, two_nodes_two_wallets_with_same_keys: OldSimulatorsAndWallets, trusted: bool
2174
+ ) -> None:
2175
+ """
2176
+ A DID is created on-chain in client0, causing a DID Wallet to be created in client1, which shares the same key.
2177
+ This can happen if someone uses the same key on multiple computers, or is syncing a wallet from scratch.
2178
+
2179
+ For this test, we assign a recovery list hash at DID creation time, but the recovery list is not yet available
2180
+ to the wallet_node that the DID Wallet is being created in (client1).
2181
+
2182
+ """
2183
+ full_nodes, wallets, _ = two_nodes_two_wallets_with_same_keys
2184
+ full_node_api = full_nodes[0]
2185
+ full_node_server = full_node_api.server
2186
+ wallet_node_0, server_0 = wallets[0]
2187
+ wallet_node_1, server_1 = wallets[1]
2188
+
2189
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
2190
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
2191
+
2192
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2193
+ ph0 = await action_scope.get_puzzle_hash(wallet_0.wallet_state_manager)
2194
+ async with wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2195
+ ph1 = await action_scope.get_puzzle_hash(wallet_1.wallet_state_manager)
2196
+
2197
+ sk0 = await wallet_node_0.wallet_state_manager.get_private_key(ph0)
2198
+ sk1 = await wallet_node_1.wallet_state_manager.get_private_key(ph1)
2199
+ assert sk0 == sk1
2200
+
2201
+ if trusted:
2202
+ wallet_node_0.config["trusted_peers"] = {
2203
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
2204
+ }
2205
+ wallet_node_1.config["trusted_peers"] = {
2206
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
2207
+ }
1950
2208
 
1951
- await wallet_environments.process_pending_states(
1952
- [
1953
- WalletStateTransition(
1954
- pre_block_balance_updates={
1955
- "xch": {
1956
- "set_remainder": True,
1957
- },
1958
- "did": {
1959
- "init": True,
1960
- "unconfirmed_wallet_balance": 101,
1961
- "pending_change": 101,
1962
- "pending_coin_removal_count": 1,
1963
- },
1964
- },
1965
- post_block_balance_updates={
1966
- "xch": {
1967
- "set_remainder": True,
1968
- },
1969
- "did": {
1970
- "confirmed_wallet_balance": 101,
1971
- "spendable_balance": 101,
1972
- "max_send_amount": 101,
1973
- "unspent_coin_count": 1,
1974
- "pending_change": -101,
1975
- "pending_coin_removal_count": -1,
1976
- },
1977
- },
1978
- ),
1979
- ]
1980
- )
1981
- # Test general string
1982
- assert did_wallet_1.did_info.origin_coin is not None # mypy
1983
- message = "Hello World"
1984
- assert did_wallet_1.did_info.origin_coin is not None
1985
- response = await api_0.sign_message_by_id(
1986
- {
1987
- "id": encode_puzzle_hash(did_wallet_1.did_info.origin_coin.name(), AddressType.DID.value),
1988
- "message": message,
1989
- }
2209
+ else:
2210
+ wallet_node_0.config["trusted_peers"] = {}
2211
+ wallet_node_1.config["trusted_peers"] = {}
2212
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
2213
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
2214
+
2215
+ await full_node_api.farm_blocks_to_wallet(1, wallet_0)
2216
+ await full_node_api.farm_blocks_to_wallet(1, wallet_1)
2217
+
2218
+ # Node 0 sets up a DID Wallet with a backup set, but num_of_backup_ids_needed=0
2219
+ # (a malformed solution, but legal for the clvm puzzle)
2220
+ recovery_list = [bytes32(bytes.fromhex("00" * 32))]
2221
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2222
+ did_wallet_0: DIDWallet = await DIDWallet.create_new_did_wallet(
2223
+ wallet_node_0.wallet_state_manager,
2224
+ wallet_0,
2225
+ uint64(101),
2226
+ action_scope,
2227
+ backups_ids=recovery_list,
2228
+ num_of_backup_ids_needed=uint64(0),
1990
2229
  )
1991
- puzzle: Program = Program.to((CHIP_0002_SIGN_MESSAGE_PREFIX, message))
1992
- assert AugSchemeMPL.verify(
1993
- G1Element.from_bytes(bytes.fromhex(response["pubkey"])),
1994
- puzzle.get_tree_hash(),
1995
- G2Element.from_bytes(bytes.fromhex(response["signature"])),
1996
- )
1997
- # Test hex string
1998
- message = "0123456789ABCDEF"
1999
- response = await api_0.sign_message_by_id(
2000
- {
2001
- "id": encode_puzzle_hash(did_wallet_1.did_info.origin_coin.name(), AddressType.DID.value),
2002
- "message": message,
2003
- "is_hex": True,
2004
- }
2005
- )
2006
- puzzle = Program.to((CHIP_0002_SIGN_MESSAGE_PREFIX, bytes.fromhex(message)))
2007
2230
 
2008
- assert AugSchemeMPL.verify(
2009
- G1Element.from_bytes(bytes.fromhex(response["pubkey"])),
2010
- puzzle.get_tree_hash(),
2011
- G2Element.from_bytes(bytes.fromhex(response["signature"])),
2012
- )
2231
+ await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
2232
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0])
2013
2233
 
2014
- # Test BLS sign string
2015
- message = "Hello World"
2016
- assert did_wallet_1.did_info.origin_coin is not None
2017
- response = await api_0.sign_message_by_id(
2018
- {
2019
- "id": encode_puzzle_hash(did_wallet_1.did_info.origin_coin.name(), AddressType.DID.value),
2020
- "message": message,
2021
- "is_hex": "False",
2022
- "safe_mode": "False",
2023
- }
2024
- )
2234
+ await time_out_assert(15, did_wallet_0.get_confirmed_balance, 101)
2235
+ await time_out_assert(15, did_wallet_0.get_unconfirmed_balance, 101)
2236
+ await time_out_assert(15, did_wallet_0.get_pending_change_balance, 0)
2025
2237
 
2026
- assert AugSchemeMPL.verify(
2027
- G1Element.from_bytes(bytes.fromhex(response["pubkey"])),
2028
- bytes(message, "utf-8"),
2029
- G2Element.from_bytes(bytes.fromhex(response["signature"])),
2030
- )
2031
- # Test BLS sign hex
2032
- message = "0123456789ABCDEF"
2033
- assert did_wallet_1.did_info.origin_coin is not None
2034
- response = await api_0.sign_message_by_id(
2035
- {
2036
- "id": encode_puzzle_hash(did_wallet_1.did_info.origin_coin.name(), AddressType.DID.value),
2037
- "message": message,
2038
- "is_hex": True,
2039
- "safe_mode": False,
2040
- }
2041
- )
2238
+ await full_node_api.farm_blocks_to_wallet(1, wallet_0)
2042
2239
 
2043
- assert AugSchemeMPL.verify(
2044
- G1Element.from_bytes(bytes.fromhex(response["pubkey"])),
2045
- bytes.fromhex(message),
2046
- G2Element.from_bytes(bytes.fromhex(response["signature"])),
2047
- )
2240
+ #######################
2241
+ all_node_0_wallets = await wallet_node_0.wallet_state_manager.user_store.get_all_wallet_info_entries()
2242
+ all_node_1_wallets = await wallet_node_1.wallet_state_manager.user_store.get_all_wallet_info_entries()
2243
+ assert len(all_node_0_wallets) == len(all_node_1_wallets)
2048
2244
 
2049
- @pytest.mark.parametrize(
2050
- "trusted",
2051
- [True, False],
2052
- )
2053
- @pytest.mark.anyio
2054
- async def test_create_did_with_recovery_list(
2055
- self, self_hostname: str, two_nodes_two_wallets_with_same_keys: OldSimulatorsAndWallets, trusted: bool
2056
- ) -> None:
2057
- """
2058
- A DID is created on-chain in client0, causing a DID Wallet to be created in client1, which shares the same key.
2059
- This can happen if someone uses the same key on multiple computers, or is syncing a wallet from scratch.
2060
-
2061
- For this test, we assign a recovery list hash at DID creation time, but the recovery list is not yet available
2062
- to the wallet_node that the DID Wallet is being created in (client1).
2063
-
2064
- """
2065
- full_nodes, wallets, _ = two_nodes_two_wallets_with_same_keys
2066
- full_node_api = full_nodes[0]
2067
- full_node_server = full_node_api.server
2068
- wallet_node_0, server_0 = wallets[0]
2069
- wallet_node_1, server_1 = wallets[1]
2070
-
2071
- wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
2072
- wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
2073
-
2074
- ph0 = await wallet_0.get_new_puzzlehash()
2075
- ph1 = await wallet_1.get_new_puzzlehash()
2076
-
2077
- sk0 = await wallet_node_0.wallet_state_manager.get_private_key(ph0)
2078
- sk1 = await wallet_node_1.wallet_state_manager.get_private_key(ph1)
2079
- assert sk0 == sk1
2080
-
2081
- if trusted:
2082
- wallet_node_0.config["trusted_peers"] = {
2083
- full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
2084
- }
2085
- wallet_node_1.config["trusted_peers"] = {
2086
- full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
2087
- }
2245
+ # Note that the inner program we expect is different than the on-chain inner.
2246
+ # This means that we have more work to do in the checks for the two different spend cases of
2247
+ # the DID wallet Singleton
2248
+ # assert (
2249
+ # json.loads(all_node_0_wallets[1].data)["current_inner"]
2250
+ # == json.loads(all_node_1_wallets[1].data)["current_inner"]
2251
+ # )
2088
2252
 
2089
- else:
2090
- wallet_node_0.config["trusted_peers"] = {}
2091
- wallet_node_1.config["trusted_peers"] = {}
2092
- await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
2093
- await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
2094
-
2095
- await full_node_api.farm_blocks_to_wallet(1, wallet_0)
2096
- await full_node_api.farm_blocks_to_wallet(1, wallet_1)
2097
-
2098
- # Node 0 sets up a DID Wallet with a backup set, but num_of_backup_ids_needed=0
2099
- # (a malformed solution, but legal for the clvm puzzle)
2100
- recovery_list = [bytes32(bytes.fromhex("00" * 32))]
2101
- async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2102
- did_wallet_0: DIDWallet = await DIDWallet.create_new_did_wallet(
2103
- wallet_node_0.wallet_state_manager,
2104
- wallet_0,
2105
- uint64(101),
2106
- action_scope,
2107
- backups_ids=recovery_list,
2108
- num_of_backup_ids_needed=uint64(0),
2109
- )
2110
2253
 
2111
- await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
2112
- await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0])
2113
-
2114
- await time_out_assert(15, did_wallet_0.get_confirmed_balance, 101)
2115
- await time_out_assert(15, did_wallet_0.get_unconfirmed_balance, 101)
2116
- await time_out_assert(15, did_wallet_0.get_pending_change_balance, 0)
2117
-
2118
- await full_node_api.farm_blocks_to_wallet(1, wallet_0)
2119
-
2120
- #######################
2121
- all_node_0_wallets = await wallet_node_0.wallet_state_manager.user_store.get_all_wallet_info_entries()
2122
- all_node_1_wallets = await wallet_node_1.wallet_state_manager.user_store.get_all_wallet_info_entries()
2123
- assert len(all_node_0_wallets) == len(all_node_1_wallets)
2124
-
2125
- # Note that the inner program we expect is different than the on-chain inner.
2126
- # This means that we have more work to do in the checks for the two different spend cases of
2127
- # the DID wallet Singleton
2128
- # assert (
2129
- # json.loads(all_node_0_wallets[1].data)["current_inner"]
2130
- # == json.loads(all_node_1_wallets[1].data)["current_inner"]
2131
- # )
2132
-
2133
- # TODO: See Issue CHIA-1544
2134
- # This test should be ported to WalletTestFramework once we can replace keys in the wallet node
2135
- @pytest.mark.parametrize(
2136
- "trusted",
2137
- [True, False],
2138
- )
2139
- @pytest.mark.anyio
2140
- async def test_did_resync(
2141
- self,
2142
- self_hostname: str,
2143
- two_wallet_nodes: tuple[list[FullNodeSimulator], list[tuple[WalletNode, ChiaServer]], BlockTools],
2144
- trusted: bool,
2145
- ) -> None:
2146
- full_nodes, wallets, _ = two_wallet_nodes
2147
- full_node_api = full_nodes[0]
2148
- full_node_server = full_node_api.full_node.server
2149
- wallet_node_1, wallet_server_1 = wallets[0]
2150
- wallet_node_2, wallet_server_2 = wallets[1]
2151
- wallet = wallet_node_1.wallet_state_manager.main_wallet
2152
- wallet2 = wallet_node_2.wallet_state_manager.main_wallet
2153
- fee = uint64(0)
2154
- wallet_api_1 = WalletRpcApi(wallet_node_1)
2155
- wallet_api_2 = WalletRpcApi(wallet_node_2)
2156
- ph = await wallet.get_new_puzzlehash()
2157
- if trusted:
2158
- wallet_node_1.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
2159
- wallet_node_2.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
2160
- else:
2161
- wallet_node_1.config["trusted_peers"] = {}
2162
- wallet_node_2.config["trusted_peers"] = {}
2163
- assert full_node_server._port is not None
2164
- await wallet_server_1.start_client(PeerInfo(self_hostname, uint16(full_node_server._port)), None)
2165
- await wallet_server_2.start_client(PeerInfo(self_hostname, uint16(full_node_server._port)), None)
2166
- await full_node_api.farm_blocks_to_wallet(1, wallet)
2254
+ # TODO: See Issue CHIA-1544
2255
+ # This test should be ported to WalletTestFramework once we can replace keys in the wallet node
2256
+ @pytest.mark.parametrize(
2257
+ "trusted",
2258
+ [True, False],
2259
+ )
2260
+ @pytest.mark.anyio
2261
+ async def test_did_resync(
2262
+ self_hostname: str,
2263
+ two_wallet_nodes: tuple[list[FullNodeSimulator], list[tuple[WalletNode, ChiaServer]], BlockTools],
2264
+ trusted: bool,
2265
+ ) -> None:
2266
+ full_nodes, wallets, _ = two_wallet_nodes
2267
+ full_node_api = full_nodes[0]
2268
+ full_node_server = full_node_api.full_node.server
2269
+ wallet_node_1, wallet_server_1 = wallets[0]
2270
+ wallet_node_2, wallet_server_2 = wallets[1]
2271
+ wallet = wallet_node_1.wallet_state_manager.main_wallet
2272
+ wallet2 = wallet_node_2.wallet_state_manager.main_wallet
2273
+ fee = uint64(0)
2274
+ wallet_api_1 = WalletRpcApi(wallet_node_1)
2275
+ wallet_api_2 = WalletRpcApi(wallet_node_2)
2276
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2277
+ ph = await action_scope.get_puzzle_hash(wallet.wallet_state_manager)
2278
+ if trusted:
2279
+ wallet_node_1.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
2280
+ wallet_node_2.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
2281
+ else:
2282
+ wallet_node_1.config["trusted_peers"] = {}
2283
+ wallet_node_2.config["trusted_peers"] = {}
2284
+ assert full_node_server._port is not None
2285
+ await wallet_server_1.start_client(PeerInfo(self_hostname, uint16(full_node_server._port)), None)
2286
+ await wallet_server_2.start_client(PeerInfo(self_hostname, uint16(full_node_server._port)), None)
2287
+ await full_node_api.farm_blocks_to_wallet(1, wallet)
2167
2288
 
2168
- async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2169
- did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
2170
- wallet_node_1.wallet_state_manager,
2171
- wallet,
2172
- uint64(101),
2173
- action_scope,
2174
- [bytes32(ph)],
2175
- uint64(1),
2176
- {"Twitter": "Test", "GitHub": "测试"},
2177
- fee=fee,
2178
- )
2179
- assert did_wallet_1.get_name() == "Profile 1"
2180
- await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
2181
- await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_1, wallet_node_2])
2182
- await time_out_assert(15, did_wallet_1.get_confirmed_balance, 101)
2183
- await time_out_assert(15, did_wallet_1.get_unconfirmed_balance, 101)
2184
- # Transfer DID
2185
- new_puzhash = await wallet2.get_new_puzzlehash()
2186
- async with did_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2187
- await did_wallet_1.transfer_did(new_puzhash, fee, True, action_scope=action_scope)
2188
- await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
2189
- await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_1, wallet_node_2])
2190
- # Check if the DID wallet is created in the wallet2
2191
- await time_out_assert(30, get_wallet_num, 2, wallet_node_2.wallet_state_manager)
2192
- await time_out_assert(30, get_wallet_num, 1, wallet_node_1.wallet_state_manager)
2193
- did_wallet_2 = wallet_node_2.wallet_state_manager.get_wallet(uint32(2), DIDWallet)
2194
- did_info = did_wallet_2.did_info
2195
- # set flag to reset wallet sync data on start
2196
- await wallet_api_1.set_wallet_resync_on_startup({"enable": True})
2197
- fingerprint_1 = wallet_node_1.logged_in_fingerprint
2198
- await wallet_api_2.set_wallet_resync_on_startup({"enable": True})
2199
- fingerprint_2 = wallet_node_2.logged_in_fingerprint
2200
- # 2 reward coins
2201
- assert len(await wallet_node_1.wallet_state_manager.coin_store.get_all_unspent_coins()) == 2
2202
- # Delete tx records
2203
- await wallet_node_1.wallet_state_manager.tx_store.rollback_to_block(0)
2204
- wallet_node_1._close()
2205
- await wallet_node_1._await_closed()
2206
- wallet_node_2._close()
2207
- await wallet_node_2._await_closed()
2208
- wallet_node_1.config["database_path"] = "wallet/db/blockchain_wallet_v2_test_1_CHALLENGE_KEY.sqlite"
2209
- wallet_node_2.config["database_path"] = "wallet/db/blockchain_wallet_v2_test_2_CHALLENGE_KEY.sqlite"
2210
- # Start resync
2211
- await wallet_node_1._start_with_fingerprint(fingerprint_1)
2212
- await wallet_node_2._start_with_fingerprint(fingerprint_2)
2213
- assert full_node_server._port is not None
2214
- await wallet_server_1.start_client(PeerInfo(self_hostname, uint16(full_node_server._port)), None)
2215
- await wallet_server_2.start_client(PeerInfo(self_hostname, uint16(full_node_server._port)), None)
2216
- await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(b"\00" * 32)))
2217
- await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=20)
2218
- await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_2, timeout=20)
2219
- await time_out_assert(30, get_wallet_num, 1, wallet_node_1.wallet_state_manager)
2220
- await time_out_assert(30, get_wallet_num, 2, wallet_node_2.wallet_state_manager)
2221
- did_wallet_2 = wallet_node_2.wallet_state_manager.get_wallet(uint32(2), DIDWallet)
2222
- assert did_info == did_wallet_2.did_info
2289
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2290
+ did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
2291
+ wallet_node_1.wallet_state_manager,
2292
+ wallet,
2293
+ uint64(101),
2294
+ action_scope,
2295
+ [bytes32(ph)],
2296
+ uint64(1),
2297
+ {"Twitter": "Test", "GitHub": "测试"},
2298
+ fee=fee,
2299
+ )
2300
+ assert did_wallet_1.get_name() == "Profile 1"
2301
+ await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
2302
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_1, wallet_node_2])
2303
+ await time_out_assert(15, did_wallet_1.get_confirmed_balance, 101)
2304
+ await time_out_assert(15, did_wallet_1.get_unconfirmed_balance, 101)
2305
+ # Transfer DID
2306
+ async with wallet2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2307
+ new_puzhash = await action_scope.get_puzzle_hash(wallet2.wallet_state_manager)
2308
+ async with did_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2309
+ await did_wallet_1.transfer_did(new_puzhash, fee, True, action_scope=action_scope)
2310
+ await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
2311
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_1, wallet_node_2])
2312
+ # Check if the DID wallet is created in the wallet2
2313
+ await time_out_assert(30, get_wallet_num, 2, wallet_node_2.wallet_state_manager)
2314
+ await time_out_assert(30, get_wallet_num, 1, wallet_node_1.wallet_state_manager)
2315
+ did_wallet_2 = wallet_node_2.wallet_state_manager.get_wallet(uint32(2), DIDWallet)
2316
+ did_info = did_wallet_2.did_info
2317
+ # set flag to reset wallet sync data on start
2318
+ await wallet_api_1.set_wallet_resync_on_startup({"enable": True})
2319
+ fingerprint_1 = wallet_node_1.logged_in_fingerprint
2320
+ await wallet_api_2.set_wallet_resync_on_startup({"enable": True})
2321
+ fingerprint_2 = wallet_node_2.logged_in_fingerprint
2322
+ # 2 reward coins
2323
+ assert len(await wallet_node_1.wallet_state_manager.coin_store.get_all_unspent_coins()) == 2
2324
+ # Delete tx records
2325
+ await wallet_node_1.wallet_state_manager.tx_store.rollback_to_block(0)
2326
+ wallet_node_1._close()
2327
+ await wallet_node_1._await_closed()
2328
+ wallet_node_2._close()
2329
+ await wallet_node_2._await_closed()
2330
+ wallet_node_1.config["database_path"] = "wallet/db/blockchain_wallet_v2_test_1_CHALLENGE_KEY.sqlite"
2331
+ wallet_node_2.config["database_path"] = "wallet/db/blockchain_wallet_v2_test_2_CHALLENGE_KEY.sqlite"
2332
+ # Start resync
2333
+ await wallet_node_1._start_with_fingerprint(fingerprint_1)
2334
+ await wallet_node_2._start_with_fingerprint(fingerprint_2)
2335
+ assert full_node_server._port is not None
2336
+ await wallet_server_1.start_client(PeerInfo(self_hostname, uint16(full_node_server._port)), None)
2337
+ await wallet_server_2.start_client(PeerInfo(self_hostname, uint16(full_node_server._port)), None)
2338
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(b"\00" * 32)))
2339
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=20)
2340
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_2, timeout=20)
2341
+ await time_out_assert(30, get_wallet_num, 1, wallet_node_1.wallet_state_manager)
2342
+ await time_out_assert(30, get_wallet_num, 2, wallet_node_2.wallet_state_manager)
2343
+ did_wallet_2 = wallet_node_2.wallet_state_manager.get_wallet(uint32(2), DIDWallet)
2344
+ assert did_info == did_wallet_2.did_info
2223
2345
 
2224
2346
 
2225
2347
  @pytest.mark.parametrize(
@@ -2232,16 +2354,24 @@ class TestDIDWallet:
2232
2354
  ],
2233
2355
  indirect=True,
2234
2356
  )
2357
+ @pytest.mark.parametrize(
2358
+ "use_alternate_recovery",
2359
+ [True, False],
2360
+ )
2235
2361
  @pytest.mark.anyio
2236
- async def test_did_coin_records(wallet_environments: WalletTestFramework, monkeypatch: pytest.MonkeyPatch) -> None:
2362
+ async def test_did_coin_records(wallet_environments: WalletTestFramework, use_alternate_recovery: bool) -> None:
2237
2363
  # Setup
2238
2364
  wallet_node = wallet_environments.environments[0].node
2239
2365
  wallet = wallet_environments.environments[0].xch_wallet
2240
2366
 
2241
2367
  # Generate DID wallet
2242
2368
  async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2243
- did_wallet: DIDWallet = await DIDWallet.create_new_did_wallet(
2244
- wallet_node.wallet_state_manager, wallet, uint64(1), action_scope
2369
+ did_wallet: DIDWallet = await make_did_wallet(
2370
+ wallet_node.wallet_state_manager,
2371
+ wallet,
2372
+ uint64(1),
2373
+ action_scope,
2374
+ use_alternate_recovery=use_alternate_recovery,
2245
2375
  )
2246
2376
 
2247
2377
  await wallet_environments.process_pending_states(
@@ -2260,11 +2390,13 @@ async def test_did_coin_records(wallet_environments: WalletTestFramework, monkey
2260
2390
  ]
2261
2391
  )
2262
2392
 
2263
- for _ in range(0, 2):
2393
+ for _ in range(2):
2264
2394
  async with did_wallet.wallet_state_manager.new_action_scope(
2265
2395
  wallet_environments.tx_config, push=True
2266
2396
  ) as action_scope:
2267
- await did_wallet.transfer_did(await wallet.get_puzzle_hash(new=False), uint64(0), True, action_scope)
2397
+ await did_wallet.transfer_did(
2398
+ await action_scope.get_puzzle_hash(did_wallet.wallet_state_manager), uint64(0), True, action_scope
2399
+ )
2268
2400
  await wallet_environments.process_pending_states(
2269
2401
  [
2270
2402
  WalletStateTransition(