chia-blockchain 2.5.4rc2__py3-none-any.whl → 2.5.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (453) hide show
  1. chia/_tests/blockchain/blockchain_test_utils.py +2 -3
  2. chia/_tests/blockchain/test_augmented_chain.py +2 -3
  3. chia/_tests/blockchain/test_blockchain.py +261 -44
  4. chia/_tests/blockchain/test_blockchain_transactions.py +4 -3
  5. chia/_tests/blockchain/test_build_chains.py +197 -1
  6. chia/_tests/blockchain/test_get_block_generator.py +1 -1
  7. chia/_tests/blockchain/test_lookup_fork_chain.py +1 -1
  8. chia/_tests/clvm/benchmark_costs.py +1 -1
  9. chia/_tests/clvm/coin_store.py +3 -4
  10. chia/_tests/clvm/test_message_conditions.py +2 -2
  11. chia/_tests/clvm/test_puzzle_compression.py +2 -3
  12. chia/_tests/clvm/test_puzzles.py +1 -2
  13. chia/_tests/clvm/test_singletons.py +2 -3
  14. chia/_tests/clvm/test_spend_sim.py +7 -7
  15. chia/_tests/cmds/cmd_test_utils.py +30 -25
  16. chia/_tests/cmds/test_dev_gh.py +1 -1
  17. chia/_tests/cmds/test_farm_cmd.py +1 -1
  18. chia/_tests/cmds/test_show.py +1 -2
  19. chia/_tests/cmds/wallet/test_did.py +101 -56
  20. chia/_tests/cmds/wallet/test_nft.py +109 -84
  21. chia/_tests/cmds/wallet/test_notifications.py +1 -1
  22. chia/_tests/cmds/wallet/test_offer.toffer +1 -1
  23. chia/_tests/cmds/wallet/test_vcs.py +8 -8
  24. chia/_tests/cmds/wallet/test_wallet.py +100 -46
  25. chia/_tests/conftest.py +31 -20
  26. chia/_tests/connection_utils.py +1 -1
  27. chia/_tests/core/consensus/stores/__init__.py +0 -0
  28. chia/_tests/core/consensus/stores/test_coin_store_protocol.py +40 -0
  29. chia/_tests/core/consensus/test_block_creation.py +2 -31
  30. chia/_tests/core/consensus/test_pot_iterations.py +38 -3
  31. chia/_tests/core/custom_types/test_proof_of_space.py +154 -26
  32. chia/_tests/core/custom_types/test_spend_bundle.py +2 -3
  33. chia/_tests/core/daemon/test_daemon.py +80 -0
  34. chia/_tests/core/data_layer/test_data_layer.py +1 -1
  35. chia/_tests/core/data_layer/test_data_layer_util.py +1 -1
  36. chia/_tests/core/data_layer/test_data_rpc.py +14 -10
  37. chia/_tests/core/data_layer/test_data_store.py +5 -5
  38. chia/_tests/core/farmer/test_farmer_api.py +2 -2
  39. chia/_tests/core/full_node/full_sync/test_full_sync.py +446 -406
  40. chia/_tests/core/full_node/ram_db.py +3 -1
  41. chia/_tests/core/full_node/stores/test_block_store.py +28 -16
  42. chia/_tests/core/full_node/stores/test_coin_store.py +277 -185
  43. chia/_tests/core/full_node/stores/test_full_node_store.py +11 -4
  44. chia/_tests/core/full_node/stores/test_hint_store.py +2 -2
  45. chia/_tests/core/full_node/test_address_manager.py +200 -27
  46. chia/_tests/core/full_node/test_block_height_map.py +2 -2
  47. chia/_tests/core/full_node/test_conditions.py +7 -6
  48. chia/_tests/core/full_node/test_full_node.py +456 -40
  49. chia/_tests/core/full_node/test_generator_tools.py +32 -2
  50. chia/_tests/core/full_node/test_hint_management.py +1 -1
  51. chia/_tests/core/full_node/test_node_load.py +20 -21
  52. chia/_tests/core/full_node/test_performance.py +3 -4
  53. chia/_tests/core/full_node/test_prev_tx_block.py +43 -0
  54. chia/_tests/core/full_node/test_subscriptions.py +1 -2
  55. chia/_tests/core/full_node/test_transactions.py +9 -5
  56. chia/_tests/core/full_node/test_tx_processing_queue.py +1 -2
  57. chia/_tests/core/large_block.py +1 -2
  58. chia/_tests/core/make_block_generator.py +3 -4
  59. chia/_tests/core/mempool/test_mempool.py +36 -86
  60. chia/_tests/core/mempool/test_mempool_fee_estimator.py +1 -1
  61. chia/_tests/core/mempool/test_mempool_item_queries.py +1 -3
  62. chia/_tests/core/mempool/test_mempool_manager.py +529 -69
  63. chia/_tests/core/mempool/test_mempool_performance.py +3 -2
  64. chia/_tests/core/mempool/test_singleton_fast_forward.py +61 -132
  65. chia/_tests/core/server/flood.py +1 -1
  66. chia/_tests/core/server/test_dos.py +1 -1
  67. chia/_tests/core/server/test_node_discovery.py +41 -27
  68. chia/_tests/core/server/test_rate_limits.py +1 -1
  69. chia/_tests/core/server/test_server.py +1 -1
  70. chia/_tests/core/services/test_services.py +5 -5
  71. chia/_tests/core/ssl/test_ssl.py +1 -1
  72. chia/_tests/core/test_cost_calculation.py +6 -6
  73. chia/_tests/core/test_crawler.py +2 -2
  74. chia/_tests/core/test_crawler_rpc.py +1 -1
  75. chia/_tests/core/test_db_conversion.py +3 -1
  76. chia/_tests/core/test_db_validation.py +5 -3
  77. chia/_tests/core/test_farmer_harvester_rpc.py +15 -15
  78. chia/_tests/core/test_filter.py +4 -1
  79. chia/_tests/core/test_full_node_rpc.py +99 -82
  80. chia/_tests/core/test_program.py +2 -2
  81. chia/_tests/core/util/test_block_cache.py +1 -1
  82. chia/_tests/core/util/test_keychain.py +2 -2
  83. chia/_tests/core/util/test_lockfile.py +1 -1
  84. chia/_tests/core/util/test_log_exceptions.py +5 -5
  85. chia/_tests/core/util/test_streamable.py +81 -22
  86. chia/_tests/db/test_db_wrapper.py +1 -3
  87. chia/_tests/environments/wallet.py +5 -5
  88. chia/_tests/farmer_harvester/test_farmer.py +9 -7
  89. chia/_tests/farmer_harvester/test_farmer_harvester.py +11 -4
  90. chia/_tests/farmer_harvester/test_filter_prefix_bits.py +6 -5
  91. chia/_tests/farmer_harvester/test_third_party_harvesters.py +15 -9
  92. chia/_tests/fee_estimation/test_fee_estimation_integration.py +1 -2
  93. chia/_tests/fee_estimation/test_fee_estimation_rpc.py +7 -5
  94. chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +1 -1
  95. chia/_tests/generator/test_compression.py +1 -2
  96. chia/_tests/generator/test_rom.py +8 -4
  97. chia/_tests/plot_sync/test_plot_sync.py +3 -3
  98. chia/_tests/plot_sync/test_receiver.py +3 -3
  99. chia/_tests/plot_sync/test_sender.py +1 -1
  100. chia/_tests/plot_sync/test_sync_simulated.py +3 -3
  101. chia/_tests/plot_sync/util.py +2 -2
  102. chia/_tests/pools/test_pool_cmdline.py +48 -21
  103. chia/_tests/pools/test_pool_puzzles_lifecycle.py +2 -3
  104. chia/_tests/pools/test_pool_rpc.py +237 -105
  105. chia/_tests/pools/test_pool_wallet.py +11 -2
  106. chia/_tests/pools/test_wallet_pool_store.py +5 -4
  107. chia/_tests/rpc/test_rpc_client.py +1 -1
  108. chia/_tests/simulation/test_simulation.py +13 -8
  109. chia/_tests/simulation/test_simulator.py +2 -2
  110. chia/_tests/timelord/test_new_peak.py +191 -47
  111. chia/_tests/timelord/test_timelord.py +1 -1
  112. chia/_tests/tools/test_full_sync.py +0 -2
  113. chia/_tests/tools/test_run_block.py +3 -1
  114. chia/_tests/util/benchmark_cost.py +3 -3
  115. chia/_tests/util/benchmarks.py +2 -2
  116. chia/_tests/util/blockchain.py +11 -5
  117. chia/_tests/util/blockchain_mock.py +1 -4
  118. chia/_tests/util/coin_store.py +29 -0
  119. chia/_tests/util/constants.py +2 -18
  120. chia/_tests/util/full_sync.py +3 -3
  121. chia/_tests/util/generator_tools_testing.py +2 -3
  122. chia/_tests/util/key_tool.py +2 -3
  123. chia/_tests/util/misc.py +33 -31
  124. chia/_tests/util/network_protocol_data.py +19 -17
  125. chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
  126. chia/_tests/util/protocol_messages_json.py +3 -1
  127. chia/_tests/util/run_block.py +2 -2
  128. chia/_tests/util/setup_nodes.py +7 -7
  129. chia/_tests/util/spend_sim.py +47 -55
  130. chia/_tests/util/test_condition_tools.py +5 -4
  131. chia/_tests/util/test_config.py +2 -2
  132. chia/_tests/util/test_dump_keyring.py +1 -1
  133. chia/_tests/util/test_full_block_utils.py +12 -14
  134. chia/_tests/util/test_misc.py +2 -2
  135. chia/_tests/util/test_paginator.py +4 -4
  136. chia/_tests/util/test_priority_mutex.py +2 -2
  137. chia/_tests/util/test_replace_str_to_bytes.py +15 -5
  138. chia/_tests/util/test_ssl_check.py +1 -1
  139. chia/_tests/util/test_testnet_overrides.py +13 -3
  140. chia/_tests/util/time_out_assert.py +4 -2
  141. chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +1 -1
  142. chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +1 -2
  143. chia/_tests/wallet/cat_wallet/test_cat_wallet.py +352 -432
  144. chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +3 -6
  145. chia/_tests/wallet/cat_wallet/test_trades.py +53 -77
  146. chia/_tests/wallet/clawback/test_clawback_decorator.py +3 -1
  147. chia/_tests/wallet/clawback/test_clawback_lifecycle.py +3 -3
  148. chia/_tests/wallet/clawback/test_clawback_metadata.py +4 -2
  149. chia/_tests/wallet/conftest.py +11 -12
  150. chia/_tests/wallet/db_wallet/test_db_graftroot.py +11 -4
  151. chia/_tests/wallet/db_wallet/test_dl_offers.py +433 -130
  152. chia/_tests/wallet/db_wallet/test_dl_wallet.py +3 -3
  153. chia/_tests/wallet/did_wallet/test_did.py +2132 -2000
  154. chia/_tests/wallet/nft_wallet/config.py +1 -1
  155. chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +1610 -742
  156. chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +486 -907
  157. chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +4 -4
  158. chia/_tests/wallet/nft_wallet/test_nft_wallet.py +517 -294
  159. chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +133 -62
  160. chia/_tests/wallet/rpc/test_wallet_rpc.py +495 -265
  161. chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +10 -6
  162. chia/_tests/wallet/sync/test_wallet_sync.py +89 -60
  163. chia/_tests/wallet/test_clvm_casts.py +88 -0
  164. chia/_tests/wallet/test_coin_management.py +1 -1
  165. chia/_tests/wallet/test_coin_selection.py +1 -1
  166. chia/_tests/wallet/test_conditions.py +1 -1
  167. chia/_tests/wallet/test_new_wallet_protocol.py +13 -11
  168. chia/_tests/wallet/test_notifications.py +5 -3
  169. chia/_tests/wallet/test_sign_coin_spends.py +6 -6
  170. chia/_tests/wallet/test_signer_protocol.py +13 -12
  171. chia/_tests/wallet/test_singleton.py +1 -1
  172. chia/_tests/wallet/test_singleton_lifecycle_fast.py +5 -7
  173. chia/_tests/wallet/test_util.py +2 -2
  174. chia/_tests/wallet/test_wallet.py +108 -29
  175. chia/_tests/wallet/test_wallet_action_scope.py +9 -2
  176. chia/_tests/wallet/test_wallet_blockchain.py +2 -3
  177. chia/_tests/wallet/test_wallet_key_val_store.py +1 -2
  178. chia/_tests/wallet/test_wallet_node.py +2 -4
  179. chia/_tests/wallet/test_wallet_retry.py +4 -2
  180. chia/_tests/wallet/test_wallet_state_manager.py +191 -5
  181. chia/_tests/wallet/test_wallet_test_framework.py +1 -1
  182. chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +8 -8
  183. chia/_tests/wallet/vc_wallet/test_vc_wallet.py +29 -12
  184. chia/_tests/wallet/wallet_block_tools.py +6 -6
  185. chia/_tests/weight_proof/test_weight_proof.py +10 -48
  186. chia/apis.py +1 -1
  187. chia/cmds/beta.py +1 -1
  188. chia/cmds/chia.py +9 -9
  189. chia/cmds/cmd_classes.py +12 -11
  190. chia/cmds/cmd_helpers.py +1 -1
  191. chia/cmds/cmds_util.py +12 -9
  192. chia/cmds/coin_funcs.py +2 -2
  193. chia/cmds/configure.py +2 -2
  194. chia/cmds/data.py +0 -2
  195. chia/cmds/data_funcs.py +1 -1
  196. chia/cmds/db_validate_func.py +1 -2
  197. chia/cmds/dev/__init__.py +0 -0
  198. chia/cmds/dev/data.py +273 -0
  199. chia/cmds/{gh.py → dev/gh.py} +5 -5
  200. chia/cmds/dev/main.py +22 -0
  201. chia/cmds/dev/mempool.py +78 -0
  202. chia/cmds/dev/mempool_funcs.py +63 -0
  203. chia/cmds/farm_funcs.py +5 -4
  204. chia/cmds/init_funcs.py +11 -11
  205. chia/cmds/keys.py +2 -2
  206. chia/cmds/keys_funcs.py +4 -4
  207. chia/cmds/netspace_funcs.py +1 -1
  208. chia/cmds/peer_funcs.py +2 -2
  209. chia/cmds/plotnft_funcs.py +72 -26
  210. chia/cmds/rpc.py +1 -1
  211. chia/cmds/show_funcs.py +5 -5
  212. chia/cmds/signer.py +8 -7
  213. chia/cmds/sim_funcs.py +8 -9
  214. chia/cmds/wallet.py +2 -2
  215. chia/cmds/wallet_funcs.py +165 -131
  216. chia/{util → consensus}/augmented_chain.py +1 -2
  217. chia/consensus/block_body_validation.py +54 -40
  218. chia/consensus/block_creation.py +42 -76
  219. chia/consensus/block_header_validation.py +32 -26
  220. chia/consensus/block_record.py +0 -3
  221. chia/consensus/blockchain.py +23 -32
  222. chia/consensus/blockchain_interface.py +1 -5
  223. chia/consensus/check_time_locks.py +57 -0
  224. chia/consensus/coin_store_protocol.py +151 -0
  225. chia/consensus/coinbase.py +0 -6
  226. chia/consensus/condition_costs.py +4 -0
  227. chia/{util → consensus}/condition_tools.py +4 -5
  228. chia/consensus/cost_calculator.py +1 -1
  229. chia/consensus/default_constants.py +32 -9
  230. chia/consensus/deficit.py +1 -3
  231. chia/consensus/difficulty_adjustment.py +1 -2
  232. chia/consensus/find_fork_point.py +1 -3
  233. chia/consensus/full_block_to_block_record.py +1 -6
  234. chia/{util → consensus}/generator_tools.py +1 -3
  235. chia/consensus/get_block_challenge.py +30 -7
  236. chia/consensus/make_sub_epoch_summary.py +1 -5
  237. chia/consensus/multiprocess_validation.py +21 -20
  238. chia/consensus/pot_iterations.py +74 -13
  239. chia/{util → consensus}/prev_transaction_block.py +1 -1
  240. chia/consensus/vdf_info_computation.py +1 -3
  241. chia/daemon/keychain_proxy.py +5 -5
  242. chia/daemon/server.py +22 -5
  243. chia/data_layer/data_layer.py +92 -51
  244. chia/{rpc → data_layer}/data_layer_rpc_api.py +1 -1
  245. chia/{rpc → data_layer}/data_layer_rpc_util.py +3 -6
  246. chia/data_layer/data_layer_util.py +4 -6
  247. chia/data_layer/data_layer_wallet.py +42 -69
  248. chia/data_layer/dl_wallet_store.py +12 -6
  249. chia/data_layer/download_data.py +3 -3
  250. chia/data_layer/s3_plugin_service.py +0 -1
  251. chia/farmer/farmer.py +3 -4
  252. chia/farmer/farmer_api.py +11 -7
  253. chia/{rpc → farmer}/farmer_rpc_client.py +1 -1
  254. chia/full_node/block_height_map.py +7 -6
  255. chia/full_node/block_store.py +5 -7
  256. chia/full_node/bundle_tools.py +1 -2
  257. chia/full_node/coin_store.py +153 -124
  258. chia/{types → full_node}/eligible_coin_spends.py +39 -70
  259. chia/full_node/fee_estimator.py +1 -1
  260. chia/full_node/fee_estimator_interface.py +0 -8
  261. chia/full_node/fee_tracker.py +25 -25
  262. chia/full_node/full_node.py +70 -53
  263. chia/full_node/full_node_api.py +57 -40
  264. chia/{rpc → full_node}/full_node_rpc_api.py +87 -8
  265. chia/{rpc → full_node}/full_node_rpc_client.py +7 -6
  266. chia/full_node/full_node_store.py +23 -8
  267. chia/full_node/mempool.py +206 -53
  268. chia/full_node/mempool_check_conditions.py +20 -63
  269. chia/full_node/mempool_manager.py +47 -45
  270. chia/full_node/subscriptions.py +1 -3
  271. chia/full_node/tx_processing_queue.py +50 -3
  272. chia/full_node/weight_proof.py +46 -37
  273. chia/harvester/harvester.py +1 -1
  274. chia/harvester/harvester_api.py +22 -7
  275. chia/introducer/introducer.py +1 -1
  276. chia/introducer/introducer_api.py +1 -1
  277. chia/plot_sync/exceptions.py +1 -1
  278. chia/plot_sync/receiver.py +1 -1
  279. chia/plot_sync/sender.py +2 -2
  280. chia/pools/pool_puzzles.py +13 -18
  281. chia/pools/pool_wallet.py +23 -46
  282. chia/protocols/farmer_protocol.py +11 -3
  283. chia/protocols/full_node_protocol.py +1 -4
  284. chia/protocols/harvester_protocol.py +3 -3
  285. chia/protocols/pool_protocol.py +1 -2
  286. chia/protocols/shared_protocol.py +3 -3
  287. chia/protocols/timelord_protocol.py +1 -3
  288. chia/protocols/wallet_protocol.py +3 -3
  289. chia/rpc/rpc_client.py +7 -8
  290. chia/rpc/rpc_server.py +3 -3
  291. chia/rpc/util.py +3 -1
  292. chia/seeder/crawler.py +1 -1
  293. chia/seeder/crawler_api.py +1 -1
  294. chia/seeder/dns_server.py +2 -0
  295. chia/seeder/start_crawler.py +3 -3
  296. chia/server/address_manager.py +286 -38
  297. chia/server/address_manager_store.py +0 -215
  298. chia/{types → server}/aliases.py +7 -7
  299. chia/server/api_protocol.py +1 -1
  300. chia/server/chia_policy.py +1 -1
  301. chia/server/node_discovery.py +76 -113
  302. chia/server/rate_limits.py +1 -1
  303. chia/server/resolve_peer_info.py +43 -0
  304. chia/server/server.py +5 -5
  305. chia/server/start_data_layer.py +4 -4
  306. chia/server/start_farmer.py +5 -4
  307. chia/server/start_full_node.py +5 -4
  308. chia/server/start_harvester.py +7 -5
  309. chia/server/start_introducer.py +2 -2
  310. chia/server/start_service.py +1 -1
  311. chia/server/start_timelord.py +7 -5
  312. chia/server/start_wallet.py +7 -5
  313. chia/server/ws_connection.py +1 -1
  314. chia/simulator/add_blocks_in_batches.py +2 -2
  315. chia/simulator/block_tools.py +245 -201
  316. chia/simulator/full_node_simulator.py +38 -10
  317. chia/simulator/setup_services.py +12 -12
  318. chia/simulator/simulator_full_node_rpc_api.py +2 -2
  319. chia/simulator/simulator_full_node_rpc_client.py +2 -2
  320. chia/simulator/simulator_test_tools.py +2 -2
  321. chia/simulator/start_simulator.py +1 -1
  322. chia/simulator/wallet_tools.py +10 -18
  323. chia/ssl/create_ssl.py +1 -1
  324. chia/timelord/iters_from_block.py +14 -14
  325. chia/timelord/timelord.py +15 -11
  326. chia/timelord/timelord_api.py +14 -2
  327. chia/timelord/timelord_state.py +20 -14
  328. chia/types/blockchain_format/program.py +53 -10
  329. chia/types/blockchain_format/proof_of_space.py +73 -19
  330. chia/types/coin_spend.py +3 -56
  331. chia/types/generator_types.py +28 -0
  332. chia/types/internal_mempool_item.py +1 -2
  333. chia/types/mempool_item.py +12 -7
  334. chia/types/unfinished_header_block.py +1 -2
  335. chia/types/validation_state.py +1 -2
  336. chia/types/weight_proof.py +1 -3
  337. chia/util/action_scope.py +3 -3
  338. chia/util/block_cache.py +1 -2
  339. chia/util/byte_types.py +1 -1
  340. chia/util/casts.py +21 -0
  341. chia/util/config.py +0 -37
  342. chia/util/db_wrapper.py +8 -1
  343. chia/util/errors.py +3 -2
  344. chia/util/initial-config.yaml +21 -5
  345. chia/util/keychain.py +6 -7
  346. chia/util/keyring_wrapper.py +5 -5
  347. chia/util/limited_semaphore.py +1 -1
  348. chia/util/priority_mutex.py +1 -1
  349. chia/util/streamable.py +63 -5
  350. chia/util/task_timing.py +1 -1
  351. chia/util/virtual_project_analysis.py +1 -1
  352. chia/wallet/cat_wallet/cat_info.py +7 -3
  353. chia/wallet/cat_wallet/cat_outer_puzzle.py +9 -5
  354. chia/wallet/cat_wallet/cat_utils.py +1 -1
  355. chia/wallet/cat_wallet/cat_wallet.py +44 -36
  356. chia/wallet/cat_wallet/lineage_store.py +7 -0
  357. chia/wallet/cat_wallet/r_cat_wallet.py +274 -0
  358. chia/wallet/conditions.py +5 -10
  359. chia/wallet/db_wallet/db_wallet_puzzles.py +4 -4
  360. chia/wallet/derivation_record.py +33 -0
  361. chia/wallet/derive_keys.py +3 -3
  362. chia/wallet/did_wallet/did_info.py +12 -3
  363. chia/wallet/did_wallet/did_wallet.py +132 -101
  364. chia/wallet/did_wallet/did_wallet_puzzles.py +9 -9
  365. chia/wallet/driver_protocol.py +3 -1
  366. chia/{types/spend_bundle.py → wallet/estimate_fees.py} +2 -7
  367. chia/wallet/nft_wallet/metadata_outer_puzzle.py +5 -3
  368. chia/wallet/nft_wallet/nft_puzzle_utils.py +1 -1
  369. chia/wallet/nft_wallet/nft_wallet.py +69 -112
  370. chia/wallet/nft_wallet/ownership_outer_puzzle.py +5 -3
  371. chia/wallet/nft_wallet/singleton_outer_puzzle.py +6 -4
  372. chia/wallet/nft_wallet/transfer_program_puzzle.py +4 -2
  373. chia/wallet/nft_wallet/uncurry_nft.py +4 -6
  374. chia/wallet/notification_manager.py +2 -3
  375. chia/wallet/outer_puzzles.py +7 -2
  376. chia/wallet/puzzle_drivers.py +1 -1
  377. chia/wallet/puzzles/clawback/drivers.py +5 -4
  378. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +1 -1
  379. chia/wallet/puzzles/singleton_top_layer.py +2 -1
  380. chia/wallet/puzzles/singleton_top_layer_v1_1.py +2 -1
  381. chia/wallet/puzzles/tails.py +1 -3
  382. chia/wallet/signer_protocol.py +5 -6
  383. chia/wallet/singleton.py +5 -4
  384. chia/wallet/singleton_record.py +1 -1
  385. chia/wallet/trade_manager.py +18 -20
  386. chia/wallet/trade_record.py +3 -6
  387. chia/wallet/trading/offer.py +12 -13
  388. chia/wallet/uncurried_puzzle.py +2 -2
  389. chia/wallet/util/compute_additions.py +58 -0
  390. chia/wallet/util/compute_hints.py +3 -3
  391. chia/wallet/util/compute_memos.py +4 -4
  392. chia/wallet/util/curry_and_treehash.py +2 -1
  393. chia/wallet/util/debug_spend_bundle.py +1 -1
  394. chia/wallet/util/merkle_tree.py +1 -1
  395. chia/wallet/util/peer_request_cache.py +1 -2
  396. chia/wallet/util/tx_config.py +3 -8
  397. chia/wallet/util/wallet_sync_utils.py +10 -5
  398. chia/wallet/util/wallet_types.py +1 -0
  399. chia/wallet/vc_wallet/cr_cat_drivers.py +17 -18
  400. chia/wallet/vc_wallet/cr_cat_wallet.py +30 -28
  401. chia/wallet/vc_wallet/cr_outer_puzzle.py +5 -3
  402. chia/wallet/vc_wallet/vc_drivers.py +50 -8
  403. chia/wallet/vc_wallet/vc_store.py +3 -5
  404. chia/wallet/vc_wallet/vc_wallet.py +15 -22
  405. chia/wallet/wallet.py +36 -46
  406. chia/wallet/wallet_action_scope.py +73 -4
  407. chia/wallet/wallet_blockchain.py +1 -3
  408. chia/wallet/wallet_interested_store.py +1 -1
  409. chia/wallet/wallet_nft_store.py +3 -3
  410. chia/wallet/wallet_node.py +17 -16
  411. chia/wallet/wallet_node_api.py +4 -5
  412. chia/wallet/wallet_pool_store.py +1 -1
  413. chia/wallet/wallet_protocol.py +2 -0
  414. chia/wallet/wallet_puzzle_store.py +1 -1
  415. chia/{rpc → wallet}/wallet_request_types.py +670 -81
  416. chia/{rpc → wallet}/wallet_rpc_api.py +735 -766
  417. chia/{rpc → wallet}/wallet_rpc_client.py +268 -420
  418. chia/wallet/wallet_singleton_store.py +8 -7
  419. chia/wallet/wallet_spend_bundle.py +4 -3
  420. chia/wallet/wallet_state_manager.py +320 -191
  421. chia/wallet/wallet_weight_proof_handler.py +1 -2
  422. chia/wallet/wsm_apis.py +98 -0
  423. {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5.dist-info}/METADATA +7 -7
  424. {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5.dist-info}/RECORD +443 -436
  425. mozilla-ca/cacert.pem +3 -165
  426. chia/_tests/fee_estimation/test_mempoolitem_height_added.py +0 -145
  427. chia/cmds/dev.py +0 -18
  428. chia/types/blockchain_format/slots.py +0 -9
  429. chia/types/blockchain_format/sub_epoch_summary.py +0 -5
  430. chia/types/end_of_slot_bundle.py +0 -5
  431. chia/types/full_block.py +0 -5
  432. chia/types/header_block.py +0 -5
  433. chia/types/spend_bundle_conditions.py +0 -7
  434. chia/types/transaction_queue_entry.py +0 -56
  435. chia/types/unfinished_block.py +0 -5
  436. /chia/cmds/{installers.py → dev/installers.py} +0 -0
  437. /chia/cmds/{sim.py → dev/sim.py} +0 -0
  438. /chia/{util → cmds}/dump_keyring.py +0 -0
  439. /chia/{full_node → consensus}/signage_point.py +0 -0
  440. /chia/{rpc → data_layer}/data_layer_rpc_client.py +0 -0
  441. /chia/{rpc → farmer}/farmer_rpc_api.py +0 -0
  442. /chia/{util → full_node}/full_block_utils.py +0 -0
  443. /chia/{rpc → harvester}/harvester_rpc_api.py +0 -0
  444. /chia/{rpc → harvester}/harvester_rpc_client.py +0 -0
  445. /chia/{full_node → protocols}/fee_estimate.py +0 -0
  446. /chia/{server → protocols}/outbound_message.py +0 -0
  447. /chia/{rpc → seeder}/crawler_rpc_api.py +0 -0
  448. /chia/{util → simulator}/vdf_prover.py +0 -0
  449. /chia/{util → ssl}/ssl_check.py +0 -0
  450. /chia/{rpc → timelord}/timelord_rpc_api.py +0 -0
  451. {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5.dist-info}/LICENSE +0 -0
  452. {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5.dist-info}/WHEEL +0 -0
  453. {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5.dist-info}/entry_points.txt +0 -0
@@ -5,21 +5,19 @@ import logging
5
5
  import sqlite3
6
6
  import time
7
7
  from collections.abc import Collection
8
- from typing import Any, Optional
8
+ from typing import Any, ClassVar, Optional
9
9
 
10
10
  import typing_extensions
11
11
  from aiosqlite import Cursor
12
+ from chia_rs import CoinState
12
13
  from chia_rs.sized_bytes import bytes32
13
14
  from chia_rs.sized_ints import uint32, uint64
14
- from clvm.casts import int_from_bytes
15
15
 
16
- from chia.protocols.wallet_protocol import CoinState
17
16
  from chia.types.blockchain_format.coin import Coin
18
17
  from chia.types.coin_record import CoinRecord
19
- from chia.types.eligible_coin_spends import UnspentLineageInfo
18
+ from chia.types.mempool_item import UnspentLineageInfo
20
19
  from chia.util.batches import to_batches
21
20
  from chia.util.db_wrapper import SQLITE_MAX_VARIABLE_NUMBER, DBWrapper2
22
- from chia.util.lru_cache import LRUCache
23
21
 
24
22
  log = logging.getLogger(__name__)
25
23
 
@@ -32,13 +30,15 @@ class CoinStore:
32
30
  """
33
31
 
34
32
  db_wrapper: DBWrapper2
35
- coins_added_at_height_cache: LRUCache[uint32, list[CoinRecord]]
33
+ # Fall back to the `coin_puzzle_hash` index if the ff unspent index
34
+ # does not exist.
35
+ _unspent_lineage_for_ph_idx: str = "coin_puzzle_hash"
36
36
 
37
37
  @classmethod
38
38
  async def create(cls, db_wrapper: DBWrapper2) -> CoinStore:
39
39
  if db_wrapper.db_version != 2:
40
40
  raise RuntimeError(f"CoinStore does not support database schema v{db_wrapper.db_version}")
41
- self = CoinStore(db_wrapper, LRUCache(100))
41
+ self = CoinStore(db_wrapper)
42
42
 
43
43
  async with self.db_wrapper.writer_maybe_transaction() as conn:
44
44
  log.info("DB: Creating coin store tables and indexes.")
@@ -69,11 +69,34 @@ class CoinStore:
69
69
  log.info("DB: Creating index coin_parent_index")
70
70
  await conn.execute("CREATE INDEX IF NOT EXISTS coin_parent_index on coin_record(coin_parent)")
71
71
 
72
+ async with conn.execute("SELECT 1 FROM coin_record LIMIT 1") as cursor:
73
+ is_new_db = await cursor.fetchone() is None
74
+ if is_new_db:
75
+ log.info("DB: Creating index coin_record_ph_ff_unspent_idx")
76
+ # This partial index optimizes fast forward singleton latest
77
+ # unspent queries. We're only adding it to new DBs to avoid
78
+ # complex migrations that affect the huge coin records table.
79
+ # The performance benefit outweighs the cost of this partial
80
+ # index as it only includes rows where spent_index is -1.
81
+ await conn.execute(
82
+ """
83
+ CREATE INDEX IF NOT EXISTS coin_record_ph_ff_unspent_idx
84
+ ON coin_record(puzzle_hash, spent_index)
85
+ WHERE spent_index = -1
86
+ """
87
+ )
88
+ async with conn.execute(
89
+ "SELECT 1 FROM sqlite_master WHERE type = 'index' AND name = 'coin_record_ph_ff_unspent_idx'"
90
+ ) as cursor:
91
+ has_ff_unspent_idx = await cursor.fetchone() is not None
92
+ if has_ff_unspent_idx:
93
+ self._unspent_lineage_for_ph_idx = "coin_record_ph_ff_unspent_idx"
94
+
72
95
  return self
73
96
 
74
97
  async def num_unspent(self) -> int:
75
98
  async with self.db_wrapper.reader_no_transaction() as conn:
76
- async with conn.execute("SELECT COUNT(*) FROM coin_record WHERE spent_index=0") as cursor:
99
+ async with conn.execute("SELECT COUNT(*) FROM coin_record WHERE spent_index <= 0") as cursor:
77
100
  row = await cursor.fetchone()
78
101
  if row is not None:
79
102
  count: int = row[0]
@@ -85,27 +108,33 @@ class CoinStore:
85
108
  height: uint32,
86
109
  timestamp: uint64,
87
110
  included_reward_coins: Collection[Coin],
88
- tx_additions: Collection[Coin],
111
+ tx_additions: Collection[tuple[bytes32, Coin, bool]],
89
112
  tx_removals: list[bytes32],
90
- ) -> list[CoinRecord]:
113
+ ) -> None:
91
114
  """
92
115
  Only called for blocks which are blocks (and thus have rewards and transactions)
93
- Returns a list of the CoinRecords that were added by this block
94
116
  """
95
117
 
96
118
  start = time.monotonic()
97
119
 
98
- additions = []
120
+ db_values_to_insert = []
99
121
 
100
- for coin in tx_additions:
101
- record: CoinRecord = CoinRecord(
102
- coin,
103
- height,
104
- uint32(0),
105
- False,
106
- timestamp,
122
+ for coin_id, coin, same_as_parent in tx_additions:
123
+ db_values_to_insert.append(
124
+ (
125
+ coin_id,
126
+ # confirmed_index
127
+ height,
128
+ # spent_index
129
+ -1 if same_as_parent else 0,
130
+ # coinbase
131
+ 0,
132
+ coin.puzzle_hash,
133
+ coin.parent_coin_info,
134
+ coin.amount.stream_to_bytes(),
135
+ timestamp,
136
+ )
107
137
  )
108
- additions.append(record)
109
138
 
110
139
  if height == 0:
111
140
  assert len(included_reward_coins) == 0
@@ -113,16 +142,24 @@ class CoinStore:
113
142
  assert len(included_reward_coins) >= 2
114
143
 
115
144
  for coin in included_reward_coins:
116
- reward_coin_r: CoinRecord = CoinRecord(
117
- coin,
118
- height,
119
- uint32(0),
120
- True,
121
- timestamp,
145
+ db_values_to_insert.append(
146
+ (
147
+ coin.name(),
148
+ # confirmed_index
149
+ height,
150
+ # spent_index
151
+ 0,
152
+ # coinbase
153
+ 1,
154
+ coin.puzzle_hash,
155
+ coin.parent_coin_info,
156
+ coin.amount.stream_to_bytes(),
157
+ timestamp,
158
+ )
122
159
  )
123
- additions.append(reward_coin_r)
124
160
 
125
- await self._add_coin_records(additions)
161
+ async with self.db_wrapper.writer_maybe_transaction() as conn:
162
+ await conn.executemany("INSERT INTO coin_record VALUES(?, ?, ?, ?, ?, ?, ?, ?)", db_values_to_insert)
126
163
  await self._set_spent(tx_removals, height)
127
164
 
128
165
  end = time.monotonic()
@@ -133,8 +170,6 @@ class CoinStore:
133
170
  + "blockchain database is on a fast drive",
134
171
  )
135
172
 
136
- return additions
137
-
138
173
  # Checks DB and DiffStores for CoinRecord with coin_name and returns it
139
174
  async def get_coin_record(self, coin_name: bytes32) -> Optional[CoinRecord]:
140
175
  async with self.db_wrapper.reader_no_transaction() as conn:
@@ -146,7 +181,8 @@ class CoinStore:
146
181
  row = await cursor.fetchone()
147
182
  if row is not None:
148
183
  coin = self.row_to_coin(row)
149
- return CoinRecord(coin, row[0], row[1], row[2], row[6])
184
+ spent_index = uint32(0) if row[1] <= 0 else uint32(row[1])
185
+ return CoinRecord(coin, row[0], spent_index, row[2], row[6])
150
186
  return None
151
187
 
152
188
  async def get_coin_records(self, names: Collection[bytes32]) -> list[CoinRecord]:
@@ -171,16 +207,13 @@ class CoinStore:
171
207
  for cursor in cursors:
172
208
  for row in await cursor.fetchall():
173
209
  coin = self.row_to_coin(row)
174
- record = CoinRecord(coin, row[0], row[1], row[2], row[6])
210
+ spent_index = uint32(0) if row[1] <= 0 else uint32(row[1])
211
+ record = CoinRecord(coin, row[0], spent_index, row[2], row[6])
175
212
  coins.append(record)
176
213
 
177
214
  return coins
178
215
 
179
216
  async def get_coins_added_at_height(self, height: uint32) -> list[CoinRecord]:
180
- coins_added: Optional[list[CoinRecord]] = self.coins_added_at_height_cache.get(height)
181
- if coins_added is not None:
182
- return coins_added
183
-
184
217
  async with self.db_wrapper.reader_no_transaction() as conn:
185
218
  async with conn.execute(
186
219
  "SELECT confirmed_index, spent_index, coinbase, puzzle_hash, "
@@ -191,8 +224,8 @@ class CoinStore:
191
224
  coins = []
192
225
  for row in rows:
193
226
  coin = self.row_to_coin(row)
194
- coins.append(CoinRecord(coin, row[0], row[1], row[2], row[6]))
195
- self.coins_added_at_height_cache.put(height, coins)
227
+ spent_index = uint32(0) if row[1] <= 0 else uint32(row[1])
228
+ coins.append(CoinRecord(coin, row[0], spent_index, row[2], row[6]))
196
229
  return coins
197
230
 
198
231
  async def get_coins_removed_at_height(self, height: uint32) -> list[CoinRecord]:
@@ -207,29 +240,12 @@ class CoinStore:
207
240
  ) as cursor:
208
241
  coins = []
209
242
  for row in await cursor.fetchall():
210
- if row[1] != 0:
243
+ if row[1] > 0:
211
244
  coin = self.row_to_coin(row)
212
245
  coin_record = CoinRecord(coin, row[0], row[1], row[2], row[6])
213
246
  coins.append(coin_record)
214
247
  return coins
215
248
 
216
- async def get_all_coins(self, include_spent_coins: bool) -> list[CoinRecord]:
217
- # WARNING: this should only be used for testing or in a simulation,
218
- # running it on a synced testnet or mainnet node will most likely result in an OOM error.
219
- coins = set()
220
-
221
- async with self.db_wrapper.reader_no_transaction() as conn:
222
- async with conn.execute(
223
- f"SELECT confirmed_index, spent_index, coinbase, puzzle_hash, "
224
- f"coin_parent, amount, timestamp FROM coin_record "
225
- f"{'' if include_spent_coins else 'INDEXED BY coin_spent_index WHERE spent_index=0'}"
226
- f" ORDER BY confirmed_index"
227
- ) as cursor:
228
- for row in await cursor.fetchall():
229
- coin = self.row_to_coin(row)
230
- coins.add(CoinRecord(coin, row[0], row[1], row[2], row[6]))
231
- return list(coins)
232
-
233
249
  # Checks DB and DiffStores for CoinRecords with puzzle_hash and returns them
234
250
  async def get_coin_records_by_puzzle_hash(
235
251
  self,
@@ -245,12 +261,13 @@ class CoinStore:
245
261
  f"SELECT confirmed_index, spent_index, coinbase, puzzle_hash, "
246
262
  f"coin_parent, amount, timestamp FROM coin_record INDEXED BY coin_puzzle_hash WHERE puzzle_hash=? "
247
263
  f"AND confirmed_index>=? AND confirmed_index<? "
248
- f"{'' if include_spent_coins else 'AND spent_index=0'}",
264
+ f"{'' if include_spent_coins else 'AND spent_index <= 0'}",
249
265
  (puzzle_hash, start_height, end_height),
250
266
  ) as cursor:
251
267
  for row in await cursor.fetchall():
252
268
  coin = self.row_to_coin(row)
253
- coins.add(CoinRecord(coin, row[0], row[1], row[2], row[6]))
269
+ spent_index = uint32(0) if row[1] <= 0 else uint32(row[1])
270
+ coins.add(CoinRecord(coin, row[0], spent_index, row[2], row[6]))
254
271
  return list(coins)
255
272
 
256
273
  async def get_coin_records_by_puzzle_hashes(
@@ -273,12 +290,13 @@ class CoinStore:
273
290
  f"coin_parent, amount, timestamp FROM coin_record INDEXED BY coin_puzzle_hash "
274
291
  f"WHERE puzzle_hash in ({'?,' * (len(puzzle_hashes) - 1)}?) "
275
292
  f"AND confirmed_index>=? AND confirmed_index<? "
276
- f"{'' if include_spent_coins else 'AND spent_index=0'}",
293
+ f"{'' if include_spent_coins else 'AND spent_index <= 0'}",
277
294
  (*puzzle_hashes_db, start_height, end_height),
278
295
  ) as cursor:
279
296
  for row in await cursor.fetchall():
280
297
  coin = self.row_to_coin(row)
281
- coins.add(CoinRecord(coin, row[0], row[1], row[2], row[6]))
298
+ spent_index = uint32(0) if row[1] <= 0 else uint32(row[1])
299
+ coins.add(CoinRecord(coin, row[0], spent_index, row[2], row[6]))
282
300
  return list(coins)
283
301
 
284
302
  async def get_coin_records_by_names(
@@ -299,12 +317,13 @@ class CoinStore:
299
317
  f"coin_parent, amount, timestamp FROM coin_record INDEXED BY sqlite_autoindex_coin_record_1 "
300
318
  f"WHERE coin_name in ({'?,' * (len(names) - 1)}?) "
301
319
  f"AND confirmed_index>=? AND confirmed_index<? "
302
- f"{'' if include_spent_coins else 'AND spent_index=0'}",
320
+ f"{'' if include_spent_coins else 'AND spent_index <= 0'}",
303
321
  [*names, start_height, end_height],
304
322
  ) as cursor:
305
323
  for row in await cursor.fetchall():
306
324
  coin = self.row_to_coin(row)
307
- coins.add(CoinRecord(coin, row[0], row[1], row[2], row[6]))
325
+ spent_index = uint32(0) if row[1] <= 0 else uint32(row[1])
326
+ coins.add(CoinRecord(coin, row[0], spent_index, row[2], row[6]))
308
327
 
309
328
  return list(coins)
310
329
 
@@ -314,7 +333,7 @@ class CoinStore:
314
333
  def row_to_coin_state(self, row: sqlite3.Row) -> CoinState:
315
334
  coin = self.row_to_coin(row)
316
335
  spent_h = None
317
- if row[1] != 0:
336
+ if row[1] > 0:
318
337
  spent_h = row[1]
319
338
  return CoinState(coin, spent_h, row[0])
320
339
 
@@ -338,7 +357,7 @@ class CoinStore:
338
357
  f"coin_parent, amount, timestamp FROM coin_record INDEXED BY coin_puzzle_hash "
339
358
  f"WHERE puzzle_hash in ({'?,' * (len(batch.entries) - 1)}?) "
340
359
  f"AND (confirmed_index>=? OR spent_index>=?)"
341
- f"{'' if include_spent_coins else 'AND spent_index=0'}"
360
+ f"{'' if include_spent_coins else ' AND spent_index <= 0'}"
342
361
  " LIMIT ?",
343
362
  (*puzzle_hashes_db, min_height, min_height, max_items - len(coins)),
344
363
  ) as cursor:
@@ -369,12 +388,13 @@ class CoinStore:
369
388
  f"SELECT confirmed_index, spent_index, coinbase, puzzle_hash, coin_parent, amount, timestamp "
370
389
  f"FROM coin_record WHERE coin_parent in ({'?,' * (len(batch.entries) - 1)}?) "
371
390
  f"AND confirmed_index>=? AND confirmed_index<? "
372
- f"{'' if include_spent_coins else 'AND spent_index=0'}",
391
+ f"{'' if include_spent_coins else 'AND spent_index <= 0'}",
373
392
  (*parent_ids_db, start_height, end_height),
374
393
  ) as cursor:
375
394
  async for row in cursor:
376
395
  coin = self.row_to_coin(row)
377
- coins.add(CoinRecord(coin, row[0], row[1], row[2], row[6]))
396
+ spent_index = uint32(0) if row[1] <= 0 else uint32(row[1])
397
+ coins.add(CoinRecord(coin, row[0], spent_index, row[2], row[6]))
378
398
 
379
399
  return list(coins)
380
400
 
@@ -403,7 +423,7 @@ class CoinStore:
403
423
  f"SELECT confirmed_index, spent_index, coinbase, puzzle_hash, coin_parent, amount, timestamp "
404
424
  f"FROM coin_record WHERE coin_name in ({'?,' * (len(batch.entries) - 1)}?) "
405
425
  f"AND (confirmed_index>=? OR spent_index>=?) {max_height_sql}"
406
- f"{'' if include_spent_coins else 'AND spent_index=0'}"
426
+ f"{'' if include_spent_coins else 'AND spent_index <= 0'}"
407
427
  " LIMIT ?",
408
428
  (*coin_ids_db, min_height, min_height, max_items - len(coins)),
409
429
  ) as cursor:
@@ -414,7 +434,7 @@ class CoinStore:
414
434
 
415
435
  return coins
416
436
 
417
- MAX_PUZZLE_HASH_BATCH_SIZE = SQLITE_MAX_VARIABLE_NUMBER - 10
437
+ MAX_PUZZLE_HASH_BATCH_SIZE: ClassVar[int] = SQLITE_MAX_VARIABLE_NUMBER - 10
418
438
 
419
439
  async def batch_coin_states_by_puzzle_hashes(
420
440
  self,
@@ -448,7 +468,7 @@ class CoinStore:
448
468
  puzzle_hash_count = len(puzzle_hashes_db)
449
469
 
450
470
  require_spent = "spent_index>0"
451
- require_unspent = "spent_index=0"
471
+ require_unspent = "spent_index <= 0"
452
472
  amount_filter = "AND amount>=? " if min_amount > 0 else ""
453
473
 
454
474
  if include_spent and include_unspent:
@@ -531,66 +551,70 @@ class CoinStore:
531
551
 
532
552
  return coin_states, next_height
533
553
 
534
- async def rollback_to_block(self, block_index: int) -> list[CoinRecord]:
554
+ async def rollback_to_block(self, block_index: int) -> dict[bytes32, CoinRecord]:
535
555
  """
536
556
  Note that block_index can be negative, in which case everything is rolled back
537
- Returns the list of coin records that have been modified
557
+ Returns a map of coin ID to coin record for modified items.
538
558
  """
539
559
 
540
560
  coin_changes: dict[bytes32, CoinRecord] = {}
541
561
  # Add coins that are confirmed in the reverted blocks to the list of updated coins.
542
562
  async with self.db_wrapper.writer_maybe_transaction() as conn:
543
- async with conn.execute(
563
+ rows = await conn.execute_fetchall(
544
564
  "SELECT confirmed_index, spent_index, coinbase, puzzle_hash, "
545
- "coin_parent, amount, timestamp FROM coin_record WHERE confirmed_index>?",
565
+ "coin_parent, amount, timestamp, coin_name FROM coin_record WHERE confirmed_index>?",
546
566
  (block_index,),
547
- ) as cursor:
548
- for row in await cursor.fetchall():
549
- coin = self.row_to_coin(row)
550
- record = CoinRecord(coin, uint32(0), row[1], row[2], uint64(0))
551
- coin_changes[record.name] = record
567
+ )
568
+ for row in rows:
569
+ coin = self.row_to_coin(row)
570
+ spent_index = uint32(0) if row[1] <= 0 else uint32(row[1])
571
+ record = CoinRecord(coin, uint32(0), spent_index, row[2], uint64(0))
572
+ coin_name = bytes32(row[7])
573
+ coin_changes[coin_name] = record
552
574
 
553
575
  # Delete reverted blocks from storage
554
576
  await conn.execute("DELETE FROM coin_record WHERE confirmed_index>?", (block_index,))
555
577
 
556
578
  # Add coins that are confirmed in the reverted blocks to the list of changed coins.
557
- async with conn.execute(
579
+ rows = await conn.execute_fetchall(
558
580
  "SELECT confirmed_index, spent_index, coinbase, puzzle_hash, "
559
- "coin_parent, amount, timestamp FROM coin_record WHERE spent_index>?",
581
+ "coin_parent, amount, timestamp, coin_name FROM coin_record WHERE spent_index>?",
560
582
  (block_index,),
561
- ) as cursor:
562
- for row in await cursor.fetchall():
563
- coin = self.row_to_coin(row)
564
- record = CoinRecord(coin, row[0], uint32(0), row[2], row[6])
565
- if record.name not in coin_changes:
566
- coin_changes[record.name] = record
567
-
568
- await conn.execute("UPDATE coin_record SET spent_index=0 WHERE spent_index>?", (block_index,))
569
- self.coins_added_at_height_cache = LRUCache(self.coins_added_at_height_cache.capacity)
570
- return list(coin_changes.values())
571
-
572
- # Store CoinRecord in DB
573
- async def _add_coin_records(self, records: list[CoinRecord]) -> None:
574
- values2 = []
575
- for record in records:
576
- values2.append(
577
- (
578
- record.coin.name(),
579
- record.confirmed_block_index,
580
- record.spent_block_index,
581
- int(record.coinbase),
582
- record.coin.puzzle_hash,
583
- record.coin.parent_coin_info,
584
- uint64(record.coin.amount).stream_to_bytes(),
585
- record.timestamp,
586
- )
587
583
  )
588
- if len(values2) > 0:
589
- async with self.db_wrapper.writer_maybe_transaction() as conn:
590
- await conn.executemany(
591
- "INSERT INTO coin_record VALUES(?, ?, ?, ?, ?, ?, ?, ?)",
592
- values2,
593
- )
584
+ for row in rows:
585
+ coin = self.row_to_coin(row)
586
+ record = CoinRecord(coin, row[0], uint32(0), row[2], row[6])
587
+ coin_name = bytes32(row[7])
588
+ if coin_name not in coin_changes:
589
+ coin_changes[coin_name] = record
590
+
591
+ # If the coin to update is not a reward coin and its parent is
592
+ # spent and has the same puzzle hash and amount, we set its
593
+ # spent_index to -1 as a potential fast forward singleton unspent
594
+ # otherwise we set it to 0 as a normal unspent.
595
+ await conn.execute(
596
+ """
597
+ UPDATE coin_record INDEXED BY coin_spent_index
598
+ SET spent_index = CASE
599
+ WHEN
600
+ coinbase = 0 AND
601
+ EXISTS (
602
+ SELECT 1
603
+ FROM coin_record AS parent INDEXED BY sqlite_autoindex_coin_record_1
604
+ WHERE
605
+ parent.coin_name = coin_record.coin_parent AND
606
+ parent.puzzle_hash = coin_record.puzzle_hash AND
607
+ parent.amount = coin_record.amount AND
608
+ parent.spent_index > 0
609
+ )
610
+ THEN -1
611
+ ELSE 0
612
+ END
613
+ WHERE spent_index > ?
614
+ """,
615
+ (block_index,),
616
+ )
617
+ return coin_changes
594
618
 
595
619
  # Update coin_record to be spent in DB
596
620
  async def _set_spent(self, coin_names: list[bytes32], index: uint32) -> None:
@@ -606,7 +630,7 @@ class CoinStore:
606
630
  ret: Cursor = await conn.execute(
607
631
  f"UPDATE coin_record INDEXED BY sqlite_autoindex_coin_record_1 "
608
632
  f"SET spent_index={index} "
609
- f"WHERE spent_index=0 "
633
+ f"WHERE spent_index <= 0 "
610
634
  f"AND coin_name IN ({name_params})",
611
635
  batch.entries,
612
636
  )
@@ -621,27 +645,32 @@ class CoinStore:
621
645
  async with self.db_wrapper.reader_no_transaction() as conn:
622
646
  async with conn.execute(
623
647
  "SELECT unspent.coin_name, "
624
- "unspent.amount, "
625
648
  "unspent.coin_parent, "
626
- "parent.amount, "
627
649
  "parent.coin_parent "
628
- "FROM coin_record AS unspent INDEXED BY coin_puzzle_hash "
650
+ "FROM coin_record AS unspent "
651
+ f"INDEXED BY {self._unspent_lineage_for_ph_idx} "
629
652
  "LEFT JOIN coin_record AS parent ON unspent.coin_parent = parent.coin_name "
630
- "WHERE unspent.spent_index = 0 "
653
+ "WHERE unspent.spent_index = -1 "
631
654
  "AND parent.spent_index > 0 "
632
655
  "AND unspent.puzzle_hash = ? "
633
- "AND parent.puzzle_hash = unspent.puzzle_hash",
656
+ "AND parent.puzzle_hash = unspent.puzzle_hash "
657
+ "AND parent.amount = unspent.amount",
634
658
  (puzzle_hash,),
635
659
  ) as cursor:
636
660
  rows = list(await cursor.fetchall())
637
661
  if len(rows) != 1:
638
662
  log.debug("Expected 1 unspent with puzzle hash %s, but found %s", puzzle_hash.hex(), len(rows))
639
663
  return None
640
- coin_id, coin_amount, parent_id, parent_amount, parent_parent_id = rows[0]
664
+ coin_id, parent_id, parent_parent_id = rows[0]
641
665
  return UnspentLineageInfo(
642
- coin_id=bytes32(coin_id),
643
- coin_amount=uint64(int_from_bytes(coin_amount)),
644
- parent_id=bytes32(parent_id),
645
- parent_amount=uint64(int_from_bytes(parent_amount)),
646
- parent_parent_id=bytes32(parent_parent_id),
666
+ coin_id=bytes32(coin_id), parent_id=bytes32(parent_id), parent_parent_id=bytes32(parent_parent_id)
647
667
  )
668
+
669
+ async def is_empty(self) -> bool:
670
+ """
671
+ Returns True if the coin store is empty, False otherwise.
672
+ """
673
+ async with self.db_wrapper.reader_no_transaction() as conn:
674
+ async with conn.execute("SELECT coin_name FROM coin_record LIMIT 1") as cursor:
675
+ row = await cursor.fetchone()
676
+ return row is None or len(row) == 0