chia-blockchain 2.4.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1028) hide show
  1. chia/__init__.py +10 -0
  2. chia/__main__.py +5 -0
  3. chia/_tests/README.md +53 -0
  4. chia/_tests/__init__.py +0 -0
  5. chia/_tests/blockchain/__init__.py +0 -0
  6. chia/_tests/blockchain/blockchain_test_utils.py +197 -0
  7. chia/_tests/blockchain/config.py +4 -0
  8. chia/_tests/blockchain/test_augmented_chain.py +147 -0
  9. chia/_tests/blockchain/test_blockchain.py +4100 -0
  10. chia/_tests/blockchain/test_blockchain_transactions.py +1050 -0
  11. chia/_tests/blockchain/test_build_chains.py +61 -0
  12. chia/_tests/blockchain/test_get_block_generator.py +72 -0
  13. chia/_tests/blockchain/test_lookup_fork_chain.py +195 -0
  14. chia/_tests/build-init-files.py +93 -0
  15. chia/_tests/build-job-matrix.py +204 -0
  16. chia/_tests/check_pytest_monitor_output.py +34 -0
  17. chia/_tests/check_sql_statements.py +73 -0
  18. chia/_tests/chia-start-sim +42 -0
  19. chia/_tests/clvm/__init__.py +0 -0
  20. chia/_tests/clvm/benchmark_costs.py +23 -0
  21. chia/_tests/clvm/coin_store.py +147 -0
  22. chia/_tests/clvm/test_chialisp_deserialization.py +101 -0
  23. chia/_tests/clvm/test_clvm_step.py +37 -0
  24. chia/_tests/clvm/test_condition_codes.py +13 -0
  25. chia/_tests/clvm/test_curry_and_treehash.py +57 -0
  26. chia/_tests/clvm/test_program.py +150 -0
  27. chia/_tests/clvm/test_puzzle_compression.py +144 -0
  28. chia/_tests/clvm/test_puzzle_drivers.py +45 -0
  29. chia/_tests/clvm/test_puzzles.py +247 -0
  30. chia/_tests/clvm/test_singletons.py +540 -0
  31. chia/_tests/clvm/test_spend_sim.py +181 -0
  32. chia/_tests/cmds/__init__.py +0 -0
  33. chia/_tests/cmds/cmd_test_utils.py +472 -0
  34. chia/_tests/cmds/config.py +3 -0
  35. chia/_tests/cmds/conftest.py +23 -0
  36. chia/_tests/cmds/test_click_types.py +195 -0
  37. chia/_tests/cmds/test_cmd_framework.py +400 -0
  38. chia/_tests/cmds/test_cmds_util.py +97 -0
  39. chia/_tests/cmds/test_daemon.py +92 -0
  40. chia/_tests/cmds/test_farm_cmd.py +67 -0
  41. chia/_tests/cmds/test_show.py +116 -0
  42. chia/_tests/cmds/test_sim.py +207 -0
  43. chia/_tests/cmds/test_timelock_args.py +75 -0
  44. chia/_tests/cmds/test_tx_config_args.py +153 -0
  45. chia/_tests/cmds/testing_classes.py +59 -0
  46. chia/_tests/cmds/wallet/__init__.py +0 -0
  47. chia/_tests/cmds/wallet/test_coins.py +195 -0
  48. chia/_tests/cmds/wallet/test_consts.py +47 -0
  49. chia/_tests/cmds/wallet/test_dao.py +565 -0
  50. chia/_tests/cmds/wallet/test_did.py +403 -0
  51. chia/_tests/cmds/wallet/test_nft.py +470 -0
  52. chia/_tests/cmds/wallet/test_notifications.py +124 -0
  53. chia/_tests/cmds/wallet/test_offer.toffer +1 -0
  54. chia/_tests/cmds/wallet/test_tx_decorators.py +27 -0
  55. chia/_tests/cmds/wallet/test_vcs.py +376 -0
  56. chia/_tests/cmds/wallet/test_wallet.py +1126 -0
  57. chia/_tests/cmds/wallet/test_wallet_check.py +111 -0
  58. chia/_tests/conftest.py +1304 -0
  59. chia/_tests/connection_utils.py +124 -0
  60. chia/_tests/core/__init__.py +0 -0
  61. chia/_tests/core/cmds/__init__.py +0 -0
  62. chia/_tests/core/cmds/test_beta.py +382 -0
  63. chia/_tests/core/cmds/test_keys.py +1734 -0
  64. chia/_tests/core/cmds/test_wallet.py +126 -0
  65. chia/_tests/core/config.py +3 -0
  66. chia/_tests/core/consensus/__init__.py +0 -0
  67. chia/_tests/core/consensus/test_block_creation.py +56 -0
  68. chia/_tests/core/consensus/test_pot_iterations.py +117 -0
  69. chia/_tests/core/custom_types/__init__.py +0 -0
  70. chia/_tests/core/custom_types/test_coin.py +109 -0
  71. chia/_tests/core/custom_types/test_proof_of_space.py +144 -0
  72. chia/_tests/core/custom_types/test_spend_bundle.py +71 -0
  73. chia/_tests/core/daemon/__init__.py +0 -0
  74. chia/_tests/core/daemon/config.py +4 -0
  75. chia/_tests/core/daemon/test_daemon.py +2128 -0
  76. chia/_tests/core/daemon/test_daemon_register.py +109 -0
  77. chia/_tests/core/daemon/test_keychain_proxy.py +100 -0
  78. chia/_tests/core/data_layer/__init__.py +0 -0
  79. chia/_tests/core/data_layer/config.py +5 -0
  80. chia/_tests/core/data_layer/conftest.py +105 -0
  81. chia/_tests/core/data_layer/test_data_cli.py +57 -0
  82. chia/_tests/core/data_layer/test_data_layer.py +83 -0
  83. chia/_tests/core/data_layer/test_data_layer_util.py +219 -0
  84. chia/_tests/core/data_layer/test_data_rpc.py +3865 -0
  85. chia/_tests/core/data_layer/test_data_store.py +2423 -0
  86. chia/_tests/core/data_layer/test_data_store_schema.py +381 -0
  87. chia/_tests/core/data_layer/test_plugin.py +91 -0
  88. chia/_tests/core/data_layer/util.py +232 -0
  89. chia/_tests/core/farmer/__init__.py +0 -0
  90. chia/_tests/core/farmer/config.py +3 -0
  91. chia/_tests/core/farmer/test_farmer_api.py +101 -0
  92. chia/_tests/core/full_node/__init__.py +0 -0
  93. chia/_tests/core/full_node/config.py +4 -0
  94. chia/_tests/core/full_node/dos/__init__.py +0 -0
  95. chia/_tests/core/full_node/dos/config.py +3 -0
  96. chia/_tests/core/full_node/full_sync/__init__.py +0 -0
  97. chia/_tests/core/full_node/full_sync/config.py +4 -0
  98. chia/_tests/core/full_node/full_sync/test_full_sync.py +448 -0
  99. chia/_tests/core/full_node/ram_db.py +27 -0
  100. chia/_tests/core/full_node/stores/__init__.py +0 -0
  101. chia/_tests/core/full_node/stores/config.py +4 -0
  102. chia/_tests/core/full_node/stores/test_block_store.py +488 -0
  103. chia/_tests/core/full_node/stores/test_coin_store.py +888 -0
  104. chia/_tests/core/full_node/stores/test_full_node_store.py +1215 -0
  105. chia/_tests/core/full_node/stores/test_hint_store.py +230 -0
  106. chia/_tests/core/full_node/stores/test_sync_store.py +135 -0
  107. chia/_tests/core/full_node/test_address_manager.py +588 -0
  108. chia/_tests/core/full_node/test_block_height_map.py +556 -0
  109. chia/_tests/core/full_node/test_conditions.py +558 -0
  110. chia/_tests/core/full_node/test_full_node.py +2445 -0
  111. chia/_tests/core/full_node/test_generator_tools.py +82 -0
  112. chia/_tests/core/full_node/test_hint_management.py +104 -0
  113. chia/_tests/core/full_node/test_node_load.py +34 -0
  114. chia/_tests/core/full_node/test_performance.py +182 -0
  115. chia/_tests/core/full_node/test_subscriptions.py +492 -0
  116. chia/_tests/core/full_node/test_transactions.py +203 -0
  117. chia/_tests/core/full_node/test_tx_processing_queue.py +154 -0
  118. chia/_tests/core/large_block.py +2388 -0
  119. chia/_tests/core/make_block_generator.py +72 -0
  120. chia/_tests/core/mempool/__init__.py +0 -0
  121. chia/_tests/core/mempool/config.py +4 -0
  122. chia/_tests/core/mempool/test_mempool.py +3180 -0
  123. chia/_tests/core/mempool/test_mempool_fee_estimator.py +104 -0
  124. chia/_tests/core/mempool/test_mempool_fee_protocol.py +55 -0
  125. chia/_tests/core/mempool/test_mempool_item_queries.py +192 -0
  126. chia/_tests/core/mempool/test_mempool_manager.py +2054 -0
  127. chia/_tests/core/mempool/test_mempool_performance.py +65 -0
  128. chia/_tests/core/mempool/test_singleton_fast_forward.py +567 -0
  129. chia/_tests/core/node_height.py +28 -0
  130. chia/_tests/core/server/__init__.py +0 -0
  131. chia/_tests/core/server/config.py +3 -0
  132. chia/_tests/core/server/flood.py +82 -0
  133. chia/_tests/core/server/serve.py +132 -0
  134. chia/_tests/core/server/test_capabilities.py +68 -0
  135. chia/_tests/core/server/test_dos.py +320 -0
  136. chia/_tests/core/server/test_event_loop.py +109 -0
  137. chia/_tests/core/server/test_loop.py +290 -0
  138. chia/_tests/core/server/test_node_discovery.py +74 -0
  139. chia/_tests/core/server/test_rate_limits.py +370 -0
  140. chia/_tests/core/server/test_server.py +225 -0
  141. chia/_tests/core/server/test_upnp.py +8 -0
  142. chia/_tests/core/services/__init__.py +0 -0
  143. chia/_tests/core/services/config.py +3 -0
  144. chia/_tests/core/services/test_services.py +166 -0
  145. chia/_tests/core/ssl/__init__.py +0 -0
  146. chia/_tests/core/ssl/config.py +3 -0
  147. chia/_tests/core/ssl/test_ssl.py +198 -0
  148. chia/_tests/core/test_coins.py +33 -0
  149. chia/_tests/core/test_cost_calculation.py +314 -0
  150. chia/_tests/core/test_crawler.py +175 -0
  151. chia/_tests/core/test_crawler_rpc.py +53 -0
  152. chia/_tests/core/test_daemon_rpc.py +24 -0
  153. chia/_tests/core/test_db_conversion.py +129 -0
  154. chia/_tests/core/test_db_validation.py +161 -0
  155. chia/_tests/core/test_farmer_harvester_rpc.py +504 -0
  156. chia/_tests/core/test_filter.py +37 -0
  157. chia/_tests/core/test_full_node_rpc.py +794 -0
  158. chia/_tests/core/test_merkle_set.py +343 -0
  159. chia/_tests/core/test_program.py +49 -0
  160. chia/_tests/core/test_rpc_util.py +87 -0
  161. chia/_tests/core/test_seeder.py +308 -0
  162. chia/_tests/core/test_setproctitle.py +13 -0
  163. chia/_tests/core/util/__init__.py +0 -0
  164. chia/_tests/core/util/config.py +4 -0
  165. chia/_tests/core/util/test_block_cache.py +44 -0
  166. chia/_tests/core/util/test_cached_bls.py +57 -0
  167. chia/_tests/core/util/test_config.py +337 -0
  168. chia/_tests/core/util/test_file_keyring_synchronization.py +105 -0
  169. chia/_tests/core/util/test_files.py +391 -0
  170. chia/_tests/core/util/test_jsonify.py +146 -0
  171. chia/_tests/core/util/test_keychain.py +514 -0
  172. chia/_tests/core/util/test_keyring_wrapper.py +490 -0
  173. chia/_tests/core/util/test_lockfile.py +380 -0
  174. chia/_tests/core/util/test_log_exceptions.py +187 -0
  175. chia/_tests/core/util/test_lru_cache.py +56 -0
  176. chia/_tests/core/util/test_significant_bits.py +40 -0
  177. chia/_tests/core/util/test_streamable.py +883 -0
  178. chia/_tests/db/__init__.py +0 -0
  179. chia/_tests/db/test_db_wrapper.py +565 -0
  180. chia/_tests/environments/__init__.py +0 -0
  181. chia/_tests/environments/common.py +35 -0
  182. chia/_tests/environments/full_node.py +47 -0
  183. chia/_tests/environments/wallet.py +368 -0
  184. chia/_tests/ether.py +19 -0
  185. chia/_tests/farmer_harvester/__init__.py +0 -0
  186. chia/_tests/farmer_harvester/config.py +3 -0
  187. chia/_tests/farmer_harvester/test_farmer.py +1264 -0
  188. chia/_tests/farmer_harvester/test_farmer_harvester.py +292 -0
  189. chia/_tests/farmer_harvester/test_filter_prefix_bits.py +130 -0
  190. chia/_tests/farmer_harvester/test_third_party_harvesters.py +501 -0
  191. chia/_tests/farmer_harvester/test_third_party_harvesters_data.json +29 -0
  192. chia/_tests/fee_estimation/__init__.py +0 -0
  193. chia/_tests/fee_estimation/config.py +3 -0
  194. chia/_tests/fee_estimation/test_fee_estimation_integration.py +262 -0
  195. chia/_tests/fee_estimation/test_fee_estimation_rpc.py +287 -0
  196. chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +145 -0
  197. chia/_tests/fee_estimation/test_mempoolitem_height_added.py +146 -0
  198. chia/_tests/generator/__init__.py +0 -0
  199. chia/_tests/generator/puzzles/__init__.py +0 -0
  200. chia/_tests/generator/puzzles/test_generator_deserialize.clsp +3 -0
  201. chia/_tests/generator/puzzles/test_generator_deserialize.clsp.hex +1 -0
  202. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp +19 -0
  203. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp.hex +1 -0
  204. chia/_tests/generator/test_compression.py +218 -0
  205. chia/_tests/generator/test_generator_types.py +44 -0
  206. chia/_tests/generator/test_rom.py +182 -0
  207. chia/_tests/plot_sync/__init__.py +0 -0
  208. chia/_tests/plot_sync/config.py +3 -0
  209. chia/_tests/plot_sync/test_delta.py +102 -0
  210. chia/_tests/plot_sync/test_plot_sync.py +617 -0
  211. chia/_tests/plot_sync/test_receiver.py +451 -0
  212. chia/_tests/plot_sync/test_sender.py +116 -0
  213. chia/_tests/plot_sync/test_sync_simulated.py +450 -0
  214. chia/_tests/plot_sync/util.py +67 -0
  215. chia/_tests/plotting/__init__.py +0 -0
  216. chia/_tests/plotting/config.py +3 -0
  217. chia/_tests/plotting/test_plot_manager.py +738 -0
  218. chia/_tests/plotting/util.py +13 -0
  219. chia/_tests/pools/__init__.py +0 -0
  220. chia/_tests/pools/config.py +5 -0
  221. chia/_tests/pools/test_pool_cmdline.py +23 -0
  222. chia/_tests/pools/test_pool_config.py +44 -0
  223. chia/_tests/pools/test_pool_puzzles_lifecycle.py +398 -0
  224. chia/_tests/pools/test_pool_rpc.py +1010 -0
  225. chia/_tests/pools/test_pool_wallet.py +201 -0
  226. chia/_tests/pools/test_wallet_pool_store.py +161 -0
  227. chia/_tests/process_junit.py +349 -0
  228. chia/_tests/rpc/__init__.py +0 -0
  229. chia/_tests/rpc/test_rpc_client.py +81 -0
  230. chia/_tests/simulation/__init__.py +0 -0
  231. chia/_tests/simulation/config.py +6 -0
  232. chia/_tests/simulation/test_simulation.py +501 -0
  233. chia/_tests/simulation/test_simulator.py +234 -0
  234. chia/_tests/simulation/test_start_simulator.py +106 -0
  235. chia/_tests/testconfig.py +13 -0
  236. chia/_tests/timelord/__init__.py +0 -0
  237. chia/_tests/timelord/config.py +3 -0
  238. chia/_tests/timelord/test_new_peak.py +437 -0
  239. chia/_tests/timelord/test_timelord.py +11 -0
  240. chia/_tests/tools/1315537.json +170 -0
  241. chia/_tests/tools/1315544.json +160 -0
  242. chia/_tests/tools/1315630.json +150 -0
  243. chia/_tests/tools/300000.json +105 -0
  244. chia/_tests/tools/442734.json +140 -0
  245. chia/_tests/tools/466212.json +130 -0
  246. chia/_tests/tools/__init__.py +0 -0
  247. chia/_tests/tools/config.py +5 -0
  248. chia/_tests/tools/test-blockchain-db.sqlite +0 -0
  249. chia/_tests/tools/test_full_sync.py +30 -0
  250. chia/_tests/tools/test_legacy_keyring.py +82 -0
  251. chia/_tests/tools/test_run_block.py +129 -0
  252. chia/_tests/util/__init__.py +0 -0
  253. chia/_tests/util/benchmark_cost.py +170 -0
  254. chia/_tests/util/benchmarks.py +154 -0
  255. chia/_tests/util/bip39_test_vectors.json +148 -0
  256. chia/_tests/util/blockchain.py +133 -0
  257. chia/_tests/util/blockchain_mock.py +132 -0
  258. chia/_tests/util/build_network_protocol_files.py +302 -0
  259. chia/_tests/util/clvm_generator.bin +0 -0
  260. chia/_tests/util/config.py +3 -0
  261. chia/_tests/util/constants.py +20 -0
  262. chia/_tests/util/db_connection.py +36 -0
  263. chia/_tests/util/full_sync.py +245 -0
  264. chia/_tests/util/gen_ssl_certs.py +115 -0
  265. chia/_tests/util/generator_tools_testing.py +47 -0
  266. chia/_tests/util/key_tool.py +37 -0
  267. chia/_tests/util/misc.py +722 -0
  268. chia/_tests/util/network_protocol_data.py +1074 -0
  269. chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
  270. chia/_tests/util/protocol_messages_json.py +2700 -0
  271. chia/_tests/util/rpc.py +23 -0
  272. chia/_tests/util/run_block.py +163 -0
  273. chia/_tests/util/setup_nodes.py +479 -0
  274. chia/_tests/util/split_managers.py +99 -0
  275. chia/_tests/util/temp_file.py +14 -0
  276. chia/_tests/util/test_action_scope.py +143 -0
  277. chia/_tests/util/test_async_pool.py +366 -0
  278. chia/_tests/util/test_build_job_matrix.py +43 -0
  279. chia/_tests/util/test_build_network_protocol_files.py +7 -0
  280. chia/_tests/util/test_chia_version.py +50 -0
  281. chia/_tests/util/test_collection.py +11 -0
  282. chia/_tests/util/test_condition_tools.py +231 -0
  283. chia/_tests/util/test_config.py +426 -0
  284. chia/_tests/util/test_dump_keyring.py +60 -0
  285. chia/_tests/util/test_errors.py +10 -0
  286. chia/_tests/util/test_full_block_utils.py +271 -0
  287. chia/_tests/util/test_installed.py +20 -0
  288. chia/_tests/util/test_limited_semaphore.py +52 -0
  289. chia/_tests/util/test_logging_filter.py +43 -0
  290. chia/_tests/util/test_misc.py +444 -0
  291. chia/_tests/util/test_network.py +74 -0
  292. chia/_tests/util/test_network_protocol_files.py +579 -0
  293. chia/_tests/util/test_network_protocol_json.py +266 -0
  294. chia/_tests/util/test_network_protocol_test.py +257 -0
  295. chia/_tests/util/test_paginator.py +72 -0
  296. chia/_tests/util/test_pprint.py +17 -0
  297. chia/_tests/util/test_priority_mutex.py +487 -0
  298. chia/_tests/util/test_recursive_replace.py +116 -0
  299. chia/_tests/util/test_replace_str_to_bytes.py +137 -0
  300. chia/_tests/util/test_service_groups.py +15 -0
  301. chia/_tests/util/test_ssl_check.py +31 -0
  302. chia/_tests/util/test_testnet_overrides.py +19 -0
  303. chia/_tests/util/test_tests_misc.py +38 -0
  304. chia/_tests/util/test_timing.py +37 -0
  305. chia/_tests/util/test_trusted_peer.py +51 -0
  306. chia/_tests/util/time_out_assert.py +154 -0
  307. chia/_tests/wallet/__init__.py +0 -0
  308. chia/_tests/wallet/cat_wallet/__init__.py +0 -0
  309. chia/_tests/wallet/cat_wallet/config.py +4 -0
  310. chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +468 -0
  311. chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +69 -0
  312. chia/_tests/wallet/cat_wallet/test_cat_wallet.py +1738 -0
  313. chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +291 -0
  314. chia/_tests/wallet/cat_wallet/test_trades.py +2578 -0
  315. chia/_tests/wallet/clawback/__init__.py +0 -0
  316. chia/_tests/wallet/clawback/config.py +3 -0
  317. chia/_tests/wallet/clawback/test_clawback_decorator.py +80 -0
  318. chia/_tests/wallet/clawback/test_clawback_lifecycle.py +292 -0
  319. chia/_tests/wallet/clawback/test_clawback_metadata.py +51 -0
  320. chia/_tests/wallet/config.py +4 -0
  321. chia/_tests/wallet/conftest.py +217 -0
  322. chia/_tests/wallet/dao_wallet/__init__.py +0 -0
  323. chia/_tests/wallet/dao_wallet/config.py +3 -0
  324. chia/_tests/wallet/dao_wallet/test_dao_clvm.py +1322 -0
  325. chia/_tests/wallet/dao_wallet/test_dao_wallets.py +3488 -0
  326. chia/_tests/wallet/db_wallet/__init__.py +0 -0
  327. chia/_tests/wallet/db_wallet/config.py +3 -0
  328. chia/_tests/wallet/db_wallet/test_db_graftroot.py +143 -0
  329. chia/_tests/wallet/db_wallet/test_dl_offers.py +491 -0
  330. chia/_tests/wallet/db_wallet/test_dl_wallet.py +823 -0
  331. chia/_tests/wallet/did_wallet/__init__.py +0 -0
  332. chia/_tests/wallet/did_wallet/config.py +4 -0
  333. chia/_tests/wallet/did_wallet/test_did.py +1481 -0
  334. chia/_tests/wallet/nft_wallet/__init__.py +0 -0
  335. chia/_tests/wallet/nft_wallet/config.py +4 -0
  336. chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +1492 -0
  337. chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +1014 -0
  338. chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +376 -0
  339. chia/_tests/wallet/nft_wallet/test_nft_offers.py +1209 -0
  340. chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +172 -0
  341. chia/_tests/wallet/nft_wallet/test_nft_wallet.py +2558 -0
  342. chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +70 -0
  343. chia/_tests/wallet/rpc/__init__.py +0 -0
  344. chia/_tests/wallet/rpc/config.py +4 -0
  345. chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +287 -0
  346. chia/_tests/wallet/rpc/test_wallet_rpc.py +3106 -0
  347. chia/_tests/wallet/simple_sync/__init__.py +0 -0
  348. chia/_tests/wallet/simple_sync/config.py +3 -0
  349. chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +719 -0
  350. chia/_tests/wallet/sync/__init__.py +0 -0
  351. chia/_tests/wallet/sync/config.py +4 -0
  352. chia/_tests/wallet/sync/test_wallet_sync.py +1529 -0
  353. chia/_tests/wallet/test_address_type.py +189 -0
  354. chia/_tests/wallet/test_bech32m.py +45 -0
  355. chia/_tests/wallet/test_clvm_streamable.py +244 -0
  356. chia/_tests/wallet/test_coin_selection.py +589 -0
  357. chia/_tests/wallet/test_conditions.py +388 -0
  358. chia/_tests/wallet/test_debug_spend_bundle.py +76 -0
  359. chia/_tests/wallet/test_new_wallet_protocol.py +1176 -0
  360. chia/_tests/wallet/test_nft_store.py +193 -0
  361. chia/_tests/wallet/test_notifications.py +196 -0
  362. chia/_tests/wallet/test_offer_parsing_performance.py +48 -0
  363. chia/_tests/wallet/test_puzzle_store.py +133 -0
  364. chia/_tests/wallet/test_sign_coin_spends.py +159 -0
  365. chia/_tests/wallet/test_signer_protocol.py +948 -0
  366. chia/_tests/wallet/test_singleton.py +122 -0
  367. chia/_tests/wallet/test_singleton_lifecycle_fast.py +772 -0
  368. chia/_tests/wallet/test_singleton_store.py +152 -0
  369. chia/_tests/wallet/test_taproot.py +19 -0
  370. chia/_tests/wallet/test_transaction_store.py +941 -0
  371. chia/_tests/wallet/test_util.py +181 -0
  372. chia/_tests/wallet/test_wallet.py +2139 -0
  373. chia/_tests/wallet/test_wallet_action_scope.py +85 -0
  374. chia/_tests/wallet/test_wallet_blockchain.py +113 -0
  375. chia/_tests/wallet/test_wallet_coin_store.py +1002 -0
  376. chia/_tests/wallet/test_wallet_interested_store.py +43 -0
  377. chia/_tests/wallet/test_wallet_key_val_store.py +40 -0
  378. chia/_tests/wallet/test_wallet_node.py +783 -0
  379. chia/_tests/wallet/test_wallet_retry.py +95 -0
  380. chia/_tests/wallet/test_wallet_state_manager.py +252 -0
  381. chia/_tests/wallet/test_wallet_test_framework.py +275 -0
  382. chia/_tests/wallet/test_wallet_trade_store.py +218 -0
  383. chia/_tests/wallet/test_wallet_user_store.py +34 -0
  384. chia/_tests/wallet/test_wallet_utils.py +155 -0
  385. chia/_tests/wallet/vc_wallet/__init__.py +0 -0
  386. chia/_tests/wallet/vc_wallet/config.py +3 -0
  387. chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +70 -0
  388. chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +883 -0
  389. chia/_tests/wallet/vc_wallet/test_vc_wallet.py +801 -0
  390. chia/_tests/wallet/wallet_block_tools.py +327 -0
  391. chia/_tests/weight_proof/__init__.py +0 -0
  392. chia/_tests/weight_proof/config.py +3 -0
  393. chia/_tests/weight_proof/test_weight_proof.py +528 -0
  394. chia/clvm/__init__.py +0 -0
  395. chia/clvm/spend_sim.py +488 -0
  396. chia/cmds/__init__.py +0 -0
  397. chia/cmds/beta.py +183 -0
  398. chia/cmds/beta_funcs.py +133 -0
  399. chia/cmds/check_wallet_db.py +418 -0
  400. chia/cmds/chia.py +143 -0
  401. chia/cmds/cmd_classes.py +315 -0
  402. chia/cmds/cmds_util.py +498 -0
  403. chia/cmds/coin_funcs.py +260 -0
  404. chia/cmds/coins.py +220 -0
  405. chia/cmds/completion.py +49 -0
  406. chia/cmds/configure.py +331 -0
  407. chia/cmds/dao.py +1008 -0
  408. chia/cmds/dao_funcs.py +576 -0
  409. chia/cmds/data.py +707 -0
  410. chia/cmds/data_funcs.py +380 -0
  411. chia/cmds/db.py +86 -0
  412. chia/cmds/db_backup_func.py +77 -0
  413. chia/cmds/db_upgrade_func.py +452 -0
  414. chia/cmds/db_validate_func.py +184 -0
  415. chia/cmds/dev.py +16 -0
  416. chia/cmds/farm.py +87 -0
  417. chia/cmds/farm_funcs.py +207 -0
  418. chia/cmds/init.py +70 -0
  419. chia/cmds/init_funcs.py +367 -0
  420. chia/cmds/installers.py +129 -0
  421. chia/cmds/keys.py +510 -0
  422. chia/cmds/keys_funcs.py +864 -0
  423. chia/cmds/netspace.py +47 -0
  424. chia/cmds/netspace_funcs.py +53 -0
  425. chia/cmds/options.py +32 -0
  426. chia/cmds/param_types.py +228 -0
  427. chia/cmds/passphrase.py +130 -0
  428. chia/cmds/passphrase_funcs.py +346 -0
  429. chia/cmds/peer.py +50 -0
  430. chia/cmds/peer_funcs.py +129 -0
  431. chia/cmds/plotnft.py +206 -0
  432. chia/cmds/plotnft_funcs.py +374 -0
  433. chia/cmds/plots.py +222 -0
  434. chia/cmds/plotters.py +17 -0
  435. chia/cmds/rpc.py +188 -0
  436. chia/cmds/show.py +71 -0
  437. chia/cmds/show_funcs.py +214 -0
  438. chia/cmds/signer.py +304 -0
  439. chia/cmds/sim.py +217 -0
  440. chia/cmds/sim_funcs.py +509 -0
  441. chia/cmds/start.py +24 -0
  442. chia/cmds/start_funcs.py +112 -0
  443. chia/cmds/stop.py +61 -0
  444. chia/cmds/units.py +11 -0
  445. chia/cmds/wallet.py +1745 -0
  446. chia/cmds/wallet_funcs.py +1800 -0
  447. chia/consensus/__init__.py +0 -0
  448. chia/consensus/block_body_validation.py +515 -0
  449. chia/consensus/block_creation.py +525 -0
  450. chia/consensus/block_header_validation.py +1064 -0
  451. chia/consensus/block_record.py +32 -0
  452. chia/consensus/block_rewards.py +53 -0
  453. chia/consensus/block_root_validation.py +46 -0
  454. chia/consensus/blockchain.py +1100 -0
  455. chia/consensus/blockchain_interface.py +56 -0
  456. chia/consensus/coinbase.py +30 -0
  457. chia/consensus/condition_costs.py +9 -0
  458. chia/consensus/constants.py +49 -0
  459. chia/consensus/cost_calculator.py +15 -0
  460. chia/consensus/default_constants.py +90 -0
  461. chia/consensus/deficit.py +55 -0
  462. chia/consensus/difficulty_adjustment.py +412 -0
  463. chia/consensus/find_fork_point.py +111 -0
  464. chia/consensus/full_block_to_block_record.py +167 -0
  465. chia/consensus/get_block_challenge.py +106 -0
  466. chia/consensus/get_block_generator.py +26 -0
  467. chia/consensus/make_sub_epoch_summary.py +210 -0
  468. chia/consensus/multiprocess_validation.py +365 -0
  469. chia/consensus/pos_quality.py +19 -0
  470. chia/consensus/pot_iterations.py +67 -0
  471. chia/consensus/puzzles/__init__.py +0 -0
  472. chia/consensus/puzzles/chialisp_deserialisation.clsp +69 -0
  473. chia/consensus/puzzles/chialisp_deserialisation.clsp.hex +1 -0
  474. chia/consensus/puzzles/rom_bootstrap_generator.clsp +37 -0
  475. chia/consensus/puzzles/rom_bootstrap_generator.clsp.hex +1 -0
  476. chia/consensus/vdf_info_computation.py +156 -0
  477. chia/daemon/__init__.py +0 -0
  478. chia/daemon/client.py +233 -0
  479. chia/daemon/keychain_proxy.py +501 -0
  480. chia/daemon/keychain_server.py +365 -0
  481. chia/daemon/server.py +1616 -0
  482. chia/daemon/windows_signal.py +56 -0
  483. chia/data_layer/__init__.py +0 -0
  484. chia/data_layer/data_layer.py +1303 -0
  485. chia/data_layer/data_layer_api.py +25 -0
  486. chia/data_layer/data_layer_errors.py +50 -0
  487. chia/data_layer/data_layer_server.py +170 -0
  488. chia/data_layer/data_layer_util.py +985 -0
  489. chia/data_layer/data_layer_wallet.py +1315 -0
  490. chia/data_layer/data_store.py +2267 -0
  491. chia/data_layer/dl_wallet_store.py +407 -0
  492. chia/data_layer/download_data.py +389 -0
  493. chia/data_layer/puzzles/__init__.py +0 -0
  494. chia/data_layer/puzzles/graftroot_dl_offers.clsp +100 -0
  495. chia/data_layer/puzzles/graftroot_dl_offers.clsp.hex +1 -0
  496. chia/data_layer/s3_plugin_config.yml +33 -0
  497. chia/data_layer/s3_plugin_service.py +468 -0
  498. chia/data_layer/util/__init__.py +0 -0
  499. chia/data_layer/util/benchmark.py +108 -0
  500. chia/data_layer/util/plugin.py +41 -0
  501. chia/farmer/__init__.py +0 -0
  502. chia/farmer/farmer.py +920 -0
  503. chia/farmer/farmer_api.py +814 -0
  504. chia/full_node/__init__.py +0 -0
  505. chia/full_node/bitcoin_fee_estimator.py +85 -0
  506. chia/full_node/block_height_map.py +271 -0
  507. chia/full_node/block_store.py +570 -0
  508. chia/full_node/bundle_tools.py +19 -0
  509. chia/full_node/coin_store.py +646 -0
  510. chia/full_node/fee_estimate.py +54 -0
  511. chia/full_node/fee_estimate_store.py +24 -0
  512. chia/full_node/fee_estimation.py +93 -0
  513. chia/full_node/fee_estimator.py +90 -0
  514. chia/full_node/fee_estimator_constants.py +38 -0
  515. chia/full_node/fee_estimator_interface.py +42 -0
  516. chia/full_node/fee_history.py +26 -0
  517. chia/full_node/fee_tracker.py +564 -0
  518. chia/full_node/full_node.py +3052 -0
  519. chia/full_node/full_node_api.py +1974 -0
  520. chia/full_node/full_node_store.py +1033 -0
  521. chia/full_node/hint_management.py +56 -0
  522. chia/full_node/hint_store.py +94 -0
  523. chia/full_node/mempool.py +583 -0
  524. chia/full_node/mempool_check_conditions.py +177 -0
  525. chia/full_node/mempool_manager.py +858 -0
  526. chia/full_node/pending_tx_cache.py +112 -0
  527. chia/full_node/puzzles/__init__.py +0 -0
  528. chia/full_node/puzzles/block_program_zero.clsp +14 -0
  529. chia/full_node/puzzles/block_program_zero.clsp.hex +1 -0
  530. chia/full_node/puzzles/decompress_coin_spend_entry.clsp +5 -0
  531. chia/full_node/puzzles/decompress_coin_spend_entry.clsp.hex +1 -0
  532. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp +7 -0
  533. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp.hex +1 -0
  534. chia/full_node/puzzles/decompress_puzzle.clsp +6 -0
  535. chia/full_node/puzzles/decompress_puzzle.clsp.hex +1 -0
  536. chia/full_node/signage_point.py +16 -0
  537. chia/full_node/subscriptions.py +248 -0
  538. chia/full_node/sync_store.py +145 -0
  539. chia/full_node/tx_processing_queue.py +78 -0
  540. chia/full_node/weight_proof.py +1719 -0
  541. chia/harvester/__init__.py +0 -0
  542. chia/harvester/harvester.py +271 -0
  543. chia/harvester/harvester_api.py +374 -0
  544. chia/introducer/__init__.py +0 -0
  545. chia/introducer/introducer.py +120 -0
  546. chia/introducer/introducer_api.py +64 -0
  547. chia/legacy/__init__.py +0 -0
  548. chia/legacy/keyring.py +154 -0
  549. chia/plot_sync/__init__.py +0 -0
  550. chia/plot_sync/delta.py +61 -0
  551. chia/plot_sync/exceptions.py +56 -0
  552. chia/plot_sync/receiver.py +385 -0
  553. chia/plot_sync/sender.py +337 -0
  554. chia/plot_sync/util.py +43 -0
  555. chia/plotters/__init__.py +0 -0
  556. chia/plotters/bladebit.py +388 -0
  557. chia/plotters/chiapos.py +63 -0
  558. chia/plotters/madmax.py +224 -0
  559. chia/plotters/plotters.py +577 -0
  560. chia/plotters/plotters_util.py +131 -0
  561. chia/plotting/__init__.py +0 -0
  562. chia/plotting/cache.py +212 -0
  563. chia/plotting/check_plots.py +283 -0
  564. chia/plotting/create_plots.py +278 -0
  565. chia/plotting/manager.py +436 -0
  566. chia/plotting/util.py +324 -0
  567. chia/pools/__init__.py +0 -0
  568. chia/pools/pool_config.py +110 -0
  569. chia/pools/pool_puzzles.py +459 -0
  570. chia/pools/pool_wallet.py +926 -0
  571. chia/pools/pool_wallet_info.py +118 -0
  572. chia/pools/puzzles/__init__.py +0 -0
  573. chia/pools/puzzles/pool_member_innerpuz.clsp +70 -0
  574. chia/pools/puzzles/pool_member_innerpuz.clsp.hex +1 -0
  575. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp +69 -0
  576. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp.hex +1 -0
  577. chia/protocols/__init__.py +0 -0
  578. chia/protocols/farmer_protocol.py +102 -0
  579. chia/protocols/full_node_protocol.py +219 -0
  580. chia/protocols/harvester_protocol.py +216 -0
  581. chia/protocols/introducer_protocol.py +26 -0
  582. chia/protocols/pool_protocol.py +177 -0
  583. chia/protocols/protocol_message_types.py +139 -0
  584. chia/protocols/protocol_state_machine.py +87 -0
  585. chia/protocols/protocol_timing.py +7 -0
  586. chia/protocols/shared_protocol.py +86 -0
  587. chia/protocols/timelord_protocol.py +93 -0
  588. chia/protocols/wallet_protocol.py +401 -0
  589. chia/py.typed +0 -0
  590. chia/rpc/__init__.py +0 -0
  591. chia/rpc/crawler_rpc_api.py +75 -0
  592. chia/rpc/data_layer_rpc_api.py +639 -0
  593. chia/rpc/data_layer_rpc_client.py +188 -0
  594. chia/rpc/data_layer_rpc_util.py +62 -0
  595. chia/rpc/farmer_rpc_api.py +360 -0
  596. chia/rpc/farmer_rpc_client.py +86 -0
  597. chia/rpc/full_node_rpc_api.py +954 -0
  598. chia/rpc/full_node_rpc_client.py +292 -0
  599. chia/rpc/harvester_rpc_api.py +136 -0
  600. chia/rpc/harvester_rpc_client.py +54 -0
  601. chia/rpc/rpc_client.py +144 -0
  602. chia/rpc/rpc_server.py +447 -0
  603. chia/rpc/timelord_rpc_api.py +27 -0
  604. chia/rpc/util.py +293 -0
  605. chia/rpc/wallet_request_types.py +688 -0
  606. chia/rpc/wallet_rpc_api.py +4779 -0
  607. chia/rpc/wallet_rpc_client.py +1844 -0
  608. chia/seeder/__init__.py +0 -0
  609. chia/seeder/crawl_store.py +427 -0
  610. chia/seeder/crawler.py +423 -0
  611. chia/seeder/crawler_api.py +129 -0
  612. chia/seeder/dns_server.py +544 -0
  613. chia/seeder/peer_record.py +146 -0
  614. chia/seeder/start_crawler.py +88 -0
  615. chia/server/__init__.py +0 -0
  616. chia/server/address_manager.py +658 -0
  617. chia/server/address_manager_store.py +237 -0
  618. chia/server/api_protocol.py +11 -0
  619. chia/server/capabilities.py +24 -0
  620. chia/server/chia_policy.py +345 -0
  621. chia/server/introducer_peers.py +76 -0
  622. chia/server/node_discovery.py +718 -0
  623. chia/server/outbound_message.py +33 -0
  624. chia/server/rate_limit_numbers.py +204 -0
  625. chia/server/rate_limits.py +113 -0
  626. chia/server/server.py +720 -0
  627. chia/server/signal_handlers.py +117 -0
  628. chia/server/ssl_context.py +32 -0
  629. chia/server/start_data_layer.py +137 -0
  630. chia/server/start_farmer.py +86 -0
  631. chia/server/start_full_node.py +106 -0
  632. chia/server/start_harvester.py +80 -0
  633. chia/server/start_introducer.py +69 -0
  634. chia/server/start_service.py +328 -0
  635. chia/server/start_timelord.py +82 -0
  636. chia/server/start_wallet.py +109 -0
  637. chia/server/upnp.py +117 -0
  638. chia/server/ws_connection.py +752 -0
  639. chia/simulator/__init__.py +0 -0
  640. chia/simulator/block_tools.py +2053 -0
  641. chia/simulator/full_node_simulator.py +802 -0
  642. chia/simulator/keyring.py +128 -0
  643. chia/simulator/setup_services.py +505 -0
  644. chia/simulator/simulator_constants.py +13 -0
  645. chia/simulator/simulator_full_node_rpc_api.py +101 -0
  646. chia/simulator/simulator_full_node_rpc_client.py +62 -0
  647. chia/simulator/simulator_protocol.py +29 -0
  648. chia/simulator/simulator_test_tools.py +163 -0
  649. chia/simulator/socket.py +27 -0
  650. chia/simulator/ssl_certs.py +114 -0
  651. chia/simulator/ssl_certs_1.py +699 -0
  652. chia/simulator/ssl_certs_10.py +699 -0
  653. chia/simulator/ssl_certs_2.py +699 -0
  654. chia/simulator/ssl_certs_3.py +699 -0
  655. chia/simulator/ssl_certs_4.py +699 -0
  656. chia/simulator/ssl_certs_5.py +699 -0
  657. chia/simulator/ssl_certs_6.py +699 -0
  658. chia/simulator/ssl_certs_7.py +699 -0
  659. chia/simulator/ssl_certs_8.py +699 -0
  660. chia/simulator/ssl_certs_9.py +699 -0
  661. chia/simulator/start_simulator.py +135 -0
  662. chia/simulator/wallet_tools.py +245 -0
  663. chia/ssl/__init__.py +0 -0
  664. chia/ssl/chia_ca.crt +19 -0
  665. chia/ssl/chia_ca.key +28 -0
  666. chia/ssl/create_ssl.py +249 -0
  667. chia/ssl/dst_root_ca.pem +20 -0
  668. chia/timelord/__init__.py +0 -0
  669. chia/timelord/iters_from_block.py +50 -0
  670. chia/timelord/timelord.py +1202 -0
  671. chia/timelord/timelord_api.py +132 -0
  672. chia/timelord/timelord_launcher.py +188 -0
  673. chia/timelord/timelord_state.py +244 -0
  674. chia/timelord/types.py +22 -0
  675. chia/types/__init__.py +0 -0
  676. chia/types/aliases.py +35 -0
  677. chia/types/block_protocol.py +20 -0
  678. chia/types/blockchain_format/__init__.py +0 -0
  679. chia/types/blockchain_format/classgroup.py +5 -0
  680. chia/types/blockchain_format/coin.py +28 -0
  681. chia/types/blockchain_format/foliage.py +8 -0
  682. chia/types/blockchain_format/pool_target.py +5 -0
  683. chia/types/blockchain_format/program.py +270 -0
  684. chia/types/blockchain_format/proof_of_space.py +135 -0
  685. chia/types/blockchain_format/reward_chain_block.py +6 -0
  686. chia/types/blockchain_format/serialized_program.py +5 -0
  687. chia/types/blockchain_format/sized_bytes.py +11 -0
  688. chia/types/blockchain_format/slots.py +9 -0
  689. chia/types/blockchain_format/sub_epoch_summary.py +5 -0
  690. chia/types/blockchain_format/tree_hash.py +72 -0
  691. chia/types/blockchain_format/vdf.py +86 -0
  692. chia/types/clvm_cost.py +13 -0
  693. chia/types/coin_record.py +43 -0
  694. chia/types/coin_spend.py +115 -0
  695. chia/types/condition_opcodes.py +73 -0
  696. chia/types/condition_with_args.py +17 -0
  697. chia/types/eligible_coin_spends.py +364 -0
  698. chia/types/end_of_slot_bundle.py +5 -0
  699. chia/types/fee_rate.py +38 -0
  700. chia/types/full_block.py +5 -0
  701. chia/types/generator_types.py +14 -0
  702. chia/types/header_block.py +5 -0
  703. chia/types/internal_mempool_item.py +19 -0
  704. chia/types/mempool_inclusion_status.py +9 -0
  705. chia/types/mempool_item.py +85 -0
  706. chia/types/mempool_submission_status.py +30 -0
  707. chia/types/mojos.py +7 -0
  708. chia/types/peer_info.py +64 -0
  709. chia/types/signing_mode.py +29 -0
  710. chia/types/spend_bundle.py +31 -0
  711. chia/types/spend_bundle_conditions.py +7 -0
  712. chia/types/transaction_queue_entry.py +55 -0
  713. chia/types/unfinished_block.py +5 -0
  714. chia/types/unfinished_header_block.py +37 -0
  715. chia/types/weight_proof.py +50 -0
  716. chia/util/__init__.py +0 -0
  717. chia/util/action_scope.py +168 -0
  718. chia/util/api_decorators.py +89 -0
  719. chia/util/async_pool.py +224 -0
  720. chia/util/augmented_chain.py +130 -0
  721. chia/util/batches.py +39 -0
  722. chia/util/bech32m.py +123 -0
  723. chia/util/beta_metrics.py +118 -0
  724. chia/util/block_cache.py +56 -0
  725. chia/util/byte_types.py +10 -0
  726. chia/util/check_fork_next_block.py +32 -0
  727. chia/util/chia_logging.py +124 -0
  728. chia/util/chia_version.py +33 -0
  729. chia/util/collection.py +17 -0
  730. chia/util/condition_tools.py +201 -0
  731. chia/util/config.py +366 -0
  732. chia/util/cpu.py +20 -0
  733. chia/util/db_synchronous.py +21 -0
  734. chia/util/db_version.py +30 -0
  735. chia/util/db_wrapper.py +427 -0
  736. chia/util/default_root.py +10 -0
  737. chia/util/dump_keyring.py +93 -0
  738. chia/util/english.txt +2048 -0
  739. chia/util/errors.py +351 -0
  740. chia/util/file_keyring.py +480 -0
  741. chia/util/files.py +95 -0
  742. chia/util/full_block_utils.py +321 -0
  743. chia/util/generator_tools.py +62 -0
  744. chia/util/hash.py +29 -0
  745. chia/util/initial-config.yaml +675 -0
  746. chia/util/inline_executor.py +24 -0
  747. chia/util/ints.py +19 -0
  748. chia/util/json_util.py +41 -0
  749. chia/util/keychain.py +673 -0
  750. chia/util/keyring_wrapper.py +266 -0
  751. chia/util/limited_semaphore.py +39 -0
  752. chia/util/lock.py +47 -0
  753. chia/util/log_exceptions.py +29 -0
  754. chia/util/logging.py +34 -0
  755. chia/util/lru_cache.py +29 -0
  756. chia/util/math.py +20 -0
  757. chia/util/network.py +240 -0
  758. chia/util/paginator.py +46 -0
  759. chia/util/path.py +29 -0
  760. chia/util/permissions.py +19 -0
  761. chia/util/pprint.py +40 -0
  762. chia/util/prev_transaction_block.py +23 -0
  763. chia/util/priority_mutex.py +92 -0
  764. chia/util/profiler.py +194 -0
  765. chia/util/recursive_replace.py +22 -0
  766. chia/util/safe_cancel_task.py +14 -0
  767. chia/util/service_groups.py +47 -0
  768. chia/util/setproctitle.py +20 -0
  769. chia/util/significant_bits.py +30 -0
  770. chia/util/ssl_check.py +213 -0
  771. chia/util/streamable.py +654 -0
  772. chia/util/task_timing.py +378 -0
  773. chia/util/timing.py +64 -0
  774. chia/util/vdf_prover.py +31 -0
  775. chia/util/ws_message.py +66 -0
  776. chia/wallet/__init__.py +0 -0
  777. chia/wallet/cat_wallet/__init__.py +0 -0
  778. chia/wallet/cat_wallet/cat_constants.py +75 -0
  779. chia/wallet/cat_wallet/cat_info.py +47 -0
  780. chia/wallet/cat_wallet/cat_outer_puzzle.py +120 -0
  781. chia/wallet/cat_wallet/cat_utils.py +163 -0
  782. chia/wallet/cat_wallet/cat_wallet.py +869 -0
  783. chia/wallet/cat_wallet/dao_cat_info.py +28 -0
  784. chia/wallet/cat_wallet/dao_cat_wallet.py +669 -0
  785. chia/wallet/cat_wallet/lineage_store.py +74 -0
  786. chia/wallet/cat_wallet/puzzles/__init__.py +0 -0
  787. chia/wallet/cat_wallet/puzzles/cat_truths.clib +31 -0
  788. chia/wallet/cat_wallet/puzzles/cat_v2.clsp +397 -0
  789. chia/wallet/cat_wallet/puzzles/cat_v2.clsp.hex +1 -0
  790. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp +25 -0
  791. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp.hex +1 -0
  792. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp +15 -0
  793. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp.hex +1 -0
  794. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp +26 -0
  795. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp.hex +1 -0
  796. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp +42 -0
  797. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp.hex +1 -0
  798. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp +24 -0
  799. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp.hex +1 -0
  800. chia/wallet/coin_selection.py +188 -0
  801. chia/wallet/conditions.py +1326 -0
  802. chia/wallet/dao_wallet/__init__.py +0 -0
  803. chia/wallet/dao_wallet/dao_info.py +61 -0
  804. chia/wallet/dao_wallet/dao_utils.py +810 -0
  805. chia/wallet/dao_wallet/dao_wallet.py +2121 -0
  806. chia/wallet/db_wallet/__init__.py +0 -0
  807. chia/wallet/db_wallet/db_wallet_puzzles.py +107 -0
  808. chia/wallet/derivation_record.py +30 -0
  809. chia/wallet/derive_keys.py +146 -0
  810. chia/wallet/did_wallet/__init__.py +0 -0
  811. chia/wallet/did_wallet/did_info.py +39 -0
  812. chia/wallet/did_wallet/did_wallet.py +1485 -0
  813. chia/wallet/did_wallet/did_wallet_puzzles.py +220 -0
  814. chia/wallet/did_wallet/puzzles/__init__.py +0 -0
  815. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp +135 -0
  816. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp.hex +1 -0
  817. chia/wallet/driver_protocol.py +26 -0
  818. chia/wallet/key_val_store.py +55 -0
  819. chia/wallet/lineage_proof.py +58 -0
  820. chia/wallet/nft_wallet/__init__.py +0 -0
  821. chia/wallet/nft_wallet/metadata_outer_puzzle.py +92 -0
  822. chia/wallet/nft_wallet/nft_info.py +120 -0
  823. chia/wallet/nft_wallet/nft_puzzles.py +305 -0
  824. chia/wallet/nft_wallet/nft_wallet.py +1686 -0
  825. chia/wallet/nft_wallet/ownership_outer_puzzle.py +101 -0
  826. chia/wallet/nft_wallet/puzzles/__init__.py +0 -0
  827. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp +6 -0
  828. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp.hex +1 -0
  829. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp +6 -0
  830. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp.hex +1 -0
  831. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp +30 -0
  832. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp.hex +1 -0
  833. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp +28 -0
  834. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp.hex +1 -0
  835. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp +100 -0
  836. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp.hex +1 -0
  837. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp +78 -0
  838. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp.hex +1 -0
  839. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp +74 -0
  840. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp.hex +1 -0
  841. chia/wallet/nft_wallet/singleton_outer_puzzle.py +101 -0
  842. chia/wallet/nft_wallet/transfer_program_puzzle.py +82 -0
  843. chia/wallet/nft_wallet/uncurry_nft.py +217 -0
  844. chia/wallet/notification_manager.py +117 -0
  845. chia/wallet/notification_store.py +178 -0
  846. chia/wallet/outer_puzzles.py +84 -0
  847. chia/wallet/payment.py +34 -0
  848. chia/wallet/puzzle_drivers.py +118 -0
  849. chia/wallet/puzzles/__init__.py +0 -0
  850. chia/wallet/puzzles/augmented_condition.clsp +13 -0
  851. chia/wallet/puzzles/augmented_condition.clsp.hex +1 -0
  852. chia/wallet/puzzles/clawback/__init__.py +0 -0
  853. chia/wallet/puzzles/clawback/drivers.py +188 -0
  854. chia/wallet/puzzles/clawback/metadata.py +38 -0
  855. chia/wallet/puzzles/clawback/puzzle_decorator.py +67 -0
  856. chia/wallet/puzzles/condition_codes.clib +77 -0
  857. chia/wallet/puzzles/curry-and-treehash.clib +102 -0
  858. chia/wallet/puzzles/curry.clib +135 -0
  859. chia/wallet/puzzles/curry_by_index.clib +16 -0
  860. chia/wallet/puzzles/dao_cat_eve.clsp +17 -0
  861. chia/wallet/puzzles/dao_cat_eve.clsp.hex +1 -0
  862. chia/wallet/puzzles/dao_cat_launcher.clsp +36 -0
  863. chia/wallet/puzzles/dao_cat_launcher.clsp.hex +1 -0
  864. chia/wallet/puzzles/dao_finished_state.clsp +35 -0
  865. chia/wallet/puzzles/dao_finished_state.clsp.hex +1 -0
  866. chia/wallet/puzzles/dao_finished_state.clsp.hex.sha256tree +1 -0
  867. chia/wallet/puzzles/dao_lockup.clsp +288 -0
  868. chia/wallet/puzzles/dao_lockup.clsp.hex +1 -0
  869. chia/wallet/puzzles/dao_lockup.clsp.hex.sha256tree +1 -0
  870. chia/wallet/puzzles/dao_proposal.clsp +377 -0
  871. chia/wallet/puzzles/dao_proposal.clsp.hex +1 -0
  872. chia/wallet/puzzles/dao_proposal.clsp.hex.sha256tree +1 -0
  873. chia/wallet/puzzles/dao_proposal_timer.clsp +78 -0
  874. chia/wallet/puzzles/dao_proposal_timer.clsp.hex +1 -0
  875. chia/wallet/puzzles/dao_proposal_timer.clsp.hex.sha256tree +1 -0
  876. chia/wallet/puzzles/dao_proposal_validator.clsp +87 -0
  877. chia/wallet/puzzles/dao_proposal_validator.clsp.hex +1 -0
  878. chia/wallet/puzzles/dao_proposal_validator.clsp.hex.sha256tree +1 -0
  879. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp +240 -0
  880. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex +1 -0
  881. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex.sha256tree +1 -0
  882. chia/wallet/puzzles/dao_treasury.clsp +115 -0
  883. chia/wallet/puzzles/dao_treasury.clsp.hex +1 -0
  884. chia/wallet/puzzles/dao_update_proposal.clsp +44 -0
  885. chia/wallet/puzzles/dao_update_proposal.clsp.hex +1 -0
  886. chia/wallet/puzzles/deployed_puzzle_hashes.json +67 -0
  887. chia/wallet/puzzles/json.clib +25 -0
  888. chia/wallet/puzzles/load_clvm.py +162 -0
  889. chia/wallet/puzzles/merkle_utils.clib +18 -0
  890. chia/wallet/puzzles/notification.clsp +7 -0
  891. chia/wallet/puzzles/notification.clsp.hex +1 -0
  892. chia/wallet/puzzles/p2_1_of_n.clsp +22 -0
  893. chia/wallet/puzzles/p2_1_of_n.clsp.hex +1 -0
  894. chia/wallet/puzzles/p2_conditions.clsp +3 -0
  895. chia/wallet/puzzles/p2_conditions.clsp.hex +1 -0
  896. chia/wallet/puzzles/p2_conditions.py +27 -0
  897. chia/wallet/puzzles/p2_delegated_conditions.clsp +18 -0
  898. chia/wallet/puzzles/p2_delegated_conditions.clsp.hex +1 -0
  899. chia/wallet/puzzles/p2_delegated_conditions.py +22 -0
  900. chia/wallet/puzzles/p2_delegated_puzzle.clsp +19 -0
  901. chia/wallet/puzzles/p2_delegated_puzzle.clsp.hex +1 -0
  902. chia/wallet/puzzles/p2_delegated_puzzle.py +35 -0
  903. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp +91 -0
  904. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp.hex +1 -0
  905. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +161 -0
  906. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp +108 -0
  907. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp.hex +1 -0
  908. chia/wallet/puzzles/p2_m_of_n_delegate_direct.py +22 -0
  909. chia/wallet/puzzles/p2_parent.clsp +19 -0
  910. chia/wallet/puzzles/p2_parent.clsp.hex +1 -0
  911. chia/wallet/puzzles/p2_puzzle_hash.clsp +18 -0
  912. chia/wallet/puzzles/p2_puzzle_hash.clsp.hex +1 -0
  913. chia/wallet/puzzles/p2_puzzle_hash.py +28 -0
  914. chia/wallet/puzzles/p2_singleton.clsp +30 -0
  915. chia/wallet/puzzles/p2_singleton.clsp.hex +1 -0
  916. chia/wallet/puzzles/p2_singleton_aggregator.clsp +81 -0
  917. chia/wallet/puzzles/p2_singleton_aggregator.clsp.hex +1 -0
  918. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp +50 -0
  919. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp.hex +1 -0
  920. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp +47 -0
  921. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp.hex +1 -0
  922. chia/wallet/puzzles/puzzle_utils.py +34 -0
  923. chia/wallet/puzzles/settlement_payments.clsp +49 -0
  924. chia/wallet/puzzles/settlement_payments.clsp.hex +1 -0
  925. chia/wallet/puzzles/sha256tree.clib +11 -0
  926. chia/wallet/puzzles/singleton_launcher.clsp +16 -0
  927. chia/wallet/puzzles/singleton_launcher.clsp.hex +1 -0
  928. chia/wallet/puzzles/singleton_top_layer.clsp +177 -0
  929. chia/wallet/puzzles/singleton_top_layer.clsp.hex +1 -0
  930. chia/wallet/puzzles/singleton_top_layer.py +295 -0
  931. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp +107 -0
  932. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp.hex +1 -0
  933. chia/wallet/puzzles/singleton_top_layer_v1_1.py +344 -0
  934. chia/wallet/puzzles/singleton_truths.clib +21 -0
  935. chia/wallet/puzzles/tails.py +344 -0
  936. chia/wallet/puzzles/utility_macros.clib +48 -0
  937. chia/wallet/signer_protocol.py +126 -0
  938. chia/wallet/singleton.py +106 -0
  939. chia/wallet/singleton_record.py +30 -0
  940. chia/wallet/trade_manager.py +1088 -0
  941. chia/wallet/trade_record.py +67 -0
  942. chia/wallet/trading/__init__.py +0 -0
  943. chia/wallet/trading/offer.py +703 -0
  944. chia/wallet/trading/trade_status.py +13 -0
  945. chia/wallet/trading/trade_store.py +526 -0
  946. chia/wallet/transaction_record.py +143 -0
  947. chia/wallet/transaction_sorting.py +14 -0
  948. chia/wallet/uncurried_puzzle.py +17 -0
  949. chia/wallet/util/__init__.py +0 -0
  950. chia/wallet/util/address_type.py +55 -0
  951. chia/wallet/util/blind_signer_tl.py +168 -0
  952. chia/wallet/util/clvm_streamable.py +203 -0
  953. chia/wallet/util/compute_hints.py +66 -0
  954. chia/wallet/util/compute_memos.py +45 -0
  955. chia/wallet/util/curry_and_treehash.py +90 -0
  956. chia/wallet/util/debug_spend_bundle.py +234 -0
  957. chia/wallet/util/merkle_tree.py +100 -0
  958. chia/wallet/util/merkle_utils.py +102 -0
  959. chia/wallet/util/new_peak_queue.py +82 -0
  960. chia/wallet/util/notifications.py +12 -0
  961. chia/wallet/util/peer_request_cache.py +174 -0
  962. chia/wallet/util/puzzle_compression.py +96 -0
  963. chia/wallet/util/puzzle_decorator.py +100 -0
  964. chia/wallet/util/puzzle_decorator_type.py +7 -0
  965. chia/wallet/util/query_filter.py +60 -0
  966. chia/wallet/util/transaction_type.py +23 -0
  967. chia/wallet/util/tx_config.py +158 -0
  968. chia/wallet/util/wallet_sync_utils.py +348 -0
  969. chia/wallet/util/wallet_types.py +65 -0
  970. chia/wallet/vc_wallet/__init__.py +0 -0
  971. chia/wallet/vc_wallet/cr_cat_drivers.py +663 -0
  972. chia/wallet/vc_wallet/cr_cat_wallet.py +875 -0
  973. chia/wallet/vc_wallet/cr_outer_puzzle.py +102 -0
  974. chia/wallet/vc_wallet/cr_puzzles/__init__.py +0 -0
  975. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp +3 -0
  976. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp.hex +1 -0
  977. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp +304 -0
  978. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp.hex +1 -0
  979. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp +45 -0
  980. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp.hex +1 -0
  981. chia/wallet/vc_wallet/vc_drivers.py +838 -0
  982. chia/wallet/vc_wallet/vc_puzzles/__init__.py +0 -0
  983. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp +30 -0
  984. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp.hex +1 -0
  985. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp +75 -0
  986. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp.hex +1 -0
  987. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp +32 -0
  988. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp.hex +1 -0
  989. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp +80 -0
  990. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp.hex +1 -0
  991. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp +163 -0
  992. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp.hex +1 -0
  993. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp +16 -0
  994. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp.hex +1 -0
  995. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp +74 -0
  996. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp.hex +1 -0
  997. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp +23 -0
  998. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp.hex +1 -0
  999. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp +64 -0
  1000. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp.hex +1 -0
  1001. chia/wallet/vc_wallet/vc_store.py +263 -0
  1002. chia/wallet/vc_wallet/vc_wallet.py +638 -0
  1003. chia/wallet/wallet.py +698 -0
  1004. chia/wallet/wallet_action_scope.py +95 -0
  1005. chia/wallet/wallet_blockchain.py +244 -0
  1006. chia/wallet/wallet_coin_record.py +72 -0
  1007. chia/wallet/wallet_coin_store.py +351 -0
  1008. chia/wallet/wallet_info.py +36 -0
  1009. chia/wallet/wallet_interested_store.py +188 -0
  1010. chia/wallet/wallet_nft_store.py +279 -0
  1011. chia/wallet/wallet_node.py +1769 -0
  1012. chia/wallet/wallet_node_api.py +201 -0
  1013. chia/wallet/wallet_pool_store.py +120 -0
  1014. chia/wallet/wallet_protocol.py +90 -0
  1015. chia/wallet/wallet_puzzle_store.py +365 -0
  1016. chia/wallet/wallet_retry_store.py +70 -0
  1017. chia/wallet/wallet_singleton_store.py +258 -0
  1018. chia/wallet/wallet_spend_bundle.py +41 -0
  1019. chia/wallet/wallet_state_manager.py +2820 -0
  1020. chia/wallet/wallet_transaction_store.py +470 -0
  1021. chia/wallet/wallet_user_store.py +110 -0
  1022. chia/wallet/wallet_weight_proof_handler.py +126 -0
  1023. chia_blockchain-2.4.4.dist-info/LICENSE +201 -0
  1024. chia_blockchain-2.4.4.dist-info/METADATA +161 -0
  1025. chia_blockchain-2.4.4.dist-info/RECORD +1028 -0
  1026. chia_blockchain-2.4.4.dist-info/WHEEL +4 -0
  1027. chia_blockchain-2.4.4.dist-info/entry_points.txt +17 -0
  1028. mozilla-ca/cacert.pem +3666 -0
@@ -0,0 +1,1769 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import contextlib
5
+ import dataclasses
6
+ import logging
7
+ import multiprocessing
8
+ import random
9
+ import sys
10
+ import time
11
+ import traceback
12
+ from pathlib import Path
13
+ from typing import (
14
+ TYPE_CHECKING,
15
+ Any,
16
+ AsyncIterator,
17
+ ClassVar,
18
+ Dict,
19
+ List,
20
+ Literal,
21
+ Optional,
22
+ Set,
23
+ Tuple,
24
+ Union,
25
+ cast,
26
+ overload,
27
+ )
28
+
29
+ import aiosqlite
30
+ from chia_rs import AugSchemeMPL, G1Element, G2Element, PrivateKey
31
+ from packaging.version import Version
32
+
33
+ from chia.consensus.blockchain import AddBlockResult
34
+ from chia.consensus.constants import ConsensusConstants
35
+ from chia.daemon.keychain_proxy import KeychainProxy, connect_to_keychain_and_validate, wrap_local_keychain
36
+ from chia.full_node.full_node_api import FullNodeAPI
37
+ from chia.protocols.full_node_protocol import RequestProofOfWeight, RespondProofOfWeight
38
+ from chia.protocols.protocol_message_types import ProtocolMessageTypes
39
+ from chia.protocols.wallet_protocol import (
40
+ CoinState,
41
+ CoinStateUpdate,
42
+ NewPeakWallet,
43
+ RegisterForCoinUpdates,
44
+ RequestBlockHeader,
45
+ RequestChildren,
46
+ RespondBlockHeader,
47
+ RespondChildren,
48
+ RespondToCoinUpdates,
49
+ SendTransaction,
50
+ )
51
+ from chia.rpc.rpc_server import StateChangedProtocol, default_get_connections
52
+ from chia.server.node_discovery import WalletPeers
53
+ from chia.server.outbound_message import Message, NodeType, make_msg
54
+ from chia.server.server import ChiaServer
55
+ from chia.server.ws_connection import WSChiaConnection
56
+ from chia.types.blockchain_format.coin import Coin
57
+ from chia.types.blockchain_format.sized_bytes import bytes32
58
+ from chia.types.header_block import HeaderBlock
59
+ from chia.types.mempool_inclusion_status import MempoolInclusionStatus
60
+ from chia.types.weight_proof import WeightProof
61
+ from chia.util.batches import to_batches
62
+ from chia.util.config import lock_and_load_config, process_config_start_method, save_config
63
+ from chia.util.db_wrapper import manage_connection
64
+ from chia.util.errors import KeychainIsEmpty, KeychainIsLocked, KeychainKeyNotFound, KeychainProxyConnectionFailure
65
+ from chia.util.hash import std_hash
66
+ from chia.util.ints import uint16, uint32, uint64, uint128
67
+ from chia.util.keychain import Keychain
68
+ from chia.util.path import path_from_root
69
+ from chia.util.profiler import mem_profile_task, profile_task
70
+ from chia.util.streamable import Streamable, streamable
71
+ from chia.wallet.puzzles.clawback.metadata import AutoClaimSettings
72
+ from chia.wallet.transaction_record import TransactionRecord
73
+ from chia.wallet.util.new_peak_queue import NewPeakItem, NewPeakQueue, NewPeakQueueTypes
74
+ from chia.wallet.util.peer_request_cache import PeerRequestCache, can_use_peer_request_cache
75
+ from chia.wallet.util.wallet_sync_utils import (
76
+ PeerRequestException,
77
+ fetch_header_blocks_in_range,
78
+ request_and_validate_additions,
79
+ request_and_validate_removals,
80
+ request_header_blocks,
81
+ sort_coin_states,
82
+ subscribe_to_coin_updates,
83
+ subscribe_to_phs,
84
+ )
85
+ from chia.wallet.util.wallet_types import CoinType, WalletType
86
+ from chia.wallet.wallet_spend_bundle import WalletSpendBundle
87
+ from chia.wallet.wallet_state_manager import WalletStateManager
88
+ from chia.wallet.wallet_weight_proof_handler import WalletWeightProofHandler, get_wp_fork_point
89
+
90
+
91
+ def get_wallet_db_path(root_path: Path, config: Dict[str, Any], key_fingerprint: str) -> Path:
92
+ """
93
+ Construct a path to the wallet db. Uses config values and the wallet key's fingerprint to
94
+ determine the wallet db filename.
95
+ """
96
+ db_path_replaced: str = (
97
+ config["database_path"].replace("CHALLENGE", config["selected_network"]).replace("KEY", key_fingerprint)
98
+ )
99
+
100
+ # "v2_r1" is the current wallet db version identifier
101
+ if "v2_r1" not in db_path_replaced:
102
+ db_path_replaced = db_path_replaced.replace("v2", "v2_r1").replace("v1", "v2_r1")
103
+
104
+ path: Path = path_from_root(root_path, db_path_replaced)
105
+ return path
106
+
107
+
108
+ @streamable
109
+ @dataclasses.dataclass(frozen=True)
110
+ class Balance(Streamable):
111
+ confirmed_wallet_balance: uint128 = uint128(0)
112
+ unconfirmed_wallet_balance: uint128 = uint128(0)
113
+ spendable_balance: uint128 = uint128(0)
114
+ pending_change: uint64 = uint64(0)
115
+ max_send_amount: uint128 = uint128(0)
116
+ unspent_coin_count: uint32 = uint32(0)
117
+ pending_coin_removal_count: uint32 = uint32(0)
118
+
119
+
120
+ @dataclasses.dataclass
121
+ class WalletNode:
122
+ if TYPE_CHECKING:
123
+ from chia.rpc.rpc_server import RpcServiceProtocol
124
+
125
+ _protocol_check: ClassVar[RpcServiceProtocol] = cast("WalletNode", None)
126
+
127
+ config: Dict[str, Any]
128
+ root_path: Path
129
+ constants: ConsensusConstants
130
+ local_keychain: Optional[Keychain] = None
131
+
132
+ log: logging.Logger = logging.getLogger(__name__)
133
+
134
+ # Sync data
135
+ state_changed_callback: Optional[StateChangedProtocol] = None
136
+ _wallet_state_manager: Optional[WalletStateManager] = None
137
+ _weight_proof_handler: Optional[WalletWeightProofHandler] = None
138
+ _server: Optional[ChiaServer] = None
139
+ sync_task: Optional[asyncio.Task[None]] = None
140
+ logged_in_fingerprint: Optional[int] = None
141
+ logged_in: bool = False
142
+ _keychain_proxy: Optional[KeychainProxy] = None
143
+ _balance_cache: Dict[int, Balance] = dataclasses.field(default_factory=dict)
144
+ # Peers that we have long synced to
145
+ synced_peers: Set[bytes32] = dataclasses.field(default_factory=set)
146
+ wallet_peers: Optional[WalletPeers] = None
147
+ peer_caches: Dict[bytes32, PeerRequestCache] = dataclasses.field(default_factory=dict)
148
+ validation_semaphore: Optional[asyncio.Semaphore] = None
149
+ local_node_synced: bool = False
150
+ LONG_SYNC_THRESHOLD: int = 300
151
+ last_wallet_tx_resend_time: int = 0
152
+ # Duration in seconds
153
+ coin_state_retry_seconds: int = 10
154
+ wallet_tx_resend_timeout_secs: int = 1800
155
+ _new_peak_queue: Optional[NewPeakQueue] = None
156
+
157
+ _shut_down: bool = False
158
+ _process_new_subscriptions_task: Optional[asyncio.Task[None]] = None
159
+ _retry_failed_states_task: Optional[asyncio.Task[None]] = None
160
+ _secondary_peer_sync_task: Optional[asyncio.Task[None]] = None
161
+ _tx_messages_in_progress: Dict[bytes32, List[bytes32]] = dataclasses.field(default_factory=dict)
162
+
163
+ @contextlib.asynccontextmanager
164
+ async def manage(self) -> AsyncIterator[None]:
165
+ await self._start()
166
+ try:
167
+ yield
168
+ finally:
169
+ self._close()
170
+ await self._await_closed()
171
+
172
+ @property
173
+ def keychain_proxy(self) -> KeychainProxy:
174
+ # This is a stop gap until the class usage is refactored such the values of
175
+ # integral attributes are known at creation of the instance.
176
+ if self._keychain_proxy is None:
177
+ raise RuntimeError("keychain proxy not assigned")
178
+
179
+ return self._keychain_proxy
180
+
181
+ @property
182
+ def wallet_state_manager(self) -> WalletStateManager:
183
+ # This is a stop gap until the class usage is refactored such the values of
184
+ # integral attributes are known at creation of the instance.
185
+ if self._wallet_state_manager is None:
186
+ raise RuntimeError("wallet state manager not assigned")
187
+
188
+ return self._wallet_state_manager
189
+
190
+ @property
191
+ def server(self) -> ChiaServer:
192
+ # This is a stop gap until the class usage is refactored such the values of
193
+ # integral attributes are known at creation of the instance.
194
+ if self._server is None:
195
+ raise RuntimeError("server not assigned")
196
+
197
+ return self._server
198
+
199
+ @property
200
+ def new_peak_queue(self) -> NewPeakQueue:
201
+ # This is a stop gap until the class usage is refactored such the values of
202
+ # integral attributes are known at creation of the instance.
203
+ if self._new_peak_queue is None:
204
+ raise RuntimeError("new peak queue not assigned")
205
+
206
+ return self._new_peak_queue
207
+
208
+ def get_connections(self, request_node_type: Optional[NodeType]) -> List[Dict[str, Any]]:
209
+ return default_get_connections(server=self.server, request_node_type=request_node_type)
210
+
211
+ async def ensure_keychain_proxy(self) -> KeychainProxy:
212
+ if self._keychain_proxy is None:
213
+ if self.local_keychain:
214
+ self._keychain_proxy = wrap_local_keychain(self.local_keychain, log=self.log)
215
+ else:
216
+ self._keychain_proxy = await connect_to_keychain_and_validate(self.root_path, self.log)
217
+ if not self._keychain_proxy:
218
+ raise KeychainProxyConnectionFailure()
219
+ return self._keychain_proxy
220
+
221
+ def get_cache_for_peer(self, peer: WSChiaConnection) -> PeerRequestCache:
222
+ if peer.peer_node_id not in self.peer_caches:
223
+ self.peer_caches[peer.peer_node_id] = PeerRequestCache()
224
+ return self.peer_caches[peer.peer_node_id]
225
+
226
+ def rollback_request_caches(self, reorg_height: int) -> None:
227
+ # Everything after reorg_height should be removed from the cache
228
+ for cache in self.peer_caches.values():
229
+ cache.clear_after_height(reorg_height)
230
+
231
+ @overload
232
+ async def get_key_for_fingerprint(self, fingerprint: Optional[int]) -> Optional[G1Element]: ...
233
+
234
+ @overload
235
+ async def get_key_for_fingerprint(
236
+ self, fingerprint: Optional[int], private: Literal[True]
237
+ ) -> Optional[PrivateKey]: ...
238
+
239
+ @overload
240
+ async def get_key_for_fingerprint(
241
+ self, fingerprint: Optional[int], private: Literal[False]
242
+ ) -> Optional[G1Element]: ...
243
+
244
+ @overload
245
+ async def get_key_for_fingerprint(
246
+ self, fingerprint: Optional[int], private: bool
247
+ ) -> Optional[Union[PrivateKey, G1Element]]: ...
248
+
249
+ async def get_key_for_fingerprint(
250
+ self, fingerprint: Optional[int], private: bool = False
251
+ ) -> Optional[Union[PrivateKey, G1Element]]:
252
+ try:
253
+ keychain_proxy = await self.ensure_keychain_proxy()
254
+ # Returns first key if fingerprint is None
255
+ key: Optional[Union[PrivateKey, G1Element]] = await keychain_proxy.get_key_for_fingerprint(
256
+ fingerprint, private=private
257
+ )
258
+ except KeychainIsEmpty:
259
+ self.log.warning("No keys present. Create keys with the UI, or with the 'chia keys' program.")
260
+ return None
261
+ except KeychainKeyNotFound:
262
+ self.log.warning(f"Key not found for fingerprint {fingerprint}")
263
+ return None
264
+ except KeychainIsLocked:
265
+ self.log.warning("Keyring is locked")
266
+ return None
267
+ except KeychainProxyConnectionFailure as e:
268
+ tb = traceback.format_exc()
269
+ self.log.error(f"Missing keychain_proxy: {e} {tb}")
270
+ raise # Re-raise so that the caller can decide whether to continue or abort
271
+
272
+ return key
273
+
274
+ async def get_key(
275
+ self, fingerprint: Optional[int], private: bool = True, find_a_default: bool = True
276
+ ) -> Optional[Union[PrivateKey, G1Element]]:
277
+ """
278
+ Attempt to get the private key for the given fingerprint. If the fingerprint is None,
279
+ get_key_for_fingerprint() will return the first private key. Similarly, if a key isn't
280
+ returned for the provided fingerprint, the first key will be returned.
281
+ """
282
+ key: Optional[Union[PrivateKey, G1Element]] = await self.get_key_for_fingerprint(fingerprint, private=private)
283
+
284
+ if key is None and fingerprint is not None and find_a_default:
285
+ key = await self.get_key_for_fingerprint(None, private=private)
286
+ if key is not None:
287
+ if isinstance(key, PrivateKey):
288
+ fp = key.get_g1().get_fingerprint()
289
+ else:
290
+ fp = key.get_fingerprint()
291
+ self.log.info(f"Using first key found (fingerprint: {fp})")
292
+
293
+ return key
294
+
295
+ def set_resync_on_startup(self, fingerprint: int, enabled: bool = True) -> None:
296
+ with lock_and_load_config(self.root_path, "config.yaml") as config:
297
+ if enabled is True:
298
+ config["wallet"]["reset_sync_for_fingerprint"] = fingerprint
299
+ self.log.info("Enabled resync for wallet fingerprint: %s", fingerprint)
300
+ else:
301
+ self.log.debug(
302
+ "Trying to disable resync: %s [%s]", fingerprint, config["wallet"].get("reset_sync_for_fingerprint")
303
+ )
304
+ if config["wallet"].get("reset_sync_for_fingerprint") == fingerprint:
305
+ del config["wallet"]["reset_sync_for_fingerprint"]
306
+ self.log.info("Disabled resync for wallet fingerprint: %s", fingerprint)
307
+ save_config(self.root_path, "config.yaml", config)
308
+
309
+ def set_auto_claim(self, auto_claim_config: AutoClaimSettings) -> Dict[str, Any]:
310
+ if auto_claim_config.batch_size < 1:
311
+ auto_claim_config = dataclasses.replace(auto_claim_config, batch_size=uint16(50))
312
+ auto_claim_config_json = auto_claim_config.to_json_dict()
313
+ if "auto_claim" not in self.config or self.config["auto_claim"] != auto_claim_config_json:
314
+ # Update in memory config
315
+ self.config["auto_claim"] = auto_claim_config_json
316
+ # Update config file
317
+ with lock_and_load_config(self.root_path, "config.yaml") as config:
318
+ config["wallet"]["auto_claim"] = self.config["auto_claim"]
319
+ save_config(self.root_path, "config.yaml", config)
320
+ return auto_claim_config.to_json_dict()
321
+
322
+ async def reset_sync_db(self, db_path: Union[Path, str], fingerprint: int) -> bool:
323
+ conn: aiosqlite.Connection
324
+ # are not part of core wallet tables, but might appear later
325
+ ignore_tables = {"lineage_proofs_", "sqlite_", "MIGRATED_VALID_TIMES_TXS", "MIGRATED_VALID_TIMES_TRADES"}
326
+ known_tables = [
327
+ "coin_record",
328
+ "transaction_record",
329
+ "derivation_paths",
330
+ "users_wallets",
331
+ "users_nfts",
332
+ "action_queue",
333
+ "all_notification_ids",
334
+ "key_val_store",
335
+ "trade_records",
336
+ "trade_record_times",
337
+ "tx_times",
338
+ "pool_state_transitions",
339
+ "singleton_records",
340
+ "mirrors",
341
+ "mirror_confirmations",
342
+ "launchers",
343
+ "launcher_confirmations",
344
+ "interested_coins",
345
+ "interested_puzzle_hashes",
346
+ "unacknowledged_asset_tokens",
347
+ "coin_of_interest_to_trade_record",
348
+ "notifications",
349
+ "retry_store",
350
+ "unacknowledged_asset_token_states",
351
+ "vc_records",
352
+ "vc_proofs",
353
+ ]
354
+
355
+ async with manage_connection(db_path) as conn:
356
+ self.log.info("Resetting wallet sync data...")
357
+ rows = list(await conn.execute_fetchall("SELECT name FROM sqlite_master WHERE type='table'"))
358
+ names = {x[0] for x in rows}
359
+ names = names - set(known_tables)
360
+ tables_to_drop = []
361
+ for name in names:
362
+ for ignore_name in ignore_tables:
363
+ if name.startswith(ignore_name):
364
+ break
365
+ else:
366
+ tables_to_drop.append(name)
367
+
368
+ await conn.execute("BEGIN")
369
+ commit = True
370
+ tables = [row[0] for row in rows]
371
+ try:
372
+ for table in tables_to_drop:
373
+ await conn.execute(f"DROP TABLE {table}")
374
+ if "coin_record" in tables:
375
+ await conn.execute("DELETE FROM coin_record")
376
+ if "interested_coins" in tables:
377
+ await conn.execute("DELETE FROM interested_coins")
378
+ if "interested_puzzle_hashes" in tables:
379
+ await conn.execute("DELETE FROM interested_puzzle_hashes")
380
+ if "key_val_store" in tables:
381
+ await conn.execute("DELETE FROM key_val_store")
382
+ if "users_nfts" in tables:
383
+ await conn.execute("DELETE FROM users_nfts")
384
+ except aiosqlite.Error:
385
+ self.log.exception("Error resetting sync tables")
386
+ commit = False
387
+ finally:
388
+ try:
389
+ if commit:
390
+ self.log.info("Reset wallet sync data completed.")
391
+ await conn.execute("COMMIT")
392
+ else:
393
+ self.log.info("Reverting reset resync changes")
394
+ await conn.execute("ROLLBACK")
395
+ except aiosqlite.Error:
396
+ self.log.exception("Error finishing reset resync db")
397
+ # disable the resync in any case
398
+ self.set_resync_on_startup(fingerprint, False)
399
+ return commit
400
+
401
+ async def _start(self) -> None:
402
+ await self._start_with_fingerprint()
403
+
404
+ async def _start_with_fingerprint(
405
+ self,
406
+ fingerprint: Optional[int] = None,
407
+ ) -> bool:
408
+ # Makes sure the coin_state_updates get higher priority than new_peak messages.
409
+ # Delayed instantiation until here to avoid errors.
410
+ # got Future <Future pending> attached to a different loop
411
+ self._new_peak_queue = NewPeakQueue(inner_queue=asyncio.PriorityQueue())
412
+ if not fingerprint:
413
+ fingerprint = self.get_last_used_fingerprint()
414
+ multiprocessing_start_method = process_config_start_method(config=self.config, log=self.log)
415
+ multiprocessing_context = multiprocessing.get_context(method=multiprocessing_start_method)
416
+ self._weight_proof_handler = WalletWeightProofHandler(self.constants, multiprocessing_context)
417
+ self.synced_peers = set()
418
+ public_key = None
419
+ private_key = await self.get_key(fingerprint, private=True, find_a_default=False)
420
+ if private_key is None:
421
+ public_key = await self.get_key(fingerprint, private=False, find_a_default=False)
422
+ else:
423
+ assert isinstance(private_key, PrivateKey)
424
+ public_key = private_key.get_g1()
425
+
426
+ if public_key is None:
427
+ private_key = await self.get_key(None, private=True, find_a_default=True)
428
+ if private_key is not None:
429
+ assert isinstance(private_key, PrivateKey)
430
+ public_key = private_key.get_g1()
431
+ else:
432
+ self.log_out()
433
+ return False
434
+ assert isinstance(public_key, G1Element)
435
+ # override with private key fetched in case it's different from what was passed
436
+ if fingerprint is None:
437
+ fingerprint = public_key.get_fingerprint()
438
+ if self.config.get("enable_profiler", False):
439
+ if sys.getprofile() is not None:
440
+ self.log.warning("not enabling profiler, getprofile() is already set")
441
+ else:
442
+ asyncio.create_task(profile_task(self.root_path, "wallet", self.log))
443
+
444
+ if self.config.get("enable_memory_profiler", False):
445
+ asyncio.create_task(mem_profile_task(self.root_path, "wallet", self.log))
446
+
447
+ path: Path = get_wallet_db_path(self.root_path, self.config, str(fingerprint))
448
+ path.parent.mkdir(parents=True, exist_ok=True)
449
+ if self.config.get("reset_sync_for_fingerprint") == fingerprint:
450
+ await self.reset_sync_db(path, fingerprint)
451
+
452
+ assert private_key is None or isinstance(private_key, PrivateKey)
453
+ self._wallet_state_manager = await WalletStateManager.create(
454
+ private_key,
455
+ self.config,
456
+ path,
457
+ self.constants,
458
+ self.server,
459
+ self.root_path,
460
+ self,
461
+ public_key,
462
+ )
463
+
464
+ if self.state_changed_callback is not None:
465
+ self.wallet_state_manager.set_callback(self.state_changed_callback)
466
+
467
+ self.last_wallet_tx_resend_time = int(time.time())
468
+ self.wallet_tx_resend_timeout_secs = self.config.get("tx_resend_timeout_secs", 60 * 60)
469
+ self.wallet_state_manager.set_pending_callback(self._pending_tx_handler)
470
+ self._shut_down = False
471
+ self._process_new_subscriptions_task = asyncio.create_task(self._process_new_subscriptions())
472
+ self._retry_failed_states_task = asyncio.create_task(self._retry_failed_states())
473
+
474
+ self.sync_event = asyncio.Event()
475
+ self.log_in(fingerprint)
476
+ self.wallet_state_manager.state_changed("sync_changed")
477
+
478
+ # Populate the balance caches for all wallets
479
+ async with self.wallet_state_manager.lock:
480
+ for wallet_id in self.wallet_state_manager.wallets:
481
+ await self._update_balance_cache(wallet_id)
482
+
483
+ async with self.wallet_state_manager.puzzle_store.lock:
484
+ index = await self.wallet_state_manager.puzzle_store.get_last_derivation_path()
485
+ if index is None or index < self.wallet_state_manager.initial_num_public_keys - 1:
486
+ await self.wallet_state_manager.create_more_puzzle_hashes(from_zero=True)
487
+
488
+ if self.wallet_peers is None:
489
+ self.initialize_wallet_peers()
490
+
491
+ return True
492
+
493
+ def _close(self) -> None:
494
+ self.log.info("self._close")
495
+ self.log_out()
496
+ self._shut_down = True
497
+ if self._weight_proof_handler is not None:
498
+ self._weight_proof_handler.cancel_weight_proof_tasks()
499
+ if self._process_new_subscriptions_task is not None:
500
+ self._process_new_subscriptions_task.cancel()
501
+ if self._retry_failed_states_task is not None:
502
+ self._retry_failed_states_task.cancel()
503
+ if self._secondary_peer_sync_task is not None:
504
+ self._secondary_peer_sync_task.cancel()
505
+
506
+ async def _await_closed(self, shutting_down: bool = True) -> None:
507
+ self.log.info("self._await_closed")
508
+ if self._server is not None:
509
+ await self.server.close_all_connections()
510
+ if self.wallet_peers is not None:
511
+ await self.wallet_peers.ensure_is_closed()
512
+ if self._wallet_state_manager is not None:
513
+ await self.wallet_state_manager._await_closed()
514
+ self._wallet_state_manager = None
515
+ if shutting_down and self._keychain_proxy is not None:
516
+ proxy = self._keychain_proxy
517
+ self._keychain_proxy = None
518
+ await proxy.close()
519
+ await asyncio.sleep(0.5) # https://docs.aiohttp.org/en/stable/client_advanced.html#graceful-shutdown
520
+ self.wallet_peers = None
521
+ self._balance_cache = {}
522
+
523
+ def _set_state_changed_callback(self, callback: StateChangedProtocol) -> None:
524
+ self.state_changed_callback = callback
525
+
526
+ if self._wallet_state_manager is not None:
527
+ self.wallet_state_manager.set_callback(self.state_changed_callback)
528
+ self.wallet_state_manager.set_pending_callback(self._pending_tx_handler)
529
+
530
+ def _pending_tx_handler(self) -> None:
531
+ if self._wallet_state_manager is None:
532
+ return None
533
+ asyncio.create_task(self._resend_queue())
534
+
535
+ async def _resend_queue(self) -> None:
536
+ if self._shut_down or self._server is None or self._wallet_state_manager is None:
537
+ return None
538
+
539
+ for msg, sent_peers in await self._messages_to_resend():
540
+ if self._shut_down or self._server is None or self._wallet_state_manager is None:
541
+ return None
542
+ full_nodes = self.server.get_connections(NodeType.FULL_NODE)
543
+ for peer in full_nodes:
544
+ if peer.peer_node_id in sent_peers:
545
+ continue
546
+ msg_name: bytes32 = std_hash(msg.data)
547
+ if (
548
+ peer.peer_node_id in self._tx_messages_in_progress
549
+ and msg_name in self._tx_messages_in_progress[peer.peer_node_id]
550
+ ):
551
+ continue
552
+ self.log.debug(f"sending: {msg}")
553
+ await peer.send_message(msg)
554
+ self._tx_messages_in_progress.setdefault(peer.peer_node_id, [])
555
+ self._tx_messages_in_progress[peer.peer_node_id].append(msg_name)
556
+
557
+ async def _messages_to_resend(self) -> List[Tuple[Message, Set[bytes32]]]:
558
+ if self._wallet_state_manager is None or self._shut_down:
559
+ return []
560
+ messages: List[Tuple[Message, Set[bytes32]]] = []
561
+
562
+ current_time = int(time.time())
563
+ retry_accepted_txs = False
564
+ if self.last_wallet_tx_resend_time < current_time - self.wallet_tx_resend_timeout_secs:
565
+ self.last_wallet_tx_resend_time = current_time
566
+ retry_accepted_txs = True
567
+ records: List[TransactionRecord] = await self.wallet_state_manager.tx_store.get_not_sent(
568
+ include_accepted_txs=retry_accepted_txs
569
+ )
570
+
571
+ for record in records:
572
+ if record.spend_bundle is None:
573
+ continue
574
+ msg = make_msg(ProtocolMessageTypes.send_transaction, SendTransaction(record.spend_bundle))
575
+ already_sent = set()
576
+ for peer, status, _ in record.sent_to:
577
+ if status == MempoolInclusionStatus.SUCCESS.value:
578
+ already_sent.add(bytes32.from_hexstr(peer))
579
+ messages.append((msg, already_sent))
580
+
581
+ return messages
582
+
583
+ async def _retry_failed_states(self) -> None:
584
+ while not self._shut_down:
585
+ try:
586
+ await asyncio.sleep(self.coin_state_retry_seconds)
587
+ if self.wallet_state_manager is None:
588
+ continue
589
+ states_to_retry = await self.wallet_state_manager.retry_store.get_all_states_to_retry()
590
+ for state, peer_id, fork_height in states_to_retry:
591
+ matching_peer = tuple(
592
+ p for p in self.server.get_connections(NodeType.FULL_NODE) if p.peer_node_id == peer_id
593
+ )
594
+ if len(matching_peer) == 0:
595
+ try:
596
+ peer = self.get_full_node_peer()
597
+ self.log.info(
598
+ f"disconnected from peer {peer_id}, state will retry with {peer.peer_node_id}"
599
+ )
600
+ except ValueError:
601
+ self.log.info(f"disconnected from all peers, cannot retry state: {state}")
602
+ continue
603
+ else:
604
+ peer = matching_peer[0]
605
+ async with self.wallet_state_manager.db_wrapper.writer():
606
+ self.log.info(f"retrying coin_state: {state}")
607
+ await self.wallet_state_manager.add_coin_states(
608
+ [state], peer, None if fork_height == 0 else fork_height
609
+ )
610
+ except asyncio.CancelledError:
611
+ self.log.info("Retry task cancelled, exiting.")
612
+ raise
613
+
614
+ async def _process_new_subscriptions(self) -> None:
615
+ while not self._shut_down:
616
+ # Here we process four types of messages in the queue, where the first one has higher priority (lower
617
+ # number in the queue), and priority decreases for each type.
618
+ peer: Optional[WSChiaConnection] = None
619
+ item: Optional[NewPeakItem] = None
620
+ try:
621
+ peer, item = None, None
622
+ item = await self.new_peak_queue.get()
623
+ assert item is not None
624
+ if item.item_type == NewPeakQueueTypes.COIN_ID_SUBSCRIPTION:
625
+ self.log.debug("Pulled from queue: %s %s", item.item_type.name, item.data)
626
+ # Subscriptions are the highest priority, because we don't want to process any more peaks or
627
+ # state updates until we are sure that we subscribed to everything that we need to. Otherwise,
628
+ # we might not be able to process some state.
629
+ coin_ids: List[bytes32] = item.data
630
+ for peer in self.server.get_connections(NodeType.FULL_NODE):
631
+ coin_states: List[CoinState] = await subscribe_to_coin_updates(coin_ids, peer, 0)
632
+ if len(coin_states) > 0:
633
+ async with self.wallet_state_manager.lock:
634
+ await self.add_states_from_peer(coin_states, peer)
635
+ elif item.item_type == NewPeakQueueTypes.PUZZLE_HASH_SUBSCRIPTION:
636
+ self.log.debug("Pulled from queue: %s %s", item.item_type.name, item.data)
637
+ puzzle_hashes: List[bytes32] = item.data
638
+ for peer in self.server.get_connections(NodeType.FULL_NODE):
639
+ # Puzzle hash subscription
640
+ coin_states = await subscribe_to_phs(puzzle_hashes, peer, 0)
641
+ if len(coin_states) > 0:
642
+ async with self.wallet_state_manager.lock:
643
+ await self.add_states_from_peer(coin_states, peer)
644
+ elif item.item_type == NewPeakQueueTypes.FULL_NODE_STATE_UPDATED:
645
+ # Note: this can take a while when we have a lot of transactions. We want to process these
646
+ # before new_peaks, since new_peak_wallet requires that we first obtain the state for that peak.
647
+ self.log.debug("Pulled from queue: %s %s", item.item_type.name, item.data[0])
648
+ coin_state_update = item.data[0]
649
+ peer = item.data[1]
650
+ assert peer is not None
651
+ await self.state_update_received(coin_state_update, peer)
652
+ elif item.item_type == NewPeakQueueTypes.NEW_PEAK_WALLET:
653
+ self.log.debug("Pulled from queue: %s %s", item.item_type.name, item.data[0])
654
+ # This can take a VERY long time, because it might trigger a long sync. It is OK if we miss some
655
+ # subscriptions or state updates, since all subscriptions and state updates will be handled by
656
+ # long_sync (up to the target height).
657
+ new_peak = item.data[0]
658
+ peer = item.data[1]
659
+ assert peer is not None
660
+ await self.new_peak_wallet(new_peak, peer)
661
+ else:
662
+ self.log.debug("Pulled from queue: UNKNOWN %s", item.item_type)
663
+ assert False
664
+ except asyncio.CancelledError:
665
+ self.log.info("Queue task cancelled, exiting.")
666
+ raise
667
+ except Exception as e:
668
+ self.log.error(f"Exception handling {item}, {e} {traceback.format_exc()}")
669
+ if peer is not None:
670
+ await peer.close(9999)
671
+
672
+ def log_in(self, fingerprint: int) -> None:
673
+ self.logged_in_fingerprint = fingerprint
674
+ self.logged_in = True
675
+ self.log.info(f"Wallet is logged in using key with fingerprint: {self.logged_in_fingerprint}")
676
+ try:
677
+ self.update_last_used_fingerprint()
678
+ except Exception:
679
+ self.log.exception("Non-fatal: Unable to update last used fingerprint.")
680
+
681
+ def log_out(self) -> None:
682
+ self.logged_in_fingerprint = None
683
+ self.logged_in = False
684
+
685
+ def update_last_used_fingerprint(self) -> None:
686
+ fingerprint = self.logged_in_fingerprint
687
+ assert fingerprint is not None
688
+ path = self.get_last_used_fingerprint_path()
689
+ path.parent.mkdir(parents=True, exist_ok=True)
690
+ path.write_text(str(fingerprint))
691
+ self.log.info(f"Updated last used fingerprint: {fingerprint}")
692
+
693
+ def get_last_used_fingerprint(self) -> Optional[int]:
694
+ fingerprint: Optional[int] = None
695
+ try:
696
+ path = self.get_last_used_fingerprint_path()
697
+ if path.exists():
698
+ fingerprint = int(path.read_text().strip())
699
+ except Exception:
700
+ self.log.exception("Non-fatal: Unable to read last used fingerprint.")
701
+ return fingerprint
702
+
703
+ def get_last_used_fingerprint_path(self) -> Path:
704
+ db_path: Path = path_from_root(self.root_path, self.config["database_path"])
705
+ fingerprint_path = db_path.parent / "last_used_fingerprint"
706
+ return fingerprint_path
707
+
708
+ def set_server(self, server: ChiaServer) -> None:
709
+ self._server = server
710
+ self.initialize_wallet_peers()
711
+
712
+ def initialize_wallet_peers(self) -> None:
713
+ self.server.on_connect = self.on_connect
714
+ network_name = self.config["selected_network"]
715
+ try:
716
+ default_port = self.config["network_overrides"]["config"][network_name]["default_full_node_port"]
717
+ except KeyError:
718
+ self.log.info("Default port field not found in config.")
719
+ default_port = None
720
+ connect_to_unknown_peers = self.config.get("connect_to_unknown_peers", True)
721
+ testing = self.config.get("testing", False)
722
+ if self.wallet_peers is None and connect_to_unknown_peers and not testing:
723
+ self.wallet_peers = WalletPeers(
724
+ self.server,
725
+ self.config["target_peer_count"],
726
+ self.root_path / Path(self.config.get("wallet_peers_file_path", "wallet/db/wallet_peers.dat")),
727
+ self.config["introducer_peer"],
728
+ self.config.get("dns_servers", ["dns-introducer.chia.net"]),
729
+ self.config["peer_connect_interval"],
730
+ network_name,
731
+ default_port,
732
+ self.log,
733
+ )
734
+ asyncio.create_task(self.wallet_peers.start())
735
+
736
+ async def on_disconnect(self, peer: WSChiaConnection) -> None:
737
+ if self.is_trusted(peer):
738
+ self.local_node_synced = False
739
+ self.initialize_wallet_peers()
740
+
741
+ if peer.peer_node_id in self.peer_caches:
742
+ self.peer_caches.pop(peer.peer_node_id)
743
+ if peer.peer_node_id in self.synced_peers:
744
+ self.synced_peers.remove(peer.peer_node_id)
745
+ if peer.peer_node_id in self._tx_messages_in_progress:
746
+ del self._tx_messages_in_progress[peer.peer_node_id]
747
+
748
+ self.wallet_state_manager.state_changed("close_connection")
749
+
750
+ async def on_connect(self, peer: WSChiaConnection) -> None:
751
+ if self._wallet_state_manager is None:
752
+ return None
753
+
754
+ if peer.protocol_version < Version("0.0.33"):
755
+ self.log.info("Disconnecting, full node running old software")
756
+ await peer.close()
757
+
758
+ trusted = self.is_trusted(peer)
759
+ if not trusted and self.local_node_synced:
760
+ await peer.close()
761
+
762
+ if peer.peer_node_id in self.synced_peers:
763
+ self.synced_peers.remove(peer.peer_node_id)
764
+
765
+ self.log.info(f"Connected peer {peer.get_peer_info()} is trusted: {trusted}")
766
+ messages_peer_ids = await self._messages_to_resend()
767
+ self.wallet_state_manager.state_changed("add_connection")
768
+ for msg, peer_ids in messages_peer_ids:
769
+ if peer.peer_node_id in peer_ids:
770
+ continue
771
+ await peer.send_message(msg)
772
+
773
+ if self.wallet_peers is not None:
774
+ await self.wallet_peers.on_connect(peer)
775
+
776
+ async def perform_atomic_rollback(self, fork_height: int, cache: Optional[PeerRequestCache] = None) -> None:
777
+ self.log.info(f"perform_atomic_rollback to {fork_height}")
778
+ # this is to start a write transaction
779
+ async with self.wallet_state_manager.db_wrapper.writer():
780
+ try:
781
+ removed_wallet_ids = await self.wallet_state_manager.reorg_rollback(fork_height)
782
+ await self.wallet_state_manager.blockchain.set_finished_sync_up_to(fork_height, in_rollback=True)
783
+ if cache is None:
784
+ self.rollback_request_caches(fork_height)
785
+ else:
786
+ cache.clear_after_height(fork_height)
787
+ except Exception as e:
788
+ tb = traceback.format_exc()
789
+ self.log.error(f"Exception while perform_atomic_rollback: {e} {tb}")
790
+ raise
791
+ else:
792
+ await self.wallet_state_manager.blockchain.clean_block_records()
793
+
794
+ for wallet_id in removed_wallet_ids:
795
+ self.wallet_state_manager.wallets.pop(wallet_id)
796
+
797
+ # this has to be called *after* the transaction commits, otherwise it
798
+ # won't see the changes (since we spawn a new task to handle potential
799
+ # resends)
800
+ self._pending_tx_handler()
801
+
802
+ async def long_sync(
803
+ self,
804
+ target_height: uint32,
805
+ full_node: WSChiaConnection,
806
+ fork_height: int,
807
+ *,
808
+ rollback: bool,
809
+ ) -> None:
810
+ """
811
+ Sync algorithm:
812
+ - Download and verify weight proof (if not trusted)
813
+ - Roll back anything after the fork point (if rollback=True)
814
+ - Subscribe to all puzzle_hashes over and over until there are no more updates
815
+ - Subscribe to all coin_ids over and over until there are no more updates
816
+ - rollback=False means that we are just double-checking with this peer to make sure we don't have any
817
+ missing transactions, so we don't need to rollback
818
+ """
819
+
820
+ def is_new_state_update(cs: CoinState) -> bool:
821
+ if cs.spent_height is None and cs.created_height is None:
822
+ return True
823
+ if cs.spent_height is not None and cs.spent_height >= fork_height:
824
+ return True
825
+ if cs.created_height is not None and cs.created_height >= fork_height:
826
+ return True
827
+ return False
828
+
829
+ trusted: bool = self.is_trusted(full_node)
830
+ self.log.info(f"Starting sync trusted: {trusted} to peer {full_node.peer_info.host}")
831
+ start_time = time.time()
832
+
833
+ if rollback:
834
+ # we should clear all peers since this is a full rollback
835
+ await self.perform_atomic_rollback(fork_height)
836
+ await self.update_ui()
837
+
838
+ # We only process new state updates to avoid slow reprocessing. We set the sync height after adding
839
+ # Things, so we don't have to reprocess these later. There can be many things in ph_update_res.
840
+ use_delta_sync = self.config.get("use_delta_sync", False)
841
+ min_height_for_subscriptions = fork_height if use_delta_sync else 0
842
+ already_checked_ph: Set[bytes32] = set()
843
+ while not self._shut_down:
844
+ await self.wallet_state_manager.create_more_puzzle_hashes()
845
+ all_puzzle_hashes = await self.get_puzzle_hashes_to_subscribe()
846
+ not_checked_puzzle_hashes = set(all_puzzle_hashes) - already_checked_ph
847
+ if not_checked_puzzle_hashes == set():
848
+ break
849
+ for batch in to_batches(not_checked_puzzle_hashes, 1000):
850
+ ph_update_res: List[CoinState] = await subscribe_to_phs(
851
+ batch.entries, full_node, min_height_for_subscriptions
852
+ )
853
+ ph_update_res = list(filter(is_new_state_update, ph_update_res))
854
+ if not await self.add_states_from_peer(ph_update_res, full_node):
855
+ # If something goes wrong, abort sync
856
+ return
857
+ already_checked_ph.update(not_checked_puzzle_hashes)
858
+
859
+ self.log.info(f"Successfully subscribed and updated {len(already_checked_ph)} puzzle hashes")
860
+
861
+ # The number of coin id updates are usually going to be significantly less than ph updates, so we can
862
+ # sync from 0 every time.
863
+ already_checked_coin_ids: Set[bytes32] = set()
864
+ while not self._shut_down:
865
+ all_coin_ids = await self.get_coin_ids_to_subscribe()
866
+ not_checked_coin_ids = set(all_coin_ids) - already_checked_coin_ids
867
+ if not_checked_coin_ids == set():
868
+ break
869
+ for batch in to_batches(not_checked_coin_ids, 1000):
870
+ c_update_res: List[CoinState] = await subscribe_to_coin_updates(
871
+ batch.entries, full_node, min_height_for_subscriptions
872
+ )
873
+
874
+ if not await self.add_states_from_peer(c_update_res, full_node):
875
+ # If something goes wrong, abort sync
876
+ return
877
+ already_checked_coin_ids.update(not_checked_coin_ids)
878
+ self.log.info(f"Successfully subscribed and updated {len(already_checked_coin_ids)} coin ids")
879
+
880
+ # Only update this fully when the entire sync has completed
881
+ await self.wallet_state_manager.blockchain.set_finished_sync_up_to(target_height)
882
+
883
+ if trusted:
884
+ self.local_node_synced = True
885
+
886
+ self.wallet_state_manager.state_changed("new_block")
887
+
888
+ self.synced_peers.add(full_node.peer_node_id)
889
+ await self.update_ui()
890
+
891
+ self.log.info(f"Sync (trusted: {trusted}) duration was: {time.time() - start_time}")
892
+
893
+ async def add_states_from_peer(
894
+ self,
895
+ items_input: List[CoinState],
896
+ peer: WSChiaConnection,
897
+ fork_height: Optional[uint32] = None,
898
+ height: Optional[uint32] = None,
899
+ ) -> bool:
900
+ # Adds the state to the wallet state manager. If the peer is trusted, we do not validate. If the peer is
901
+ # untrusted we do, but we might not add the state, since we need to receive the new_peak message as well.
902
+ assert self._wallet_state_manager is not None
903
+ trusted = self.is_trusted(peer)
904
+ # Validate states in parallel, apply serial
905
+ # TODO: optimize fetching
906
+ if self.validation_semaphore is None:
907
+ self.validation_semaphore = asyncio.Semaphore(10)
908
+
909
+ # Rollback is handled in wallet_short_sync_backtrack for untrusted peers, so we don't need to do it here.
910
+ # Also it's not safe to rollback, an untrusted peer can give us old fork point and make our TX disappear.
911
+ # wallet_short_sync_backtrack can safely rollback because we validated the weight for the new peak so we
912
+ # know the peer is telling the truth about the reorg.
913
+
914
+ # If there is a fork, we need to ensure that we roll back in trusted mode to properly handle reorgs
915
+ cache: PeerRequestCache = self.get_cache_for_peer(peer)
916
+
917
+ if (
918
+ trusted
919
+ and fork_height is not None
920
+ and height is not None
921
+ and fork_height != height - 1
922
+ and peer.peer_node_id in self.synced_peers
923
+ ):
924
+ # only one peer told us to rollback so only clear for that peer
925
+ await self.perform_atomic_rollback(fork_height, cache=cache)
926
+ else:
927
+ if fork_height is not None:
928
+ # only one peer told us to rollback so only clear for that peer
929
+ cache.clear_after_height(fork_height)
930
+ self.log.info(f"clear_after_height {fork_height} for peer {peer}")
931
+ if not trusted:
932
+ # Rollback race_cache not in clear_after_height to avoid applying rollbacks from new peak processing
933
+ cache.rollback_race_cache(fork_height=fork_height)
934
+
935
+ all_tasks: List[asyncio.Task[None]] = []
936
+ target_concurrent_tasks: int = 30
937
+
938
+ # Ensure the list is sorted
939
+ unique_items = set(items_input)
940
+ before = len(unique_items)
941
+ items = await self.wallet_state_manager.filter_spam(sort_coin_states(unique_items))
942
+ num_filtered = before - len(items)
943
+ if num_filtered > 0:
944
+ self.log.info(f"Filtered {num_filtered} spam transactions")
945
+
946
+ async def validate_and_add(inner_states: List[CoinState], inner_idx_start: int) -> None:
947
+ try:
948
+ assert self.validation_semaphore is not None
949
+ async with self.validation_semaphore:
950
+ valid_states = [
951
+ inner_state
952
+ for inner_state in inner_states
953
+ if await self.validate_received_state_from_peer(inner_state, peer, cache, fork_height)
954
+ ]
955
+ if len(valid_states) > 0:
956
+ async with self.wallet_state_manager.db_wrapper.writer():
957
+ self.log.info(
958
+ f"new coin state received ({inner_idx_start}-"
959
+ f"{inner_idx_start + len(inner_states) - 1}/ {len(updated_coin_states)})"
960
+ )
961
+ await self.wallet_state_manager.add_coin_states(valid_states, peer, fork_height)
962
+ except Exception as e:
963
+ tb = traceback.format_exc()
964
+ log_level = logging.DEBUG if peer.closed or self._shut_down else logging.ERROR
965
+ self.log.log(log_level, f"validate_and_add failed - exception: {e}, traceback: {tb}")
966
+
967
+ # Keep chunk size below 1000 just in case, windows has sqlite limits of 999 per query
968
+ # Untrusted has a smaller batch size since validation has to happen which takes a while
969
+ chunk_size: int = 900 if trusted else 10
970
+
971
+ reorged_coin_states = []
972
+ updated_coin_states = []
973
+ for coin_state in items:
974
+ if coin_state.created_height is None:
975
+ reorged_coin_states.append(coin_state)
976
+ else:
977
+ updated_coin_states.append(coin_state)
978
+
979
+ # Reorged coin states don't require any validation in untrusted mode, so we can just always apply them upfront
980
+ # instead of adding them to the race cache in untrusted mode.
981
+ for batch in to_batches(reorged_coin_states, chunk_size):
982
+ self.log.info(f"Process reorged states: ({len(batch.entries)} / {len(reorged_coin_states)})")
983
+ if not await self.wallet_state_manager.add_coin_states(batch.entries, peer, fork_height):
984
+ self.log.debug("Processing reorged states failed")
985
+ return False
986
+
987
+ idx = 1
988
+ for batch in to_batches(updated_coin_states, chunk_size):
989
+ if self._server is None:
990
+ self.log.error("No server")
991
+ await asyncio.gather(*all_tasks)
992
+ return False
993
+ if peer.peer_node_id not in self.server.all_connections:
994
+ self.log.error(f"Disconnected from peer {peer.peer_node_id} host {peer.peer_info.host}")
995
+ await asyncio.gather(*all_tasks)
996
+ return False
997
+ if trusted:
998
+ async with self.wallet_state_manager.db_wrapper.writer():
999
+ self.log.info(
1000
+ f"new coin state received ({idx}-{idx + len(batch.entries) - 1}/ {len(updated_coin_states)})"
1001
+ )
1002
+ if not await self.wallet_state_manager.add_coin_states(batch.entries, peer, fork_height):
1003
+ return False
1004
+ else:
1005
+ if fork_height is not None:
1006
+ cache.add_states_to_race_cache(batch.entries)
1007
+ else:
1008
+ while len(all_tasks) >= target_concurrent_tasks:
1009
+ all_tasks = [task for task in all_tasks if not task.done()]
1010
+ await asyncio.sleep(0.1)
1011
+ if self._shut_down:
1012
+ self.log.info("Terminating receipt and validation due to shut down request")
1013
+ await asyncio.gather(*all_tasks)
1014
+ return False
1015
+ all_tasks.append(asyncio.create_task(validate_and_add(batch.entries, idx)))
1016
+ idx += len(batch.entries)
1017
+
1018
+ still_connected = self._server is not None and peer.peer_node_id in self.server.all_connections
1019
+ await asyncio.gather(*all_tasks)
1020
+ await self.update_ui()
1021
+ return still_connected and self._server is not None and peer.peer_node_id in self.server.all_connections
1022
+
1023
+ def is_timestamp_in_sync(self, timestamp: uint64) -> bool:
1024
+ return self.config.get("testing", False) or uint64(time.time()) - timestamp < 600
1025
+
1026
+ def is_trusted(self, peer: WSChiaConnection) -> bool:
1027
+ return self.server.is_trusted_peer(peer, self.config.get("trusted_peers", {}))
1028
+
1029
+ async def state_update_received(self, request: CoinStateUpdate, peer: WSChiaConnection) -> None:
1030
+ # This gets called every time there is a new coin or puzzle hash change in the DB
1031
+ # that is of interest to this wallet. It is not guaranteed to come for every height. This message is guaranteed
1032
+ # to come before the corresponding new_peak for each height. We handle this differently for trusted and
1033
+ # untrusted peers. For trusted, we always process the state, and we process reorgs as well.
1034
+ for coin in request.items:
1035
+ self.log.info(f"request coin: {coin.coin.name().hex()}{coin}")
1036
+
1037
+ async with self.wallet_state_manager.lock:
1038
+ await self.add_states_from_peer(
1039
+ request.items,
1040
+ peer,
1041
+ request.fork_height,
1042
+ request.height,
1043
+ )
1044
+
1045
+ def get_full_node_peer(self) -> WSChiaConnection:
1046
+ """
1047
+ Get a full node, preferring synced & trusted > synced & untrusted > unsynced & trusted > unsynced & untrusted
1048
+ """
1049
+ full_nodes: List[WSChiaConnection] = self.get_full_node_peers_in_order()
1050
+ if len(full_nodes) == 0:
1051
+ raise ValueError("No peer connected")
1052
+ return full_nodes[0]
1053
+
1054
+ def get_full_node_peers_in_order(self) -> List[WSChiaConnection]:
1055
+ """
1056
+ Get all full nodes sorted:
1057
+ preferring synced & trusted > synced & untrusted > unsynced & trusted > unsynced & untrusted
1058
+ """
1059
+ if self._server is None:
1060
+ return []
1061
+
1062
+ synced_and_trusted: List[WSChiaConnection] = []
1063
+ synced: List[WSChiaConnection] = []
1064
+ trusted: List[WSChiaConnection] = []
1065
+ neither: List[WSChiaConnection] = []
1066
+ all_nodes: List[WSChiaConnection] = self.server.get_connections(NodeType.FULL_NODE)
1067
+ random.shuffle(all_nodes)
1068
+ for node in all_nodes:
1069
+ we_synced_to_it = node.peer_node_id in self.synced_peers
1070
+ is_trusted = self.is_trusted(node)
1071
+ if we_synced_to_it and is_trusted:
1072
+ synced_and_trusted.append(node)
1073
+ elif we_synced_to_it:
1074
+ synced.append(node)
1075
+ elif is_trusted:
1076
+ trusted.append(node)
1077
+ else:
1078
+ neither.append(node)
1079
+ return synced_and_trusted + synced + trusted + neither
1080
+
1081
+ async def get_timestamp_for_height_from_peer(self, height: uint32, peer: WSChiaConnection) -> Optional[uint64]:
1082
+ """
1083
+ Returns the timestamp for transaction block at h=height, if not transaction block, backtracks until it finds
1084
+ a transaction block
1085
+ """
1086
+ cache = self.get_cache_for_peer(peer)
1087
+ request_height: int = height
1088
+ while request_height >= 0:
1089
+ cached_timestamp = cache.get_height_timestamp(uint32(request_height))
1090
+ if cached_timestamp is not None:
1091
+ return cached_timestamp
1092
+ block = cache.get_block(uint32(request_height))
1093
+ if block is None:
1094
+ self.log.debug(f"get_timestamp_for_height_from_peer cache miss for height {request_height}")
1095
+ response: Optional[List[HeaderBlock]] = await request_header_blocks(
1096
+ peer, uint32(request_height), uint32(request_height)
1097
+ )
1098
+ if response is not None and len(response) > 0:
1099
+ self.log.debug(f"get_timestamp_for_height_from_peer add to cache for height {request_height}")
1100
+ cache.add_to_blocks(response[0])
1101
+ block = response[0]
1102
+ elif request_height < height:
1103
+ # The peer might be slightly behind but still synced, so we should allow fetching one more block
1104
+ break
1105
+ else:
1106
+ self.log.debug(f"get_timestamp_for_height_from_peer use cached block for height {request_height}")
1107
+
1108
+ if block is not None and block.foliage_transaction_block is not None:
1109
+ return block.foliage_transaction_block.timestamp
1110
+
1111
+ request_height -= 1
1112
+
1113
+ return None
1114
+
1115
+ async def get_timestamp_for_height(self, height: uint32) -> uint64:
1116
+ for peer in self.get_full_node_peers_in_order():
1117
+ timestamp = await self.get_timestamp_for_height_from_peer(height, peer)
1118
+ if timestamp is not None:
1119
+ return timestamp
1120
+ raise PeerRequestException("Error fetching timestamp from all peers")
1121
+
1122
+ async def new_peak_wallet(self, new_peak: NewPeakWallet, peer: WSChiaConnection) -> None:
1123
+ if self._wallet_state_manager is None:
1124
+ # When logging out of wallet
1125
+ self.log.debug("state manager is None (shutdown)")
1126
+ return
1127
+ trusted: bool = self.is_trusted(peer)
1128
+ peak_hb: Optional[HeaderBlock] = await self.wallet_state_manager.blockchain.get_peak_block()
1129
+ if peak_hb is not None and new_peak.weight < peak_hb.weight:
1130
+ # Discards old blocks, but accepts blocks that are equal in weight to peak
1131
+ self.log.debug("skip block with lower weight.")
1132
+ return
1133
+
1134
+ request = RequestBlockHeader(new_peak.height)
1135
+ response: Optional[RespondBlockHeader] = await peer.call_api(FullNodeAPI.request_block_header, request)
1136
+ if response is None:
1137
+ self.log.warning(f"Peer {peer.get_peer_info()} did not respond in time.")
1138
+ await peer.close(120)
1139
+ return
1140
+
1141
+ new_peak_hb: HeaderBlock = response.header_block
1142
+ # check response is what we asked for
1143
+ if (
1144
+ new_peak_hb.header_hash != new_peak.header_hash
1145
+ or new_peak_hb.weight != new_peak.weight
1146
+ or new_peak_hb.height != new_peak.height
1147
+ ):
1148
+ self.log.warning(f"bad header block response from Peer {peer.get_peer_info()}.")
1149
+ # todo maybe accept the block if
1150
+ # new_peak_hb.height == new_peak.height and new_peak_hb.weight >= new_peak.weight
1151
+
1152
+ # dont disconnect from peer, this might be a reorg
1153
+ return
1154
+
1155
+ latest_timestamp = await self.get_timestamp_for_height_from_peer(new_peak_hb.height, peer)
1156
+ if latest_timestamp is None or not self.is_timestamp_in_sync(latest_timestamp):
1157
+ if trusted:
1158
+ self.log.debug(f"Trusted peer {peer.get_peer_info()} is not synced.")
1159
+ else:
1160
+ self.log.warning(f"Non-trusted peer {peer.get_peer_info()} is not synced, disconnecting")
1161
+ await peer.close(120)
1162
+ return
1163
+
1164
+ if self.is_trusted(peer):
1165
+ await self.new_peak_from_trusted(new_peak_hb, latest_timestamp, peer)
1166
+ else:
1167
+ if not await self.new_peak_from_untrusted(new_peak_hb, peer):
1168
+ return
1169
+
1170
+ # todo why do we call this if there was an exception / the sync is not finished
1171
+ async with self.wallet_state_manager.lock:
1172
+ await self.wallet_state_manager.new_peak(new_peak.height)
1173
+
1174
+ # Check if any coin needs auto spending
1175
+ if self.config.get("auto_claim", {}).get("enabled", False):
1176
+ await self.wallet_state_manager.auto_claim_coins()
1177
+
1178
+ if peer.peer_node_id in self.synced_peers:
1179
+ await self.wallet_state_manager.blockchain.set_finished_sync_up_to(new_peak.height)
1180
+
1181
+ async def new_peak_from_trusted(
1182
+ self, new_peak_hb: HeaderBlock, latest_timestamp: uint64, peer: WSChiaConnection
1183
+ ) -> None:
1184
+ async with self.wallet_state_manager.set_sync_mode(new_peak_hb.height) as current_height:
1185
+ await self.wallet_state_manager.blockchain.set_peak_block(new_peak_hb, latest_timestamp)
1186
+ # Sync to trusted node if we haven't done so yet. As long as we have synced once (and not
1187
+ # disconnected), we assume that the full node will continue to give us state updates, so we do
1188
+ # not need to resync.
1189
+ if peer.peer_node_id not in self.synced_peers:
1190
+ await self.long_sync(new_peak_hb.height, peer, uint32(max(0, current_height - 256)), rollback=True)
1191
+
1192
+ async def new_peak_from_untrusted(self, new_peak_hb: HeaderBlock, peer: WSChiaConnection) -> bool:
1193
+ far_behind: bool = (
1194
+ new_peak_hb.height - await self.wallet_state_manager.blockchain.get_finished_sync_up_to()
1195
+ > self.LONG_SYNC_THRESHOLD
1196
+ )
1197
+
1198
+ if new_peak_hb.height < self.constants.WEIGHT_PROOF_RECENT_BLOCKS:
1199
+ # this is the case happens chain is shorter then WEIGHT_PROOF_RECENT_BLOCKS
1200
+ return await self.sync_from_untrusted_close_to_peak(new_peak_hb, peer)
1201
+
1202
+ if not far_behind and peer.peer_node_id in self.synced_peers:
1203
+ # This is the (untrusted) case where we already synced and are not too far behind. Here we just
1204
+ # fetch one by one.
1205
+ return await self.sync_from_untrusted_close_to_peak(new_peak_hb, peer)
1206
+
1207
+ # we haven't synced fully to this peer yet
1208
+ syncing = False
1209
+ if far_behind or len(self.synced_peers) == 0:
1210
+ syncing = True
1211
+
1212
+ secondary_sync_running = (
1213
+ self._secondary_peer_sync_task is not None and self._secondary_peer_sync_task.done() is False
1214
+ )
1215
+ if not syncing and secondary_sync_running:
1216
+ self.log.info("Will not do secondary sync, there is already another sync task running.")
1217
+ return False
1218
+
1219
+ try:
1220
+ await self.long_sync_from_untrusted(syncing, new_peak_hb, peer)
1221
+ except Exception:
1222
+ self.log.exception(f"Error syncing to {peer.get_peer_info()}")
1223
+ await peer.close()
1224
+ return False
1225
+ return True
1226
+
1227
+ async def long_sync_from_untrusted(self, syncing: bool, new_peak_hb: HeaderBlock, peer: WSChiaConnection) -> None:
1228
+ current_height: uint32 = await self.wallet_state_manager.blockchain.get_finished_sync_up_to()
1229
+ fork_point_weight_proof = await self.fetch_and_update_weight_proof(peer, new_peak_hb)
1230
+ # This usually happens the first time we start up the wallet. We roll back slightly to be
1231
+ # safe, but we don't want to rollback too much (hence 16)
1232
+ fork_point_rollback: int = max(0, current_height - 16)
1233
+ # If the weight proof fork point is in the past, rollback more to ensure we don't have duplicate
1234
+ fork_point_syncing = min(fork_point_rollback, fork_point_weight_proof)
1235
+
1236
+ if syncing:
1237
+ async with self.wallet_state_manager.set_sync_mode(new_peak_hb.height):
1238
+ await self.long_sync(new_peak_hb.height, peer, fork_point_syncing, rollback=True)
1239
+ return
1240
+
1241
+ # we exit earlier in the case where syncing is False and a Secondary sync is running
1242
+ assert self._secondary_peer_sync_task is None or self._secondary_peer_sync_task.done()
1243
+ self.log.info("Secondary peer syncing")
1244
+ # In this case we will not rollback so it's OK to check some older updates as well, to ensure
1245
+ # that no recent transactions are being hidden.
1246
+ self._secondary_peer_sync_task = asyncio.create_task(
1247
+ self.long_sync(new_peak_hb.height, peer, 0, rollback=False)
1248
+ )
1249
+
1250
+ async def sync_from_untrusted_close_to_peak(self, new_peak_hb: HeaderBlock, peer: WSChiaConnection) -> bool:
1251
+ async with self.wallet_state_manager.lock:
1252
+ peak_hb = await self.wallet_state_manager.blockchain.get_peak_block()
1253
+ if peak_hb is None or new_peak_hb.weight > peak_hb.weight:
1254
+ backtrack_fork_height: int = await self.wallet_short_sync_backtrack(new_peak_hb, peer)
1255
+ else:
1256
+ backtrack_fork_height = new_peak_hb.height - 1
1257
+ fork_height = max(backtrack_fork_height, 0)
1258
+
1259
+ use_delta_sync = self.config.get("use_delta_sync", False)
1260
+ min_height_for_subscriptions = fork_height if use_delta_sync else 0
1261
+ cache = self.get_cache_for_peer(peer)
1262
+ if peer.peer_node_id not in self.synced_peers:
1263
+ # Edge case, this happens when the peak < WEIGHT_PROOF_RECENT_BLOCKS
1264
+ # we still want to subscribe for all phs and coins.
1265
+ # (Hints are not in filter)
1266
+ all_coin_ids: List[bytes32] = await self.get_coin_ids_to_subscribe()
1267
+ phs: List[bytes32] = await self.get_puzzle_hashes_to_subscribe()
1268
+ ph_updates: List[CoinState] = await subscribe_to_phs(phs, peer, min_height_for_subscriptions)
1269
+ coin_updates: List[CoinState] = await subscribe_to_coin_updates(
1270
+ all_coin_ids, peer, min_height_for_subscriptions
1271
+ )
1272
+ success = await self.add_states_from_peer(
1273
+ ph_updates + coin_updates,
1274
+ peer,
1275
+ fork_height=uint32(fork_height),
1276
+ )
1277
+ if success:
1278
+ self.synced_peers.add(peer.peer_node_id)
1279
+ else:
1280
+ if peak_hb is not None and new_peak_hb.weight <= peak_hb.weight:
1281
+ # Don't process blocks at the same weight
1282
+ return False
1283
+
1284
+ # For every block, we need to apply the cache from race_cache
1285
+ for potential_height in range(backtrack_fork_height + 1, new_peak_hb.height + 1):
1286
+ try:
1287
+ race_cache = cache.get_race_cache(potential_height)
1288
+ except KeyError:
1289
+ continue
1290
+
1291
+ self.log.info(f"Apply race cache - height: {potential_height}, coin_states: {race_cache}")
1292
+ await self.add_states_from_peer(list(race_cache), peer)
1293
+
1294
+ # Clear old entries that are no longer relevant
1295
+ cache.cleanup_race_cache(min_height=backtrack_fork_height)
1296
+
1297
+ self.wallet_state_manager.state_changed("new_block")
1298
+ self.log.info(f"Finished processing new peak of {new_peak_hb.height}")
1299
+ return True
1300
+
1301
+ async def wallet_short_sync_backtrack(self, header_block: HeaderBlock, peer: WSChiaConnection) -> int:
1302
+ peak: Optional[HeaderBlock] = await self.wallet_state_manager.blockchain.get_peak_block()
1303
+
1304
+ top = header_block
1305
+ blocks = [top]
1306
+ # Fetch blocks backwards until we hit the one that we have,
1307
+ # then complete them with additions / removals going forward
1308
+ fork_height = 0
1309
+ if self.wallet_state_manager.blockchain.contains_block(header_block.prev_header_hash):
1310
+ fork_height = header_block.height - 1
1311
+
1312
+ while not self.wallet_state_manager.blockchain.contains_block(top.prev_header_hash) and top.height > 0:
1313
+ request_prev = RequestBlockHeader(uint32(top.height - 1))
1314
+ response_prev: Optional[RespondBlockHeader] = await peer.call_api(
1315
+ FullNodeAPI.request_block_header, request_prev
1316
+ )
1317
+ if response_prev is None or not isinstance(response_prev, RespondBlockHeader):
1318
+ raise RuntimeError("bad block header response from peer while syncing")
1319
+ prev_head = response_prev.header_block
1320
+ blocks.append(prev_head)
1321
+ top = prev_head
1322
+ fork_height = top.height - 1
1323
+
1324
+ blocks.reverse()
1325
+ # Roll back coins and transactions
1326
+ peak_height = await self.wallet_state_manager.blockchain.get_finished_sync_up_to()
1327
+ if fork_height < peak_height:
1328
+ self.log.info(f"Rolling back to {fork_height}")
1329
+ # we should clear all peers since this is a full rollback
1330
+ await self.perform_atomic_rollback(fork_height)
1331
+ await self.update_ui()
1332
+
1333
+ if peak is not None:
1334
+ assert header_block.weight >= peak.weight
1335
+ for block in blocks:
1336
+ # Set blockchain to the latest peak
1337
+ res, err = await self.wallet_state_manager.blockchain.add_block(block)
1338
+ if res == AddBlockResult.INVALID_BLOCK:
1339
+ raise ValueError(err)
1340
+
1341
+ return fork_height
1342
+
1343
+ async def update_ui(self) -> None:
1344
+ for wallet_id, wallet in self.wallet_state_manager.wallets.items():
1345
+ self.wallet_state_manager.state_changed("coin_removed", wallet_id)
1346
+ self.wallet_state_manager.state_changed("coin_added", wallet_id)
1347
+
1348
+ async def fetch_and_update_weight_proof(self, peer: WSChiaConnection, peak: HeaderBlock) -> int:
1349
+ assert self._weight_proof_handler is not None
1350
+ weight_request = RequestProofOfWeight(peak.height, peak.header_hash)
1351
+ wp_timeout = self.config.get("weight_proof_timeout", 360)
1352
+ self.log.debug(f"weight proof timeout is {wp_timeout} sec")
1353
+ weight_proof_response: RespondProofOfWeight = await peer.call_api(
1354
+ FullNodeAPI.request_proof_of_weight, weight_request, timeout=wp_timeout
1355
+ )
1356
+
1357
+ if weight_proof_response is None:
1358
+ raise Exception("weight proof response was none")
1359
+
1360
+ weight_proof = weight_proof_response.wp
1361
+
1362
+ if weight_proof.recent_chain_data[-1].height != peak.height:
1363
+ raise Exception("weight proof height does not match peak")
1364
+ if weight_proof.recent_chain_data[-1].weight != peak.weight:
1365
+ raise Exception("weight proof weight does not match peak")
1366
+ if weight_proof.recent_chain_data[-1].header_hash != peak.header_hash:
1367
+ raise Exception("weight proof peak hash does not match peak")
1368
+
1369
+ old_proof = self.wallet_state_manager.blockchain.synced_weight_proof
1370
+ block_records = await self._weight_proof_handler.validate_weight_proof(weight_proof, False, old_proof)
1371
+
1372
+ await self.wallet_state_manager.blockchain.new_valid_weight_proof(weight_proof, block_records)
1373
+
1374
+ return get_wp_fork_point(self.constants, old_proof, weight_proof)
1375
+
1376
+ async def get_puzzle_hashes_to_subscribe(self) -> List[bytes32]:
1377
+ all_puzzle_hashes = await self.wallet_state_manager.puzzle_store.get_all_puzzle_hashes(1)
1378
+ # Get all phs from interested store
1379
+ interested_puzzle_hashes = [
1380
+ t[0] for t in await self.wallet_state_manager.interested_store.get_interested_puzzle_hashes()
1381
+ ]
1382
+ all_puzzle_hashes.update(interested_puzzle_hashes)
1383
+ return list(all_puzzle_hashes)
1384
+
1385
+ async def get_coin_ids_to_subscribe(self) -> List[bytes32]:
1386
+ coin_ids = await self.wallet_state_manager.trade_manager.get_coins_of_interest()
1387
+ coin_ids.update(await self.wallet_state_manager.interested_store.get_interested_coin_ids())
1388
+ return list(coin_ids)
1389
+
1390
+ async def validate_received_state_from_peer(
1391
+ self,
1392
+ coin_state: CoinState,
1393
+ peer: WSChiaConnection,
1394
+ peer_request_cache: PeerRequestCache,
1395
+ fork_height: Optional[uint32],
1396
+ ) -> bool:
1397
+ """
1398
+ Returns True if the coin_state is valid and included in the blockchain proved by the weight proof.
1399
+ """
1400
+ if peer.closed:
1401
+ return False
1402
+ # Only use the cache if we are talking about states before the fork point. If we are evaluating something
1403
+ # in a reorg, we cannot use the cache, since we don't know if it's actually in the new chain after the reorg.
1404
+ if can_use_peer_request_cache(coin_state, peer_request_cache, fork_height):
1405
+ return True
1406
+
1407
+ spent_height: Optional[uint32] = None if coin_state.spent_height is None else uint32(coin_state.spent_height)
1408
+ confirmed_height: Optional[uint32] = (
1409
+ None if coin_state.created_height is None else uint32(coin_state.created_height)
1410
+ )
1411
+ current = await self.wallet_state_manager.coin_store.get_coin_record(coin_state.coin.name())
1412
+ # if remote state is same as current local state we skip validation
1413
+
1414
+ # CoinRecord unspent = height 0, coin state = None. We adjust for comparison below
1415
+ current_spent_height = None
1416
+ if current is not None and current.spent_block_height != 0:
1417
+ current_spent_height = current.spent_block_height
1418
+
1419
+ # Same as current state, nothing to do
1420
+ if (
1421
+ current is not None
1422
+ and current_spent_height == spent_height
1423
+ and current.confirmed_block_height == confirmed_height
1424
+ ):
1425
+ peer_request_cache.add_to_states_validated(coin_state)
1426
+ return True
1427
+
1428
+ reorg_mode = False
1429
+
1430
+ # If coin was removed from the blockchain
1431
+ if confirmed_height is None:
1432
+ if current is None:
1433
+ # Coin does not exist in local DB, so no need to do anything
1434
+ return False
1435
+ # This coin got reorged
1436
+ reorg_mode = True
1437
+ confirmed_height = current.confirmed_block_height
1438
+
1439
+ # request header block for created height
1440
+ state_block: Optional[HeaderBlock] = peer_request_cache.get_block(confirmed_height)
1441
+ if state_block is None or reorg_mode:
1442
+ state_blocks = await request_header_blocks(peer, confirmed_height, confirmed_height)
1443
+ if state_blocks is None:
1444
+ return False
1445
+ state_block = state_blocks[0]
1446
+ assert state_block is not None
1447
+ peer_request_cache.add_to_blocks(state_block)
1448
+
1449
+ # get proof of inclusion
1450
+ assert state_block.foliage_transaction_block is not None
1451
+ validate_additions_result = await request_and_validate_additions(
1452
+ peer,
1453
+ peer_request_cache,
1454
+ state_block.height,
1455
+ state_block.header_hash,
1456
+ coin_state.coin.puzzle_hash,
1457
+ state_block.foliage_transaction_block.additions_root,
1458
+ )
1459
+
1460
+ if validate_additions_result is False:
1461
+ self.log.warning("Validate false 1")
1462
+ await peer.close(9999)
1463
+ return False
1464
+
1465
+ # If spent_height is None, we need to validate that the creation block is actually in the longest blockchain.
1466
+ # Otherwise, we don't have to, since we will validate the spent block later.
1467
+ if coin_state.spent_height is None:
1468
+ validated = await self.validate_block_inclusion(state_block, peer, peer_request_cache)
1469
+ if not validated:
1470
+ return False
1471
+
1472
+ # TODO: make sure all cases are covered
1473
+ if current is not None:
1474
+ if spent_height is None and current.spent_block_height != 0:
1475
+ # Peer is telling us that coin that was previously known to be spent is not spent anymore
1476
+ # Check old state
1477
+
1478
+ spent_state_blocks: Optional[List[HeaderBlock]] = await request_header_blocks(
1479
+ peer, current.spent_block_height, current.spent_block_height
1480
+ )
1481
+ if spent_state_blocks is None:
1482
+ return False
1483
+ spent_state_block = spent_state_blocks[0]
1484
+ assert spent_state_block.height == current.spent_block_height
1485
+ assert spent_state_block.foliage_transaction_block is not None
1486
+ peer_request_cache.add_to_blocks(spent_state_block)
1487
+
1488
+ validate_removals_result: bool = await request_and_validate_removals(
1489
+ peer,
1490
+ current.spent_block_height,
1491
+ spent_state_block.header_hash,
1492
+ coin_state.coin.name(),
1493
+ spent_state_block.foliage_transaction_block.removals_root,
1494
+ )
1495
+ if validate_removals_result is False:
1496
+ self.log.warning("Validate false 2")
1497
+ await peer.close(9999)
1498
+ return False
1499
+ validated = await self.validate_block_inclusion(spent_state_block, peer, peer_request_cache)
1500
+ if not validated:
1501
+ return False
1502
+
1503
+ if spent_height is not None:
1504
+ # request header block for created height
1505
+ cached_spent_state_block = peer_request_cache.get_block(spent_height)
1506
+ if cached_spent_state_block is None:
1507
+ spent_state_blocks = await request_header_blocks(peer, spent_height, spent_height)
1508
+ if spent_state_blocks is None:
1509
+ return False
1510
+ spent_state_block = spent_state_blocks[0]
1511
+ assert spent_state_block.height == spent_height
1512
+ assert spent_state_block.foliage_transaction_block is not None
1513
+ peer_request_cache.add_to_blocks(spent_state_block)
1514
+ else:
1515
+ spent_state_block = cached_spent_state_block
1516
+ assert spent_state_block is not None
1517
+ assert spent_state_block.foliage_transaction_block is not None
1518
+ validate_removals_result = await request_and_validate_removals(
1519
+ peer,
1520
+ spent_state_block.height,
1521
+ spent_state_block.header_hash,
1522
+ coin_state.coin.name(),
1523
+ spent_state_block.foliage_transaction_block.removals_root,
1524
+ )
1525
+ if validate_removals_result is False:
1526
+ self.log.warning("Validate false 3")
1527
+ await peer.close(9999)
1528
+ return False
1529
+ validated = await self.validate_block_inclusion(spent_state_block, peer, peer_request_cache)
1530
+ if not validated:
1531
+ return False
1532
+ peer_request_cache.add_to_states_validated(coin_state)
1533
+
1534
+ return True
1535
+
1536
+ async def validate_block_inclusion(
1537
+ self, block: HeaderBlock, peer: WSChiaConnection, peer_request_cache: PeerRequestCache
1538
+ ) -> bool:
1539
+ if self.wallet_state_manager.blockchain.contains_height(block.height):
1540
+ stored_hash = self.wallet_state_manager.blockchain.height_to_hash(block.height)
1541
+ stored_record = self.wallet_state_manager.blockchain.try_block_record(stored_hash)
1542
+ if stored_record is not None:
1543
+ if stored_record.header_hash == block.header_hash:
1544
+ return True
1545
+
1546
+ weight_proof: Optional[WeightProof] = self.wallet_state_manager.blockchain.synced_weight_proof
1547
+ if weight_proof is None:
1548
+ return False
1549
+
1550
+ if block.height >= weight_proof.recent_chain_data[0].height:
1551
+ # this was already validated as part of the wp validation
1552
+ index = block.height - weight_proof.recent_chain_data[0].height
1553
+ if index >= len(weight_proof.recent_chain_data):
1554
+ return False
1555
+ if weight_proof.recent_chain_data[index].header_hash != block.header_hash:
1556
+ self.log.error("Failed validation 1")
1557
+ return False
1558
+ return True
1559
+
1560
+ # block is not included in wp recent chain
1561
+ start = uint32(block.height + 1)
1562
+ compare_to_recent = False
1563
+ inserted: int = 0
1564
+ first_height_recent = weight_proof.recent_chain_data[0].height
1565
+ if start > first_height_recent - 1000:
1566
+ # compare up to weight_proof.recent_chain_data[0].height
1567
+ compare_to_recent = True
1568
+ end = first_height_recent
1569
+ else:
1570
+ # get ses from wp
1571
+ start_height = block.height
1572
+ end_height = block.height + 32
1573
+ ses_start_height = 0
1574
+ end = uint32(0)
1575
+ for idx, ses in enumerate(weight_proof.sub_epochs):
1576
+ if idx == len(weight_proof.sub_epochs) - 1:
1577
+ break
1578
+ next_ses_height = uint32(
1579
+ (idx + 1) * self.constants.SUB_EPOCH_BLOCKS + weight_proof.sub_epochs[idx + 1].num_blocks_overflow
1580
+ )
1581
+ # start_ses_hash
1582
+ if ses_start_height <= start_height < next_ses_height:
1583
+ inserted = idx + 1
1584
+ if ses_start_height < end_height < next_ses_height:
1585
+ end = next_ses_height
1586
+ break
1587
+ else:
1588
+ if idx > len(weight_proof.sub_epochs) - 3:
1589
+ break
1590
+ # else add extra ses as request start <-> end spans two ses
1591
+ end = uint32(
1592
+ (idx + 2) * self.constants.SUB_EPOCH_BLOCKS
1593
+ + weight_proof.sub_epochs[idx + 2].num_blocks_overflow
1594
+ )
1595
+ inserted += 1
1596
+ break
1597
+ ses_start_height = next_ses_height
1598
+
1599
+ if end == 0:
1600
+ self.log.error("Error finding sub epoch")
1601
+ return False
1602
+ all_peers_c = self.server.get_connections(NodeType.FULL_NODE)
1603
+ all_peers = [(con, self.is_trusted(con)) for con in all_peers_c]
1604
+ blocks: Optional[List[HeaderBlock]] = await fetch_header_blocks_in_range(
1605
+ start, end, peer_request_cache, all_peers
1606
+ )
1607
+ if blocks is None:
1608
+ log_level = logging.DEBUG if self._shut_down or peer.closed else logging.ERROR
1609
+ self.log.log(log_level, f"Error fetching blocks {start} {end}")
1610
+ return False
1611
+
1612
+ if compare_to_recent and weight_proof.recent_chain_data[0].header_hash != blocks[-1].header_hash:
1613
+ self.log.error("Failed validation 3")
1614
+ return False
1615
+
1616
+ if not compare_to_recent:
1617
+ last = blocks[-1].finished_sub_slots[-1].reward_chain.get_hash()
1618
+ if last != weight_proof.sub_epochs[inserted].reward_chain_hash:
1619
+ self.log.error("Failed validation 4")
1620
+ return False
1621
+ pk_m_sig: List[Tuple[G1Element, bytes32, G2Element]] = []
1622
+ sigs_to_cache: List[HeaderBlock] = []
1623
+ blocks_to_cache: List[Tuple[bytes32, uint32]] = []
1624
+
1625
+ signatures_to_validate: int = 30
1626
+ for idx in range(len(blocks)):
1627
+ en_block = blocks[idx]
1628
+ if idx < signatures_to_validate and not peer_request_cache.in_block_signatures_validated(en_block):
1629
+ # Validate that the block is buried in the foliage by checking the signatures
1630
+ pk_m_sig.append(
1631
+ (
1632
+ en_block.reward_chain_block.proof_of_space.plot_public_key,
1633
+ en_block.foliage.foliage_block_data.get_hash(),
1634
+ en_block.foliage.foliage_block_data_signature,
1635
+ )
1636
+ )
1637
+ sigs_to_cache.append(en_block)
1638
+
1639
+ # This is the reward chain challenge. If this is in the cache, it means the prev block
1640
+ # has been validated. We must at least check the first block to ensure they are connected
1641
+ reward_chain_hash: bytes32 = en_block.reward_chain_block.reward_chain_ip_vdf.challenge
1642
+ if idx != 0 and peer_request_cache.in_blocks_validated(reward_chain_hash):
1643
+ # As soon as we see a block we have already concluded is in the chain, we can quit.
1644
+ if idx > signatures_to_validate:
1645
+ break
1646
+ else:
1647
+ # Validate that the block is committed to by the weight proof
1648
+ if idx == 0:
1649
+ prev_block_rc_hash: bytes32 = block.reward_chain_block.get_hash()
1650
+ prev_hash = block.header_hash
1651
+ else:
1652
+ prev_block_rc_hash = blocks[idx - 1].reward_chain_block.get_hash()
1653
+ prev_hash = blocks[idx - 1].header_hash
1654
+
1655
+ if not en_block.prev_header_hash == prev_hash:
1656
+ self.log.error("Failed validation 5")
1657
+ return False
1658
+
1659
+ if len(en_block.finished_sub_slots) > 0:
1660
+ reversed_slots = en_block.finished_sub_slots.copy()
1661
+ reversed_slots.reverse()
1662
+ for slot_idx, slot in enumerate(reversed_slots[:-1]):
1663
+ hash_val = reversed_slots[slot_idx + 1].reward_chain.get_hash()
1664
+ if not hash_val == slot.reward_chain.end_of_slot_vdf.challenge:
1665
+ self.log.error("Failed validation 6")
1666
+ return False
1667
+ if not prev_block_rc_hash == reversed_slots[-1].reward_chain.end_of_slot_vdf.challenge:
1668
+ self.log.error("Failed validation 7")
1669
+ return False
1670
+ else:
1671
+ if not prev_block_rc_hash == reward_chain_hash:
1672
+ self.log.error("Failed validation 8")
1673
+ return False
1674
+ blocks_to_cache.append((reward_chain_hash, en_block.height))
1675
+
1676
+ agg_sig: G2Element = AugSchemeMPL.aggregate([sig for (_, _, sig) in pk_m_sig])
1677
+ if not AugSchemeMPL.aggregate_verify([pk for (pk, _, _) in pk_m_sig], [m for (_, m, _) in pk_m_sig], agg_sig):
1678
+ self.log.error("Failed signature validation")
1679
+ return False
1680
+ for header_block in sigs_to_cache:
1681
+ peer_request_cache.add_to_block_signatures_validated(header_block)
1682
+ for reward_chain_hash, height in blocks_to_cache:
1683
+ peer_request_cache.add_to_blocks_validated(reward_chain_hash, height)
1684
+ return True
1685
+
1686
+ async def get_coin_state(
1687
+ self, coin_names: List[bytes32], peer: WSChiaConnection, fork_height: Optional[uint32] = None
1688
+ ) -> List[CoinState]:
1689
+ msg = RegisterForCoinUpdates(coin_names, uint32(0))
1690
+ coin_state: Optional[RespondToCoinUpdates] = await peer.call_api(FullNodeAPI.register_interest_in_coin, msg)
1691
+ if coin_state is None or not isinstance(coin_state, RespondToCoinUpdates):
1692
+ raise PeerRequestException(f"Was not able to get states for {coin_names}")
1693
+
1694
+ if not self.is_trusted(peer):
1695
+ valid_list = []
1696
+ for coin in coin_state.coin_states:
1697
+ if coin.coin.name() not in coin_names:
1698
+ await peer.close(9999)
1699
+ self.log.warning(f"Peer {peer.peer_node_id} sent us an unrequested coin state. Banning.")
1700
+ raise PeerRequestException(f"Peer sent us unrequested coin state {coin}")
1701
+ valid = await self.validate_received_state_from_peer(
1702
+ coin, peer, self.get_cache_for_peer(peer), fork_height
1703
+ )
1704
+ if valid:
1705
+ valid_list.append(coin)
1706
+ return valid_list
1707
+
1708
+ return coin_state.coin_states
1709
+
1710
+ async def fetch_children(
1711
+ self, coin_name: bytes32, peer: WSChiaConnection, fork_height: Optional[uint32] = None
1712
+ ) -> List[CoinState]:
1713
+ response: Optional[RespondChildren] = await peer.call_api(
1714
+ FullNodeAPI.request_children, RequestChildren(coin_name)
1715
+ )
1716
+ if response is None or not isinstance(response, RespondChildren):
1717
+ raise PeerRequestException(f"Was not able to obtain children {response}")
1718
+
1719
+ if not self.is_trusted(peer):
1720
+ request_cache = self.get_cache_for_peer(peer)
1721
+ validated = []
1722
+ for state in response.coin_states:
1723
+ valid = await self.validate_received_state_from_peer(state, peer, request_cache, fork_height)
1724
+ if valid:
1725
+ validated.append(state)
1726
+ return validated
1727
+ return response.coin_states
1728
+
1729
+ # For RPC only. You should use wallet_state_manager.add_pending_transaction for normal wallet business.
1730
+ async def push_tx(self, spend_bundle: WalletSpendBundle) -> None:
1731
+ msg = make_msg(ProtocolMessageTypes.send_transaction, SendTransaction(spend_bundle))
1732
+ full_nodes = self.server.get_connections(NodeType.FULL_NODE)
1733
+ for peer in full_nodes:
1734
+ await peer.send_message(msg)
1735
+
1736
+ async def _update_balance_cache(self, wallet_id: uint32) -> None:
1737
+ assert self.wallet_state_manager.lock.locked(), "WalletStateManager.lock required"
1738
+ wallet = self.wallet_state_manager.wallets[wallet_id]
1739
+ if wallet.type() == WalletType.CRCAT:
1740
+ coin_type = CoinType.CRCAT
1741
+ else:
1742
+ coin_type = CoinType.NORMAL
1743
+ unspent_records = await self.wallet_state_manager.coin_store.get_unspent_coins_for_wallet(wallet_id, coin_type)
1744
+ balance = await wallet.get_confirmed_balance(unspent_records)
1745
+ pending_balance = await wallet.get_unconfirmed_balance(unspent_records)
1746
+ spendable_balance = await wallet.get_spendable_balance(unspent_records)
1747
+ pending_change = await wallet.get_pending_change_balance()
1748
+ max_send_amount = await wallet.get_max_send_amount(unspent_records)
1749
+
1750
+ unconfirmed_removals: Dict[bytes32, Coin] = await wallet.wallet_state_manager.unconfirmed_removals_for_wallet(
1751
+ wallet_id
1752
+ )
1753
+ self._balance_cache[wallet_id] = Balance(
1754
+ confirmed_wallet_balance=balance,
1755
+ unconfirmed_wallet_balance=pending_balance,
1756
+ spendable_balance=spendable_balance,
1757
+ pending_change=pending_change,
1758
+ max_send_amount=max_send_amount,
1759
+ unspent_coin_count=uint32(len(unspent_records)),
1760
+ pending_coin_removal_count=uint32(len(unconfirmed_removals)),
1761
+ )
1762
+
1763
+ async def get_balance(self, wallet_id: uint32) -> Balance:
1764
+ self.log.debug(f"get_balance - wallet_id: {wallet_id}")
1765
+ if not self.wallet_state_manager.sync_mode:
1766
+ self.log.debug(f"get_balance - Updating cache for {wallet_id}")
1767
+ async with self.wallet_state_manager.lock:
1768
+ await self._update_balance_cache(wallet_id)
1769
+ return self._balance_cache.get(wallet_id, Balance())