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
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
4
|
import logging
|
|
5
|
+
import random
|
|
5
6
|
from collections.abc import Awaitable, Collection, Sequence
|
|
6
7
|
from typing import Any, Callable, ClassVar, Optional, Union
|
|
7
8
|
|
|
@@ -10,9 +11,14 @@ from chia_rs import (
|
|
|
10
11
|
ELIGIBLE_FOR_DEDUP,
|
|
11
12
|
ELIGIBLE_FOR_FF,
|
|
12
13
|
AugSchemeMPL,
|
|
14
|
+
CoinSpend,
|
|
13
15
|
ConsensusConstants,
|
|
14
16
|
G2Element,
|
|
17
|
+
SpendBundle,
|
|
18
|
+
SpendBundleConditions,
|
|
19
|
+
SpendConditions,
|
|
15
20
|
get_conditions_from_spendbundle,
|
|
21
|
+
run_block_generator2,
|
|
16
22
|
)
|
|
17
23
|
from chia_rs.sized_bytes import bytes32
|
|
18
24
|
from chia_rs.sized_ints import uint8, uint32, uint64
|
|
@@ -21,10 +27,17 @@ from chiabip158 import PyBIP158
|
|
|
21
27
|
from chia._tests.conftest import ConsensusMode
|
|
22
28
|
from chia._tests.util.misc import Marks, datacases, invariant_check_mempool
|
|
23
29
|
from chia._tests.util.setup_nodes import OldSimulatorsAndWallets, setup_simulators_and_wallets
|
|
30
|
+
from chia.consensus.check_time_locks import check_time_locks
|
|
24
31
|
from chia.consensus.condition_costs import ConditionCost
|
|
25
32
|
from chia.consensus.default_constants import DEFAULT_CONSTANTS
|
|
33
|
+
from chia.full_node.eligible_coin_spends import (
|
|
34
|
+
DedupCoinSpend,
|
|
35
|
+
EligibilityAndAdditions,
|
|
36
|
+
IdenticalSpendDedup,
|
|
37
|
+
SkipDedup,
|
|
38
|
+
run_for_cost,
|
|
39
|
+
)
|
|
26
40
|
from chia.full_node.mempool import MAX_SKIPPED_ITEMS, PRIORITY_TX_THRESHOLD
|
|
27
|
-
from chia.full_node.mempool_check_conditions import mempool_check_time_locks
|
|
28
41
|
from chia.full_node.mempool_manager import (
|
|
29
42
|
MEMPOOL_MIN_FEE_INCREASE,
|
|
30
43
|
QUOTE_BYTES,
|
|
@@ -44,28 +57,26 @@ from chia.protocols.full_node_protocol import RequestBlock, RespondBlock
|
|
|
44
57
|
from chia.protocols.protocol_message_types import ProtocolMessageTypes
|
|
45
58
|
from chia.simulator.full_node_simulator import FullNodeSimulator
|
|
46
59
|
from chia.simulator.simulator_protocol import FarmNewBlockProtocol
|
|
60
|
+
from chia.simulator.wallet_tools import WalletTool
|
|
47
61
|
from chia.types.blockchain_format.coin import Coin
|
|
48
|
-
from chia.types.blockchain_format.program import INFINITE_COST, Program
|
|
62
|
+
from chia.types.blockchain_format.program import DEFAULT_FLAGS, INFINITE_COST, Program
|
|
49
63
|
from chia.types.blockchain_format.serialized_program import SerializedProgram
|
|
50
64
|
from chia.types.clvm_cost import CLVMCost
|
|
51
65
|
from chia.types.coin_record import CoinRecord
|
|
52
|
-
from chia.types.coin_spend import
|
|
66
|
+
from chia.types.coin_spend import make_spend
|
|
53
67
|
from chia.types.condition_opcodes import ConditionOpcode
|
|
54
|
-
from chia.types.
|
|
55
|
-
DedupCoinSpend,
|
|
56
|
-
EligibilityAndAdditions,
|
|
57
|
-
EligibleCoinSpends,
|
|
58
|
-
SkipDedup,
|
|
59
|
-
UnspentLineageInfo,
|
|
60
|
-
run_for_cost,
|
|
61
|
-
)
|
|
68
|
+
from chia.types.condition_with_args import ConditionWithArgs
|
|
62
69
|
from chia.types.mempool_inclusion_status import MempoolInclusionStatus
|
|
63
|
-
from chia.types.mempool_item import BundleCoinSpend, MempoolItem
|
|
70
|
+
from chia.types.mempool_item import BundleCoinSpend, MempoolItem, UnspentLineageInfo
|
|
64
71
|
from chia.types.peer_info import PeerInfo
|
|
65
|
-
from chia.
|
|
66
|
-
from chia.
|
|
72
|
+
from chia.util.casts import int_to_bytes
|
|
73
|
+
from chia.util.default_root import DEFAULT_ROOT_PATH
|
|
67
74
|
from chia.util.errors import Err, ValidationError
|
|
68
75
|
from chia.wallet.conditions import AssertCoinAnnouncement
|
|
76
|
+
from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import (
|
|
77
|
+
DEFAULT_HIDDEN_PUZZLE_HASH,
|
|
78
|
+
calculate_synthetic_secret_key,
|
|
79
|
+
)
|
|
69
80
|
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
|
|
70
81
|
from chia.wallet.wallet import Wallet
|
|
71
82
|
from chia.wallet.wallet_coin_record import WalletCoinRecord
|
|
@@ -90,6 +101,28 @@ TEST_COIN_RECORD3 = CoinRecord(TEST_COIN3, uint32(0), uint32(0), False, TEST_TIM
|
|
|
90
101
|
TEST_HEIGHT = uint32(5)
|
|
91
102
|
|
|
92
103
|
|
|
104
|
+
@pytest.fixture(name="test_bundles")
|
|
105
|
+
def test_bundles_fixture() -> list[SpendBundle]:
|
|
106
|
+
ret: list[SpendBundle] = []
|
|
107
|
+
|
|
108
|
+
bundle_path_dir = DEFAULT_ROOT_PATH.parent.joinpath("test-bundles")
|
|
109
|
+
for p in bundle_path_dir.iterdir():
|
|
110
|
+
if not p.is_file(): # pragma: no cover
|
|
111
|
+
continue
|
|
112
|
+
if p.suffix != ".bundle": # pragma: no cover
|
|
113
|
+
continue
|
|
114
|
+
if len(p.name) != 64 + 7: # pragma: no cover
|
|
115
|
+
continue
|
|
116
|
+
|
|
117
|
+
sb = SpendBundle.from_bytes(p.read_bytes())
|
|
118
|
+
ret.append(sb)
|
|
119
|
+
|
|
120
|
+
print(f"loaded {len(ret)} spend bundles from disk")
|
|
121
|
+
|
|
122
|
+
ret.sort(key=lambda x: x.name())
|
|
123
|
+
return ret
|
|
124
|
+
|
|
125
|
+
|
|
93
126
|
@pytest.mark.parametrize("clvm_hex", ["80", "ff8080", "ff7f03", "ffff8080ff8080"])
|
|
94
127
|
def test_clvm_canonical(clvm_hex: str) -> None:
|
|
95
128
|
clvm_buf = bytes.fromhex(clvm_hex)
|
|
@@ -158,6 +191,14 @@ def test_atom_canonical(clvm_hex: str, expect: int) -> None:
|
|
|
158
191
|
assert is_canonical
|
|
159
192
|
|
|
160
193
|
|
|
194
|
+
@pytest.mark.anyio
|
|
195
|
+
async def test_bundles_are_canonical(test_bundles: list[SpendBundle]) -> None:
|
|
196
|
+
for sb in test_bundles:
|
|
197
|
+
for spend in sb.coin_spends:
|
|
198
|
+
assert is_clvm_canonical(bytes(spend.puzzle_reveal))
|
|
199
|
+
assert is_clvm_canonical(bytes(spend.solution))
|
|
200
|
+
|
|
201
|
+
|
|
161
202
|
@dataclasses.dataclass(frozen=True)
|
|
162
203
|
class TestBlockRecord:
|
|
163
204
|
"""
|
|
@@ -318,6 +359,8 @@ def make_test_conds(
|
|
|
318
359
|
[],
|
|
319
360
|
[],
|
|
320
361
|
flags,
|
|
362
|
+
execution_cost=0,
|
|
363
|
+
condition_cost=0,
|
|
321
364
|
)
|
|
322
365
|
for coin_id, parent_id, puzzle_hash, amount, flags, create_coin in spend_info
|
|
323
366
|
],
|
|
@@ -390,7 +433,7 @@ class TestCheckTimeLocks:
|
|
|
390
433
|
expected: Optional[Err],
|
|
391
434
|
) -> None:
|
|
392
435
|
assert (
|
|
393
|
-
|
|
436
|
+
check_time_locks(
|
|
394
437
|
dict(self.REMOVALS),
|
|
395
438
|
conds,
|
|
396
439
|
self.PREV_BLOCK_HEIGHT,
|
|
@@ -541,6 +584,9 @@ def make_bundle_spends_map_and_fee(
|
|
|
541
584
|
eligible_for_dedup=eligibility_info.is_eligible_for_dedup,
|
|
542
585
|
eligible_for_fast_forward=eligibility_info.ff_puzzle_hash is not None,
|
|
543
586
|
additions=eligibility_info.spend_additions,
|
|
587
|
+
latest_singleton_lineage=UnspentLineageInfo(coin_id, coin_spend.coin.parent_coin_info, bytes32([0] * 32))
|
|
588
|
+
if eligibility_info.ff_puzzle_hash is not None
|
|
589
|
+
else None,
|
|
544
590
|
)
|
|
545
591
|
fee = uint64(removals_amount - additions_amount)
|
|
546
592
|
return bundle_coin_spends, fee
|
|
@@ -1161,7 +1207,7 @@ async def test_total_mempool_fees() -> None:
|
|
|
1161
1207
|
async def test_create_bundle_from_mempool(reverse_tx_order: bool) -> None:
|
|
1162
1208
|
async def make_coin_spends(coins: list[Coin], *, high_fees: bool = True) -> list[CoinSpend]:
|
|
1163
1209
|
spends_list = []
|
|
1164
|
-
for i in range(
|
|
1210
|
+
for i in range(len(coins)):
|
|
1165
1211
|
coin_spend = make_spend(
|
|
1166
1212
|
coins[i],
|
|
1167
1213
|
IDENTITY_PUZZLE,
|
|
@@ -1185,7 +1231,7 @@ async def test_create_bundle_from_mempool(reverse_tx_order: bool) -> None:
|
|
|
1185
1231
|
spends = low_rate_spends + high_rate_spends if reverse_tx_order else high_rate_spends + low_rate_spends
|
|
1186
1232
|
await send_spends_to_mempool(spends)
|
|
1187
1233
|
assert mempool_manager.peak is not None
|
|
1188
|
-
result =
|
|
1234
|
+
result = mempool_manager.create_bundle_from_mempool(mempool_manager.peak.header_hash)
|
|
1189
1235
|
assert result is not None
|
|
1190
1236
|
# Make sure we filled the block with only high rate spends
|
|
1191
1237
|
assert len([s for s in high_rate_spends if s in result[0].coin_spends]) == len(result[0].coin_spends)
|
|
@@ -1282,7 +1328,7 @@ async def test_create_bundle_from_mempool_on_max_cost(num_skipped_items: int, ca
|
|
|
1282
1328
|
|
|
1283
1329
|
assert mempool_manager.peak is not None
|
|
1284
1330
|
caplog.set_level(logging.DEBUG)
|
|
1285
|
-
result =
|
|
1331
|
+
result = mempool_manager.create_bundle_from_mempool(mempool_manager.peak.header_hash)
|
|
1286
1332
|
assert result is not None
|
|
1287
1333
|
agg, additions = result
|
|
1288
1334
|
skipped_due_to_eligible_coins = sum(
|
|
@@ -1565,14 +1611,14 @@ def test_dedup_info_nothing_to_do() -> None:
|
|
|
1565
1611
|
]
|
|
1566
1612
|
sb = spend_bundle_from_conditions(conditions, TEST_COIN, sig)
|
|
1567
1613
|
mempool_item = mempool_item_from_spendbundle(sb)
|
|
1568
|
-
|
|
1569
|
-
unique_coin_spends, cost_saving, unique_additions =
|
|
1614
|
+
dedup_coin_spends = IdenticalSpendDedup()
|
|
1615
|
+
unique_coin_spends, cost_saving, unique_additions = dedup_coin_spends.get_deduplication_info(
|
|
1570
1616
|
bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.conds.cost
|
|
1571
1617
|
)
|
|
1572
1618
|
assert unique_coin_spends == sb.coin_spends
|
|
1573
1619
|
assert cost_saving == 0
|
|
1574
1620
|
assert unique_additions == [Coin(TEST_COIN_ID, IDENTITY_PUZZLE_HASH, uint64(1))]
|
|
1575
|
-
assert
|
|
1621
|
+
assert dedup_coin_spends == IdenticalSpendDedup()
|
|
1576
1622
|
|
|
1577
1623
|
|
|
1578
1624
|
def test_dedup_info_eligible_1st_time() -> None:
|
|
@@ -1584,9 +1630,9 @@ def test_dedup_info_eligible_1st_time() -> None:
|
|
|
1584
1630
|
sb = spend_bundle_from_conditions(conditions, TEST_COIN)
|
|
1585
1631
|
mempool_item = mempool_item_from_spendbundle(sb)
|
|
1586
1632
|
assert mempool_item.conds is not None
|
|
1587
|
-
|
|
1633
|
+
dedup_coin_spends = IdenticalSpendDedup()
|
|
1588
1634
|
solution = SerializedProgram.to(conditions)
|
|
1589
|
-
unique_coin_spends, cost_saving, unique_additions =
|
|
1635
|
+
unique_coin_spends, cost_saving, unique_additions = dedup_coin_spends.get_deduplication_info(
|
|
1590
1636
|
bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.conds.cost
|
|
1591
1637
|
)
|
|
1592
1638
|
assert unique_coin_spends == sb.coin_spends
|
|
@@ -1595,7 +1641,7 @@ def test_dedup_info_eligible_1st_time() -> None:
|
|
|
1595
1641
|
Coin(TEST_COIN_ID, IDENTITY_PUZZLE_HASH, uint64(1)),
|
|
1596
1642
|
Coin(TEST_COIN_ID, IDENTITY_PUZZLE_HASH, uint64(TEST_COIN_AMOUNT - 1)),
|
|
1597
1643
|
}
|
|
1598
|
-
assert
|
|
1644
|
+
assert dedup_coin_spends == IdenticalSpendDedup({TEST_COIN_ID: DedupCoinSpend(solution=solution, cost=None)})
|
|
1599
1645
|
|
|
1600
1646
|
|
|
1601
1647
|
def test_dedup_info_eligible_but_different_solution() -> None:
|
|
@@ -1605,12 +1651,12 @@ def test_dedup_info_eligible_but_different_solution() -> None:
|
|
|
1605
1651
|
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT],
|
|
1606
1652
|
]
|
|
1607
1653
|
initial_solution = SerializedProgram.to(initial_conditions)
|
|
1608
|
-
|
|
1654
|
+
dedup_coin_spends = IdenticalSpendDedup({TEST_COIN_ID: DedupCoinSpend(solution=initial_solution, cost=None)})
|
|
1609
1655
|
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT]]
|
|
1610
1656
|
sb = spend_bundle_from_conditions(conditions, TEST_COIN)
|
|
1611
1657
|
mempool_item = mempool_item_from_spendbundle(sb)
|
|
1612
1658
|
with pytest.raises(SkipDedup, match="Solution is different from what we're deduplicating on"):
|
|
1613
|
-
|
|
1659
|
+
dedup_coin_spends.get_deduplication_info(
|
|
1614
1660
|
bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.conds.cost
|
|
1615
1661
|
)
|
|
1616
1662
|
|
|
@@ -1622,7 +1668,7 @@ def test_dedup_info_eligible_2nd_time_and_another_1st_time() -> None:
|
|
|
1622
1668
|
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT - 1],
|
|
1623
1669
|
]
|
|
1624
1670
|
initial_solution = SerializedProgram.to(initial_conditions)
|
|
1625
|
-
|
|
1671
|
+
dedup_coin_spends = IdenticalSpendDedup({TEST_COIN_ID: DedupCoinSpend(solution=initial_solution, cost=None)})
|
|
1626
1672
|
sb1 = spend_bundle_from_conditions(initial_conditions, TEST_COIN)
|
|
1627
1673
|
second_conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT2]]
|
|
1628
1674
|
second_solution = SerializedProgram.to(second_conditions)
|
|
@@ -1630,7 +1676,7 @@ def test_dedup_info_eligible_2nd_time_and_another_1st_time() -> None:
|
|
|
1630
1676
|
sb = SpendBundle.aggregate([sb1, sb2])
|
|
1631
1677
|
mempool_item = mempool_item_from_spendbundle(sb)
|
|
1632
1678
|
assert mempool_item.conds is not None
|
|
1633
|
-
unique_coin_spends, cost_saving, unique_additions =
|
|
1679
|
+
unique_coin_spends, cost_saving, unique_additions = dedup_coin_spends.get_deduplication_info(
|
|
1634
1680
|
bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.conds.cost
|
|
1635
1681
|
)
|
|
1636
1682
|
# Only the eligible one that we encountered more than once gets deduplicated
|
|
@@ -1640,13 +1686,13 @@ def test_dedup_info_eligible_2nd_time_and_another_1st_time() -> None:
|
|
|
1640
1686
|
assert unique_additions == [Coin(TEST_COIN_ID2, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT2)]
|
|
1641
1687
|
# The coin we encountered a second time has its cost and additions properly updated
|
|
1642
1688
|
# The coin we encountered for the first time gets cost None and an empty set of additions
|
|
1643
|
-
|
|
1689
|
+
expected_dedup_coin_spends = IdenticalSpendDedup(
|
|
1644
1690
|
{
|
|
1645
1691
|
TEST_COIN_ID: DedupCoinSpend(solution=initial_solution, cost=saved_cost),
|
|
1646
1692
|
TEST_COIN_ID2: DedupCoinSpend(solution=second_solution, cost=None),
|
|
1647
1693
|
}
|
|
1648
1694
|
)
|
|
1649
|
-
assert
|
|
1695
|
+
assert dedup_coin_spends == expected_dedup_coin_spends
|
|
1650
1696
|
|
|
1651
1697
|
|
|
1652
1698
|
def test_dedup_info_eligible_3rd_time_another_2nd_time_and_one_non_eligible() -> None:
|
|
@@ -1659,7 +1705,7 @@ def test_dedup_info_eligible_3rd_time_another_2nd_time_and_one_non_eligible() ->
|
|
|
1659
1705
|
second_conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT2]]
|
|
1660
1706
|
second_solution = SerializedProgram.to(second_conditions)
|
|
1661
1707
|
saved_cost = uint64(3600044)
|
|
1662
|
-
|
|
1708
|
+
dedup_coin_spends = IdenticalSpendDedup(
|
|
1663
1709
|
{
|
|
1664
1710
|
TEST_COIN_ID: DedupCoinSpend(solution=initial_solution, cost=saved_cost),
|
|
1665
1711
|
TEST_COIN_ID2: DedupCoinSpend(solution=second_solution, cost=None),
|
|
@@ -1678,20 +1724,20 @@ def test_dedup_info_eligible_3rd_time_another_2nd_time_and_one_non_eligible() ->
|
|
|
1678
1724
|
sb = SpendBundle.aggregate([sb1, sb2, sb3])
|
|
1679
1725
|
mempool_item = mempool_item_from_spendbundle(sb)
|
|
1680
1726
|
assert mempool_item.conds is not None
|
|
1681
|
-
unique_coin_spends, cost_saving, unique_additions =
|
|
1727
|
+
unique_coin_spends, cost_saving, unique_additions = dedup_coin_spends.get_deduplication_info(
|
|
1682
1728
|
bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.conds.cost
|
|
1683
1729
|
)
|
|
1684
1730
|
assert unique_coin_spends == sb3.coin_spends
|
|
1685
1731
|
saved_cost2 = uint64(1800044)
|
|
1686
1732
|
assert cost_saving == saved_cost + saved_cost2
|
|
1687
1733
|
assert unique_additions == [Coin(TEST_COIN_ID3, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT3)]
|
|
1688
|
-
|
|
1734
|
+
expected_dedup_coin_spends = IdenticalSpendDedup(
|
|
1689
1735
|
{
|
|
1690
1736
|
TEST_COIN_ID: DedupCoinSpend(initial_solution, saved_cost),
|
|
1691
1737
|
TEST_COIN_ID2: DedupCoinSpend(second_solution, saved_cost2),
|
|
1692
1738
|
}
|
|
1693
1739
|
)
|
|
1694
|
-
assert
|
|
1740
|
+
assert dedup_coin_spends == expected_dedup_coin_spends
|
|
1695
1741
|
|
|
1696
1742
|
|
|
1697
1743
|
@pytest.mark.anyio
|
|
@@ -1806,8 +1852,9 @@ async def test_identical_spend_aggregation_e2e(
|
|
|
1806
1852
|
full_node_api: FullNodeSimulator, wallet_node: WalletNode
|
|
1807
1853
|
) -> tuple[Wallet, list[WalletCoinRecord], bytes32]:
|
|
1808
1854
|
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
1809
|
-
|
|
1810
|
-
|
|
1855
|
+
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
1856
|
+
ph = await action_scope.get_puzzle_hash(wallet.wallet_state_manager)
|
|
1857
|
+
phs = [await action_scope.get_puzzle_hash(wallet.wallet_state_manager) for _ in range(3)]
|
|
1811
1858
|
for _ in range(2):
|
|
1812
1859
|
await farm_a_block(full_node_api, wallet_node, ph)
|
|
1813
1860
|
async with wallet.wallet_state_manager.new_action_scope(
|
|
@@ -2298,9 +2345,7 @@ class TestCoins:
|
|
|
2298
2345
|
self.coin_records[c.name()] = CoinRecord(c, uint32(0), uint32(0), False, TEST_TIMESTAMP)
|
|
2299
2346
|
self.lineage_info = {}
|
|
2300
2347
|
for ph, c in lineage.items():
|
|
2301
|
-
self.lineage_info[ph] = UnspentLineageInfo(
|
|
2302
|
-
c.name(), c.amount, c.parent_coin_info, uint64(1337), bytes32([42] * 32)
|
|
2303
|
-
)
|
|
2348
|
+
self.lineage_info[ph] = UnspentLineageInfo(c.name(), c.parent_coin_info, bytes32([42] * 32))
|
|
2304
2349
|
|
|
2305
2350
|
def spend_coin(self, coin_id: bytes32, height: uint32 = uint32(10)) -> None:
|
|
2306
2351
|
self.coin_records[coin_id] = dataclasses.replace(self.coin_records[coin_id], spent_block_index=height)
|
|
@@ -2311,9 +2356,7 @@ class TestCoins:
|
|
|
2311
2356
|
else:
|
|
2312
2357
|
assert coin.puzzle_hash == puzzle_hash
|
|
2313
2358
|
prev = self.lineage_info[puzzle_hash]
|
|
2314
|
-
self.lineage_info[puzzle_hash] = UnspentLineageInfo(
|
|
2315
|
-
coin.name(), coin.amount, coin.parent_coin_info, prev.coin_amount, prev.coin_id
|
|
2316
|
-
)
|
|
2359
|
+
self.lineage_info[puzzle_hash] = UnspentLineageInfo(coin.name(), coin.parent_coin_info, prev.coin_id)
|
|
2317
2360
|
|
|
2318
2361
|
async def get_coin_records(self, coin_ids: Collection[bytes32]) -> list[CoinRecord]:
|
|
2319
2362
|
ret = []
|
|
@@ -2329,26 +2372,23 @@ class TestCoins:
|
|
|
2329
2372
|
|
|
2330
2373
|
|
|
2331
2374
|
# creates a CoinSpend of a made up
|
|
2332
|
-
def make_singleton_spend(
|
|
2375
|
+
def make_singleton_spend(
|
|
2376
|
+
launcher_id: bytes32, parent_parent_id: bytes32 = bytes32([3] * 32), child_amount: int = 1
|
|
2377
|
+
) -> CoinSpend:
|
|
2333
2378
|
from chia_rs import supports_fast_forward
|
|
2334
2379
|
|
|
2335
2380
|
from chia.wallet.lineage_proof import LineageProof
|
|
2336
|
-
from chia.wallet.puzzles.singleton_top_layer_v1_1 import
|
|
2337
|
-
puzzle_for_singleton,
|
|
2338
|
-
solution_for_singleton,
|
|
2339
|
-
)
|
|
2381
|
+
from chia.wallet.puzzles.singleton_top_layer_v1_1 import puzzle_for_singleton, solution_for_singleton
|
|
2340
2382
|
|
|
2341
|
-
singleton_puzzle =
|
|
2383
|
+
singleton_puzzle = puzzle_for_singleton(launcher_id, Program.to(1)).to_serialized()
|
|
2342
2384
|
|
|
2343
2385
|
PARENT_COIN = Coin(parent_parent_id, singleton_puzzle.get_tree_hash(), uint64(1))
|
|
2344
2386
|
COIN = Coin(PARENT_COIN.name(), singleton_puzzle.get_tree_hash(), uint64(1))
|
|
2345
2387
|
|
|
2346
2388
|
lineage_proof = LineageProof(parent_parent_id, IDENTITY_PUZZLE_HASH, uint64(1))
|
|
2347
2389
|
|
|
2348
|
-
inner_solution = Program.to([[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, uint64(
|
|
2349
|
-
singleton_solution =
|
|
2350
|
-
solution_for_singleton(lineage_proof, uint64(1), inner_solution)
|
|
2351
|
-
)
|
|
2390
|
+
inner_solution = Program.to([[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, uint64(child_amount)]])
|
|
2391
|
+
singleton_solution = solution_for_singleton(lineage_proof, uint64(1), inner_solution).to_serialized()
|
|
2352
2392
|
|
|
2353
2393
|
ret = CoinSpend(COIN, singleton_puzzle, singleton_solution)
|
|
2354
2394
|
|
|
@@ -2364,7 +2404,7 @@ async def setup_mempool(coins: TestCoins) -> MempoolManager:
|
|
|
2364
2404
|
coins.get_unspent_lineage_info,
|
|
2365
2405
|
DEFAULT_CONSTANTS,
|
|
2366
2406
|
)
|
|
2367
|
-
test_block_record = create_test_block_record(height=uint32(
|
|
2407
|
+
test_block_record = create_test_block_record(height=uint32(5000000), timestamp=uint64(12345678))
|
|
2368
2408
|
await mempool_manager.new_peak(test_block_record, None)
|
|
2369
2409
|
return mempool_manager
|
|
2370
2410
|
|
|
@@ -2426,8 +2466,11 @@ async def test_new_peak_ff_eviction(
|
|
|
2426
2466
|
assert bundle_add_info.status == MempoolInclusionStatus.SUCCESS
|
|
2427
2467
|
item = mempool_manager.get_mempool_item(bundle.name())
|
|
2428
2468
|
assert item is not None
|
|
2429
|
-
|
|
2430
|
-
assert item.bundle_coin_spends[
|
|
2469
|
+
singleton_name = singleton_spend.coin.name()
|
|
2470
|
+
assert item.bundle_coin_spends[singleton_name].eligible_for_fast_forward
|
|
2471
|
+
latest_singleton_lineage = item.bundle_coin_spends[singleton_name].latest_singleton_lineage
|
|
2472
|
+
assert latest_singleton_lineage is not None
|
|
2473
|
+
assert latest_singleton_lineage.coin_id == singleton_name
|
|
2431
2474
|
|
|
2432
2475
|
spent_coins: list[bytes32] = []
|
|
2433
2476
|
|
|
@@ -2457,7 +2500,9 @@ async def test_new_peak_ff_eviction(
|
|
|
2457
2500
|
item = mempool_manager.get_mempool_item(bundle.name())
|
|
2458
2501
|
assert item is not None
|
|
2459
2502
|
assert item.bundle_coin_spends[singleton_spend.coin.name()].eligible_for_fast_forward
|
|
2460
|
-
|
|
2503
|
+
latest_singleton_lineage = item.bundle_coin_spends[singleton_spend.coin.name()].latest_singleton_lineage
|
|
2504
|
+
assert latest_singleton_lineage is not None
|
|
2505
|
+
assert latest_singleton_lineage.coin_id == singleton_spend.coin.name()
|
|
2461
2506
|
|
|
2462
2507
|
|
|
2463
2508
|
@pytest.mark.anyio
|
|
@@ -2525,9 +2570,11 @@ async def test_multiple_ff(use_optimization: bool) -> None:
|
|
|
2525
2570
|
item = mempool_manager.get_mempool_item(bundle.name())
|
|
2526
2571
|
assert item is not None
|
|
2527
2572
|
spend = item.bundle_coin_spends[singleton_spend1.coin.name()]
|
|
2528
|
-
assert spend.
|
|
2573
|
+
assert spend.latest_singleton_lineage is not None
|
|
2574
|
+
assert spend.latest_singleton_lineage.coin_id == singleton_spend3.coin.name()
|
|
2529
2575
|
spend = item.bundle_coin_spends[singleton_spend2.coin.name()]
|
|
2530
|
-
assert spend.
|
|
2576
|
+
assert spend.latest_singleton_lineage is not None
|
|
2577
|
+
assert spend.latest_singleton_lineage.coin_id == singleton_spend3.coin.name()
|
|
2531
2578
|
|
|
2532
2579
|
|
|
2533
2580
|
@pytest.mark.anyio
|
|
@@ -2574,7 +2621,8 @@ async def test_advancing_ff(use_optimization: bool) -> None:
|
|
|
2574
2621
|
assert item is not None
|
|
2575
2622
|
spend = item.bundle_coin_spends[spend_a.coin.name()]
|
|
2576
2623
|
assert spend.eligible_for_fast_forward
|
|
2577
|
-
assert spend.
|
|
2624
|
+
assert spend.latest_singleton_lineage is not None
|
|
2625
|
+
assert spend.latest_singleton_lineage.coin_id == spend_a.coin.name()
|
|
2578
2626
|
|
|
2579
2627
|
coins.update_lineage(singleton_ph, spend_b.coin)
|
|
2580
2628
|
coins.spend_coin(spend_a.coin.name(), uint32(11))
|
|
@@ -2585,7 +2633,8 @@ async def test_advancing_ff(use_optimization: bool) -> None:
|
|
|
2585
2633
|
assert item is not None
|
|
2586
2634
|
spend = item.bundle_coin_spends[spend_a.coin.name()]
|
|
2587
2635
|
assert spend.eligible_for_fast_forward
|
|
2588
|
-
assert spend.
|
|
2636
|
+
assert spend.latest_singleton_lineage is not None
|
|
2637
|
+
assert spend.latest_singleton_lineage.coin_id == spend_b.coin.name()
|
|
2589
2638
|
|
|
2590
2639
|
coins.update_lineage(singleton_ph, spend_c.coin)
|
|
2591
2640
|
coins.spend_coin(spend_b.coin.name(), uint32(12))
|
|
@@ -2596,12 +2645,313 @@ async def test_advancing_ff(use_optimization: bool) -> None:
|
|
|
2596
2645
|
assert item is not None
|
|
2597
2646
|
spend = item.bundle_coin_spends[spend_a.coin.name()]
|
|
2598
2647
|
assert spend.eligible_for_fast_forward
|
|
2599
|
-
assert spend.
|
|
2648
|
+
assert spend.latest_singleton_lineage is not None
|
|
2649
|
+
assert spend.latest_singleton_lineage.coin_id == spend_c.coin.name()
|
|
2650
|
+
|
|
2651
|
+
|
|
2652
|
+
@pytest.mark.parametrize("old", [True, False])
|
|
2653
|
+
def test_no_peak(old: bool, transactions_1000: list[SpendBundle]) -> None:
|
|
2654
|
+
bundles = transactions_1000[:10]
|
|
2655
|
+
all_coins = [s.coin for b in bundles for s in b.coin_spends]
|
|
2656
|
+
coins = TestCoins(all_coins, {})
|
|
2657
|
+
|
|
2658
|
+
mempool_manager = MempoolManager(
|
|
2659
|
+
coins.get_coin_records,
|
|
2660
|
+
coins.get_unspent_lineage_info,
|
|
2661
|
+
DEFAULT_CONSTANTS,
|
|
2662
|
+
)
|
|
2663
|
+
|
|
2664
|
+
create_block = mempool_manager.create_block_generator if old else mempool_manager.create_block_generator2
|
|
2665
|
+
|
|
2666
|
+
assert create_block(bytes32([1] * 32), 10.0) is None
|
|
2667
|
+
|
|
2668
|
+
|
|
2669
|
+
@pytest.fixture(name="test_wallet")
|
|
2670
|
+
def test_wallet_fixture() -> WalletTool:
|
|
2671
|
+
return WalletTool(DEFAULT_CONSTANTS)
|
|
2672
|
+
|
|
2673
|
+
|
|
2674
|
+
@pytest.fixture(name="transactions_1000")
|
|
2675
|
+
def transactions_1000_fixture(test_wallet: WalletTool, seeded_random: random.Random) -> list[SpendBundle]:
|
|
2676
|
+
op = ConditionOpcode
|
|
2677
|
+
bundles: list[SpendBundle] = []
|
|
2678
|
+
|
|
2679
|
+
test_conditions = [
|
|
2680
|
+
op.AGG_SIG_PARENT,
|
|
2681
|
+
op.AGG_SIG_PUZZLE,
|
|
2682
|
+
op.AGG_SIG_AMOUNT,
|
|
2683
|
+
op.AGG_SIG_PUZZLE_AMOUNT,
|
|
2684
|
+
op.AGG_SIG_PARENT_AMOUNT,
|
|
2685
|
+
op.AGG_SIG_PARENT_PUZZLE,
|
|
2686
|
+
op.AGG_SIG_UNSAFE,
|
|
2687
|
+
op.AGG_SIG_ME,
|
|
2688
|
+
op.CREATE_COIN,
|
|
2689
|
+
op.CREATE_COIN_ANNOUNCEMENT,
|
|
2690
|
+
op.CREATE_PUZZLE_ANNOUNCEMENT,
|
|
2691
|
+
op.ASSERT_MY_COIN_ID,
|
|
2692
|
+
op.ASSERT_MY_PARENT_ID,
|
|
2693
|
+
op.ASSERT_MY_PUZZLEHASH,
|
|
2694
|
+
op.ASSERT_MY_AMOUNT,
|
|
2695
|
+
]
|
|
2696
|
+
|
|
2697
|
+
print("generating 1000 coins and spend bundles")
|
|
2698
|
+
for i in range(1000):
|
|
2699
|
+
# generate a coin with a dummy parent coin ID
|
|
2700
|
+
puzzle = test_wallet.get_new_puzzle()
|
|
2701
|
+
coin = Coin(bytes32(i.to_bytes(32, byteorder="big")), puzzle.get_tree_hash(), uint64(100 * i))
|
|
2702
|
+
|
|
2703
|
+
conditions: dict[ConditionOpcode, list[ConditionWithArgs]] = {
|
|
2704
|
+
ConditionOpcode.CREATE_COIN: [
|
|
2705
|
+
ConditionWithArgs(
|
|
2706
|
+
ConditionOpcode.CREATE_COIN, [test_wallet.get_new_puzzle().get_tree_hash(), int_to_bytes(25 * i)]
|
|
2707
|
+
)
|
|
2708
|
+
]
|
|
2709
|
+
}
|
|
2710
|
+
# generate a somewhat arbitrarty set of conditions for the spend, just
|
|
2711
|
+
# to have some diversity and make the block interesting
|
|
2712
|
+
num_conditions = seeded_random.randint(0, 10)
|
|
2713
|
+
for c in seeded_random.sample(test_conditions, num_conditions):
|
|
2714
|
+
if c in set(
|
|
2715
|
+
[
|
|
2716
|
+
op.AGG_SIG_PARENT,
|
|
2717
|
+
op.AGG_SIG_PUZZLE,
|
|
2718
|
+
op.AGG_SIG_AMOUNT,
|
|
2719
|
+
op.AGG_SIG_PUZZLE_AMOUNT,
|
|
2720
|
+
op.AGG_SIG_PARENT_AMOUNT,
|
|
2721
|
+
op.AGG_SIG_PARENT_PUZZLE,
|
|
2722
|
+
op.AGG_SIG_UNSAFE,
|
|
2723
|
+
op.AGG_SIG_ME,
|
|
2724
|
+
]
|
|
2725
|
+
):
|
|
2726
|
+
secret_key = test_wallet.get_private_key_for_puzzle_hash(coin.puzzle_hash)
|
|
2727
|
+
synthetic_secret_key = calculate_synthetic_secret_key(secret_key, DEFAULT_HIDDEN_PUZZLE_HASH)
|
|
2728
|
+
cond = ConditionWithArgs(c, [bytes(synthetic_secret_key.get_g1()), b"foobar"])
|
|
2729
|
+
elif c == op.CREATE_COIN:
|
|
2730
|
+
cond = ConditionWithArgs(c, [test_wallet.get_new_puzzle().get_tree_hash(), int_to_bytes(i)])
|
|
2731
|
+
elif c in set([op.CREATE_COIN_ANNOUNCEMENT, op.CREATE_PUZZLE_ANNOUNCEMENT]):
|
|
2732
|
+
cond = ConditionWithArgs(c, [b"foobar"])
|
|
2733
|
+
elif c == op.ASSERT_MY_COIN_ID:
|
|
2734
|
+
cond = ConditionWithArgs(c, [coin.name()])
|
|
2735
|
+
elif c == op.ASSERT_MY_PARENT_ID:
|
|
2736
|
+
cond = ConditionWithArgs(c, [coin.parent_coin_info])
|
|
2737
|
+
elif c == op.ASSERT_MY_PUZZLEHASH:
|
|
2738
|
+
cond = ConditionWithArgs(c, [coin.puzzle_hash])
|
|
2739
|
+
elif c == op.ASSERT_MY_AMOUNT:
|
|
2740
|
+
cond = ConditionWithArgs(c, [int_to_bytes(coin.amount)])
|
|
2741
|
+
conditions.setdefault(c, []).append(cond)
|
|
2742
|
+
|
|
2743
|
+
# generate a spend of that coin
|
|
2744
|
+
bundle = test_wallet.generate_signed_transaction(
|
|
2745
|
+
uint64(50 * i), test_wallet.get_new_puzzle().get_tree_hash(), coin, conditions
|
|
2746
|
+
)
|
|
2747
|
+
bundles.append(bundle)
|
|
2748
|
+
return bundles
|
|
2749
|
+
|
|
2750
|
+
|
|
2751
|
+
# if we try to fill the mempool with more than 550, all spends won't
|
|
2752
|
+
# necessarily fit in the block, which the test assumes
|
|
2753
|
+
@pytest.mark.anyio
|
|
2754
|
+
@pytest.mark.parametrize("mempool_size", [1, 2, 100, 300, 400, 550, 730])
|
|
2755
|
+
@pytest.mark.parametrize("seed", [0, 1, 2, 3, 4])
|
|
2756
|
+
@pytest.mark.parametrize("old", [True, False])
|
|
2757
|
+
async def test_create_block_generator(
|
|
2758
|
+
mempool_size: int, seed: int, old: bool, transactions_1000: list[SpendBundle]
|
|
2759
|
+
) -> None:
|
|
2760
|
+
# the old way of creating bloks doesn't fit this many transactions, so we
|
|
2761
|
+
# expect it to fail
|
|
2762
|
+
expect_failure = mempool_size == 730 and old
|
|
2763
|
+
|
|
2764
|
+
bundles = transactions_1000
|
|
2765
|
+
all_coins = [s.coin for b in bundles for s in b.coin_spends]
|
|
2766
|
+
coins = TestCoins(all_coins, {})
|
|
2767
|
+
|
|
2768
|
+
rng = random.Random(seed)
|
|
2769
|
+
|
|
2770
|
+
# run the test multiple times, generating different combinations of mempools
|
|
2771
|
+
mempool_manager = await setup_mempool(coins)
|
|
2772
|
+
|
|
2773
|
+
included_bundles = rng.sample(bundles, mempool_size)
|
|
2774
|
+
expected_additions: set[Coin] = set()
|
|
2775
|
+
expected_removals: set[Coin] = set()
|
|
2776
|
+
expected_signature = G2Element()
|
|
2777
|
+
for sb in included_bundles:
|
|
2778
|
+
pre_validation = await mempool_manager.pre_validate_spendbundle(sb)
|
|
2779
|
+
bundle_add_info = await mempool_manager.add_spend_bundle(
|
|
2780
|
+
sb, pre_validation, sb.name(), first_added_height=uint32(1)
|
|
2781
|
+
)
|
|
2782
|
+
expected_additions.update(sb.additions())
|
|
2783
|
+
expected_removals.update(sb.removals())
|
|
2784
|
+
|
|
2785
|
+
expected_signature += sb.aggregated_signature
|
|
2786
|
+
assert bundle_add_info.status == MempoolInclusionStatus.SUCCESS
|
|
2787
|
+
item = mempool_manager.get_mempool_item(sb.name())
|
|
2788
|
+
assert item is not None
|
|
2789
|
+
all_items = mempool_manager.mempool.all_items()
|
|
2790
|
+
assert len(list(all_items)) == len(included_bundles)
|
|
2791
|
+
|
|
2792
|
+
invariant_check_mempool(mempool_manager.mempool)
|
|
2793
|
+
|
|
2794
|
+
assert mempool_manager.peak is not None
|
|
2795
|
+
create_block = mempool_manager.create_block_generator if old else mempool_manager.create_block_generator2
|
|
2796
|
+
new_block_gen = create_block(mempool_manager.peak.header_hash, 10.0)
|
|
2797
|
+
assert new_block_gen is not None
|
|
2798
|
+
|
|
2799
|
+
# now, make sure the generator we got is valid
|
|
2800
|
+
|
|
2801
|
+
if expect_failure:
|
|
2802
|
+
assert len(expected_additions) != len(new_block_gen.additions)
|
|
2803
|
+
assert expected_additions != set(new_block_gen.additions)
|
|
2804
|
+
assert len(expected_removals) != len(new_block_gen.removals)
|
|
2805
|
+
assert expected_removals != set(new_block_gen.removals)
|
|
2806
|
+
assert expected_signature != new_block_gen.signature
|
|
2807
|
+
else:
|
|
2808
|
+
assert len(expected_additions) == len(new_block_gen.additions)
|
|
2809
|
+
assert expected_additions == set(new_block_gen.additions)
|
|
2810
|
+
assert len(expected_removals) == len(new_block_gen.removals)
|
|
2811
|
+
assert expected_removals == set(new_block_gen.removals)
|
|
2812
|
+
assert expected_signature == new_block_gen.signature
|
|
2813
|
+
|
|
2814
|
+
err, conds = run_block_generator2(
|
|
2815
|
+
bytes(new_block_gen.program),
|
|
2816
|
+
new_block_gen.generator_refs,
|
|
2817
|
+
DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
|
|
2818
|
+
DEFAULT_FLAGS,
|
|
2819
|
+
new_block_gen.signature,
|
|
2820
|
+
None,
|
|
2821
|
+
DEFAULT_CONSTANTS,
|
|
2822
|
+
)
|
|
2823
|
+
|
|
2824
|
+
assert err is None
|
|
2825
|
+
assert conds is not None
|
|
2826
|
+
|
|
2827
|
+
if expect_failure:
|
|
2828
|
+
assert len(conds.spends) != len(expected_removals)
|
|
2829
|
+
else:
|
|
2830
|
+
assert len(conds.spends) == len(expected_removals)
|
|
2831
|
+
assert conds.cost < DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM
|
|
2832
|
+
assert new_block_gen.cost == conds.cost
|
|
2833
|
+
|
|
2834
|
+
num_additions = 0
|
|
2835
|
+
for spend in conds.spends:
|
|
2836
|
+
assert Coin(spend.parent_id, spend.puzzle_hash, uint64(spend.coin_amount)) in expected_removals
|
|
2837
|
+
for add2 in spend.create_coin:
|
|
2838
|
+
assert Coin(spend.coin_id, add2[0], uint64(add2[1])) in expected_additions
|
|
2839
|
+
num_additions += 1
|
|
2840
|
+
|
|
2841
|
+
assert num_additions == len(new_block_gen.additions)
|
|
2842
|
+
|
|
2843
|
+
|
|
2844
|
+
# if we try to fill the mempool with more than 550, all spends won't
|
|
2845
|
+
# necessarily fit in the block, which the test assumes
|
|
2846
|
+
@pytest.mark.anyio
|
|
2847
|
+
@pytest.mark.parametrize("seed", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
|
|
2848
|
+
@pytest.mark.parametrize("old", [True, False])
|
|
2849
|
+
async def test_create_block_generator_real_bundles(seed: int, old: bool, test_bundles: list[SpendBundle]) -> None:
|
|
2850
|
+
all_coins = [s.coin for b in test_bundles for s in b.coin_spends]
|
|
2851
|
+
coins = TestCoins(all_coins, {})
|
|
2852
|
+
|
|
2853
|
+
rng = random.Random(seed)
|
|
2854
|
+
|
|
2855
|
+
mempool_manager = await setup_mempool(coins)
|
|
2856
|
+
|
|
2857
|
+
included_bundles = rng.sample(test_bundles, len(test_bundles) // 5)
|
|
2858
|
+
for sb in included_bundles:
|
|
2859
|
+
pre_validation = await mempool_manager.pre_validate_spendbundle(sb)
|
|
2860
|
+
bundle_add_info = await mempool_manager.add_spend_bundle(
|
|
2861
|
+
sb, pre_validation, sb.name(), first_added_height=uint32(1)
|
|
2862
|
+
)
|
|
2863
|
+
|
|
2864
|
+
# in the test bundles, we have some duplicate spends
|
|
2865
|
+
# just ignore them for now
|
|
2866
|
+
if bundle_add_info.status == MempoolInclusionStatus.FAILED:
|
|
2867
|
+
assert bundle_add_info.error == Err.DOUBLE_SPEND
|
|
2868
|
+
continue
|
|
2869
|
+
assert bundle_add_info.status == MempoolInclusionStatus.SUCCESS
|
|
2870
|
+
item = mempool_manager.get_mempool_item(sb.name())
|
|
2871
|
+
assert item is not None
|
|
2872
|
+
|
|
2873
|
+
invariant_check_mempool(mempool_manager.mempool)
|
|
2874
|
+
|
|
2875
|
+
assert mempool_manager.peak is not None
|
|
2876
|
+
create_block = mempool_manager.create_block_generator if old else mempool_manager.create_block_generator2
|
|
2877
|
+
new_block_gen = create_block(mempool_manager.peak.header_hash, 10.0)
|
|
2878
|
+
assert new_block_gen is not None
|
|
2879
|
+
|
|
2880
|
+
# now, make sure the generator we got is valid
|
|
2881
|
+
|
|
2882
|
+
err, conds = run_block_generator2(
|
|
2883
|
+
bytes(new_block_gen.program),
|
|
2884
|
+
new_block_gen.generator_refs,
|
|
2885
|
+
DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM,
|
|
2886
|
+
DEFAULT_FLAGS,
|
|
2887
|
+
new_block_gen.signature,
|
|
2888
|
+
None,
|
|
2889
|
+
DEFAULT_CONSTANTS,
|
|
2890
|
+
)
|
|
2891
|
+
|
|
2892
|
+
assert err is None
|
|
2893
|
+
assert conds is not None
|
|
2894
|
+
|
|
2895
|
+
assert conds.cost == new_block_gen.cost
|
|
2896
|
+
|
|
2897
|
+
removals: set[Coin] = set()
|
|
2898
|
+
additions: set[Coin] = set()
|
|
2899
|
+
|
|
2900
|
+
for spend in conds.spends:
|
|
2901
|
+
removals.add(Coin(spend.parent_id, spend.puzzle_hash, uint64(spend.coin_amount)))
|
|
2902
|
+
for add in spend.create_coin:
|
|
2903
|
+
additions.add(Coin(spend.coin_id, add[0], uint64(add[1])))
|
|
2904
|
+
|
|
2905
|
+
assert removals == set(new_block_gen.removals)
|
|
2906
|
+
assert additions == set(new_block_gen.additions)
|
|
2907
|
+
|
|
2908
|
+
|
|
2909
|
+
@pytest.mark.anyio
|
|
2910
|
+
async def test_spending_singleton_to_invalidate_existing_ff_spends() -> None:
|
|
2911
|
+
"""
|
|
2912
|
+
This test covers the scenario where we attempt to add a transaction to the
|
|
2913
|
+
mempool that contains a singleton that is spent in a way that tries to
|
|
2914
|
+
invalidate existing fast forward spends from existing items in the mempool.
|
|
2915
|
+
"""
|
|
2916
|
+
LAUNCHER_ID = bytes32([1] * 32)
|
|
2917
|
+
PARENT_PARENT = bytes32([2] * 32)
|
|
2918
|
+
singleton_spend1 = make_singleton_spend(LAUNCHER_ID, PARENT_PARENT)
|
|
2919
|
+
# This differs in the child amount
|
|
2920
|
+
singleton_spend2 = make_singleton_spend(LAUNCHER_ID, PARENT_PARENT, child_amount=3)
|
|
2921
|
+
coins = TestCoins(
|
|
2922
|
+
coins=[singleton_spend1.coin, singleton_spend2.coin, TEST_COIN, TEST_COIN2],
|
|
2923
|
+
lineage={singleton_spend2.coin.puzzle_hash: singleton_spend2.coin},
|
|
2924
|
+
)
|
|
2925
|
+
mempool_manager = await setup_mempool(coins)
|
|
2926
|
+
coin_spend1 = make_spend(
|
|
2927
|
+
TEST_COIN, IDENTITY_PUZZLE, Program.to([[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 42]])
|
|
2928
|
+
)
|
|
2929
|
+
sb1 = SpendBundle([singleton_spend1, coin_spend1], G2Element())
|
|
2930
|
+
sb1_conds = make_test_conds(spend_ids=[(singleton_spend1.coin, ELIGIBLE_FOR_FF), (TEST_COIN, 0)], cost=100_000_000)
|
|
2931
|
+
bundle_add_info1 = await mempool_manager.add_spend_bundle(sb1, sb1_conds, sb1.name(), uint32(1))
|
|
2932
|
+
assert bundle_add_info1.status == MempoolInclusionStatus.SUCCESS
|
|
2933
|
+
invariant_check_mempool(mempool_manager.mempool)
|
|
2934
|
+
# Trying to spend the same singleton with a different child amount should
|
|
2935
|
+
# trigger a conflict on any replace by fee attempt.
|
|
2936
|
+
coin_spend2 = make_spend(
|
|
2937
|
+
TEST_COIN2, IDENTITY_PUZZLE, Program.to([[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 42]])
|
|
2938
|
+
)
|
|
2939
|
+
sb2 = SpendBundle([singleton_spend2, coin_spend1, coin_spend2], G2Element())
|
|
2940
|
+
# This singleton spend is not eligible for fast forward as its next
|
|
2941
|
+
# iteration has a different amount.
|
|
2942
|
+
sb2_conds = make_test_conds(spend_ids=[(singleton_spend2.coin, 0), (TEST_COIN, 0), (TEST_COIN2, 0)], cost=1337)
|
|
2943
|
+
# This transaction conflicts with the previous one no matter what fee you
|
|
2944
|
+
# pay, because we're changing the fast forward eligibility flag for the
|
|
2945
|
+
# singleton spend.
|
|
2946
|
+
bundle_add_info2 = await mempool_manager.add_spend_bundle(sb2, sb2_conds, sb2.name(), uint32(1))
|
|
2947
|
+
assert bundle_add_info2.error == Err.MEMPOOL_CONFLICT
|
|
2948
|
+
assert bundle_add_info2.status == MempoolInclusionStatus.PENDING
|
|
2600
2949
|
|
|
2601
2950
|
|
|
2602
2951
|
@pytest.mark.parametrize("flags", [ELIGIBLE_FOR_DEDUP, ELIGIBLE_FOR_FF, ELIGIBLE_FOR_FF | ELIGIBLE_FOR_DEDUP])
|
|
2952
|
+
@pytest.mark.parametrize("old", [True, False])
|
|
2603
2953
|
@pytest.mark.anyio
|
|
2604
|
-
async def test_check_removals_with_block_creation(flags: int) -> None:
|
|
2954
|
+
async def test_check_removals_with_block_creation(flags: int, old: bool) -> None:
|
|
2605
2955
|
LAUNCHER_ID = bytes32([1] * 32)
|
|
2606
2956
|
PARENT_PARENT = bytes32([2] * 32)
|
|
2607
2957
|
singleton_spend = make_singleton_spend(LAUNCHER_ID, PARENT_PARENT)
|
|
@@ -2630,13 +2980,15 @@ async def test_check_removals_with_block_creation(flags: int) -> None:
|
|
|
2630
2980
|
bundle_add_info2 = await mempool_manager.add_spend_bundle(sb2, sb2_conds, sb2.name(), uint32(1))
|
|
2631
2981
|
assert bundle_add_info2.status == MempoolInclusionStatus.SUCCESS
|
|
2632
2982
|
assert mempool_manager.peak is not None
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
assert len(additions) == 1
|
|
2637
|
-
assert set(additions) == {
|
|
2638
|
-
|
|
2639
|
-
|
|
2983
|
+
create_block = mempool_manager.create_block_generator if old else mempool_manager.create_block_generator2
|
|
2984
|
+
new_block_gen = create_block(mempool_manager.peak.header_hash, 10.0)
|
|
2985
|
+
assert new_block_gen is not None
|
|
2986
|
+
assert len(new_block_gen.additions) == 1
|
|
2987
|
+
assert set(new_block_gen.additions) == {
|
|
2988
|
+
Coin(singleton_spend.coin.name(), singleton_spend.coin.puzzle_hash, uint64(1))
|
|
2989
|
+
}
|
|
2990
|
+
assert len(new_block_gen.removals) == 2
|
|
2991
|
+
assert set(new_block_gen.removals) == {singleton_spend.coin, TEST_COIN}
|
|
2640
2992
|
|
|
2641
2993
|
|
|
2642
2994
|
@pytest.mark.anyio
|
|
@@ -2809,3 +3161,111 @@ def test_check_removals(case: CheckRemovalsCase) -> None:
|
|
|
2809
3161
|
assert err == expected_err
|
|
2810
3162
|
assert len(conflicts) == len(expected_conflicts)
|
|
2811
3163
|
assert set(conflicts) == set(expected_conflicts)
|
|
3164
|
+
|
|
3165
|
+
|
|
3166
|
+
@pytest.mark.anyio
|
|
3167
|
+
async def test_new_peak_deferred_ff_items() -> None:
|
|
3168
|
+
"""
|
|
3169
|
+
Covers the case where we update lineage info for multiple fast forward
|
|
3170
|
+
singletons at new peak.
|
|
3171
|
+
"""
|
|
3172
|
+
singleton_spend1 = make_singleton_spend(bytes32([1] * 32))
|
|
3173
|
+
singleton1_id = singleton_spend1.coin.name()
|
|
3174
|
+
singleton_spend2 = make_singleton_spend(bytes32([2] * 32))
|
|
3175
|
+
singleton2_id = singleton_spend2.coin.name()
|
|
3176
|
+
coins = TestCoins(
|
|
3177
|
+
[singleton_spend1.coin, singleton_spend2.coin, TEST_COIN, TEST_COIN2],
|
|
3178
|
+
{
|
|
3179
|
+
singleton_spend1.coin.puzzle_hash: singleton_spend1.coin,
|
|
3180
|
+
singleton_spend2.coin.puzzle_hash: singleton_spend2.coin,
|
|
3181
|
+
},
|
|
3182
|
+
)
|
|
3183
|
+
mempool_manager = await setup_mempool(coins)
|
|
3184
|
+
# Let's submit the two singletons transactions to the mempool
|
|
3185
|
+
sb_names = []
|
|
3186
|
+
for singleton_spend, regular_coin in [(singleton_spend1, TEST_COIN), (singleton_spend2, TEST_COIN2)]:
|
|
3187
|
+
sb = SpendBundle([singleton_spend, mk_coin_spend(regular_coin)], G2Element())
|
|
3188
|
+
sb_name = sb.name()
|
|
3189
|
+
await mempool_manager.add_spend_bundle(
|
|
3190
|
+
sb,
|
|
3191
|
+
make_test_conds(spend_ids=[(singleton_spend.coin, ELIGIBLE_FOR_FF), (regular_coin, 0)], cost=1337),
|
|
3192
|
+
sb_name,
|
|
3193
|
+
uint32(1),
|
|
3194
|
+
)
|
|
3195
|
+
assert mempool_manager.get_mempool_item(sb_name) is not None
|
|
3196
|
+
sb_names.append(sb_name)
|
|
3197
|
+
# Let's advance the mempool by spending these singletons into new lineages
|
|
3198
|
+
singleton1_new_latest = Coin(singleton1_id, singleton_spend1.coin.puzzle_hash, singleton_spend1.coin.amount)
|
|
3199
|
+
coins.update_lineage(singleton_spend1.coin.puzzle_hash, singleton1_new_latest)
|
|
3200
|
+
singleton2_new_latest = Coin(singleton2_id, singleton_spend2.coin.puzzle_hash, singleton_spend2.coin.amount)
|
|
3201
|
+
coins.update_lineage(singleton_spend2.coin.puzzle_hash, singleton2_new_latest)
|
|
3202
|
+
await advance_mempool(mempool_manager, [singleton1_id, singleton2_id], use_optimization=True)
|
|
3203
|
+
# Both items should get updated with their related latest lineages
|
|
3204
|
+
mi1 = mempool_manager.get_mempool_item(sb_names[0])
|
|
3205
|
+
assert mi1 is not None
|
|
3206
|
+
latest_singleton_lineage1 = mi1.bundle_coin_spends[singleton1_id].latest_singleton_lineage
|
|
3207
|
+
assert latest_singleton_lineage1 is not None
|
|
3208
|
+
assert latest_singleton_lineage1.coin_id == singleton1_new_latest.name()
|
|
3209
|
+
mi2 = mempool_manager.get_mempool_item(sb_names[1])
|
|
3210
|
+
assert mi2 is not None
|
|
3211
|
+
latest_singleton_lineage2 = mi2.bundle_coin_spends[singleton2_id].latest_singleton_lineage
|
|
3212
|
+
assert latest_singleton_lineage2 is not None
|
|
3213
|
+
assert latest_singleton_lineage2.coin_id == singleton2_new_latest.name()
|
|
3214
|
+
|
|
3215
|
+
|
|
3216
|
+
@pytest.mark.anyio
|
|
3217
|
+
async def test_different_ff_versions() -> None:
|
|
3218
|
+
"""
|
|
3219
|
+
Covers the case where we send an item with an older ff singleton version
|
|
3220
|
+
while the mempool is aware of a newer lineage.
|
|
3221
|
+
"""
|
|
3222
|
+
launcher_id = bytes32([1] * 32)
|
|
3223
|
+
singleton_spend1 = make_singleton_spend(launcher_id, bytes32([2] * 32))
|
|
3224
|
+
version1_id = singleton_spend1.coin.name()
|
|
3225
|
+
singleton_spend2 = make_singleton_spend(launcher_id, bytes32([3] * 32))
|
|
3226
|
+
version2_id = singleton_spend2.coin.name()
|
|
3227
|
+
singleton_ph = singleton_spend2.coin.puzzle_hash
|
|
3228
|
+
coins = TestCoins(
|
|
3229
|
+
[singleton_spend1.coin, singleton_spend2.coin, TEST_COIN, TEST_COIN2], {singleton_ph: singleton_spend2.coin}
|
|
3230
|
+
)
|
|
3231
|
+
mempool_manager = await setup_mempool(coins)
|
|
3232
|
+
mempool_items: list[MempoolItem] = []
|
|
3233
|
+
for singleton_spend, regular_coin in [(singleton_spend1, TEST_COIN), (singleton_spend2, TEST_COIN2)]:
|
|
3234
|
+
sb = SpendBundle([singleton_spend, mk_coin_spend(regular_coin)], G2Element())
|
|
3235
|
+
sb_name = sb.name()
|
|
3236
|
+
await mempool_manager.add_spend_bundle(
|
|
3237
|
+
sb,
|
|
3238
|
+
make_test_conds(spend_ids=[(singleton_spend.coin, ELIGIBLE_FOR_FF), (regular_coin, 0)], cost=1337),
|
|
3239
|
+
sb_name,
|
|
3240
|
+
uint32(1),
|
|
3241
|
+
)
|
|
3242
|
+
mi = mempool_manager.get_mempool_item(sb_name)
|
|
3243
|
+
assert mi is not None
|
|
3244
|
+
mempool_items.append(mi)
|
|
3245
|
+
[mi1, mi2] = mempool_items
|
|
3246
|
+
latest_lineage_id = version2_id
|
|
3247
|
+
assert latest_lineage_id != version1_id
|
|
3248
|
+
# Bundle coin spends key points to version 1 but the lineage is latest (v2)
|
|
3249
|
+
latest_singleton_lineage1 = mi1.bundle_coin_spends[version1_id].latest_singleton_lineage
|
|
3250
|
+
assert latest_singleton_lineage1 is not None
|
|
3251
|
+
assert latest_singleton_lineage1.coin_id == latest_lineage_id
|
|
3252
|
+
# Both the bundle coin spends key and the lineage point to latest (v2)
|
|
3253
|
+
latest_singleton_lineage2 = mi2.bundle_coin_spends[version2_id].latest_singleton_lineage
|
|
3254
|
+
assert latest_singleton_lineage2 is not None
|
|
3255
|
+
assert latest_singleton_lineage2.coin_id == latest_lineage_id
|
|
3256
|
+
# Let's update the lineage with a new version of the singleton
|
|
3257
|
+
new_latest_lineage = Coin(version2_id, singleton_ph, singleton_spend2.coin.amount)
|
|
3258
|
+
new_latest_lineage_id = new_latest_lineage.name()
|
|
3259
|
+
coins.update_lineage(singleton_ph, new_latest_lineage)
|
|
3260
|
+
await advance_mempool(mempool_manager, [version1_id, version2_id], use_optimization=True)
|
|
3261
|
+
# Both items should get updated with the latest lineage
|
|
3262
|
+
new_mi1 = mempool_manager.get_mempool_item(mi1.spend_bundle_name)
|
|
3263
|
+
assert new_mi1 is not None
|
|
3264
|
+
latest_singleton_lineage1 = new_mi1.bundle_coin_spends[version1_id].latest_singleton_lineage
|
|
3265
|
+
assert latest_singleton_lineage1 is not None
|
|
3266
|
+
assert latest_singleton_lineage1.coin_id == new_latest_lineage_id
|
|
3267
|
+
new_mi2 = mempool_manager.get_mempool_item(mi2.spend_bundle_name)
|
|
3268
|
+
assert new_mi2 is not None
|
|
3269
|
+
latest_singleton_lineage2 = new_mi2.bundle_coin_spends[version2_id].latest_singleton_lineage
|
|
3270
|
+
assert latest_singleton_lineage2 is not None
|
|
3271
|
+
assert latest_singleton_lineage2.coin_id == new_latest_lineage_id
|