chia-blockchain 2.5.2rc2__py3-none-any.whl → 2.5.3rc2__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/__init__.py +7 -0
- chia/_tests/blockchain/blockchain_test_utils.py +1 -1
- chia/_tests/blockchain/test_augmented_chain.py +54 -5
- chia/_tests/blockchain/test_blockchain.py +5 -12
- chia/_tests/blockchain/test_blockchain_transactions.py +3 -5
- chia/_tests/blockchain/test_get_block_generator.py +2 -2
- chia/_tests/blockchain/test_lookup_fork_chain.py +2 -2
- chia/_tests/clvm/benchmark_costs.py +2 -1
- chia/_tests/clvm/coin_store.py +4 -3
- chia/_tests/clvm/test_chialisp_deserialization.py +2 -2
- chia/_tests/clvm/test_curry_and_treehash.py +1 -1
- chia/_tests/clvm/test_puzzle_compression.py +2 -2
- chia/_tests/clvm/test_puzzles.py +2 -2
- chia/_tests/clvm/test_singletons.py +2 -2
- chia/_tests/clvm/test_spend_sim.py +1 -1
- chia/_tests/cmds/cmd_test_utils.py +2 -2
- chia/_tests/cmds/test_click_types.py +2 -2
- chia/_tests/cmds/test_cmd_framework.py +6 -6
- chia/_tests/cmds/test_show.py +4 -3
- chia/_tests/cmds/test_tx_config_args.py +1 -1
- chia/_tests/cmds/testing_classes.py +2 -2
- chia/_tests/cmds/wallet/test_consts.py +2 -2
- chia/_tests/cmds/wallet/test_did.py +2 -2
- chia/_tests/cmds/wallet/test_nft.py +2 -2
- chia/_tests/cmds/wallet/test_notifications.py +3 -2
- chia/_tests/cmds/wallet/test_vcs.py +2 -2
- chia/_tests/cmds/wallet/test_wallet.py +4 -8
- chia/_tests/conftest.py +4 -3
- chia/_tests/connection_utils.py +2 -2
- chia/_tests/core/cmds/test_keys.py +1 -2
- chia/_tests/core/cmds/test_wallet.py +2 -2
- chia/_tests/core/consensus/test_block_creation.py +2 -2
- chia/_tests/core/consensus/test_pot_iterations.py +1 -1
- chia/_tests/core/custom_types/test_coin.py +2 -2
- chia/_tests/core/custom_types/test_proof_of_space.py +2 -2
- chia/_tests/core/custom_types/test_spend_bundle.py +2 -2
- chia/_tests/core/data_layer/conftest.py +1 -1
- 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 +2 -2
- chia/_tests/core/data_layer/test_data_store.py +1 -1
- chia/_tests/core/data_layer/test_data_store_schema.py +1 -1
- chia/_tests/core/data_layer/util.py +2 -1
- chia/_tests/core/farmer/test_farmer_api.py +1 -1
- chia/_tests/core/full_node/full_sync/test_full_sync.py +1 -7
- chia/_tests/core/full_node/ram_db.py +2 -1
- chia/_tests/core/full_node/stores/test_block_store.py +2 -2
- chia/_tests/core/full_node/stores/test_coin_store.py +2 -2
- chia/_tests/core/full_node/stores/test_full_node_store.py +3 -3
- chia/_tests/core/full_node/stores/test_hint_store.py +2 -2
- chia/_tests/core/full_node/stores/test_sync_store.py +1 -1
- chia/_tests/core/full_node/test_address_manager.py +1 -1
- chia/_tests/core/full_node/test_block_height_map.py +2 -2
- chia/_tests/core/full_node/test_conditions.py +1 -1
- chia/_tests/core/full_node/test_full_node.py +346 -164
- chia/_tests/core/full_node/test_generator_tools.py +3 -2
- chia/_tests/core/full_node/test_hint_management.py +2 -2
- chia/_tests/core/full_node/test_performance.py +2 -15
- chia/_tests/core/full_node/test_subscriptions.py +1 -1
- chia/_tests/core/full_node/test_transactions.py +186 -185
- chia/_tests/core/full_node/test_tx_processing_queue.py +1 -1
- chia/_tests/core/make_block_generator.py +2 -2
- chia/_tests/core/mempool/test_mempool.py +165 -22
- chia/_tests/core/mempool/test_mempool_fee_estimator.py +1 -1
- chia/_tests/core/mempool/test_mempool_fee_protocol.py +1 -1
- chia/_tests/core/mempool/test_mempool_manager.py +476 -66
- chia/_tests/core/mempool/test_mempool_performance.py +2 -2
- chia/_tests/core/mempool/test_singleton_fast_forward.py +19 -25
- chia/_tests/core/node_height.py +2 -1
- chia/_tests/core/server/test_capabilities.py +1 -1
- chia/_tests/core/server/test_dos.py +36 -28
- chia/_tests/core/server/test_loop.py +3 -3
- chia/_tests/core/server/test_rate_limits.py +1 -1
- chia/_tests/core/server/test_server.py +2 -2
- chia/_tests/core/services/test_services.py +1 -1
- chia/_tests/core/ssl/test_ssl.py +1 -1
- chia/_tests/core/test_coins.py +2 -1
- chia/_tests/core/test_cost_calculation.py +2 -2
- chia/_tests/core/test_crawler.py +2 -2
- chia/_tests/core/test_db_conversion.py +2 -2
- chia/_tests/core/test_db_validation.py +26 -13
- chia/_tests/core/test_farmer_harvester_rpc.py +2 -2
- chia/_tests/core/test_full_node_rpc.py +2 -2
- chia/_tests/core/test_merkle_set.py +2 -2
- chia/_tests/core/test_program.py +2 -2
- chia/_tests/core/test_rpc_util.py +1 -1
- chia/_tests/core/test_seeder.py +1 -1
- chia/_tests/core/util/test_block_cache.py +3 -3
- chia/_tests/core/util/test_jsonify.py +3 -2
- chia/_tests/core/util/test_keychain.py +3 -3
- chia/_tests/core/util/test_streamable.py +3 -4
- chia/_tests/environments/wallet.py +3 -2
- chia/_tests/farmer_harvester/test_farmer.py +3 -4
- chia/_tests/farmer_harvester/test_farmer_harvester.py +2 -2
- chia/_tests/farmer_harvester/test_filter_prefix_bits.py +2 -2
- chia/_tests/farmer_harvester/test_third_party_harvesters.py +3 -4
- chia/_tests/fee_estimation/test_fee_estimation_integration.py +1 -1
- chia/_tests/fee_estimation/test_fee_estimation_rpc.py +2 -2
- chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +1 -1
- chia/_tests/fee_estimation/test_mempoolitem_height_added.py +3 -4
- chia/_tests/generator/test_compression.py +20 -10
- chia/_tests/generator/test_rom.py +7 -9
- chia/_tests/plot_sync/test_delta.py +2 -2
- chia/_tests/plot_sync/test_plot_sync.py +2 -2
- chia/_tests/plot_sync/test_receiver.py +2 -2
- chia/_tests/plot_sync/test_sender.py +2 -2
- chia/_tests/plot_sync/test_sync_simulated.py +2 -2
- chia/_tests/plot_sync/util.py +3 -2
- chia/_tests/plotting/test_plot_manager.py +1 -1
- chia/_tests/pools/test_pool_cli_parsing.py +3 -2
- chia/_tests/pools/test_pool_cmdline.py +2 -2
- chia/_tests/pools/test_pool_puzzles_lifecycle.py +3 -3
- chia/_tests/pools/test_pool_rpc.py +4 -5
- chia/_tests/pools/test_pool_wallet.py +1 -1
- chia/_tests/pools/test_wallet_pool_store.py +2 -2
- chia/_tests/rpc/test_rpc_client.py +1 -1
- chia/_tests/rpc/test_rpc_server.py +1 -1
- chia/_tests/simulation/test_simulation.py +36 -8
- chia/_tests/simulation/test_simulator.py +5 -5
- chia/_tests/simulation/test_start_simulator.py +2 -2
- chia/_tests/timelord/test_new_peak.py +2 -2
- chia/_tests/tools/test_run_block.py +3 -2
- chia/_tests/util/benchmark_cost.py +2 -2
- chia/_tests/util/benchmarks.py +17 -6
- chia/_tests/util/blockchain.py +2 -1
- chia/_tests/util/blockchain_mock.py +9 -5
- chia/_tests/util/build_network_protocol_files.py +2 -1
- chia/_tests/util/constants.py +2 -1
- chia/_tests/util/full_sync.py +6 -3
- chia/_tests/util/gen_ssl_certs.py +2 -2
- chia/_tests/util/generator_tools_testing.py +4 -3
- chia/_tests/util/get_name_puzzle_conditions.py +2 -2
- chia/_tests/util/misc.py +16 -2
- chia/_tests/util/network_protocol_data.py +17 -7
- chia/_tests/util/run_block.py +6 -8
- chia/_tests/util/setup_nodes.py +4 -3
- chia/_tests/util/spend_sim.py +9 -5
- chia/_tests/util/test_condition_tools.py +2 -2
- chia/_tests/util/test_config.py +2 -1
- chia/_tests/util/test_errors.py +2 -1
- chia/_tests/util/test_full_block_utils.py +17 -7
- chia/_tests/util/test_misc.py +1 -1
- chia/_tests/util/test_network_protocol_test.py +24 -24
- chia/_tests/util/test_replace_str_to_bytes.py +2 -2
- chia/_tests/util/test_trusted_peer.py +1 -1
- chia/_tests/util/time_out_assert.py +20 -7
- chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +1 -1
- chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +2 -2
- chia/_tests/wallet/cat_wallet/test_cat_wallet.py +5 -6
- chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +17 -15
- chia/_tests/wallet/cat_wallet/test_trades.py +2 -2
- chia/_tests/wallet/clawback/test_clawback_lifecycle.py +2 -2
- chia/_tests/wallet/clawback/test_clawback_metadata.py +2 -2
- chia/_tests/wallet/conftest.py +3 -3
- chia/_tests/wallet/db_wallet/test_db_graftroot.py +3 -5
- chia/_tests/wallet/db_wallet/test_dl_offers.py +2 -2
- chia/_tests/wallet/db_wallet/test_dl_wallet.py +433 -384
- chia/_tests/wallet/did_wallet/test_did.py +3 -3
- chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +2 -2
- chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +2 -2
- chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +3 -4
- chia/_tests/wallet/nft_wallet/test_nft_offers.py +1293 -703
- chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +28 -30
- chia/_tests/wallet/nft_wallet/test_nft_wallet.py +2 -2
- chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +2 -2
- chia/_tests/wallet/rpc/config.py +1 -1
- chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +2 -2
- chia/_tests/wallet/rpc/test_wallet_rpc.py +20 -77
- chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +9 -7
- chia/_tests/wallet/sync/test_wallet_sync.py +79 -31
- chia/_tests/wallet/test_clvm_streamable.py +2 -2
- chia/_tests/wallet/test_coin_management.py +7 -7
- chia/_tests/wallet/test_coin_selection.py +20 -2
- chia/_tests/wallet/test_conditions.py +2 -2
- chia/_tests/wallet/test_debug_spend_bundle.py +2 -2
- chia/_tests/wallet/test_new_wallet_protocol.py +2 -2
- chia/_tests/wallet/test_nft_store.py +2 -2
- chia/_tests/wallet/test_notifications.py +2 -2
- chia/_tests/wallet/test_puzzle_store.py +2 -2
- chia/_tests/wallet/test_sign_coin_spends.py +2 -2
- chia/_tests/wallet/test_signer_protocol.py +3 -3
- chia/_tests/wallet/test_singleton.py +3 -11
- chia/_tests/wallet/test_singleton_lifecycle_fast.py +12 -13
- chia/_tests/wallet/test_singleton_store.py +2 -4
- chia/_tests/wallet/test_transaction_store.py +2 -2
- chia/_tests/wallet/test_util.py +2 -2
- chia/_tests/wallet/test_wallet.py +53 -49
- chia/_tests/wallet/test_wallet_action_scope.py +24 -6
- chia/_tests/wallet/test_wallet_blockchain.py +1 -1
- chia/_tests/wallet/test_wallet_coin_store.py +2 -2
- chia/_tests/wallet/test_wallet_interested_store.py +2 -2
- chia/_tests/wallet/test_wallet_node.py +3 -3
- chia/_tests/wallet/test_wallet_retry.py +3 -3
- chia/_tests/wallet/test_wallet_state_manager.py +8 -8
- chia/_tests/wallet/test_wallet_test_framework.py +1 -1
- chia/_tests/wallet/test_wallet_trade_store.py +2 -2
- chia/_tests/wallet/test_wallet_utils.py +2 -2
- chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +3 -2
- chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +15 -15
- chia/_tests/wallet/vc_wallet/test_vc_wallet.py +5 -3
- chia/_tests/wallet/wallet_block_tools.py +15 -7
- chia/_tests/weight_proof/test_weight_proof.py +3 -3
- chia/cmds/chia.py +0 -2
- chia/cmds/cmd_classes.py +3 -3
- chia/cmds/cmd_helpers.py +4 -4
- chia/cmds/cmds_util.py +2 -2
- chia/cmds/coin_funcs.py +3 -2
- chia/cmds/coins.py +1 -1
- chia/cmds/data.py +2 -2
- chia/cmds/data_funcs.py +3 -2
- chia/cmds/db_upgrade_func.py +2 -2
- chia/cmds/db_validate_func.py +15 -8
- chia/cmds/farm.py +2 -4
- chia/cmds/keys.py +0 -2
- chia/cmds/keys_funcs.py +1 -1
- chia/cmds/netspace_funcs.py +2 -1
- chia/cmds/param_types.py +2 -2
- chia/cmds/plotnft.py +2 -2
- chia/cmds/plotnft_funcs.py +2 -2
- chia/cmds/rpc.py +1 -1
- chia/cmds/show.py +1 -2
- chia/cmds/show_funcs.py +6 -3
- chia/cmds/signer.py +1 -2
- chia/cmds/sim.py +1 -2
- chia/cmds/sim_funcs.py +2 -2
- chia/cmds/wallet.py +2 -2
- chia/cmds/wallet_funcs.py +4 -11
- chia/consensus/block_body_validation.py +3 -4
- chia/consensus/block_creation.py +10 -6
- chia/consensus/block_header_validation.py +3 -4
- chia/consensus/block_record.py +2 -3
- chia/consensus/block_rewards.py +1 -1
- chia/consensus/blockchain.py +20 -17
- chia/consensus/blockchain_interface.py +5 -4
- chia/consensus/coinbase.py +2 -2
- chia/consensus/constants.py +1 -1
- chia/consensus/cost_calculator.py +2 -1
- chia/consensus/default_constants.py +4 -3
- chia/consensus/deficit.py +3 -2
- chia/consensus/difficulty_adjustment.py +8 -9
- chia/consensus/find_fork_point.py +4 -3
- chia/consensus/full_block_to_block_record.py +4 -3
- chia/consensus/get_block_challenge.py +4 -3
- chia/consensus/get_block_generator.py +3 -2
- chia/consensus/make_sub_epoch_summary.py +3 -2
- chia/consensus/multiprocess_validation.py +9 -4
- chia/consensus/pos_quality.py +1 -1
- chia/consensus/pot_iterations.py +4 -3
- chia/consensus/vdf_info_computation.py +4 -3
- chia/daemon/client.py +1 -1
- chia/daemon/keychain_server.py +1 -1
- chia/daemon/server.py +1 -1
- chia/daemon/windows_signal.py +1 -1
- chia/data_layer/data_layer.py +4 -3
- chia/data_layer/data_layer_errors.py +1 -1
- chia/data_layer/data_layer_util.py +2 -2
- chia/data_layer/data_layer_wallet.py +47 -69
- chia/data_layer/data_store.py +1 -1
- chia/data_layer/dl_wallet_store.py +5 -6
- chia/data_layer/download_data.py +1 -1
- chia/data_layer/s3_plugin_service.py +4 -4
- chia/data_layer/singleton_record.py +23 -0
- chia/data_layer/util/benchmark.py +2 -1
- chia/farmer/farmer.py +4 -6
- chia/farmer/farmer_api.py +4 -6
- chia/full_node/bitcoin_fee_estimator.py +2 -1
- chia/full_node/block_height_map.py +2 -2
- chia/full_node/block_store.py +8 -9
- chia/{util → full_node}/check_fork_next_block.py +2 -1
- chia/full_node/coin_store.py +10 -10
- chia/full_node/fee_estimate.py +2 -1
- chia/full_node/fee_estimation.py +2 -1
- chia/full_node/fee_estimator.py +2 -1
- chia/full_node/fee_estimator_interface.py +1 -1
- chia/full_node/fee_history.py +2 -1
- chia/full_node/fee_tracker.py +2 -1
- chia/full_node/full_node.py +15 -13
- chia/full_node/full_node_api.py +12 -32
- chia/full_node/full_node_store.py +4 -3
- chia/full_node/hint_management.py +2 -1
- chia/full_node/hint_store.py +3 -3
- chia/full_node/mempool.py +80 -12
- chia/full_node/mempool_check_conditions.py +6 -7
- chia/full_node/mempool_manager.py +168 -21
- chia/full_node/pending_tx_cache.py +2 -2
- chia/full_node/subscriptions.py +2 -2
- chia/full_node/sync_store.py +2 -3
- chia/full_node/tx_processing_queue.py +2 -1
- chia/full_node/weight_proof.py +5 -8
- chia/harvester/harvester.py +5 -3
- chia/harvester/harvester_api.py +2 -2
- chia/introducer/introducer.py +30 -2
- chia/introducer/introducer_api.py +9 -1
- chia/legacy/keyring.py +1 -2
- chia/plot_sync/exceptions.py +2 -1
- chia/plot_sync/receiver.py +2 -2
- chia/plot_sync/sender.py +1 -1
- chia/plotting/cache.py +2 -2
- chia/plotting/check_plots.py +4 -2
- chia/plotting/create_plots.py +1 -1
- chia/plotting/manager.py +3 -3
- chia/plotting/util.py +2 -2
- chia/pools/pool_config.py +1 -1
- chia/pools/pool_puzzles.py +23 -17
- chia/pools/pool_wallet.py +22 -9
- chia/pools/pool_wallet_info.py +2 -2
- chia/protocols/farmer_protocol.py +3 -6
- chia/protocols/full_node_protocol.py +3 -2
- chia/protocols/harvester_protocol.py +3 -4
- chia/protocols/pool_protocol.py +2 -2
- chia/protocols/shared_protocol.py +2 -1
- chia/protocols/timelord_protocol.py +4 -4
- chia/protocols/wallet_protocol.py +2 -2
- chia/rpc/data_layer_rpc_api.py +3 -4
- chia/rpc/data_layer_rpc_client.py +3 -2
- chia/rpc/farmer_rpc_api.py +2 -2
- chia/rpc/farmer_rpc_client.py +2 -1
- chia/rpc/full_node_rpc_api.py +3 -2
- chia/rpc/full_node_rpc_client.py +3 -2
- chia/rpc/harvester_rpc_api.py +2 -1
- chia/rpc/rpc_client.py +2 -2
- chia/rpc/rpc_server.py +1 -1
- chia/rpc/wallet_request_types.py +2 -62
- chia/rpc/wallet_rpc_api.py +98 -628
- chia/rpc/wallet_rpc_client.py +5 -253
- chia/seeder/crawl_store.py +1 -1
- chia/seeder/crawler.py +2 -2
- chia/seeder/peer_record.py +2 -1
- chia/seeder/start_crawler.py +3 -1
- chia/server/address_manager.py +2 -1
- chia/server/address_manager_store.py +1 -1
- chia/server/capabilities.py +2 -1
- chia/server/introducer_peers.py +2 -1
- chia/server/node_discovery.py +1 -1
- chia/server/outbound_message.py +2 -1
- chia/server/server.py +2 -2
- chia/server/start_data_layer.py +2 -1
- chia/server/start_farmer.py +3 -1
- chia/server/start_full_node.py +4 -2
- chia/server/start_harvester.py +3 -1
- chia/server/start_introducer.py +12 -1
- chia/server/start_service.py +2 -1
- chia/server/start_timelord.py +3 -1
- chia/server/start_wallet.py +3 -1
- chia/server/upnp.py +1 -2
- chia/server/ws_connection.py +3 -4
- chia/simulator/add_blocks_in_batches.py +5 -3
- chia/simulator/block_tools.py +16 -12
- chia/simulator/full_node_simulator.py +9 -14
- chia/simulator/setup_services.py +5 -3
- chia/simulator/simulator_full_node_rpc_api.py +3 -2
- chia/simulator/simulator_full_node_rpc_client.py +3 -2
- chia/simulator/simulator_protocol.py +3 -2
- chia/simulator/simulator_test_tools.py +2 -2
- chia/simulator/start_simulator.py +3 -2
- chia/simulator/wallet_tools.py +3 -4
- chia/timelord/iters_from_block.py +4 -4
- chia/timelord/timelord.py +7 -12
- chia/timelord/timelord_api.py +3 -3
- chia/timelord/timelord_state.py +4 -3
- chia/types/block_protocol.py +2 -2
- chia/types/blockchain_format/coin.py +2 -2
- chia/types/blockchain_format/program.py +1 -1
- chia/types/blockchain_format/proof_of_space.py +3 -4
- chia/types/blockchain_format/tree_hash.py +1 -1
- chia/types/blockchain_format/vdf.py +3 -4
- chia/types/clvm_cost.py +1 -1
- chia/types/coin_record.py +4 -3
- chia/types/coin_spend.py +1 -1
- chia/types/eligible_coin_spends.py +9 -5
- chia/types/fee_rate.py +1 -1
- chia/types/generator_types.py +3 -3
- chia/types/internal_mempool_item.py +3 -2
- chia/types/mempool_item.py +10 -3
- chia/types/mempool_submission_status.py +2 -1
- chia/types/mojos.py +1 -1
- chia/types/peer_info.py +2 -1
- chia/types/transaction_queue_entry.py +2 -1
- chia/types/unfinished_header_block.py +4 -4
- chia/types/validation_state.py +2 -1
- chia/types/weight_proof.py +1 -9
- chia/util/augmented_chain.py +20 -9
- chia/util/block_cache.py +8 -4
- chia/util/condition_tools.py +2 -2
- chia/util/full_block_utils.py +3 -4
- chia/util/generator_tools.py +2 -2
- chia/util/initial-config.yaml +2 -11
- chia/util/network.py +2 -2
- chia/util/prev_transaction_block.py +2 -1
- chia/util/task_timing.py +1 -1
- chia/util/vdf_prover.py +3 -3
- chia/util/ws_message.py +1 -1
- chia/wallet/cat_wallet/cat_info.py +3 -2
- chia/wallet/cat_wallet/cat_outer_puzzle.py +3 -2
- chia/wallet/cat_wallet/cat_utils.py +6 -4
- chia/wallet/cat_wallet/cat_wallet.py +16 -18
- chia/wallet/cat_wallet/lineage_store.py +2 -1
- chia/wallet/coin_selection.py +5 -5
- chia/wallet/conditions.py +22 -16
- chia/wallet/db_wallet/db_wallet_puzzles.py +15 -15
- chia/wallet/derivation_record.py +2 -2
- chia/wallet/derive_keys.py +2 -2
- chia/wallet/did_wallet/did_info.py +3 -2
- chia/wallet/did_wallet/did_wallet.py +41 -19
- chia/wallet/did_wallet/did_wallet_puzzles.py +18 -12
- chia/wallet/driver_protocol.py +1 -1
- chia/wallet/lineage_proof.py +3 -2
- chia/wallet/nft_wallet/metadata_outer_puzzle.py +6 -7
- chia/wallet/nft_wallet/nft_info.py +5 -5
- chia/wallet/nft_wallet/nft_puzzle_utils.py +293 -0
- chia/wallet/nft_wallet/nft_puzzles.py +21 -298
- chia/wallet/nft_wallet/nft_wallet.py +47 -62
- chia/wallet/nft_wallet/ownership_outer_puzzle.py +4 -8
- chia/wallet/nft_wallet/singleton_outer_puzzle.py +3 -2
- chia/wallet/nft_wallet/transfer_program_puzzle.py +6 -10
- chia/wallet/nft_wallet/uncurry_nft.py +6 -8
- chia/wallet/notification_manager.py +5 -5
- chia/wallet/notification_store.py +3 -2
- chia/wallet/outer_puzzles.py +2 -1
- chia/wallet/puzzles/clawback/drivers.py +21 -8
- chia/wallet/puzzles/clawback/metadata.py +3 -2
- chia/wallet/puzzles/clawback/puzzle_decorator.py +5 -4
- chia/wallet/puzzles/deployed_puzzle_hashes.json +0 -10
- chia/wallet/puzzles/p2_conditions.py +3 -2
- chia/wallet/puzzles/p2_delegated_conditions.py +3 -2
- chia/wallet/puzzles/p2_delegated_puzzle.py +3 -2
- chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +3 -3
- chia/wallet/puzzles/p2_m_of_n_delegate_direct.py +3 -2
- chia/wallet/puzzles/p2_puzzle_hash.py +4 -3
- chia/wallet/puzzles/puzzle_utils.py +3 -2
- chia/wallet/puzzles/singleton_top_layer.py +26 -10
- chia/wallet/puzzles/singleton_top_layer_v1_1.py +21 -9
- chia/wallet/puzzles/tails.py +21 -129
- chia/wallet/signer_protocol.py +3 -2
- chia/wallet/singleton.py +12 -6
- chia/wallet/singleton_record.py +3 -2
- chia/wallet/trade_manager.py +31 -55
- chia/wallet/trade_record.py +3 -2
- chia/wallet/trading/offer.py +14 -13
- chia/wallet/trading/trade_store.py +3 -4
- chia/wallet/transaction_record.py +2 -2
- chia/wallet/util/blind_signer_tl.py +3 -2
- chia/wallet/util/compute_hints.py +3 -2
- chia/wallet/util/compute_memos.py +2 -2
- chia/wallet/util/curry_and_treehash.py +1 -2
- chia/wallet/util/merkle_tree.py +1 -1
- chia/wallet/util/merkle_utils.py +1 -1
- chia/wallet/util/new_peak_queue.py +2 -1
- chia/wallet/util/notifications.py +5 -4
- chia/wallet/util/peer_request_cache.py +3 -2
- chia/wallet/util/puzzle_compression.py +6 -4
- chia/wallet/util/puzzle_decorator.py +6 -4
- chia/wallet/util/query_filter.py +3 -2
- chia/wallet/util/tx_config.py +3 -3
- chia/wallet/util/wallet_sync_utils.py +2 -2
- chia/wallet/util/wallet_types.py +2 -3
- chia/wallet/vc_wallet/cr_cat_drivers.py +18 -22
- chia/wallet/vc_wallet/cr_cat_wallet.py +14 -10
- chia/wallet/vc_wallet/cr_outer_puzzle.py +2 -2
- chia/wallet/vc_wallet/vc_drivers.py +50 -68
- chia/wallet/vc_wallet/vc_store.py +2 -2
- chia/wallet/vc_wallet/vc_wallet.py +47 -15
- chia/wallet/wallet.py +51 -46
- chia/wallet/wallet_action_scope.py +4 -0
- chia/wallet/wallet_blockchain.py +12 -7
- chia/wallet/wallet_coin_record.py +3 -2
- chia/wallet/wallet_coin_store.py +3 -2
- chia/wallet/wallet_info.py +2 -1
- chia/wallet/wallet_interested_store.py +3 -2
- chia/wallet/wallet_nft_store.py +4 -4
- chia/wallet/wallet_node.py +3 -4
- chia/wallet/wallet_pool_store.py +3 -4
- chia/wallet/wallet_protocol.py +19 -5
- chia/wallet/wallet_puzzle_store.py +2 -2
- chia/wallet/wallet_retry_store.py +3 -6
- chia/wallet/wallet_singleton_store.py +2 -2
- chia/wallet/wallet_state_manager.py +20 -197
- chia/wallet/wallet_transaction_store.py +2 -2
- chia/wallet/wallet_user_store.py +2 -1
- chia/wallet/wallet_weight_proof_handler.py +3 -2
- {chia_blockchain-2.5.2rc2.dist-info → chia_blockchain-2.5.3rc2.dist-info}/METADATA +3 -2
- chia_blockchain-2.5.3rc2.dist-info/RECORD +891 -0
- mozilla-ca/cacert.pem +64 -33
- chia/_tests/clvm/test_condition_codes.py +0 -13
- chia/_tests/cmds/wallet/test_dao.py +0 -565
- chia/_tests/wallet/dao_wallet/__init__.py +0 -0
- chia/_tests/wallet/dao_wallet/config.py +0 -3
- chia/_tests/wallet/dao_wallet/test_dao_clvm.py +0 -1330
- chia/_tests/wallet/dao_wallet/test_dao_wallets.py +0 -3488
- chia/cmds/dao.py +0 -1064
- chia/cmds/dao_funcs.py +0 -598
- chia/consensus/puzzles/__init__.py +0 -0
- chia/consensus/puzzles/chialisp_deserialisation.clsp +0 -69
- chia/consensus/puzzles/chialisp_deserialisation.clsp.hex +0 -1
- chia/consensus/puzzles/rom_bootstrap_generator.clsp +0 -37
- chia/consensus/puzzles/rom_bootstrap_generator.clsp.hex +0 -1
- chia/full_node/puzzles/__init__.py +0 -0
- chia/full_node/puzzles/block_program_zero.clsp +0 -14
- chia/full_node/puzzles/block_program_zero.clsp.hex +0 -1
- chia/full_node/puzzles/decompress_coin_spend_entry.clsp +0 -5
- chia/full_node/puzzles/decompress_coin_spend_entry.clsp.hex +0 -1
- chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp +0 -7
- chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp.hex +0 -1
- chia/full_node/puzzles/decompress_puzzle.clsp +0 -6
- chia/full_node/puzzles/decompress_puzzle.clsp.hex +0 -1
- chia/pools/puzzles/__init__.py +0 -0
- chia/pools/puzzles/pool_member_innerpuz.clsp +0 -70
- chia/pools/puzzles/pool_member_innerpuz.clsp.hex +0 -1
- chia/pools/puzzles/pool_waitingroom_innerpuz.clsp +0 -69
- chia/pools/puzzles/pool_waitingroom_innerpuz.clsp.hex +0 -1
- chia/simulator/simulator_constants.py +0 -13
- chia/types/blockchain_format/foliage.py +0 -8
- chia/types/blockchain_format/pool_target.py +0 -5
- chia/types/blockchain_format/reward_chain_block.py +0 -6
- chia/types/blockchain_format/sized_bytes.py +0 -11
- chia/util/ints.py +0 -19
- chia/wallet/cat_wallet/dao_cat_info.py +0 -28
- chia/wallet/cat_wallet/dao_cat_wallet.py +0 -669
- chia/wallet/cat_wallet/puzzles/__init__.py +0 -0
- chia/wallet/cat_wallet/puzzles/cat_truths.clib +0 -31
- chia/wallet/cat_wallet/puzzles/cat_v2.clsp +0 -397
- chia/wallet/cat_wallet/puzzles/cat_v2.clsp.hex +0 -1
- chia/wallet/cat_wallet/puzzles/delegated_tail.clsp +0 -25
- chia/wallet/cat_wallet/puzzles/delegated_tail.clsp.hex +0 -1
- chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp +0 -15
- chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp.hex +0 -1
- chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp +0 -26
- chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp.hex +0 -1
- chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp +0 -42
- chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp.hex +0 -1
- chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp +0 -24
- chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp.hex +0 -1
- chia/wallet/dao_wallet/__init__.py +0 -0
- chia/wallet/dao_wallet/dao_info.py +0 -61
- chia/wallet/dao_wallet/dao_utils.py +0 -811
- chia/wallet/dao_wallet/dao_wallet.py +0 -2119
- chia/wallet/did_wallet/puzzles/__init__.py +0 -0
- chia/wallet/did_wallet/puzzles/did_innerpuz.clsp +0 -135
- chia/wallet/did_wallet/puzzles/did_innerpuz.clsp.hex +0 -1
- chia/wallet/payment.py +0 -33
- chia/wallet/puzzles/augmented_condition.clsp +0 -13
- chia/wallet/puzzles/augmented_condition.clsp.hex +0 -1
- chia/wallet/puzzles/condition_codes.clib +0 -77
- chia/wallet/puzzles/curry-and-treehash.clib +0 -102
- chia/wallet/puzzles/curry.clib +0 -135
- chia/wallet/puzzles/curry_by_index.clib +0 -16
- chia/wallet/puzzles/dao_cat_eve.clsp +0 -17
- chia/wallet/puzzles/dao_cat_eve.clsp.hex +0 -1
- chia/wallet/puzzles/dao_cat_launcher.clsp +0 -36
- chia/wallet/puzzles/dao_cat_launcher.clsp.hex +0 -1
- chia/wallet/puzzles/dao_finished_state.clsp +0 -35
- chia/wallet/puzzles/dao_finished_state.clsp.hex +0 -1
- chia/wallet/puzzles/dao_finished_state.clsp.hex.sha256tree +0 -1
- chia/wallet/puzzles/dao_lockup.clsp +0 -288
- chia/wallet/puzzles/dao_lockup.clsp.hex +0 -1
- chia/wallet/puzzles/dao_lockup.clsp.hex.sha256tree +0 -1
- chia/wallet/puzzles/dao_proposal.clsp +0 -377
- chia/wallet/puzzles/dao_proposal.clsp.hex +0 -1
- chia/wallet/puzzles/dao_proposal.clsp.hex.sha256tree +0 -1
- chia/wallet/puzzles/dao_proposal_timer.clsp +0 -78
- chia/wallet/puzzles/dao_proposal_timer.clsp.hex +0 -1
- chia/wallet/puzzles/dao_proposal_timer.clsp.hex.sha256tree +0 -1
- chia/wallet/puzzles/dao_proposal_validator.clsp +0 -87
- chia/wallet/puzzles/dao_proposal_validator.clsp.hex +0 -1
- chia/wallet/puzzles/dao_proposal_validator.clsp.hex.sha256tree +0 -1
- chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp +0 -240
- chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex +0 -1
- chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex.sha256tree +0 -1
- chia/wallet/puzzles/dao_treasury.clsp +0 -115
- chia/wallet/puzzles/dao_treasury.clsp.hex +0 -1
- chia/wallet/puzzles/dao_update_proposal.clsp +0 -44
- chia/wallet/puzzles/dao_update_proposal.clsp.hex +0 -1
- chia/wallet/puzzles/json.clib +0 -25
- chia/wallet/puzzles/merkle_utils.clib +0 -18
- chia/wallet/puzzles/notification.clsp +0 -7
- chia/wallet/puzzles/notification.clsp.hex +0 -1
- chia/wallet/puzzles/p2_1_of_n.clsp +0 -22
- chia/wallet/puzzles/p2_1_of_n.clsp.hex +0 -1
- chia/wallet/puzzles/p2_conditions.clsp +0 -3
- chia/wallet/puzzles/p2_conditions.clsp.hex +0 -1
- chia/wallet/puzzles/p2_delegated_conditions.clsp +0 -18
- chia/wallet/puzzles/p2_delegated_conditions.clsp.hex +0 -1
- chia/wallet/puzzles/p2_delegated_puzzle.clsp +0 -19
- chia/wallet/puzzles/p2_delegated_puzzle.clsp.hex +0 -1
- chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp +0 -91
- chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp.hex +0 -1
- chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp +0 -108
- chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp.hex +0 -1
- chia/wallet/puzzles/p2_parent.clsp +0 -19
- chia/wallet/puzzles/p2_parent.clsp.hex +0 -1
- chia/wallet/puzzles/p2_puzzle_hash.clsp +0 -18
- chia/wallet/puzzles/p2_puzzle_hash.clsp.hex +0 -1
- chia/wallet/puzzles/p2_singleton.clsp +0 -30
- chia/wallet/puzzles/p2_singleton.clsp.hex +0 -1
- chia/wallet/puzzles/p2_singleton_aggregator.clsp +0 -81
- chia/wallet/puzzles/p2_singleton_aggregator.clsp.hex +0 -1
- chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp +0 -50
- chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp.hex +0 -1
- chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp +0 -47
- chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp.hex +0 -1
- chia/wallet/puzzles/settlement_payments.clsp +0 -49
- chia/wallet/puzzles/settlement_payments.clsp.hex +0 -1
- chia/wallet/puzzles/sha256tree.clib +0 -11
- chia/wallet/puzzles/singleton_launcher.clsp +0 -16
- chia/wallet/puzzles/singleton_launcher.clsp.hex +0 -1
- chia/wallet/puzzles/singleton_top_layer.clsp +0 -177
- chia/wallet/puzzles/singleton_top_layer.clsp.hex +0 -1
- chia/wallet/puzzles/singleton_top_layer_v1_1.clsp +0 -107
- chia/wallet/puzzles/singleton_top_layer_v1_1.clsp.hex +0 -1
- chia/wallet/puzzles/singleton_truths.clib +0 -21
- chia/wallet/vc_wallet/cr_puzzles/__init__.py +0 -0
- chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp +0 -3
- chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp.hex +0 -1
- chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp +0 -304
- chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp.hex +0 -1
- chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp +0 -45
- chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp.hex +0 -1
- chia/wallet/vc_wallet/vc_puzzles/__init__.py +0 -0
- chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp +0 -30
- chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp.hex +0 -1
- chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp +0 -75
- chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp.hex +0 -1
- chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp +0 -32
- chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp.hex +0 -1
- chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp +0 -80
- chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp.hex +0 -1
- chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp +0 -163
- chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp.hex +0 -1
- chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp +0 -16
- chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp.hex +0 -1
- chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp +0 -74
- chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp.hex +0 -1
- chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp +0 -23
- chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp.hex +0 -1
- chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp +0 -64
- chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp.hex +0 -1
- chia_blockchain-2.5.2rc2.dist-info/RECORD +0 -1042
- {chia_blockchain-2.5.2rc2.dist-info → chia_blockchain-2.5.3rc2.dist-info}/LICENSE +0 -0
- {chia_blockchain-2.5.2rc2.dist-info → chia_blockchain-2.5.3rc2.dist-info}/WHEEL +0 -0
- {chia_blockchain-2.5.2rc2.dist-info → chia_blockchain-2.5.3rc2.dist-info}/entry_points.txt +0 -0
|
@@ -2,18 +2,26 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import dataclasses
|
|
4
4
|
import logging
|
|
5
|
-
from collections.abc import Awaitable, Collection
|
|
6
|
-
from typing import Any, Callable, ClassVar, Optional
|
|
5
|
+
from collections.abc import Awaitable, Collection, Sequence
|
|
6
|
+
from typing import Any, Callable, ClassVar, Optional, Union
|
|
7
7
|
|
|
8
8
|
import pytest
|
|
9
|
-
from chia_rs import
|
|
9
|
+
from chia_rs import (
|
|
10
|
+
ELIGIBLE_FOR_DEDUP,
|
|
11
|
+
ELIGIBLE_FOR_FF,
|
|
12
|
+
AugSchemeMPL,
|
|
13
|
+
ConsensusConstants,
|
|
14
|
+
G2Element,
|
|
15
|
+
get_conditions_from_spendbundle,
|
|
16
|
+
)
|
|
17
|
+
from chia_rs.sized_bytes import bytes32
|
|
18
|
+
from chia_rs.sized_ints import uint8, uint32, uint64
|
|
10
19
|
from chiabip158 import PyBIP158
|
|
11
20
|
|
|
12
21
|
from chia._tests.conftest import ConsensusMode
|
|
13
22
|
from chia._tests.util.misc import invariant_check_mempool
|
|
14
23
|
from chia._tests.util.setup_nodes import OldSimulatorsAndWallets, setup_simulators_and_wallets
|
|
15
24
|
from chia.consensus.condition_costs import ConditionCost
|
|
16
|
-
from chia.consensus.constants import ConsensusConstants
|
|
17
25
|
from chia.consensus.default_constants import DEFAULT_CONSTANTS
|
|
18
26
|
from chia.full_node.mempool import MAX_SKIPPED_ITEMS, PRIORITY_TX_THRESHOLD
|
|
19
27
|
from chia.full_node.mempool_check_conditions import mempool_check_time_locks
|
|
@@ -36,7 +44,6 @@ from chia.simulator.simulator_protocol import FarmNewBlockProtocol
|
|
|
36
44
|
from chia.types.blockchain_format.coin import Coin
|
|
37
45
|
from chia.types.blockchain_format.program import INFINITE_COST, Program
|
|
38
46
|
from chia.types.blockchain_format.serialized_program import SerializedProgram
|
|
39
|
-
from chia.types.blockchain_format.sized_bytes import bytes32
|
|
40
47
|
from chia.types.clvm_cost import CLVMCost
|
|
41
48
|
from chia.types.coin_record import CoinRecord
|
|
42
49
|
from chia.types.coin_spend import CoinSpend, make_spend
|
|
@@ -45,6 +52,7 @@ from chia.types.eligible_coin_spends import (
|
|
|
45
52
|
DedupCoinSpend,
|
|
46
53
|
EligibilityAndAdditions,
|
|
47
54
|
EligibleCoinSpends,
|
|
55
|
+
SkipDedup,
|
|
48
56
|
UnspentLineageInfo,
|
|
49
57
|
run_for_cost,
|
|
50
58
|
)
|
|
@@ -54,9 +62,7 @@ from chia.types.peer_info import PeerInfo
|
|
|
54
62
|
from chia.types.spend_bundle import SpendBundle
|
|
55
63
|
from chia.types.spend_bundle_conditions import SpendBundleConditions, SpendConditions
|
|
56
64
|
from chia.util.errors import Err, ValidationError
|
|
57
|
-
from chia.util.ints import uint8, uint32, uint64
|
|
58
65
|
from chia.wallet.conditions import AssertCoinAnnouncement
|
|
59
|
-
from chia.wallet.payment import Payment
|
|
60
66
|
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
|
|
61
67
|
from chia.wallet.wallet import Wallet
|
|
62
68
|
from chia.wallet.wallet_coin_record import WalletCoinRecord
|
|
@@ -202,15 +208,22 @@ def make_test_conds(
|
|
|
202
208
|
before_seconds_relative: Optional[int] = None,
|
|
203
209
|
before_seconds_absolute: Optional[int] = None,
|
|
204
210
|
cost: int = 0,
|
|
205
|
-
spend_ids:
|
|
211
|
+
spend_ids: Sequence[tuple[Union[bytes32, Coin], int]] = [(TEST_COIN_ID, 0)],
|
|
206
212
|
) -> SpendBundleConditions:
|
|
213
|
+
spend_info: list[tuple[bytes32, bytes32, bytes32, uint64, int]] = []
|
|
214
|
+
for coin, flags in spend_ids:
|
|
215
|
+
if isinstance(coin, Coin):
|
|
216
|
+
spend_info.append((coin.name(), coin.parent_coin_info, coin.puzzle_hash, coin.amount, flags))
|
|
217
|
+
else:
|
|
218
|
+
spend_info.append((coin, IDENTITY_PUZZLE_HASH, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT, flags))
|
|
219
|
+
|
|
207
220
|
return SpendBundleConditions(
|
|
208
221
|
[
|
|
209
222
|
SpendConditions(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
223
|
+
coin_id,
|
|
224
|
+
parent_id,
|
|
225
|
+
puzzle_hash,
|
|
226
|
+
amount,
|
|
214
227
|
None if height_relative is None else uint32(height_relative),
|
|
215
228
|
None if seconds_relative is None else uint64(seconds_relative),
|
|
216
229
|
None if before_height_relative is None else uint32(before_height_relative),
|
|
@@ -225,9 +238,9 @@ def make_test_conds(
|
|
|
225
238
|
[],
|
|
226
239
|
[],
|
|
227
240
|
[],
|
|
228
|
-
|
|
241
|
+
flags,
|
|
229
242
|
)
|
|
230
|
-
for
|
|
243
|
+
for coin_id, parent_id, puzzle_hash, amount, flags in spend_info
|
|
231
244
|
],
|
|
232
245
|
0,
|
|
233
246
|
uint32(height_absolute),
|
|
@@ -746,19 +759,25 @@ def mk_item(
|
|
|
746
759
|
assert_height: Optional[int] = None,
|
|
747
760
|
assert_before_height: Optional[int] = None,
|
|
748
761
|
assert_before_seconds: Optional[int] = None,
|
|
762
|
+
flags: list[int] = [],
|
|
749
763
|
) -> MempoolItem:
|
|
750
764
|
# we don't actually care about the puzzle and solutions for the purpose of
|
|
751
765
|
# can_replace()
|
|
752
|
-
spend_ids = []
|
|
766
|
+
spend_ids: list[tuple[bytes32, int]] = []
|
|
753
767
|
coin_spends = []
|
|
754
768
|
bundle_coin_spends = {}
|
|
755
|
-
|
|
769
|
+
if len(flags) < len(coins):
|
|
770
|
+
flags.extend([0] * (len(coins) - len(flags)))
|
|
771
|
+
for c, f in zip(coins, flags):
|
|
756
772
|
coin_id = c.name()
|
|
757
|
-
spend_ids.append(coin_id)
|
|
773
|
+
spend_ids.append((coin_id, f))
|
|
758
774
|
spend = make_spend(c, SerializedProgram.to(None), SerializedProgram.to(None))
|
|
759
775
|
coin_spends.append(spend)
|
|
760
776
|
bundle_coin_spends[coin_id] = BundleCoinSpend(
|
|
761
|
-
coin_spend=spend,
|
|
777
|
+
coin_spend=spend,
|
|
778
|
+
eligible_for_dedup=bool(f & ELIGIBLE_FOR_DEDUP),
|
|
779
|
+
eligible_for_fast_forward=bool(f & ELIGIBLE_FOR_FF),
|
|
780
|
+
additions=[],
|
|
762
781
|
)
|
|
763
782
|
spend_bundle = SpendBundle(coin_spends, G2Element())
|
|
764
783
|
conds = make_test_conds(cost=cost, spend_ids=spend_ids)
|
|
@@ -812,6 +831,46 @@ coins = make_test_coins()
|
|
|
812
831
|
([mk_item(coins[0:2])], mk_item(coins[0:2], fee=10000000), True),
|
|
813
832
|
# or if we spend the same coins with additional coins
|
|
814
833
|
([mk_item(coins[0:2])], mk_item(coins[0:3], fee=10000000), True),
|
|
834
|
+
# you're not allowed to clear the fast-forward or dedup flag. It's OK to set it
|
|
835
|
+
# and leave it unchanged
|
|
836
|
+
([mk_item(coins[0:2])], mk_item(coins[0:3], flags=[ELIGIBLE_FOR_DEDUP, 0, 0], fee=10000000), True),
|
|
837
|
+
([mk_item(coins[0:2])], mk_item(coins[0:3], flags=[ELIGIBLE_FOR_FF, 0, 0], fee=10000000), True),
|
|
838
|
+
# flag cleared
|
|
839
|
+
([mk_item(coins[0:2], flags=[ELIGIBLE_FOR_DEDUP, 0])], mk_item(coins[0:3], fee=10000000), False),
|
|
840
|
+
([mk_item(coins[0:2], flags=[ELIGIBLE_FOR_FF, 0])], mk_item(coins[0:3], fee=10000000), False),
|
|
841
|
+
# unchanged
|
|
842
|
+
(
|
|
843
|
+
[mk_item(coins[0:2], flags=[ELIGIBLE_FOR_DEDUP, 0])],
|
|
844
|
+
mk_item(coins[0:3], flags=[ELIGIBLE_FOR_DEDUP, 0, 0], fee=10000000),
|
|
845
|
+
True,
|
|
846
|
+
),
|
|
847
|
+
(
|
|
848
|
+
[mk_item(coins[0:2], flags=[ELIGIBLE_FOR_FF, 0])],
|
|
849
|
+
mk_item(coins[0:3], flags=[ELIGIBLE_FOR_FF, 0, 0], fee=10000000),
|
|
850
|
+
True,
|
|
851
|
+
),
|
|
852
|
+
# the spends are independent
|
|
853
|
+
(
|
|
854
|
+
[mk_item(coins[0:2], flags=[ELIGIBLE_FOR_DEDUP, 0])],
|
|
855
|
+
mk_item(coins[0:3], flags=[0, ELIGIBLE_FOR_DEDUP, 0], fee=10000000),
|
|
856
|
+
False,
|
|
857
|
+
),
|
|
858
|
+
(
|
|
859
|
+
[mk_item(coins[0:2], flags=[ELIGIBLE_FOR_FF, 0])],
|
|
860
|
+
mk_item(coins[0:3], flags=[0, ELIGIBLE_FOR_FF, 0], fee=10000000),
|
|
861
|
+
False,
|
|
862
|
+
),
|
|
863
|
+
# the bits are independent
|
|
864
|
+
(
|
|
865
|
+
[mk_item(coins[0:2], flags=[ELIGIBLE_FOR_DEDUP, 0])],
|
|
866
|
+
mk_item(coins[0:3], flags=[ELIGIBLE_FOR_FF, 0, 0], fee=10000000),
|
|
867
|
+
False,
|
|
868
|
+
),
|
|
869
|
+
(
|
|
870
|
+
[mk_item(coins[0:2], flags=[ELIGIBLE_FOR_DEDUP, 0])],
|
|
871
|
+
mk_item(coins[0:3], flags=[ELIGIBLE_FOR_FF, 0, 0], fee=10000000),
|
|
872
|
+
False,
|
|
873
|
+
),
|
|
815
874
|
# FEE- AND FEE RATE RULES
|
|
816
875
|
# if we're replacing two items, each paying a fee of 100, we need to
|
|
817
876
|
# spend (at least) the same coins and pay at least 10000000 higher fee
|
|
@@ -1007,9 +1066,6 @@ async def test_total_mempool_fees() -> None:
|
|
|
1007
1066
|
@pytest.mark.parametrize("reverse_tx_order", [True, False])
|
|
1008
1067
|
@pytest.mark.anyio
|
|
1009
1068
|
async def test_create_bundle_from_mempool(reverse_tx_order: bool) -> None:
|
|
1010
|
-
async def get_unspent_lineage_info_for_puzzle_hash(_: bytes32) -> Optional[UnspentLineageInfo]:
|
|
1011
|
-
assert False # pragma: no cover
|
|
1012
|
-
|
|
1013
1069
|
async def make_coin_spends(coins: list[Coin], *, high_fees: bool = True) -> list[CoinSpend]:
|
|
1014
1070
|
spends_list = []
|
|
1015
1071
|
for i in range(0, len(coins)):
|
|
@@ -1036,9 +1092,7 @@ async def test_create_bundle_from_mempool(reverse_tx_order: bool) -> None:
|
|
|
1036
1092
|
spends = low_rate_spends + high_rate_spends if reverse_tx_order else high_rate_spends + low_rate_spends
|
|
1037
1093
|
await send_spends_to_mempool(spends)
|
|
1038
1094
|
assert mempool_manager.peak is not None
|
|
1039
|
-
result = await mempool_manager.create_bundle_from_mempool(
|
|
1040
|
-
mempool_manager.peak.header_hash, get_unspent_lineage_info_for_puzzle_hash
|
|
1041
|
-
)
|
|
1095
|
+
result = await mempool_manager.create_bundle_from_mempool(mempool_manager.peak.header_hash)
|
|
1042
1096
|
assert result is not None
|
|
1043
1097
|
# Make sure we filled the block with only high rate spends
|
|
1044
1098
|
assert len([s for s in high_rate_spends if s in result[0].coin_spends]) == len(result[0].coin_spends)
|
|
@@ -1057,9 +1111,6 @@ async def test_create_bundle_from_mempool_on_max_cost(num_skipped_items: int, ca
|
|
|
1057
1111
|
2. After skipping MAX_SKIPPED_ITEMS, we stop processing further items.
|
|
1058
1112
|
"""
|
|
1059
1113
|
|
|
1060
|
-
async def get_unspent_lineage_info_for_puzzle_hash(_: bytes32) -> Optional[UnspentLineageInfo]:
|
|
1061
|
-
assert False # pragma: no cover
|
|
1062
|
-
|
|
1063
1114
|
MAX_BLOCK_CLVM_COST = 550_000_000
|
|
1064
1115
|
|
|
1065
1116
|
mempool_manager, coins = await setup_mempool_with_coins(
|
|
@@ -1123,7 +1174,7 @@ async def test_create_bundle_from_mempool_on_max_cost(num_skipped_items: int, ca
|
|
|
1123
1174
|
g1 = sk.get_g1()
|
|
1124
1175
|
sig = AugSchemeMPL.sign(sk, b"foobar", g1)
|
|
1125
1176
|
for i in range(num_skipped_items + 1, num_skipped_items + 5):
|
|
1126
|
-
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, coins[i].amount
|
|
1177
|
+
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, coins[i].amount]]
|
|
1127
1178
|
# Make the first of these without eligible coins
|
|
1128
1179
|
if i == num_skipped_items + 1:
|
|
1129
1180
|
conditions.append([ConditionOpcode.AGG_SIG_UNSAFE, bytes(g1), b"foobar"])
|
|
@@ -1132,22 +1183,17 @@ async def test_create_bundle_from_mempool_on_max_cost(num_skipped_items: int, ca
|
|
|
1132
1183
|
aggsig = G2Element()
|
|
1133
1184
|
sb, _, res = await generate_and_add_spendbundle(mempool_manager, conditions, coins[i], aggsig)
|
|
1134
1185
|
extra_sbs.append(sb)
|
|
1135
|
-
coin = Coin(coins[i].name(), IDENTITY_PUZZLE_HASH, uint64(coins[i].amount
|
|
1186
|
+
coin = Coin(coins[i].name(), IDENTITY_PUZZLE_HASH, uint64(coins[i].amount))
|
|
1136
1187
|
extra_additions.append(coin)
|
|
1137
1188
|
assert res[1] == MempoolInclusionStatus.SUCCESS
|
|
1138
1189
|
|
|
1139
1190
|
assert mempool_manager.peak is not None
|
|
1140
1191
|
caplog.set_level(logging.DEBUG)
|
|
1141
|
-
result = await mempool_manager.create_bundle_from_mempool(
|
|
1142
|
-
mempool_manager.peak.header_hash, get_unspent_lineage_info_for_puzzle_hash
|
|
1143
|
-
)
|
|
1192
|
+
result = await mempool_manager.create_bundle_from_mempool(mempool_manager.peak.header_hash)
|
|
1144
1193
|
assert result is not None
|
|
1145
1194
|
agg, additions = result
|
|
1146
1195
|
skipped_due_to_eligible_coins = sum(
|
|
1147
|
-
1
|
|
1148
|
-
for line in caplog.text.split("\n")
|
|
1149
|
-
if "Exception while checking a mempool item for deduplication: Skipping transaction with eligible coin(s)"
|
|
1150
|
-
in line
|
|
1196
|
+
1 for line in caplog.text.split("\n") if "Skipping transaction with dedup or FF spends" in line
|
|
1151
1197
|
)
|
|
1152
1198
|
if num_skipped_items == PRIORITY_TX_THRESHOLD:
|
|
1153
1199
|
# We skipped enough big cost items to reach `PRIORITY_TX_THRESHOLD`,
|
|
@@ -1440,7 +1486,7 @@ def test_dedup_info_eligible_1st_time() -> None:
|
|
|
1440
1486
|
# Eligible coin encountered for the first time
|
|
1441
1487
|
conditions = [
|
|
1442
1488
|
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1],
|
|
1443
|
-
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH,
|
|
1489
|
+
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT - 1],
|
|
1444
1490
|
]
|
|
1445
1491
|
sb = spend_bundle_from_conditions(conditions, TEST_COIN)
|
|
1446
1492
|
mempool_item = mempool_item_from_spendbundle(sb)
|
|
@@ -1454,7 +1500,7 @@ def test_dedup_info_eligible_1st_time() -> None:
|
|
|
1454
1500
|
assert cost_saving == 0
|
|
1455
1501
|
assert set(unique_additions) == {
|
|
1456
1502
|
Coin(TEST_COIN_ID, IDENTITY_PUZZLE_HASH, uint64(1)),
|
|
1457
|
-
Coin(TEST_COIN_ID, IDENTITY_PUZZLE_HASH, uint64(
|
|
1503
|
+
Coin(TEST_COIN_ID, IDENTITY_PUZZLE_HASH, uint64(TEST_COIN_AMOUNT - 1)),
|
|
1458
1504
|
}
|
|
1459
1505
|
assert eligible_coin_spends == EligibleCoinSpends({TEST_COIN_ID: DedupCoinSpend(solution=solution, cost=None)})
|
|
1460
1506
|
|
|
@@ -1463,14 +1509,14 @@ def test_dedup_info_eligible_but_different_solution() -> None:
|
|
|
1463
1509
|
# Eligible coin but different solution from the one we encountered
|
|
1464
1510
|
initial_conditions = [
|
|
1465
1511
|
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1],
|
|
1466
|
-
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH,
|
|
1512
|
+
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT],
|
|
1467
1513
|
]
|
|
1468
1514
|
initial_solution = SerializedProgram.to(initial_conditions)
|
|
1469
1515
|
eligible_coin_spends = EligibleCoinSpends({TEST_COIN_ID: DedupCoinSpend(solution=initial_solution, cost=None)})
|
|
1470
|
-
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH,
|
|
1516
|
+
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT]]
|
|
1471
1517
|
sb = spend_bundle_from_conditions(conditions, TEST_COIN)
|
|
1472
1518
|
mempool_item = mempool_item_from_spendbundle(sb)
|
|
1473
|
-
with pytest.raises(
|
|
1519
|
+
with pytest.raises(SkipDedup, match="Solution is different from what we're deduplicating on"):
|
|
1474
1520
|
eligible_coin_spends.get_deduplication_info(
|
|
1475
1521
|
bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.conds.cost
|
|
1476
1522
|
)
|
|
@@ -1480,12 +1526,12 @@ def test_dedup_info_eligible_2nd_time_and_another_1st_time() -> None:
|
|
|
1480
1526
|
# Eligible coin encountered a second time, and another for the first time
|
|
1481
1527
|
initial_conditions = [
|
|
1482
1528
|
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1],
|
|
1483
|
-
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH,
|
|
1529
|
+
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT - 1],
|
|
1484
1530
|
]
|
|
1485
1531
|
initial_solution = SerializedProgram.to(initial_conditions)
|
|
1486
1532
|
eligible_coin_spends = EligibleCoinSpends({TEST_COIN_ID: DedupCoinSpend(solution=initial_solution, cost=None)})
|
|
1487
1533
|
sb1 = spend_bundle_from_conditions(initial_conditions, TEST_COIN)
|
|
1488
|
-
second_conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH,
|
|
1534
|
+
second_conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT2]]
|
|
1489
1535
|
second_solution = SerializedProgram.to(second_conditions)
|
|
1490
1536
|
sb2 = spend_bundle_from_conditions(second_conditions, TEST_COIN2)
|
|
1491
1537
|
sb = SpendBundle.aggregate([sb1, sb2])
|
|
@@ -1498,7 +1544,7 @@ def test_dedup_info_eligible_2nd_time_and_another_1st_time() -> None:
|
|
|
1498
1544
|
assert unique_coin_spends == sb2.coin_spends
|
|
1499
1545
|
saved_cost = uint64(3600044)
|
|
1500
1546
|
assert cost_saving == saved_cost
|
|
1501
|
-
assert unique_additions == [Coin(TEST_COIN_ID2, IDENTITY_PUZZLE_HASH,
|
|
1547
|
+
assert unique_additions == [Coin(TEST_COIN_ID2, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT2)]
|
|
1502
1548
|
# The coin we encountered a second time has its cost and additions properly updated
|
|
1503
1549
|
# The coin we encountered for the first time gets cost None and an empty set of additions
|
|
1504
1550
|
expected_eligible_spends = EligibleCoinSpends(
|
|
@@ -1514,10 +1560,10 @@ def test_dedup_info_eligible_3rd_time_another_2nd_time_and_one_non_eligible() ->
|
|
|
1514
1560
|
# Eligible coin encountered a third time, another for the second time and one non eligible
|
|
1515
1561
|
initial_conditions = [
|
|
1516
1562
|
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1],
|
|
1517
|
-
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH,
|
|
1563
|
+
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT - 1],
|
|
1518
1564
|
]
|
|
1519
1565
|
initial_solution = SerializedProgram.to(initial_conditions)
|
|
1520
|
-
second_conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH,
|
|
1566
|
+
second_conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT2]]
|
|
1521
1567
|
second_solution = SerializedProgram.to(second_conditions)
|
|
1522
1568
|
saved_cost = uint64(3600044)
|
|
1523
1569
|
eligible_coin_spends = EligibleCoinSpends(
|
|
@@ -1533,7 +1579,7 @@ def test_dedup_info_eligible_3rd_time_another_2nd_time_and_one_non_eligible() ->
|
|
|
1533
1579
|
sig = AugSchemeMPL.sign(sk, b"foobar", g1)
|
|
1534
1580
|
sb3_conditions = [
|
|
1535
1581
|
[ConditionOpcode.AGG_SIG_UNSAFE, g1, b"foobar"],
|
|
1536
|
-
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH,
|
|
1582
|
+
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT3],
|
|
1537
1583
|
]
|
|
1538
1584
|
sb3 = spend_bundle_from_conditions(sb3_conditions, TEST_COIN3, sig)
|
|
1539
1585
|
sb = SpendBundle.aggregate([sb1, sb2, sb3])
|
|
@@ -1545,7 +1591,7 @@ def test_dedup_info_eligible_3rd_time_another_2nd_time_and_one_non_eligible() ->
|
|
|
1545
1591
|
assert unique_coin_spends == sb3.coin_spends
|
|
1546
1592
|
saved_cost2 = uint64(1800044)
|
|
1547
1593
|
assert cost_saving == saved_cost + saved_cost2
|
|
1548
|
-
assert unique_additions == [Coin(TEST_COIN_ID3, IDENTITY_PUZZLE_HASH,
|
|
1594
|
+
assert unique_additions == [Coin(TEST_COIN_ID3, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT3)]
|
|
1549
1595
|
expected_eligible_spends = EligibleCoinSpends(
|
|
1550
1596
|
{
|
|
1551
1597
|
TEST_COIN_ID: DedupCoinSpend(initial_solution, saved_cost),
|
|
@@ -1581,7 +1627,12 @@ async def test_coin_spending_different_ways_then_finding_it_spent_in_new_peak(ne
|
|
|
1581
1627
|
# Create a bunch of mempool items that spend the coin in different ways
|
|
1582
1628
|
for i in range(3):
|
|
1583
1629
|
_, _, result = await generate_and_add_spendbundle(
|
|
1584
|
-
mempool_manager,
|
|
1630
|
+
mempool_manager,
|
|
1631
|
+
[
|
|
1632
|
+
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, coin.amount],
|
|
1633
|
+
[ConditionOpcode.CREATE_COIN_ANNOUNCEMENT, uint64(i)],
|
|
1634
|
+
],
|
|
1635
|
+
coin,
|
|
1585
1636
|
)
|
|
1586
1637
|
assert result[1] == MempoolInclusionStatus.SUCCESS
|
|
1587
1638
|
assert len(list(mempool_manager.mempool.get_items_by_coin_id(coin_id))) == 3
|
|
@@ -1662,11 +1713,10 @@ async def test_identical_spend_aggregation_e2e(
|
|
|
1662
1713
|
phs = [await wallet.get_new_puzzlehash() for _ in range(3)]
|
|
1663
1714
|
for _ in range(2):
|
|
1664
1715
|
await farm_a_block(full_node_api, wallet_node, ph)
|
|
1665
|
-
other_recipients = [Payment(puzzle_hash=p, amount=uint64(200), memos=[]) for p in phs[1:]]
|
|
1666
1716
|
async with wallet.wallet_state_manager.new_action_scope(
|
|
1667
1717
|
DEFAULT_TX_CONFIG, push=False, sign=True
|
|
1668
1718
|
) as action_scope:
|
|
1669
|
-
await wallet.generate_signed_transaction(uint64(200), phs
|
|
1719
|
+
await wallet.generate_signed_transaction([uint64(200)] * len(phs), phs, action_scope)
|
|
1670
1720
|
[tx] = action_scope.side_effects.transactions
|
|
1671
1721
|
assert tx.spend_bundle is not None
|
|
1672
1722
|
await send_to_mempool(full_node_api, tx.spend_bundle)
|
|
@@ -1685,9 +1735,9 @@ async def test_identical_spend_aggregation_e2e(
|
|
|
1685
1735
|
async with wallet.wallet_state_manager.new_action_scope(
|
|
1686
1736
|
DEFAULT_TX_CONFIG, push=False, merge_spends=False, sign=True
|
|
1687
1737
|
) as action_scope:
|
|
1688
|
-
await wallet.generate_signed_transaction(uint64(30), ph, action_scope, coins={coins[0].coin})
|
|
1689
|
-
await wallet.generate_signed_transaction(uint64(30), ph, action_scope, coins={coins[1].coin})
|
|
1690
|
-
await wallet.generate_signed_transaction(uint64(30), ph, action_scope, coins={coins[2].coin})
|
|
1738
|
+
await wallet.generate_signed_transaction([uint64(30)], [ph], action_scope, coins={coins[0].coin})
|
|
1739
|
+
await wallet.generate_signed_transaction([uint64(30)], [ph], action_scope, coins={coins[1].coin})
|
|
1740
|
+
await wallet.generate_signed_transaction([uint64(30)], [ph], action_scope, coins={coins[2].coin})
|
|
1691
1741
|
[tx_a, tx_b, tx_c] = action_scope.side_effects.transactions
|
|
1692
1742
|
assert tx_a.spend_bundle is not None
|
|
1693
1743
|
assert tx_b.spend_bundle is not None
|
|
@@ -1705,7 +1755,9 @@ async def test_identical_spend_aggregation_e2e(
|
|
|
1705
1755
|
async with wallet.wallet_state_manager.new_action_scope(
|
|
1706
1756
|
DEFAULT_TX_CONFIG, push=False, merge_spends=False, sign=True
|
|
1707
1757
|
) as action_scope:
|
|
1708
|
-
await wallet.generate_signed_transaction(
|
|
1758
|
+
await wallet.generate_signed_transaction(
|
|
1759
|
+
[uint64(200)], [IDENTITY_PUZZLE_HASH], action_scope, coins={coins[3].coin}
|
|
1760
|
+
)
|
|
1709
1761
|
[tx] = action_scope.side_effects.transactions
|
|
1710
1762
|
assert tx.spend_bundle is not None
|
|
1711
1763
|
await send_to_mempool(full_node_api, tx.spend_bundle)
|
|
@@ -1714,9 +1766,8 @@ async def test_identical_spend_aggregation_e2e(
|
|
|
1714
1766
|
coins_with_identity_ph = await full_node_api.full_node.coin_store.get_coin_records_by_puzzle_hash(
|
|
1715
1767
|
False, IDENTITY_PUZZLE_HASH
|
|
1716
1768
|
)
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
)
|
|
1769
|
+
coin = coins_with_identity_ph[0].coin
|
|
1770
|
+
sb = spend_bundle_from_conditions([[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, coin.amount]], coin)
|
|
1720
1771
|
await send_to_mempool(full_node_api, sb)
|
|
1721
1772
|
await farm_a_block(full_node_api, wallet_node, ph)
|
|
1722
1773
|
# Grab the eligible coin to spend as E in DE and EF transactions
|
|
@@ -1732,16 +1783,16 @@ async def test_identical_spend_aggregation_e2e(
|
|
|
1732
1783
|
DEFAULT_TX_CONFIG, push=False, merge_spends=False, sign=True
|
|
1733
1784
|
) as action_scope:
|
|
1734
1785
|
await wallet.generate_signed_transaction(
|
|
1735
|
-
uint64(100),
|
|
1736
|
-
ph,
|
|
1786
|
+
[uint64(100)],
|
|
1787
|
+
[ph],
|
|
1737
1788
|
action_scope,
|
|
1738
1789
|
fee=uint64(0),
|
|
1739
1790
|
coins={coins[4].coin},
|
|
1740
1791
|
extra_conditions=(e_announcement,),
|
|
1741
1792
|
)
|
|
1742
1793
|
await wallet.generate_signed_transaction(
|
|
1743
|
-
uint64(150),
|
|
1744
|
-
ph,
|
|
1794
|
+
[uint64(150)],
|
|
1795
|
+
[ph],
|
|
1745
1796
|
action_scope,
|
|
1746
1797
|
fee=uint64(0),
|
|
1747
1798
|
coins={coins[5].coin},
|
|
@@ -1753,7 +1804,7 @@ async def test_identical_spend_aggregation_e2e(
|
|
|
1753
1804
|
# Create transaction E now that spends e_coin to create another eligible
|
|
1754
1805
|
# coin as well as the announcement consumed by D and F
|
|
1755
1806
|
conditions: list[list[Any]] = [
|
|
1756
|
-
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH,
|
|
1807
|
+
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, e_coin.amount],
|
|
1757
1808
|
[ConditionOpcode.CREATE_COIN_ANNOUNCEMENT, message],
|
|
1758
1809
|
]
|
|
1759
1810
|
sb_e = spend_bundle_from_conditions(conditions, e_coin)
|
|
@@ -1767,7 +1818,8 @@ async def test_identical_spend_aggregation_e2e(
|
|
|
1767
1818
|
# Send also a transaction EG that spends E differently from DE and EF,
|
|
1768
1819
|
# so that it doesn't get deduplicated on E with them
|
|
1769
1820
|
conditions = [
|
|
1770
|
-
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, e_coin.amount
|
|
1821
|
+
[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, e_coin.amount],
|
|
1822
|
+
[ConditionOpcode.ASSERT_MY_COIN_ID, e_coin.name()],
|
|
1771
1823
|
[ConditionOpcode.CREATE_COIN_ANNOUNCEMENT, message],
|
|
1772
1824
|
]
|
|
1773
1825
|
sb_e2 = spend_bundle_from_conditions(conditions, e_coin)
|
|
@@ -1777,7 +1829,7 @@ async def test_identical_spend_aggregation_e2e(
|
|
|
1777
1829
|
DEFAULT_TX_CONFIG, push=False, merge_spends=False, sign=True
|
|
1778
1830
|
) as action_scope:
|
|
1779
1831
|
await wallet.generate_signed_transaction(
|
|
1780
|
-
uint64(13), ph, action_scope, coins={g_coin}, extra_conditions=(e_announcement,)
|
|
1832
|
+
[uint64(13)], [ph], action_scope, coins={g_coin}, extra_conditions=(e_announcement,)
|
|
1781
1833
|
)
|
|
1782
1834
|
[tx_g] = action_scope.side_effects.transactions
|
|
1783
1835
|
assert tx_g.spend_bundle is not None
|
|
@@ -1808,7 +1860,7 @@ async def test_identical_spend_aggregation_e2e(
|
|
|
1808
1860
|
False, IDENTITY_PUZZLE_HASH
|
|
1809
1861
|
)
|
|
1810
1862
|
assert len(eligible_coins) == 1
|
|
1811
|
-
assert eligible_coins[0].coin.amount ==
|
|
1863
|
+
assert eligible_coins[0].coin.amount == e_coin.amount
|
|
1812
1864
|
|
|
1813
1865
|
|
|
1814
1866
|
# we have two coins in this test. They have different birth heights (and
|
|
@@ -2091,3 +2143,361 @@ async def test_fill_rate_block_validation(
|
|
|
2091
2143
|
rb_res_parsed = RespondBlock.from_bytes(rb_res.data)
|
|
2092
2144
|
assert rb_res_parsed.block.transactions_info is not None
|
|
2093
2145
|
assert rb_res_parsed.block.transactions_info.cost == expected_block_cost
|
|
2146
|
+
|
|
2147
|
+
|
|
2148
|
+
@pytest.mark.parametrize("optimized_path", [True, False])
|
|
2149
|
+
@pytest.mark.anyio
|
|
2150
|
+
async def test_height_added_to_mempool(optimized_path: bool) -> None:
|
|
2151
|
+
"""
|
|
2152
|
+
This test covers scenarios when the mempool is updated or rebuilt, to make
|
|
2153
|
+
sure that mempool items maintain correct height added to mempool values.
|
|
2154
|
+
We control whether we're updating the mempool or rebuilding it, through the
|
|
2155
|
+
`optimized_path` param.
|
|
2156
|
+
"""
|
|
2157
|
+
mempool_manager = await instantiate_mempool_manager(get_coin_records_for_test_coins)
|
|
2158
|
+
assert mempool_manager.peak is not None
|
|
2159
|
+
assert mempool_manager.peak.height == TEST_HEIGHT
|
|
2160
|
+
assert mempool_manager.peak.header_hash == height_hash(TEST_HEIGHT)
|
|
2161
|
+
# Create a mempool item and keep track of its height added to mempool
|
|
2162
|
+
_, sb_name, _ = await generate_and_add_spendbundle(
|
|
2163
|
+
mempool_manager, [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1]]
|
|
2164
|
+
)
|
|
2165
|
+
mi = mempool_manager.get_mempool_item(sb_name)
|
|
2166
|
+
assert mi is not None
|
|
2167
|
+
original_height = mi.height_added_to_mempool
|
|
2168
|
+
# Let's get a new peak that doesn't include our item, and make sure the
|
|
2169
|
+
# height added to mempool remains correct.
|
|
2170
|
+
test_new_peak = TestBlockRecord(
|
|
2171
|
+
header_hash=height_hash(TEST_HEIGHT + 1),
|
|
2172
|
+
height=uint32(TEST_HEIGHT + 1),
|
|
2173
|
+
timestamp=uint64(TEST_TIMESTAMP + 42),
|
|
2174
|
+
prev_transaction_block_height=TEST_HEIGHT,
|
|
2175
|
+
prev_transaction_block_hash=height_hash(TEST_HEIGHT),
|
|
2176
|
+
)
|
|
2177
|
+
if optimized_path:
|
|
2178
|
+
# Spend an unrelated coin to get the mempool updated
|
|
2179
|
+
spent_coins = [TEST_COIN_ID2]
|
|
2180
|
+
else:
|
|
2181
|
+
# Trigger the slow path to get the mempool rebuilt
|
|
2182
|
+
spent_coins = None
|
|
2183
|
+
await mempool_manager.new_peak(test_new_peak, spent_coins)
|
|
2184
|
+
assert mempool_manager.peak.height == TEST_HEIGHT + 1
|
|
2185
|
+
assert mempool_manager.peak.header_hash == height_hash(TEST_HEIGHT + 1)
|
|
2186
|
+
# Make sure our item is still in the mempool, and that its height added to
|
|
2187
|
+
# mempool value is still correct.
|
|
2188
|
+
mempool_item = mempool_manager.get_mempool_item(sb_name)
|
|
2189
|
+
assert mempool_item is not None
|
|
2190
|
+
assert mempool_item.height_added_to_mempool == original_height
|
|
2191
|
+
|
|
2192
|
+
|
|
2193
|
+
# This is a test utility to provide a simple view of the coin table for the
|
|
2194
|
+
# mempool manager.
|
|
2195
|
+
class TestCoins:
|
|
2196
|
+
coin_records: dict[bytes32, CoinRecord]
|
|
2197
|
+
lineage_info: dict[bytes32, UnspentLineageInfo]
|
|
2198
|
+
|
|
2199
|
+
def __init__(self, coins: list[Coin], lineage: dict[bytes32, Coin]) -> None:
|
|
2200
|
+
self.coin_records = {}
|
|
2201
|
+
for c in coins:
|
|
2202
|
+
self.coin_records[c.name()] = CoinRecord(c, uint32(0), uint32(0), False, TEST_TIMESTAMP)
|
|
2203
|
+
self.lineage_info = {}
|
|
2204
|
+
for ph, c in lineage.items():
|
|
2205
|
+
self.lineage_info[ph] = UnspentLineageInfo(
|
|
2206
|
+
c.name(), c.amount, c.parent_coin_info, uint64(1337), bytes32([42] * 32)
|
|
2207
|
+
)
|
|
2208
|
+
|
|
2209
|
+
def spend_coin(self, coin_id: bytes32, height: uint32 = uint32(10)) -> None:
|
|
2210
|
+
self.coin_records[coin_id] = dataclasses.replace(self.coin_records[coin_id], spent_block_index=height)
|
|
2211
|
+
|
|
2212
|
+
def update_lineage(self, puzzle_hash: bytes32, coin: Optional[Coin]) -> None:
|
|
2213
|
+
if coin is None:
|
|
2214
|
+
self.lineage_info.pop(puzzle_hash)
|
|
2215
|
+
else:
|
|
2216
|
+
assert coin.puzzle_hash == puzzle_hash
|
|
2217
|
+
prev = self.lineage_info[puzzle_hash]
|
|
2218
|
+
self.lineage_info[puzzle_hash] = UnspentLineageInfo(
|
|
2219
|
+
coin.name(), coin.amount, coin.parent_coin_info, prev.coin_amount, prev.coin_id
|
|
2220
|
+
)
|
|
2221
|
+
|
|
2222
|
+
async def get_coin_records(self, coin_ids: Collection[bytes32]) -> list[CoinRecord]:
|
|
2223
|
+
ret = []
|
|
2224
|
+
for coin_id in coin_ids:
|
|
2225
|
+
rec = self.coin_records.get(coin_id)
|
|
2226
|
+
if rec is not None:
|
|
2227
|
+
ret.append(rec)
|
|
2228
|
+
|
|
2229
|
+
return ret
|
|
2230
|
+
|
|
2231
|
+
async def get_unspent_lineage_info(self, ph: bytes32) -> Optional[UnspentLineageInfo]:
|
|
2232
|
+
return self.lineage_info.get(ph)
|
|
2233
|
+
|
|
2234
|
+
|
|
2235
|
+
# creates a CoinSpend of a made up
|
|
2236
|
+
def make_singleton_spend(launcher_id: bytes32, parent_parent_id: bytes32 = bytes32([3] * 32)) -> CoinSpend:
|
|
2237
|
+
from chia_rs import supports_fast_forward
|
|
2238
|
+
|
|
2239
|
+
from chia.wallet.lineage_proof import LineageProof
|
|
2240
|
+
from chia.wallet.puzzles.singleton_top_layer_v1_1 import (
|
|
2241
|
+
puzzle_for_singleton,
|
|
2242
|
+
solution_for_singleton,
|
|
2243
|
+
)
|
|
2244
|
+
|
|
2245
|
+
singleton_puzzle = SerializedProgram.from_program(puzzle_for_singleton(launcher_id, Program.to(1)))
|
|
2246
|
+
|
|
2247
|
+
PARENT_COIN = Coin(parent_parent_id, singleton_puzzle.get_tree_hash(), uint64(1))
|
|
2248
|
+
COIN = Coin(PARENT_COIN.name(), singleton_puzzle.get_tree_hash(), uint64(1))
|
|
2249
|
+
|
|
2250
|
+
lineage_proof = LineageProof(parent_parent_id, IDENTITY_PUZZLE_HASH, uint64(1))
|
|
2251
|
+
|
|
2252
|
+
inner_solution = Program.to([[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, uint64(1)]])
|
|
2253
|
+
singleton_solution = SerializedProgram.from_program(
|
|
2254
|
+
solution_for_singleton(lineage_proof, uint64(1), inner_solution)
|
|
2255
|
+
)
|
|
2256
|
+
|
|
2257
|
+
ret = CoinSpend(COIN, singleton_puzzle, singleton_solution)
|
|
2258
|
+
|
|
2259
|
+
# we make sure the spend actually supports fast forward
|
|
2260
|
+
assert supports_fast_forward(ret)
|
|
2261
|
+
assert ret.coin.puzzle_hash == ret.puzzle_reveal.get_tree_hash()
|
|
2262
|
+
return ret
|
|
2263
|
+
|
|
2264
|
+
|
|
2265
|
+
async def setup_mempool(coins: TestCoins) -> MempoolManager:
|
|
2266
|
+
mempool_manager = MempoolManager(
|
|
2267
|
+
coins.get_coin_records,
|
|
2268
|
+
coins.get_unspent_lineage_info,
|
|
2269
|
+
DEFAULT_CONSTANTS,
|
|
2270
|
+
)
|
|
2271
|
+
test_block_record = create_test_block_record(height=uint32(10), timestamp=uint64(12345678))
|
|
2272
|
+
await mempool_manager.new_peak(test_block_record, None)
|
|
2273
|
+
return mempool_manager
|
|
2274
|
+
|
|
2275
|
+
|
|
2276
|
+
# adds a new peak to the memepool manager with the specified coin IDs spent
|
|
2277
|
+
async def advance_mempool(
|
|
2278
|
+
mempool: MempoolManager, spent_coins: list[bytes32], *, use_optimization: bool = True
|
|
2279
|
+
) -> None:
|
|
2280
|
+
br = mempool.peak
|
|
2281
|
+
assert br is not None
|
|
2282
|
+
|
|
2283
|
+
if use_optimization:
|
|
2284
|
+
next_height = uint32(br.height + 1)
|
|
2285
|
+
else:
|
|
2286
|
+
next_height = uint32(br.height + 2)
|
|
2287
|
+
|
|
2288
|
+
assert br.timestamp is not None
|
|
2289
|
+
prev_block_hash = br.header_hash
|
|
2290
|
+
br = create_test_block_record(height=next_height, timestamp=uint64(br.timestamp + 10))
|
|
2291
|
+
|
|
2292
|
+
if use_optimization:
|
|
2293
|
+
assert prev_block_hash == br.prev_transaction_block_hash
|
|
2294
|
+
else:
|
|
2295
|
+
assert prev_block_hash != br.prev_transaction_block_hash
|
|
2296
|
+
|
|
2297
|
+
await mempool.new_peak(br, spent_coins)
|
|
2298
|
+
invariant_check_mempool(mempool.mempool)
|
|
2299
|
+
|
|
2300
|
+
|
|
2301
|
+
@pytest.mark.anyio
|
|
2302
|
+
@pytest.mark.parametrize("spend_singleton", [True, False])
|
|
2303
|
+
@pytest.mark.parametrize("spend_plain", [True, False])
|
|
2304
|
+
@pytest.mark.parametrize("use_optimization", [True, False])
|
|
2305
|
+
@pytest.mark.parametrize("reverse_spend_order", [True, False])
|
|
2306
|
+
async def test_new_peak_ff_eviction(
|
|
2307
|
+
spend_singleton: bool, spend_plain: bool, use_optimization: bool, reverse_spend_order: bool
|
|
2308
|
+
) -> None:
|
|
2309
|
+
LAUNCHER_ID = bytes32([1] * 32)
|
|
2310
|
+
singleton_spend = make_singleton_spend(LAUNCHER_ID)
|
|
2311
|
+
|
|
2312
|
+
coin_spend = make_spend(
|
|
2313
|
+
TEST_COIN,
|
|
2314
|
+
IDENTITY_PUZZLE,
|
|
2315
|
+
Program.to([[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1336]]),
|
|
2316
|
+
)
|
|
2317
|
+
bundle = SpendBundle([singleton_spend, coin_spend], G2Element())
|
|
2318
|
+
|
|
2319
|
+
coins = TestCoins([singleton_spend.coin, TEST_COIN], {singleton_spend.coin.puzzle_hash: singleton_spend.coin})
|
|
2320
|
+
|
|
2321
|
+
mempool_manager = await setup_mempool(coins)
|
|
2322
|
+
|
|
2323
|
+
bundle_add_info = await mempool_manager.add_spend_bundle(
|
|
2324
|
+
bundle,
|
|
2325
|
+
make_test_conds(spend_ids=[(singleton_spend.coin, ELIGIBLE_FOR_FF), (TEST_COIN, 0)], cost=1000000),
|
|
2326
|
+
bundle.name(),
|
|
2327
|
+
first_added_height=uint32(1),
|
|
2328
|
+
)
|
|
2329
|
+
|
|
2330
|
+
assert bundle_add_info.status == MempoolInclusionStatus.SUCCESS
|
|
2331
|
+
item = mempool_manager.get_mempool_item(bundle.name())
|
|
2332
|
+
assert item is not None
|
|
2333
|
+
assert item.bundle_coin_spends[singleton_spend.coin.name()].eligible_for_fast_forward
|
|
2334
|
+
assert item.bundle_coin_spends[singleton_spend.coin.name()].latest_singleton_coin == singleton_spend.coin.name()
|
|
2335
|
+
|
|
2336
|
+
spent_coins: list[bytes32] = []
|
|
2337
|
+
|
|
2338
|
+
if spend_singleton:
|
|
2339
|
+
# pretend that we melted the singleton, the FF spend
|
|
2340
|
+
coins.update_lineage(singleton_spend.coin.puzzle_hash, None)
|
|
2341
|
+
coins.spend_coin(singleton_spend.coin.name(), uint32(11))
|
|
2342
|
+
spent_coins.append(singleton_spend.coin.name())
|
|
2343
|
+
|
|
2344
|
+
if spend_plain:
|
|
2345
|
+
# pretend that we spend singleton, the FF spend
|
|
2346
|
+
coins.spend_coin(coin_spend.coin.name(), uint32(11))
|
|
2347
|
+
spent_coins.append(coin_spend.coin.name())
|
|
2348
|
+
|
|
2349
|
+
assert bundle_add_info.status == MempoolInclusionStatus.SUCCESS
|
|
2350
|
+
invariant_check_mempool(mempool_manager.mempool)
|
|
2351
|
+
|
|
2352
|
+
if reverse_spend_order:
|
|
2353
|
+
spent_coins.reverse()
|
|
2354
|
+
|
|
2355
|
+
await advance_mempool(mempool_manager, spent_coins, use_optimization=use_optimization)
|
|
2356
|
+
|
|
2357
|
+
# make sure the mempool item is evicted
|
|
2358
|
+
if spend_singleton or spend_plain:
|
|
2359
|
+
assert mempool_manager.get_mempool_item(bundle.name()) is None
|
|
2360
|
+
else:
|
|
2361
|
+
item = mempool_manager.get_mempool_item(bundle.name())
|
|
2362
|
+
assert item is not None
|
|
2363
|
+
assert item.bundle_coin_spends[singleton_spend.coin.name()].eligible_for_fast_forward
|
|
2364
|
+
assert item.bundle_coin_spends[singleton_spend.coin.name()].latest_singleton_coin == singleton_spend.coin.name()
|
|
2365
|
+
|
|
2366
|
+
|
|
2367
|
+
@pytest.mark.anyio
|
|
2368
|
+
@pytest.mark.parametrize("use_optimization", [True, False])
|
|
2369
|
+
async def test_multiple_ff(use_optimization: bool) -> None:
|
|
2370
|
+
# create two different singleton spends of the same singleton, that support
|
|
2371
|
+
# fast forward. Then update the latest singleton coin and ensure both
|
|
2372
|
+
# entries in the mempool are updated accordingly
|
|
2373
|
+
|
|
2374
|
+
PARENT_PARENT1 = bytes32([4] * 32)
|
|
2375
|
+
PARENT_PARENT2 = bytes32([5] * 32)
|
|
2376
|
+
PARENT_PARENT3 = bytes32([6] * 32)
|
|
2377
|
+
|
|
2378
|
+
# two different spends of the same singleton. both can be fast-forwarded
|
|
2379
|
+
LAUNCHER_ID = bytes32([1] * 32)
|
|
2380
|
+
singleton_spend1 = make_singleton_spend(LAUNCHER_ID, PARENT_PARENT1)
|
|
2381
|
+
singleton_spend2 = make_singleton_spend(LAUNCHER_ID, PARENT_PARENT2)
|
|
2382
|
+
|
|
2383
|
+
# in the next block, this will be the latest singleton coin
|
|
2384
|
+
singleton_spend3 = make_singleton_spend(LAUNCHER_ID, PARENT_PARENT3)
|
|
2385
|
+
|
|
2386
|
+
coin_spend = make_spend(
|
|
2387
|
+
TEST_COIN,
|
|
2388
|
+
IDENTITY_PUZZLE,
|
|
2389
|
+
Program.to([[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1336]]),
|
|
2390
|
+
)
|
|
2391
|
+
bundle = SpendBundle([singleton_spend1, singleton_spend2, coin_spend], G2Element())
|
|
2392
|
+
|
|
2393
|
+
# the singleton puzzle hash resulves to the most recent singleton coin, number 2
|
|
2394
|
+
# pretend that coin1 is spent
|
|
2395
|
+
singleton_ph = singleton_spend2.coin.puzzle_hash
|
|
2396
|
+
coins = TestCoins([singleton_spend1.coin, singleton_spend2.coin, TEST_COIN], {singleton_ph: singleton_spend2.coin})
|
|
2397
|
+
|
|
2398
|
+
mempool_manager = await setup_mempool(coins)
|
|
2399
|
+
|
|
2400
|
+
bundle_add_info = await mempool_manager.add_spend_bundle(
|
|
2401
|
+
bundle,
|
|
2402
|
+
make_test_conds(
|
|
2403
|
+
spend_ids=[
|
|
2404
|
+
(singleton_spend1.coin, ELIGIBLE_FOR_FF),
|
|
2405
|
+
(singleton_spend2.coin, ELIGIBLE_FOR_FF),
|
|
2406
|
+
(TEST_COIN, 0),
|
|
2407
|
+
],
|
|
2408
|
+
cost=1000000,
|
|
2409
|
+
),
|
|
2410
|
+
bundle.name(),
|
|
2411
|
+
first_added_height=uint32(1),
|
|
2412
|
+
)
|
|
2413
|
+
assert bundle_add_info.status == MempoolInclusionStatus.SUCCESS
|
|
2414
|
+
invariant_check_mempool(mempool_manager.mempool)
|
|
2415
|
+
|
|
2416
|
+
item = mempool_manager.get_mempool_item(bundle.name())
|
|
2417
|
+
assert item is not None
|
|
2418
|
+
assert item.bundle_coin_spends[singleton_spend1.coin.name()].eligible_for_fast_forward
|
|
2419
|
+
assert item.bundle_coin_spends[singleton_spend2.coin.name()].eligible_for_fast_forward
|
|
2420
|
+
assert not item.bundle_coin_spends[coin_spend.coin.name()].eligible_for_fast_forward
|
|
2421
|
+
|
|
2422
|
+
# spend the singleton coin2 and make coin3 the latest version
|
|
2423
|
+
coins.update_lineage(singleton_ph, singleton_spend3.coin)
|
|
2424
|
+
coins.spend_coin(singleton_spend2.coin.name(), uint32(11))
|
|
2425
|
+
|
|
2426
|
+
await advance_mempool(mempool_manager, [singleton_spend2.coin.name()], use_optimization=use_optimization)
|
|
2427
|
+
|
|
2428
|
+
# we can still fast-forward the singleton spends, the bundle should still be valid
|
|
2429
|
+
item = mempool_manager.get_mempool_item(bundle.name())
|
|
2430
|
+
assert item is not None
|
|
2431
|
+
spend = item.bundle_coin_spends[singleton_spend1.coin.name()]
|
|
2432
|
+
assert spend.latest_singleton_coin == singleton_spend3.coin.name()
|
|
2433
|
+
spend = item.bundle_coin_spends[singleton_spend2.coin.name()]
|
|
2434
|
+
assert spend.latest_singleton_coin == singleton_spend3.coin.name()
|
|
2435
|
+
|
|
2436
|
+
|
|
2437
|
+
@pytest.mark.anyio
|
|
2438
|
+
@pytest.mark.parametrize("use_optimization", [True, False])
|
|
2439
|
+
async def test_advancing_ff(use_optimization: bool) -> None:
|
|
2440
|
+
# add a FF spend under coin1, advance it twice
|
|
2441
|
+
# the second time we have to search for it with a linear search, because
|
|
2442
|
+
# it's filed under the original coin
|
|
2443
|
+
|
|
2444
|
+
PARENT_PARENT1 = bytes32([4] * 32)
|
|
2445
|
+
PARENT_PARENT2 = bytes32([5] * 32)
|
|
2446
|
+
PARENT_PARENT3 = bytes32([6] * 32)
|
|
2447
|
+
|
|
2448
|
+
# two different spends of the same singleton. both can be fast-forwarded
|
|
2449
|
+
LAUNCHER_ID = bytes32([1] * 32)
|
|
2450
|
+
spend_a = make_singleton_spend(LAUNCHER_ID, PARENT_PARENT1)
|
|
2451
|
+
spend_b = make_singleton_spend(LAUNCHER_ID, PARENT_PARENT2)
|
|
2452
|
+
spend_c = make_singleton_spend(LAUNCHER_ID, PARENT_PARENT3)
|
|
2453
|
+
|
|
2454
|
+
coin_spend = make_spend(
|
|
2455
|
+
TEST_COIN,
|
|
2456
|
+
IDENTITY_PUZZLE,
|
|
2457
|
+
Program.to([[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1336]]),
|
|
2458
|
+
)
|
|
2459
|
+
bundle = SpendBundle([spend_a, coin_spend], G2Element())
|
|
2460
|
+
|
|
2461
|
+
# the singleton puzzle hash resulves to the most recent singleton coin, number 2
|
|
2462
|
+
# pretend that coin1 is spent
|
|
2463
|
+
singleton_ph = spend_a.coin.puzzle_hash
|
|
2464
|
+
coins = TestCoins([spend_a.coin, spend_b.coin, spend_c.coin, TEST_COIN], {singleton_ph: spend_a.coin})
|
|
2465
|
+
|
|
2466
|
+
mempool_manager = await setup_mempool(coins)
|
|
2467
|
+
|
|
2468
|
+
bundle_add_info = await mempool_manager.add_spend_bundle(
|
|
2469
|
+
bundle,
|
|
2470
|
+
make_test_conds(spend_ids=[(spend_a.coin, ELIGIBLE_FOR_FF), (TEST_COIN, 0)], cost=1000000),
|
|
2471
|
+
bundle.name(),
|
|
2472
|
+
first_added_height=uint32(1),
|
|
2473
|
+
)
|
|
2474
|
+
assert bundle_add_info.status == MempoolInclusionStatus.SUCCESS
|
|
2475
|
+
invariant_check_mempool(mempool_manager.mempool)
|
|
2476
|
+
|
|
2477
|
+
item = mempool_manager.get_mempool_item(bundle.name())
|
|
2478
|
+
assert item is not None
|
|
2479
|
+
spend = item.bundle_coin_spends[spend_a.coin.name()]
|
|
2480
|
+
assert spend.eligible_for_fast_forward
|
|
2481
|
+
assert spend.latest_singleton_coin == spend_a.coin.name()
|
|
2482
|
+
|
|
2483
|
+
coins.update_lineage(singleton_ph, spend_b.coin)
|
|
2484
|
+
coins.spend_coin(spend_a.coin.name(), uint32(11))
|
|
2485
|
+
|
|
2486
|
+
await advance_mempool(mempool_manager, [spend_a.coin.name()])
|
|
2487
|
+
|
|
2488
|
+
item = mempool_manager.get_mempool_item(bundle.name())
|
|
2489
|
+
assert item is not None
|
|
2490
|
+
spend = item.bundle_coin_spends[spend_a.coin.name()]
|
|
2491
|
+
assert spend.eligible_for_fast_forward
|
|
2492
|
+
assert spend.latest_singleton_coin == spend_b.coin.name()
|
|
2493
|
+
|
|
2494
|
+
coins.update_lineage(singleton_ph, spend_c.coin)
|
|
2495
|
+
coins.spend_coin(spend_b.coin.name(), uint32(12))
|
|
2496
|
+
|
|
2497
|
+
await advance_mempool(mempool_manager, [spend_b.coin.name()], use_optimization=use_optimization)
|
|
2498
|
+
|
|
2499
|
+
item = mempool_manager.get_mempool_item(bundle.name())
|
|
2500
|
+
assert item is not None
|
|
2501
|
+
spend = item.bundle_coin_spends[spend_a.coin.name()]
|
|
2502
|
+
assert spend.eligible_for_fast_forward
|
|
2503
|
+
assert spend.latest_singleton_coin == spend_c.coin.name()
|