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.
- chia/_tests/blockchain/blockchain_test_utils.py +2 -3
- chia/_tests/blockchain/test_augmented_chain.py +2 -3
- chia/_tests/blockchain/test_blockchain.py +261 -44
- chia/_tests/blockchain/test_blockchain_transactions.py +4 -3
- chia/_tests/blockchain/test_build_chains.py +197 -1
- chia/_tests/blockchain/test_get_block_generator.py +1 -1
- chia/_tests/blockchain/test_lookup_fork_chain.py +1 -1
- chia/_tests/clvm/benchmark_costs.py +1 -1
- chia/_tests/clvm/coin_store.py +3 -4
- chia/_tests/clvm/test_message_conditions.py +2 -2
- chia/_tests/clvm/test_puzzle_compression.py +2 -3
- chia/_tests/clvm/test_puzzles.py +1 -2
- chia/_tests/clvm/test_singletons.py +2 -3
- chia/_tests/clvm/test_spend_sim.py +7 -7
- chia/_tests/cmds/cmd_test_utils.py +30 -25
- chia/_tests/cmds/test_dev_gh.py +1 -1
- chia/_tests/cmds/test_farm_cmd.py +1 -1
- chia/_tests/cmds/test_show.py +1 -2
- chia/_tests/cmds/wallet/test_did.py +101 -56
- chia/_tests/cmds/wallet/test_nft.py +109 -84
- chia/_tests/cmds/wallet/test_notifications.py +1 -1
- chia/_tests/cmds/wallet/test_offer.toffer +1 -1
- chia/_tests/cmds/wallet/test_vcs.py +8 -8
- chia/_tests/cmds/wallet/test_wallet.py +100 -46
- chia/_tests/conftest.py +31 -20
- chia/_tests/connection_utils.py +1 -1
- chia/_tests/core/consensus/stores/__init__.py +0 -0
- chia/_tests/core/consensus/stores/test_coin_store_protocol.py +40 -0
- chia/_tests/core/consensus/test_block_creation.py +2 -31
- chia/_tests/core/consensus/test_pot_iterations.py +38 -3
- chia/_tests/core/custom_types/test_proof_of_space.py +154 -26
- chia/_tests/core/custom_types/test_spend_bundle.py +2 -3
- chia/_tests/core/daemon/test_daemon.py +80 -0
- chia/_tests/core/data_layer/test_data_layer.py +1 -1
- chia/_tests/core/data_layer/test_data_layer_util.py +1 -1
- chia/_tests/core/data_layer/test_data_rpc.py +14 -10
- chia/_tests/core/data_layer/test_data_store.py +5 -5
- chia/_tests/core/farmer/test_farmer_api.py +2 -2
- chia/_tests/core/full_node/full_sync/test_full_sync.py +446 -406
- chia/_tests/core/full_node/ram_db.py +3 -1
- chia/_tests/core/full_node/stores/test_block_store.py +28 -16
- chia/_tests/core/full_node/stores/test_coin_store.py +277 -185
- chia/_tests/core/full_node/stores/test_full_node_store.py +11 -4
- chia/_tests/core/full_node/stores/test_hint_store.py +2 -2
- chia/_tests/core/full_node/test_address_manager.py +200 -27
- chia/_tests/core/full_node/test_block_height_map.py +2 -2
- chia/_tests/core/full_node/test_conditions.py +7 -6
- chia/_tests/core/full_node/test_full_node.py +456 -40
- chia/_tests/core/full_node/test_generator_tools.py +32 -2
- chia/_tests/core/full_node/test_hint_management.py +1 -1
- chia/_tests/core/full_node/test_node_load.py +20 -21
- chia/_tests/core/full_node/test_performance.py +3 -4
- chia/_tests/core/full_node/test_prev_tx_block.py +43 -0
- chia/_tests/core/full_node/test_subscriptions.py +1 -2
- chia/_tests/core/full_node/test_transactions.py +9 -5
- chia/_tests/core/full_node/test_tx_processing_queue.py +1 -2
- chia/_tests/core/large_block.py +1 -2
- chia/_tests/core/make_block_generator.py +3 -4
- chia/_tests/core/mempool/test_mempool.py +36 -86
- chia/_tests/core/mempool/test_mempool_fee_estimator.py +1 -1
- chia/_tests/core/mempool/test_mempool_item_queries.py +1 -3
- chia/_tests/core/mempool/test_mempool_manager.py +529 -69
- chia/_tests/core/mempool/test_mempool_performance.py +3 -2
- chia/_tests/core/mempool/test_singleton_fast_forward.py +61 -132
- chia/_tests/core/server/flood.py +1 -1
- chia/_tests/core/server/test_dos.py +1 -1
- chia/_tests/core/server/test_node_discovery.py +41 -27
- chia/_tests/core/server/test_rate_limits.py +1 -1
- chia/_tests/core/server/test_server.py +1 -1
- chia/_tests/core/services/test_services.py +5 -5
- chia/_tests/core/ssl/test_ssl.py +1 -1
- chia/_tests/core/test_cost_calculation.py +6 -6
- chia/_tests/core/test_crawler.py +2 -2
- chia/_tests/core/test_crawler_rpc.py +1 -1
- chia/_tests/core/test_db_conversion.py +3 -1
- chia/_tests/core/test_db_validation.py +5 -3
- chia/_tests/core/test_farmer_harvester_rpc.py +15 -15
- chia/_tests/core/test_filter.py +4 -1
- chia/_tests/core/test_full_node_rpc.py +99 -82
- chia/_tests/core/test_program.py +2 -2
- chia/_tests/core/util/test_block_cache.py +1 -1
- chia/_tests/core/util/test_keychain.py +2 -2
- chia/_tests/core/util/test_lockfile.py +1 -1
- chia/_tests/core/util/test_log_exceptions.py +5 -5
- chia/_tests/core/util/test_streamable.py +81 -22
- chia/_tests/db/test_db_wrapper.py +1 -3
- chia/_tests/environments/wallet.py +5 -5
- chia/_tests/farmer_harvester/test_farmer.py +9 -7
- chia/_tests/farmer_harvester/test_farmer_harvester.py +11 -4
- chia/_tests/farmer_harvester/test_filter_prefix_bits.py +6 -5
- chia/_tests/farmer_harvester/test_third_party_harvesters.py +15 -9
- chia/_tests/fee_estimation/test_fee_estimation_integration.py +1 -2
- chia/_tests/fee_estimation/test_fee_estimation_rpc.py +7 -5
- chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +1 -1
- chia/_tests/generator/test_compression.py +1 -2
- chia/_tests/generator/test_rom.py +8 -4
- chia/_tests/plot_sync/test_plot_sync.py +3 -3
- chia/_tests/plot_sync/test_receiver.py +3 -3
- chia/_tests/plot_sync/test_sender.py +1 -1
- chia/_tests/plot_sync/test_sync_simulated.py +3 -3
- chia/_tests/plot_sync/util.py +2 -2
- chia/_tests/pools/test_pool_cmdline.py +48 -21
- chia/_tests/pools/test_pool_puzzles_lifecycle.py +2 -3
- chia/_tests/pools/test_pool_rpc.py +237 -105
- chia/_tests/pools/test_pool_wallet.py +11 -2
- chia/_tests/pools/test_wallet_pool_store.py +5 -4
- chia/_tests/rpc/test_rpc_client.py +1 -1
- chia/_tests/simulation/test_simulation.py +13 -8
- chia/_tests/simulation/test_simulator.py +2 -2
- chia/_tests/timelord/test_new_peak.py +191 -47
- chia/_tests/timelord/test_timelord.py +1 -1
- chia/_tests/tools/test_full_sync.py +0 -2
- chia/_tests/tools/test_run_block.py +3 -1
- chia/_tests/util/benchmark_cost.py +3 -3
- chia/_tests/util/benchmarks.py +2 -2
- chia/_tests/util/blockchain.py +11 -5
- chia/_tests/util/blockchain_mock.py +1 -4
- chia/_tests/util/coin_store.py +29 -0
- chia/_tests/util/constants.py +2 -18
- chia/_tests/util/full_sync.py +3 -3
- chia/_tests/util/generator_tools_testing.py +2 -3
- chia/_tests/util/key_tool.py +2 -3
- chia/_tests/util/misc.py +33 -31
- chia/_tests/util/network_protocol_data.py +19 -17
- chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
- chia/_tests/util/protocol_messages_json.py +3 -1
- chia/_tests/util/run_block.py +2 -2
- chia/_tests/util/setup_nodes.py +7 -7
- chia/_tests/util/spend_sim.py +47 -55
- chia/_tests/util/test_condition_tools.py +5 -4
- chia/_tests/util/test_config.py +2 -2
- chia/_tests/util/test_dump_keyring.py +1 -1
- chia/_tests/util/test_full_block_utils.py +12 -14
- chia/_tests/util/test_misc.py +2 -2
- chia/_tests/util/test_paginator.py +4 -4
- chia/_tests/util/test_priority_mutex.py +2 -2
- chia/_tests/util/test_replace_str_to_bytes.py +15 -5
- chia/_tests/util/test_ssl_check.py +1 -1
- chia/_tests/util/test_testnet_overrides.py +13 -3
- chia/_tests/util/time_out_assert.py +4 -2
- chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +1 -1
- chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +1 -2
- chia/_tests/wallet/cat_wallet/test_cat_wallet.py +352 -432
- chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +3 -6
- chia/_tests/wallet/cat_wallet/test_trades.py +53 -77
- chia/_tests/wallet/clawback/test_clawback_decorator.py +3 -1
- chia/_tests/wallet/clawback/test_clawback_lifecycle.py +3 -3
- chia/_tests/wallet/clawback/test_clawback_metadata.py +4 -2
- chia/_tests/wallet/conftest.py +11 -12
- chia/_tests/wallet/db_wallet/test_db_graftroot.py +11 -4
- chia/_tests/wallet/db_wallet/test_dl_offers.py +433 -130
- chia/_tests/wallet/db_wallet/test_dl_wallet.py +3 -3
- chia/_tests/wallet/did_wallet/test_did.py +2132 -2000
- chia/_tests/wallet/nft_wallet/config.py +1 -1
- chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +1610 -742
- chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +486 -907
- chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +4 -4
- chia/_tests/wallet/nft_wallet/test_nft_wallet.py +517 -294
- chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +133 -62
- chia/_tests/wallet/rpc/test_wallet_rpc.py +495 -265
- chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +10 -6
- chia/_tests/wallet/sync/test_wallet_sync.py +89 -60
- chia/_tests/wallet/test_clvm_casts.py +88 -0
- chia/_tests/wallet/test_coin_management.py +1 -1
- chia/_tests/wallet/test_coin_selection.py +1 -1
- chia/_tests/wallet/test_conditions.py +1 -1
- chia/_tests/wallet/test_new_wallet_protocol.py +13 -11
- chia/_tests/wallet/test_notifications.py +5 -3
- chia/_tests/wallet/test_sign_coin_spends.py +6 -6
- chia/_tests/wallet/test_signer_protocol.py +13 -12
- chia/_tests/wallet/test_singleton.py +1 -1
- chia/_tests/wallet/test_singleton_lifecycle_fast.py +5 -7
- chia/_tests/wallet/test_util.py +2 -2
- chia/_tests/wallet/test_wallet.py +108 -29
- chia/_tests/wallet/test_wallet_action_scope.py +9 -2
- chia/_tests/wallet/test_wallet_blockchain.py +2 -3
- chia/_tests/wallet/test_wallet_key_val_store.py +1 -2
- chia/_tests/wallet/test_wallet_node.py +2 -4
- chia/_tests/wallet/test_wallet_retry.py +4 -2
- chia/_tests/wallet/test_wallet_state_manager.py +191 -5
- chia/_tests/wallet/test_wallet_test_framework.py +1 -1
- chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +8 -8
- chia/_tests/wallet/vc_wallet/test_vc_wallet.py +29 -12
- chia/_tests/wallet/wallet_block_tools.py +6 -6
- chia/_tests/weight_proof/test_weight_proof.py +10 -48
- chia/apis.py +1 -1
- chia/cmds/beta.py +1 -1
- chia/cmds/chia.py +9 -9
- chia/cmds/cmd_classes.py +12 -11
- chia/cmds/cmd_helpers.py +1 -1
- chia/cmds/cmds_util.py +12 -9
- chia/cmds/coin_funcs.py +2 -2
- chia/cmds/configure.py +2 -2
- chia/cmds/data.py +0 -2
- chia/cmds/data_funcs.py +1 -1
- chia/cmds/db_validate_func.py +1 -2
- chia/cmds/dev/__init__.py +0 -0
- chia/cmds/dev/data.py +273 -0
- chia/cmds/{gh.py → dev/gh.py} +5 -5
- chia/cmds/dev/main.py +22 -0
- chia/cmds/dev/mempool.py +78 -0
- chia/cmds/dev/mempool_funcs.py +63 -0
- chia/cmds/farm_funcs.py +5 -4
- chia/cmds/init_funcs.py +11 -11
- chia/cmds/keys.py +2 -2
- chia/cmds/keys_funcs.py +4 -4
- chia/cmds/netspace_funcs.py +1 -1
- chia/cmds/peer_funcs.py +2 -2
- chia/cmds/plotnft_funcs.py +72 -26
- chia/cmds/rpc.py +1 -1
- chia/cmds/show_funcs.py +5 -5
- chia/cmds/signer.py +8 -7
- chia/cmds/sim_funcs.py +8 -9
- chia/cmds/wallet.py +2 -2
- chia/cmds/wallet_funcs.py +165 -131
- chia/{util → consensus}/augmented_chain.py +1 -2
- chia/consensus/block_body_validation.py +54 -40
- chia/consensus/block_creation.py +42 -76
- chia/consensus/block_header_validation.py +32 -26
- chia/consensus/block_record.py +0 -3
- chia/consensus/blockchain.py +23 -32
- chia/consensus/blockchain_interface.py +1 -5
- chia/consensus/check_time_locks.py +57 -0
- chia/consensus/coin_store_protocol.py +151 -0
- chia/consensus/coinbase.py +0 -6
- chia/consensus/condition_costs.py +4 -0
- chia/{util → consensus}/condition_tools.py +4 -5
- chia/consensus/cost_calculator.py +1 -1
- chia/consensus/default_constants.py +32 -9
- chia/consensus/deficit.py +1 -3
- chia/consensus/difficulty_adjustment.py +1 -2
- chia/consensus/find_fork_point.py +1 -3
- chia/consensus/full_block_to_block_record.py +1 -6
- chia/{util → consensus}/generator_tools.py +1 -3
- chia/consensus/get_block_challenge.py +30 -7
- chia/consensus/make_sub_epoch_summary.py +1 -5
- chia/consensus/multiprocess_validation.py +21 -20
- chia/consensus/pot_iterations.py +74 -13
- chia/{util → consensus}/prev_transaction_block.py +1 -1
- chia/consensus/vdf_info_computation.py +1 -3
- chia/daemon/keychain_proxy.py +5 -5
- chia/daemon/server.py +22 -5
- chia/data_layer/data_layer.py +92 -51
- chia/{rpc → data_layer}/data_layer_rpc_api.py +1 -1
- chia/{rpc → data_layer}/data_layer_rpc_util.py +3 -6
- chia/data_layer/data_layer_util.py +4 -6
- chia/data_layer/data_layer_wallet.py +42 -69
- chia/data_layer/dl_wallet_store.py +12 -6
- chia/data_layer/download_data.py +3 -3
- chia/data_layer/s3_plugin_service.py +0 -1
- chia/farmer/farmer.py +3 -4
- chia/farmer/farmer_api.py +11 -7
- chia/{rpc → farmer}/farmer_rpc_client.py +1 -1
- chia/full_node/block_height_map.py +7 -6
- chia/full_node/block_store.py +5 -7
- chia/full_node/bundle_tools.py +1 -2
- chia/full_node/coin_store.py +153 -124
- chia/{types → full_node}/eligible_coin_spends.py +39 -70
- chia/full_node/fee_estimator.py +1 -1
- chia/full_node/fee_estimator_interface.py +0 -8
- chia/full_node/fee_tracker.py +25 -25
- chia/full_node/full_node.py +70 -53
- chia/full_node/full_node_api.py +57 -40
- chia/{rpc → full_node}/full_node_rpc_api.py +87 -8
- chia/{rpc → full_node}/full_node_rpc_client.py +7 -6
- chia/full_node/full_node_store.py +23 -8
- chia/full_node/mempool.py +206 -53
- chia/full_node/mempool_check_conditions.py +20 -63
- chia/full_node/mempool_manager.py +47 -45
- chia/full_node/subscriptions.py +1 -3
- chia/full_node/tx_processing_queue.py +50 -3
- chia/full_node/weight_proof.py +46 -37
- chia/harvester/harvester.py +1 -1
- chia/harvester/harvester_api.py +22 -7
- chia/introducer/introducer.py +1 -1
- chia/introducer/introducer_api.py +1 -1
- chia/plot_sync/exceptions.py +1 -1
- chia/plot_sync/receiver.py +1 -1
- chia/plot_sync/sender.py +2 -2
- chia/pools/pool_puzzles.py +13 -18
- chia/pools/pool_wallet.py +23 -46
- chia/protocols/farmer_protocol.py +11 -3
- chia/protocols/full_node_protocol.py +1 -4
- chia/protocols/harvester_protocol.py +3 -3
- chia/protocols/pool_protocol.py +1 -2
- chia/protocols/shared_protocol.py +3 -3
- chia/protocols/timelord_protocol.py +1 -3
- chia/protocols/wallet_protocol.py +3 -3
- chia/rpc/rpc_client.py +7 -8
- chia/rpc/rpc_server.py +3 -3
- chia/rpc/util.py +3 -1
- chia/seeder/crawler.py +1 -1
- chia/seeder/crawler_api.py +1 -1
- chia/seeder/dns_server.py +2 -0
- chia/seeder/start_crawler.py +3 -3
- chia/server/address_manager.py +286 -38
- chia/server/address_manager_store.py +0 -215
- chia/{types → server}/aliases.py +7 -7
- chia/server/api_protocol.py +1 -1
- chia/server/chia_policy.py +1 -1
- chia/server/node_discovery.py +76 -113
- chia/server/rate_limits.py +1 -1
- chia/server/resolve_peer_info.py +43 -0
- chia/server/server.py +5 -5
- chia/server/start_data_layer.py +4 -4
- chia/server/start_farmer.py +5 -4
- chia/server/start_full_node.py +5 -4
- chia/server/start_harvester.py +7 -5
- chia/server/start_introducer.py +2 -2
- chia/server/start_service.py +1 -1
- chia/server/start_timelord.py +7 -5
- chia/server/start_wallet.py +7 -5
- chia/server/ws_connection.py +1 -1
- chia/simulator/add_blocks_in_batches.py +2 -2
- chia/simulator/block_tools.py +245 -201
- chia/simulator/full_node_simulator.py +38 -10
- chia/simulator/setup_services.py +12 -12
- chia/simulator/simulator_full_node_rpc_api.py +2 -2
- chia/simulator/simulator_full_node_rpc_client.py +2 -2
- chia/simulator/simulator_test_tools.py +2 -2
- chia/simulator/start_simulator.py +1 -1
- chia/simulator/wallet_tools.py +10 -18
- chia/ssl/create_ssl.py +1 -1
- chia/timelord/iters_from_block.py +14 -14
- chia/timelord/timelord.py +15 -11
- chia/timelord/timelord_api.py +14 -2
- chia/timelord/timelord_state.py +20 -14
- chia/types/blockchain_format/program.py +53 -10
- chia/types/blockchain_format/proof_of_space.py +73 -19
- chia/types/coin_spend.py +3 -56
- chia/types/generator_types.py +28 -0
- chia/types/internal_mempool_item.py +1 -2
- chia/types/mempool_item.py +12 -7
- chia/types/unfinished_header_block.py +1 -2
- chia/types/validation_state.py +1 -2
- chia/types/weight_proof.py +1 -3
- chia/util/action_scope.py +3 -3
- chia/util/block_cache.py +1 -2
- chia/util/byte_types.py +1 -1
- chia/util/casts.py +21 -0
- chia/util/config.py +0 -37
- chia/util/db_wrapper.py +8 -1
- chia/util/errors.py +3 -2
- chia/util/initial-config.yaml +21 -5
- chia/util/keychain.py +6 -7
- chia/util/keyring_wrapper.py +5 -5
- chia/util/limited_semaphore.py +1 -1
- chia/util/priority_mutex.py +1 -1
- chia/util/streamable.py +63 -5
- chia/util/task_timing.py +1 -1
- chia/util/virtual_project_analysis.py +1 -1
- chia/wallet/cat_wallet/cat_info.py +7 -3
- chia/wallet/cat_wallet/cat_outer_puzzle.py +9 -5
- chia/wallet/cat_wallet/cat_utils.py +1 -1
- chia/wallet/cat_wallet/cat_wallet.py +44 -36
- chia/wallet/cat_wallet/lineage_store.py +7 -0
- chia/wallet/cat_wallet/r_cat_wallet.py +274 -0
- chia/wallet/conditions.py +5 -10
- chia/wallet/db_wallet/db_wallet_puzzles.py +4 -4
- chia/wallet/derivation_record.py +33 -0
- chia/wallet/derive_keys.py +3 -3
- chia/wallet/did_wallet/did_info.py +12 -3
- chia/wallet/did_wallet/did_wallet.py +132 -101
- chia/wallet/did_wallet/did_wallet_puzzles.py +9 -9
- chia/wallet/driver_protocol.py +3 -1
- chia/{types/spend_bundle.py → wallet/estimate_fees.py} +2 -7
- chia/wallet/nft_wallet/metadata_outer_puzzle.py +5 -3
- chia/wallet/nft_wallet/nft_puzzle_utils.py +1 -1
- chia/wallet/nft_wallet/nft_wallet.py +69 -112
- chia/wallet/nft_wallet/ownership_outer_puzzle.py +5 -3
- chia/wallet/nft_wallet/singleton_outer_puzzle.py +6 -4
- chia/wallet/nft_wallet/transfer_program_puzzle.py +4 -2
- chia/wallet/nft_wallet/uncurry_nft.py +4 -6
- chia/wallet/notification_manager.py +2 -3
- chia/wallet/outer_puzzles.py +7 -2
- chia/wallet/puzzle_drivers.py +1 -1
- chia/wallet/puzzles/clawback/drivers.py +5 -4
- chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +1 -1
- chia/wallet/puzzles/singleton_top_layer.py +2 -1
- chia/wallet/puzzles/singleton_top_layer_v1_1.py +2 -1
- chia/wallet/puzzles/tails.py +1 -3
- chia/wallet/signer_protocol.py +5 -6
- chia/wallet/singleton.py +5 -4
- chia/wallet/singleton_record.py +1 -1
- chia/wallet/trade_manager.py +18 -20
- chia/wallet/trade_record.py +3 -6
- chia/wallet/trading/offer.py +12 -13
- chia/wallet/uncurried_puzzle.py +2 -2
- chia/wallet/util/compute_additions.py +58 -0
- chia/wallet/util/compute_hints.py +3 -3
- chia/wallet/util/compute_memos.py +4 -4
- chia/wallet/util/curry_and_treehash.py +2 -1
- chia/wallet/util/debug_spend_bundle.py +1 -1
- chia/wallet/util/merkle_tree.py +1 -1
- chia/wallet/util/peer_request_cache.py +1 -2
- chia/wallet/util/tx_config.py +3 -8
- chia/wallet/util/wallet_sync_utils.py +10 -5
- chia/wallet/util/wallet_types.py +1 -0
- chia/wallet/vc_wallet/cr_cat_drivers.py +17 -18
- chia/wallet/vc_wallet/cr_cat_wallet.py +30 -28
- chia/wallet/vc_wallet/cr_outer_puzzle.py +5 -3
- chia/wallet/vc_wallet/vc_drivers.py +50 -8
- chia/wallet/vc_wallet/vc_store.py +3 -5
- chia/wallet/vc_wallet/vc_wallet.py +15 -22
- chia/wallet/wallet.py +36 -46
- chia/wallet/wallet_action_scope.py +73 -4
- chia/wallet/wallet_blockchain.py +1 -3
- chia/wallet/wallet_interested_store.py +1 -1
- chia/wallet/wallet_nft_store.py +3 -3
- chia/wallet/wallet_node.py +17 -16
- chia/wallet/wallet_node_api.py +4 -5
- chia/wallet/wallet_pool_store.py +1 -1
- chia/wallet/wallet_protocol.py +2 -0
- chia/wallet/wallet_puzzle_store.py +1 -1
- chia/{rpc → wallet}/wallet_request_types.py +670 -81
- chia/{rpc → wallet}/wallet_rpc_api.py +735 -766
- chia/{rpc → wallet}/wallet_rpc_client.py +268 -420
- chia/wallet/wallet_singleton_store.py +8 -7
- chia/wallet/wallet_spend_bundle.py +4 -3
- chia/wallet/wallet_state_manager.py +320 -191
- chia/wallet/wallet_weight_proof_handler.py +1 -2
- chia/wallet/wsm_apis.py +98 -0
- {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5.dist-info}/METADATA +7 -7
- {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5.dist-info}/RECORD +443 -436
- mozilla-ca/cacert.pem +3 -165
- chia/_tests/fee_estimation/test_mempoolitem_height_added.py +0 -145
- chia/cmds/dev.py +0 -18
- chia/types/blockchain_format/slots.py +0 -9
- chia/types/blockchain_format/sub_epoch_summary.py +0 -5
- chia/types/end_of_slot_bundle.py +0 -5
- chia/types/full_block.py +0 -5
- chia/types/header_block.py +0 -5
- chia/types/spend_bundle_conditions.py +0 -7
- chia/types/transaction_queue_entry.py +0 -56
- chia/types/unfinished_block.py +0 -5
- /chia/cmds/{installers.py → dev/installers.py} +0 -0
- /chia/cmds/{sim.py → dev/sim.py} +0 -0
- /chia/{util → cmds}/dump_keyring.py +0 -0
- /chia/{full_node → consensus}/signage_point.py +0 -0
- /chia/{rpc → data_layer}/data_layer_rpc_client.py +0 -0
- /chia/{rpc → farmer}/farmer_rpc_api.py +0 -0
- /chia/{util → full_node}/full_block_utils.py +0 -0
- /chia/{rpc → harvester}/harvester_rpc_api.py +0 -0
- /chia/{rpc → harvester}/harvester_rpc_client.py +0 -0
- /chia/{full_node → protocols}/fee_estimate.py +0 -0
- /chia/{server → protocols}/outbound_message.py +0 -0
- /chia/{rpc → seeder}/crawler_rpc_api.py +0 -0
- /chia/{util → simulator}/vdf_prover.py +0 -0
- /chia/{util → ssl}/ssl_check.py +0 -0
- /chia/{rpc → timelord}/timelord_rpc_api.py +0 -0
- {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5.dist-info}/LICENSE +0 -0
- {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5.dist-info}/WHEEL +0 -0
- {chia_blockchain-2.5.4rc2.dist-info → chia_blockchain-2.5.5.dist-info}/entry_points.txt +0 -0
chia/full_node/coin_store.py
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
) ->
|
|
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
|
-
|
|
120
|
+
db_values_to_insert = []
|
|
99
121
|
|
|
100
|
-
for coin in tx_additions:
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
195
|
-
|
|
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]
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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]
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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) ->
|
|
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
|
|
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
|
-
|
|
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
|
-
)
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
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
|
-
|
|
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
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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,
|
|
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
|