chia-blockchain 2.5.1rc1__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 +10 -0
- chia/__main__.py +5 -0
- chia/_tests/README.md +53 -0
- chia/_tests/__init__.py +0 -0
- chia/_tests/blockchain/__init__.py +0 -0
- chia/_tests/blockchain/blockchain_test_utils.py +195 -0
- chia/_tests/blockchain/config.py +4 -0
- chia/_tests/blockchain/test_augmented_chain.py +145 -0
- chia/_tests/blockchain/test_blockchain.py +4202 -0
- chia/_tests/blockchain/test_blockchain_transactions.py +1031 -0
- chia/_tests/blockchain/test_build_chains.py +59 -0
- chia/_tests/blockchain/test_get_block_generator.py +72 -0
- chia/_tests/blockchain/test_lookup_fork_chain.py +194 -0
- chia/_tests/build-init-files.py +92 -0
- chia/_tests/build-job-matrix.py +204 -0
- chia/_tests/check_pytest_monitor_output.py +34 -0
- chia/_tests/check_sql_statements.py +72 -0
- chia/_tests/chia-start-sim +42 -0
- chia/_tests/clvm/__init__.py +0 -0
- chia/_tests/clvm/benchmark_costs.py +23 -0
- chia/_tests/clvm/coin_store.py +149 -0
- chia/_tests/clvm/test_chialisp_deserialization.py +101 -0
- chia/_tests/clvm/test_clvm_step.py +37 -0
- chia/_tests/clvm/test_condition_codes.py +13 -0
- chia/_tests/clvm/test_curry_and_treehash.py +55 -0
- chia/_tests/clvm/test_message_conditions.py +184 -0
- chia/_tests/clvm/test_program.py +150 -0
- chia/_tests/clvm/test_puzzle_compression.py +143 -0
- chia/_tests/clvm/test_puzzle_drivers.py +45 -0
- chia/_tests/clvm/test_puzzles.py +242 -0
- chia/_tests/clvm/test_singletons.py +540 -0
- chia/_tests/clvm/test_spend_sim.py +181 -0
- chia/_tests/cmds/__init__.py +0 -0
- chia/_tests/cmds/cmd_test_utils.py +469 -0
- chia/_tests/cmds/config.py +3 -0
- chia/_tests/cmds/conftest.py +23 -0
- chia/_tests/cmds/test_click_types.py +200 -0
- chia/_tests/cmds/test_cmd_framework.py +620 -0
- chia/_tests/cmds/test_cmds_util.py +97 -0
- chia/_tests/cmds/test_daemon.py +92 -0
- chia/_tests/cmds/test_dev_gh.py +131 -0
- chia/_tests/cmds/test_farm_cmd.py +66 -0
- chia/_tests/cmds/test_show.py +116 -0
- chia/_tests/cmds/test_sim.py +207 -0
- chia/_tests/cmds/test_timelock_args.py +75 -0
- chia/_tests/cmds/test_tx_config_args.py +154 -0
- chia/_tests/cmds/testing_classes.py +59 -0
- chia/_tests/cmds/wallet/__init__.py +0 -0
- chia/_tests/cmds/wallet/test_consts.py +47 -0
- chia/_tests/cmds/wallet/test_dao.py +565 -0
- chia/_tests/cmds/wallet/test_did.py +403 -0
- chia/_tests/cmds/wallet/test_nft.py +471 -0
- chia/_tests/cmds/wallet/test_notifications.py +124 -0
- chia/_tests/cmds/wallet/test_offer.toffer +1 -0
- chia/_tests/cmds/wallet/test_tx_decorators.py +27 -0
- chia/_tests/cmds/wallet/test_vcs.py +400 -0
- chia/_tests/cmds/wallet/test_wallet.py +1125 -0
- chia/_tests/cmds/wallet/test_wallet_check.py +109 -0
- chia/_tests/conftest.py +1419 -0
- chia/_tests/connection_utils.py +125 -0
- chia/_tests/core/__init__.py +0 -0
- chia/_tests/core/cmds/__init__.py +0 -0
- chia/_tests/core/cmds/test_beta.py +382 -0
- chia/_tests/core/cmds/test_keys.py +1734 -0
- chia/_tests/core/cmds/test_wallet.py +126 -0
- chia/_tests/core/config.py +3 -0
- chia/_tests/core/consensus/__init__.py +0 -0
- chia/_tests/core/consensus/test_block_creation.py +54 -0
- chia/_tests/core/consensus/test_pot_iterations.py +117 -0
- chia/_tests/core/custom_types/__init__.py +0 -0
- chia/_tests/core/custom_types/test_coin.py +107 -0
- chia/_tests/core/custom_types/test_proof_of_space.py +144 -0
- chia/_tests/core/custom_types/test_spend_bundle.py +70 -0
- chia/_tests/core/daemon/__init__.py +0 -0
- chia/_tests/core/daemon/config.py +4 -0
- chia/_tests/core/daemon/test_daemon.py +2128 -0
- chia/_tests/core/daemon/test_daemon_register.py +109 -0
- chia/_tests/core/daemon/test_keychain_proxy.py +101 -0
- chia/_tests/core/data_layer/__init__.py +0 -0
- chia/_tests/core/data_layer/config.py +5 -0
- chia/_tests/core/data_layer/conftest.py +106 -0
- chia/_tests/core/data_layer/test_data_cli.py +56 -0
- chia/_tests/core/data_layer/test_data_layer.py +83 -0
- chia/_tests/core/data_layer/test_data_layer_util.py +218 -0
- chia/_tests/core/data_layer/test_data_rpc.py +3847 -0
- chia/_tests/core/data_layer/test_data_store.py +2424 -0
- chia/_tests/core/data_layer/test_data_store_schema.py +381 -0
- chia/_tests/core/data_layer/test_plugin.py +91 -0
- chia/_tests/core/data_layer/util.py +233 -0
- chia/_tests/core/farmer/__init__.py +0 -0
- chia/_tests/core/farmer/config.py +3 -0
- chia/_tests/core/farmer/test_farmer_api.py +103 -0
- chia/_tests/core/full_node/__init__.py +0 -0
- chia/_tests/core/full_node/config.py +4 -0
- chia/_tests/core/full_node/dos/__init__.py +0 -0
- chia/_tests/core/full_node/dos/config.py +3 -0
- chia/_tests/core/full_node/full_sync/__init__.py +0 -0
- chia/_tests/core/full_node/full_sync/config.py +4 -0
- chia/_tests/core/full_node/full_sync/test_full_sync.py +443 -0
- chia/_tests/core/full_node/ram_db.py +27 -0
- chia/_tests/core/full_node/stores/__init__.py +0 -0
- chia/_tests/core/full_node/stores/config.py +4 -0
- chia/_tests/core/full_node/stores/test_block_store.py +590 -0
- chia/_tests/core/full_node/stores/test_coin_store.py +897 -0
- chia/_tests/core/full_node/stores/test_full_node_store.py +1219 -0
- chia/_tests/core/full_node/stores/test_hint_store.py +229 -0
- chia/_tests/core/full_node/stores/test_sync_store.py +135 -0
- chia/_tests/core/full_node/test_address_manager.py +588 -0
- chia/_tests/core/full_node/test_block_height_map.py +556 -0
- chia/_tests/core/full_node/test_conditions.py +556 -0
- chia/_tests/core/full_node/test_full_node.py +2700 -0
- chia/_tests/core/full_node/test_generator_tools.py +82 -0
- chia/_tests/core/full_node/test_hint_management.py +104 -0
- chia/_tests/core/full_node/test_node_load.py +34 -0
- chia/_tests/core/full_node/test_performance.py +179 -0
- chia/_tests/core/full_node/test_subscriptions.py +492 -0
- chia/_tests/core/full_node/test_transactions.py +203 -0
- chia/_tests/core/full_node/test_tx_processing_queue.py +155 -0
- chia/_tests/core/large_block.py +2388 -0
- chia/_tests/core/make_block_generator.py +70 -0
- chia/_tests/core/mempool/__init__.py +0 -0
- chia/_tests/core/mempool/config.py +4 -0
- chia/_tests/core/mempool/test_mempool.py +3255 -0
- chia/_tests/core/mempool/test_mempool_fee_estimator.py +104 -0
- chia/_tests/core/mempool/test_mempool_fee_protocol.py +55 -0
- chia/_tests/core/mempool/test_mempool_item_queries.py +190 -0
- chia/_tests/core/mempool/test_mempool_manager.py +2084 -0
- chia/_tests/core/mempool/test_mempool_performance.py +64 -0
- chia/_tests/core/mempool/test_singleton_fast_forward.py +567 -0
- chia/_tests/core/node_height.py +28 -0
- chia/_tests/core/server/__init__.py +0 -0
- chia/_tests/core/server/config.py +3 -0
- chia/_tests/core/server/flood.py +84 -0
- chia/_tests/core/server/serve.py +135 -0
- chia/_tests/core/server/test_api_protocol.py +21 -0
- chia/_tests/core/server/test_capabilities.py +66 -0
- chia/_tests/core/server/test_dos.py +319 -0
- chia/_tests/core/server/test_event_loop.py +109 -0
- chia/_tests/core/server/test_loop.py +294 -0
- chia/_tests/core/server/test_node_discovery.py +73 -0
- chia/_tests/core/server/test_rate_limits.py +482 -0
- chia/_tests/core/server/test_server.py +226 -0
- chia/_tests/core/server/test_upnp.py +8 -0
- chia/_tests/core/services/__init__.py +0 -0
- chia/_tests/core/services/config.py +3 -0
- chia/_tests/core/services/test_services.py +188 -0
- chia/_tests/core/ssl/__init__.py +0 -0
- chia/_tests/core/ssl/config.py +3 -0
- chia/_tests/core/ssl/test_ssl.py +202 -0
- chia/_tests/core/test_coins.py +33 -0
- chia/_tests/core/test_cost_calculation.py +313 -0
- chia/_tests/core/test_crawler.py +175 -0
- chia/_tests/core/test_crawler_rpc.py +53 -0
- chia/_tests/core/test_daemon_rpc.py +24 -0
- chia/_tests/core/test_db_conversion.py +130 -0
- chia/_tests/core/test_db_validation.py +162 -0
- chia/_tests/core/test_farmer_harvester_rpc.py +505 -0
- chia/_tests/core/test_filter.py +35 -0
- chia/_tests/core/test_full_node_rpc.py +768 -0
- chia/_tests/core/test_merkle_set.py +343 -0
- chia/_tests/core/test_program.py +47 -0
- chia/_tests/core/test_rpc_util.py +86 -0
- chia/_tests/core/test_seeder.py +420 -0
- chia/_tests/core/test_setproctitle.py +13 -0
- chia/_tests/core/util/__init__.py +0 -0
- chia/_tests/core/util/config.py +4 -0
- chia/_tests/core/util/test_block_cache.py +44 -0
- chia/_tests/core/util/test_cached_bls.py +57 -0
- chia/_tests/core/util/test_config.py +337 -0
- chia/_tests/core/util/test_file_keyring_synchronization.py +105 -0
- chia/_tests/core/util/test_files.py +391 -0
- chia/_tests/core/util/test_jsonify.py +146 -0
- chia/_tests/core/util/test_keychain.py +522 -0
- chia/_tests/core/util/test_keyring_wrapper.py +491 -0
- chia/_tests/core/util/test_lockfile.py +380 -0
- chia/_tests/core/util/test_log_exceptions.py +187 -0
- chia/_tests/core/util/test_lru_cache.py +56 -0
- chia/_tests/core/util/test_significant_bits.py +40 -0
- chia/_tests/core/util/test_streamable.py +883 -0
- chia/_tests/db/__init__.py +0 -0
- chia/_tests/db/test_db_wrapper.py +566 -0
- chia/_tests/environments/__init__.py +0 -0
- chia/_tests/environments/common.py +35 -0
- chia/_tests/environments/full_node.py +47 -0
- chia/_tests/environments/wallet.py +429 -0
- chia/_tests/ether.py +19 -0
- chia/_tests/farmer_harvester/__init__.py +0 -0
- chia/_tests/farmer_harvester/config.py +3 -0
- chia/_tests/farmer_harvester/test_farmer.py +1264 -0
- chia/_tests/farmer_harvester/test_farmer_harvester.py +292 -0
- chia/_tests/farmer_harvester/test_filter_prefix_bits.py +131 -0
- chia/_tests/farmer_harvester/test_third_party_harvesters.py +528 -0
- chia/_tests/farmer_harvester/test_third_party_harvesters_data.json +29 -0
- chia/_tests/fee_estimation/__init__.py +0 -0
- chia/_tests/fee_estimation/config.py +3 -0
- chia/_tests/fee_estimation/test_fee_estimation_integration.py +262 -0
- chia/_tests/fee_estimation/test_fee_estimation_rpc.py +287 -0
- chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +144 -0
- chia/_tests/fee_estimation/test_mempoolitem_height_added.py +146 -0
- chia/_tests/generator/__init__.py +0 -0
- chia/_tests/generator/puzzles/__init__.py +0 -0
- chia/_tests/generator/puzzles/test_generator_deserialize.clsp +3 -0
- chia/_tests/generator/puzzles/test_generator_deserialize.clsp.hex +1 -0
- chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp +19 -0
- chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp.hex +1 -0
- chia/_tests/generator/test_compression.py +201 -0
- chia/_tests/generator/test_generator_types.py +44 -0
- chia/_tests/generator/test_rom.py +180 -0
- chia/_tests/plot_sync/__init__.py +0 -0
- chia/_tests/plot_sync/config.py +3 -0
- chia/_tests/plot_sync/test_delta.py +101 -0
- chia/_tests/plot_sync/test_plot_sync.py +618 -0
- chia/_tests/plot_sync/test_receiver.py +451 -0
- chia/_tests/plot_sync/test_sender.py +116 -0
- chia/_tests/plot_sync/test_sync_simulated.py +451 -0
- chia/_tests/plot_sync/util.py +68 -0
- chia/_tests/plotting/__init__.py +0 -0
- chia/_tests/plotting/config.py +3 -0
- chia/_tests/plotting/test_plot_manager.py +781 -0
- chia/_tests/plotting/util.py +12 -0
- chia/_tests/pools/__init__.py +0 -0
- chia/_tests/pools/config.py +5 -0
- chia/_tests/pools/test_pool_cli_parsing.py +128 -0
- chia/_tests/pools/test_pool_cmdline.py +1001 -0
- chia/_tests/pools/test_pool_config.py +42 -0
- chia/_tests/pools/test_pool_puzzles_lifecycle.py +397 -0
- chia/_tests/pools/test_pool_rpc.py +1123 -0
- chia/_tests/pools/test_pool_wallet.py +205 -0
- chia/_tests/pools/test_wallet_pool_store.py +161 -0
- chia/_tests/process_junit.py +348 -0
- chia/_tests/rpc/__init__.py +0 -0
- chia/_tests/rpc/test_rpc_client.py +138 -0
- chia/_tests/rpc/test_rpc_server.py +183 -0
- chia/_tests/simulation/__init__.py +0 -0
- chia/_tests/simulation/config.py +6 -0
- chia/_tests/simulation/test_simulation.py +501 -0
- chia/_tests/simulation/test_simulator.py +232 -0
- chia/_tests/simulation/test_start_simulator.py +107 -0
- chia/_tests/testconfig.py +13 -0
- chia/_tests/timelord/__init__.py +0 -0
- chia/_tests/timelord/config.py +3 -0
- chia/_tests/timelord/test_new_peak.py +437 -0
- chia/_tests/timelord/test_timelord.py +11 -0
- chia/_tests/tools/1315537.json +170 -0
- chia/_tests/tools/1315544.json +160 -0
- chia/_tests/tools/1315630.json +150 -0
- chia/_tests/tools/300000.json +105 -0
- chia/_tests/tools/442734.json +140 -0
- chia/_tests/tools/466212.json +130 -0
- chia/_tests/tools/__init__.py +0 -0
- chia/_tests/tools/config.py +5 -0
- chia/_tests/tools/test-blockchain-db.sqlite +0 -0
- chia/_tests/tools/test_full_sync.py +30 -0
- chia/_tests/tools/test_legacy_keyring.py +82 -0
- chia/_tests/tools/test_run_block.py +128 -0
- chia/_tests/tools/test_virtual_project.py +591 -0
- chia/_tests/util/__init__.py +0 -0
- chia/_tests/util/benchmark_cost.py +170 -0
- chia/_tests/util/benchmarks.py +153 -0
- chia/_tests/util/bip39_test_vectors.json +148 -0
- chia/_tests/util/blockchain.py +134 -0
- chia/_tests/util/blockchain_mock.py +132 -0
- chia/_tests/util/build_network_protocol_files.py +302 -0
- chia/_tests/util/clvm_generator.bin +0 -0
- chia/_tests/util/config.py +3 -0
- chia/_tests/util/constants.py +20 -0
- chia/_tests/util/db_connection.py +37 -0
- chia/_tests/util/full_sync.py +253 -0
- chia/_tests/util/gen_ssl_certs.py +114 -0
- chia/_tests/util/generator_tools_testing.py +45 -0
- chia/_tests/util/get_name_puzzle_conditions.py +52 -0
- chia/_tests/util/key_tool.py +36 -0
- chia/_tests/util/misc.py +675 -0
- chia/_tests/util/network_protocol_data.py +1072 -0
- chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
- chia/_tests/util/protocol_messages_json.py +2701 -0
- chia/_tests/util/rpc.py +26 -0
- chia/_tests/util/run_block.py +163 -0
- chia/_tests/util/setup_nodes.py +481 -0
- chia/_tests/util/spend_sim.py +492 -0
- chia/_tests/util/split_managers.py +102 -0
- chia/_tests/util/temp_file.py +14 -0
- chia/_tests/util/test_action_scope.py +144 -0
- chia/_tests/util/test_async_pool.py +366 -0
- chia/_tests/util/test_build_job_matrix.py +42 -0
- chia/_tests/util/test_build_network_protocol_files.py +7 -0
- chia/_tests/util/test_chia_version.py +50 -0
- chia/_tests/util/test_collection.py +11 -0
- chia/_tests/util/test_condition_tools.py +229 -0
- chia/_tests/util/test_config.py +426 -0
- chia/_tests/util/test_dump_keyring.py +60 -0
- chia/_tests/util/test_errors.py +10 -0
- chia/_tests/util/test_full_block_utils.py +279 -0
- chia/_tests/util/test_installed.py +20 -0
- chia/_tests/util/test_limited_semaphore.py +53 -0
- chia/_tests/util/test_logging_filter.py +42 -0
- chia/_tests/util/test_misc.py +445 -0
- chia/_tests/util/test_network.py +73 -0
- chia/_tests/util/test_network_protocol_files.py +578 -0
- chia/_tests/util/test_network_protocol_json.py +267 -0
- chia/_tests/util/test_network_protocol_test.py +256 -0
- chia/_tests/util/test_paginator.py +71 -0
- chia/_tests/util/test_pprint.py +17 -0
- chia/_tests/util/test_priority_mutex.py +488 -0
- chia/_tests/util/test_recursive_replace.py +116 -0
- chia/_tests/util/test_replace_str_to_bytes.py +137 -0
- chia/_tests/util/test_service_groups.py +15 -0
- chia/_tests/util/test_ssl_check.py +31 -0
- chia/_tests/util/test_testnet_overrides.py +19 -0
- chia/_tests/util/test_tests_misc.py +38 -0
- chia/_tests/util/test_timing.py +37 -0
- chia/_tests/util/test_trusted_peer.py +51 -0
- chia/_tests/util/time_out_assert.py +191 -0
- chia/_tests/wallet/__init__.py +0 -0
- chia/_tests/wallet/cat_wallet/__init__.py +0 -0
- chia/_tests/wallet/cat_wallet/config.py +4 -0
- chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +468 -0
- chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +69 -0
- chia/_tests/wallet/cat_wallet/test_cat_wallet.py +1826 -0
- chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +291 -0
- chia/_tests/wallet/cat_wallet/test_trades.py +2600 -0
- chia/_tests/wallet/clawback/__init__.py +0 -0
- chia/_tests/wallet/clawback/config.py +3 -0
- chia/_tests/wallet/clawback/test_clawback_decorator.py +78 -0
- chia/_tests/wallet/clawback/test_clawback_lifecycle.py +292 -0
- chia/_tests/wallet/clawback/test_clawback_metadata.py +50 -0
- chia/_tests/wallet/config.py +4 -0
- chia/_tests/wallet/conftest.py +278 -0
- chia/_tests/wallet/dao_wallet/__init__.py +0 -0
- chia/_tests/wallet/dao_wallet/config.py +3 -0
- chia/_tests/wallet/dao_wallet/test_dao_clvm.py +1330 -0
- chia/_tests/wallet/dao_wallet/test_dao_wallets.py +3488 -0
- chia/_tests/wallet/db_wallet/__init__.py +0 -0
- chia/_tests/wallet/db_wallet/config.py +3 -0
- chia/_tests/wallet/db_wallet/test_db_graftroot.py +141 -0
- chia/_tests/wallet/db_wallet/test_dl_offers.py +491 -0
- chia/_tests/wallet/db_wallet/test_dl_wallet.py +823 -0
- chia/_tests/wallet/did_wallet/__init__.py +0 -0
- chia/_tests/wallet/did_wallet/config.py +4 -0
- chia/_tests/wallet/did_wallet/test_did.py +2284 -0
- chia/_tests/wallet/nft_wallet/__init__.py +0 -0
- chia/_tests/wallet/nft_wallet/config.py +4 -0
- chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +1493 -0
- chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +1024 -0
- chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +375 -0
- chia/_tests/wallet/nft_wallet/test_nft_offers.py +1209 -0
- chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +172 -0
- chia/_tests/wallet/nft_wallet/test_nft_wallet.py +2584 -0
- chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +70 -0
- chia/_tests/wallet/rpc/__init__.py +0 -0
- chia/_tests/wallet/rpc/config.py +4 -0
- chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +285 -0
- chia/_tests/wallet/rpc/test_wallet_rpc.py +3153 -0
- chia/_tests/wallet/simple_sync/__init__.py +0 -0
- chia/_tests/wallet/simple_sync/config.py +3 -0
- chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +718 -0
- chia/_tests/wallet/sync/__init__.py +0 -0
- chia/_tests/wallet/sync/config.py +4 -0
- chia/_tests/wallet/sync/test_wallet_sync.py +1692 -0
- chia/_tests/wallet/test_address_type.py +189 -0
- chia/_tests/wallet/test_bech32m.py +45 -0
- chia/_tests/wallet/test_clvm_streamable.py +244 -0
- chia/_tests/wallet/test_coin_management.py +354 -0
- chia/_tests/wallet/test_coin_selection.py +588 -0
- chia/_tests/wallet/test_conditions.py +400 -0
- chia/_tests/wallet/test_debug_spend_bundle.py +218 -0
- chia/_tests/wallet/test_new_wallet_protocol.py +1174 -0
- chia/_tests/wallet/test_nft_store.py +192 -0
- chia/_tests/wallet/test_notifications.py +196 -0
- chia/_tests/wallet/test_offer_parsing_performance.py +48 -0
- chia/_tests/wallet/test_puzzle_store.py +132 -0
- chia/_tests/wallet/test_sign_coin_spends.py +159 -0
- chia/_tests/wallet/test_signer_protocol.py +947 -0
- chia/_tests/wallet/test_singleton.py +122 -0
- chia/_tests/wallet/test_singleton_lifecycle_fast.py +772 -0
- chia/_tests/wallet/test_singleton_store.py +152 -0
- chia/_tests/wallet/test_taproot.py +19 -0
- chia/_tests/wallet/test_transaction_store.py +945 -0
- chia/_tests/wallet/test_util.py +185 -0
- chia/_tests/wallet/test_wallet.py +2139 -0
- chia/_tests/wallet/test_wallet_action_scope.py +85 -0
- chia/_tests/wallet/test_wallet_blockchain.py +111 -0
- chia/_tests/wallet/test_wallet_coin_store.py +1002 -0
- chia/_tests/wallet/test_wallet_interested_store.py +43 -0
- chia/_tests/wallet/test_wallet_key_val_store.py +40 -0
- chia/_tests/wallet/test_wallet_node.py +780 -0
- chia/_tests/wallet/test_wallet_retry.py +95 -0
- chia/_tests/wallet/test_wallet_state_manager.py +259 -0
- chia/_tests/wallet/test_wallet_test_framework.py +275 -0
- chia/_tests/wallet/test_wallet_trade_store.py +218 -0
- chia/_tests/wallet/test_wallet_user_store.py +34 -0
- chia/_tests/wallet/test_wallet_utils.py +156 -0
- chia/_tests/wallet/vc_wallet/__init__.py +0 -0
- chia/_tests/wallet/vc_wallet/config.py +3 -0
- chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +70 -0
- chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +883 -0
- chia/_tests/wallet/vc_wallet/test_vc_wallet.py +830 -0
- chia/_tests/wallet/wallet_block_tools.py +327 -0
- chia/_tests/weight_proof/__init__.py +0 -0
- chia/_tests/weight_proof/config.py +3 -0
- chia/_tests/weight_proof/test_weight_proof.py +528 -0
- chia/apis.py +19 -0
- chia/clvm/__init__.py +0 -0
- chia/cmds/__init__.py +0 -0
- chia/cmds/beta.py +184 -0
- chia/cmds/beta_funcs.py +137 -0
- chia/cmds/check_wallet_db.py +420 -0
- chia/cmds/chia.py +151 -0
- chia/cmds/cmd_classes.py +323 -0
- chia/cmds/cmd_helpers.py +242 -0
- chia/cmds/cmds_util.py +488 -0
- chia/cmds/coin_funcs.py +275 -0
- chia/cmds/coins.py +182 -0
- chia/cmds/completion.py +49 -0
- chia/cmds/configure.py +332 -0
- chia/cmds/dao.py +1064 -0
- chia/cmds/dao_funcs.py +598 -0
- chia/cmds/data.py +708 -0
- chia/cmds/data_funcs.py +385 -0
- chia/cmds/db.py +87 -0
- chia/cmds/db_backup_func.py +77 -0
- chia/cmds/db_upgrade_func.py +452 -0
- chia/cmds/db_validate_func.py +184 -0
- chia/cmds/dev.py +18 -0
- chia/cmds/farm.py +100 -0
- chia/cmds/farm_funcs.py +200 -0
- chia/cmds/gh.py +275 -0
- chia/cmds/init.py +63 -0
- chia/cmds/init_funcs.py +367 -0
- chia/cmds/installers.py +131 -0
- chia/cmds/keys.py +527 -0
- chia/cmds/keys_funcs.py +863 -0
- chia/cmds/netspace.py +50 -0
- chia/cmds/netspace_funcs.py +54 -0
- chia/cmds/options.py +32 -0
- chia/cmds/param_types.py +238 -0
- chia/cmds/passphrase.py +131 -0
- chia/cmds/passphrase_funcs.py +292 -0
- chia/cmds/peer.py +51 -0
- chia/cmds/peer_funcs.py +129 -0
- chia/cmds/plotnft.py +260 -0
- chia/cmds/plotnft_funcs.py +405 -0
- chia/cmds/plots.py +230 -0
- chia/cmds/plotters.py +18 -0
- chia/cmds/rpc.py +208 -0
- chia/cmds/show.py +72 -0
- chia/cmds/show_funcs.py +215 -0
- chia/cmds/signer.py +296 -0
- chia/cmds/sim.py +225 -0
- chia/cmds/sim_funcs.py +509 -0
- chia/cmds/start.py +24 -0
- chia/cmds/start_funcs.py +109 -0
- chia/cmds/stop.py +62 -0
- chia/cmds/units.py +9 -0
- chia/cmds/wallet.py +1901 -0
- chia/cmds/wallet_funcs.py +1874 -0
- chia/consensus/__init__.py +0 -0
- chia/consensus/block_body_validation.py +562 -0
- chia/consensus/block_creation.py +546 -0
- chia/consensus/block_header_validation.py +1059 -0
- chia/consensus/block_record.py +31 -0
- chia/consensus/block_rewards.py +53 -0
- chia/consensus/blockchain.py +1087 -0
- chia/consensus/blockchain_interface.py +56 -0
- chia/consensus/coinbase.py +30 -0
- chia/consensus/condition_costs.py +9 -0
- chia/consensus/constants.py +49 -0
- chia/consensus/cost_calculator.py +15 -0
- chia/consensus/default_constants.py +89 -0
- chia/consensus/deficit.py +55 -0
- chia/consensus/difficulty_adjustment.py +412 -0
- chia/consensus/find_fork_point.py +111 -0
- chia/consensus/full_block_to_block_record.py +167 -0
- chia/consensus/get_block_challenge.py +106 -0
- chia/consensus/get_block_generator.py +27 -0
- chia/consensus/make_sub_epoch_summary.py +210 -0
- chia/consensus/multiprocess_validation.py +268 -0
- chia/consensus/pos_quality.py +19 -0
- chia/consensus/pot_iterations.py +67 -0
- chia/consensus/puzzles/__init__.py +0 -0
- chia/consensus/puzzles/chialisp_deserialisation.clsp +69 -0
- chia/consensus/puzzles/chialisp_deserialisation.clsp.hex +1 -0
- chia/consensus/puzzles/rom_bootstrap_generator.clsp +37 -0
- chia/consensus/puzzles/rom_bootstrap_generator.clsp.hex +1 -0
- chia/consensus/vdf_info_computation.py +156 -0
- chia/daemon/__init__.py +0 -0
- chia/daemon/client.py +252 -0
- chia/daemon/keychain_proxy.py +502 -0
- chia/daemon/keychain_server.py +365 -0
- chia/daemon/server.py +1606 -0
- chia/daemon/windows_signal.py +56 -0
- chia/data_layer/__init__.py +0 -0
- chia/data_layer/data_layer.py +1291 -0
- chia/data_layer/data_layer_api.py +33 -0
- chia/data_layer/data_layer_errors.py +50 -0
- chia/data_layer/data_layer_server.py +170 -0
- chia/data_layer/data_layer_util.py +985 -0
- chia/data_layer/data_layer_wallet.py +1311 -0
- chia/data_layer/data_store.py +2267 -0
- chia/data_layer/dl_wallet_store.py +407 -0
- chia/data_layer/download_data.py +389 -0
- chia/data_layer/puzzles/__init__.py +0 -0
- chia/data_layer/puzzles/graftroot_dl_offers.clsp +100 -0
- chia/data_layer/puzzles/graftroot_dl_offers.clsp.hex +1 -0
- chia/data_layer/s3_plugin_config.yml +33 -0
- chia/data_layer/s3_plugin_service.py +468 -0
- chia/data_layer/util/__init__.py +0 -0
- chia/data_layer/util/benchmark.py +107 -0
- chia/data_layer/util/plugin.py +40 -0
- chia/farmer/__init__.py +0 -0
- chia/farmer/farmer.py +923 -0
- chia/farmer/farmer_api.py +820 -0
- chia/full_node/__init__.py +0 -0
- chia/full_node/bitcoin_fee_estimator.py +85 -0
- chia/full_node/block_height_map.py +271 -0
- chia/full_node/block_store.py +576 -0
- chia/full_node/bundle_tools.py +19 -0
- chia/full_node/coin_store.py +647 -0
- chia/full_node/fee_estimate.py +54 -0
- chia/full_node/fee_estimate_store.py +24 -0
- chia/full_node/fee_estimation.py +92 -0
- chia/full_node/fee_estimator.py +90 -0
- chia/full_node/fee_estimator_constants.py +38 -0
- chia/full_node/fee_estimator_interface.py +42 -0
- chia/full_node/fee_history.py +25 -0
- chia/full_node/fee_tracker.py +564 -0
- chia/full_node/full_node.py +3327 -0
- chia/full_node/full_node_api.py +2025 -0
- chia/full_node/full_node_store.py +1033 -0
- chia/full_node/hint_management.py +56 -0
- chia/full_node/hint_store.py +93 -0
- chia/full_node/mempool.py +589 -0
- chia/full_node/mempool_check_conditions.py +146 -0
- chia/full_node/mempool_manager.py +853 -0
- chia/full_node/pending_tx_cache.py +112 -0
- chia/full_node/puzzles/__init__.py +0 -0
- chia/full_node/puzzles/block_program_zero.clsp +14 -0
- chia/full_node/puzzles/block_program_zero.clsp.hex +1 -0
- chia/full_node/puzzles/decompress_coin_spend_entry.clsp +5 -0
- chia/full_node/puzzles/decompress_coin_spend_entry.clsp.hex +1 -0
- chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp +7 -0
- chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp.hex +1 -0
- chia/full_node/puzzles/decompress_puzzle.clsp +6 -0
- chia/full_node/puzzles/decompress_puzzle.clsp.hex +1 -0
- chia/full_node/signage_point.py +16 -0
- chia/full_node/subscriptions.py +247 -0
- chia/full_node/sync_store.py +146 -0
- chia/full_node/tx_processing_queue.py +78 -0
- chia/full_node/util/__init__.py +0 -0
- chia/full_node/weight_proof.py +1720 -0
- chia/harvester/__init__.py +0 -0
- chia/harvester/harvester.py +272 -0
- chia/harvester/harvester_api.py +380 -0
- chia/introducer/__init__.py +0 -0
- chia/introducer/introducer.py +122 -0
- chia/introducer/introducer_api.py +70 -0
- chia/legacy/__init__.py +0 -0
- chia/legacy/keyring.py +155 -0
- chia/plot_sync/__init__.py +0 -0
- chia/plot_sync/delta.py +61 -0
- chia/plot_sync/exceptions.py +56 -0
- chia/plot_sync/receiver.py +386 -0
- chia/plot_sync/sender.py +340 -0
- chia/plot_sync/util.py +43 -0
- chia/plotters/__init__.py +0 -0
- chia/plotters/bladebit.py +388 -0
- chia/plotters/chiapos.py +63 -0
- chia/plotters/madmax.py +224 -0
- chia/plotters/plotters.py +577 -0
- chia/plotters/plotters_util.py +133 -0
- chia/plotting/__init__.py +0 -0
- chia/plotting/cache.py +213 -0
- chia/plotting/check_plots.py +283 -0
- chia/plotting/create_plots.py +278 -0
- chia/plotting/manager.py +436 -0
- chia/plotting/util.py +336 -0
- chia/pools/__init__.py +0 -0
- chia/pools/pool_config.py +110 -0
- chia/pools/pool_puzzles.py +459 -0
- chia/pools/pool_wallet.py +933 -0
- chia/pools/pool_wallet_info.py +118 -0
- chia/pools/puzzles/__init__.py +0 -0
- chia/pools/puzzles/pool_member_innerpuz.clsp +70 -0
- chia/pools/puzzles/pool_member_innerpuz.clsp.hex +1 -0
- chia/pools/puzzles/pool_waitingroom_innerpuz.clsp +69 -0
- chia/pools/puzzles/pool_waitingroom_innerpuz.clsp.hex +1 -0
- chia/protocols/__init__.py +0 -0
- chia/protocols/farmer_protocol.py +102 -0
- chia/protocols/full_node_protocol.py +219 -0
- chia/protocols/harvester_protocol.py +216 -0
- chia/protocols/introducer_protocol.py +25 -0
- chia/protocols/pool_protocol.py +177 -0
- chia/protocols/protocol_message_types.py +139 -0
- chia/protocols/protocol_state_machine.py +87 -0
- chia/protocols/protocol_timing.py +8 -0
- chia/protocols/shared_protocol.py +86 -0
- chia/protocols/timelord_protocol.py +93 -0
- chia/protocols/wallet_protocol.py +401 -0
- chia/py.typed +0 -0
- chia/rpc/__init__.py +0 -0
- chia/rpc/crawler_rpc_api.py +80 -0
- chia/rpc/data_layer_rpc_api.py +644 -0
- chia/rpc/data_layer_rpc_client.py +188 -0
- chia/rpc/data_layer_rpc_util.py +58 -0
- chia/rpc/farmer_rpc_api.py +365 -0
- chia/rpc/farmer_rpc_client.py +86 -0
- chia/rpc/full_node_rpc_api.py +959 -0
- chia/rpc/full_node_rpc_client.py +292 -0
- chia/rpc/harvester_rpc_api.py +141 -0
- chia/rpc/harvester_rpc_client.py +54 -0
- chia/rpc/rpc_client.py +164 -0
- chia/rpc/rpc_server.py +521 -0
- chia/rpc/timelord_rpc_api.py +32 -0
- chia/rpc/util.py +93 -0
- chia/rpc/wallet_request_types.py +904 -0
- chia/rpc/wallet_rpc_api.py +4943 -0
- chia/rpc/wallet_rpc_client.py +1814 -0
- chia/seeder/__init__.py +0 -0
- chia/seeder/crawl_store.py +425 -0
- chia/seeder/crawler.py +410 -0
- chia/seeder/crawler_api.py +135 -0
- chia/seeder/dns_server.py +593 -0
- chia/seeder/peer_record.py +146 -0
- chia/seeder/start_crawler.py +92 -0
- chia/server/__init__.py +0 -0
- chia/server/address_manager.py +658 -0
- chia/server/address_manager_store.py +237 -0
- chia/server/api_protocol.py +116 -0
- chia/server/capabilities.py +24 -0
- chia/server/chia_policy.py +346 -0
- chia/server/introducer_peers.py +76 -0
- chia/server/node_discovery.py +714 -0
- chia/server/outbound_message.py +33 -0
- chia/server/rate_limit_numbers.py +214 -0
- chia/server/rate_limits.py +153 -0
- chia/server/server.py +741 -0
- chia/server/signal_handlers.py +120 -0
- chia/server/ssl_context.py +32 -0
- chia/server/start_data_layer.py +151 -0
- chia/server/start_farmer.py +98 -0
- chia/server/start_full_node.py +112 -0
- chia/server/start_harvester.py +93 -0
- chia/server/start_introducer.py +81 -0
- chia/server/start_service.py +316 -0
- chia/server/start_timelord.py +89 -0
- chia/server/start_wallet.py +113 -0
- chia/server/upnp.py +118 -0
- chia/server/ws_connection.py +766 -0
- chia/simulator/__init__.py +0 -0
- chia/simulator/add_blocks_in_batches.py +54 -0
- chia/simulator/block_tools.py +2054 -0
- chia/simulator/full_node_simulator.py +794 -0
- chia/simulator/keyring.py +128 -0
- chia/simulator/setup_services.py +506 -0
- chia/simulator/simulator_constants.py +13 -0
- chia/simulator/simulator_full_node_rpc_api.py +99 -0
- chia/simulator/simulator_full_node_rpc_client.py +60 -0
- chia/simulator/simulator_protocol.py +29 -0
- chia/simulator/simulator_test_tools.py +164 -0
- chia/simulator/socket.py +24 -0
- chia/simulator/ssl_certs.py +114 -0
- chia/simulator/ssl_certs_1.py +697 -0
- chia/simulator/ssl_certs_10.py +697 -0
- chia/simulator/ssl_certs_2.py +697 -0
- chia/simulator/ssl_certs_3.py +697 -0
- chia/simulator/ssl_certs_4.py +697 -0
- chia/simulator/ssl_certs_5.py +697 -0
- chia/simulator/ssl_certs_6.py +697 -0
- chia/simulator/ssl_certs_7.py +697 -0
- chia/simulator/ssl_certs_8.py +697 -0
- chia/simulator/ssl_certs_9.py +697 -0
- chia/simulator/start_simulator.py +143 -0
- chia/simulator/wallet_tools.py +246 -0
- chia/ssl/__init__.py +0 -0
- chia/ssl/chia_ca.crt +19 -0
- chia/ssl/chia_ca.key +28 -0
- chia/ssl/create_ssl.py +249 -0
- chia/ssl/dst_root_ca.pem +20 -0
- chia/timelord/__init__.py +0 -0
- chia/timelord/iters_from_block.py +50 -0
- chia/timelord/timelord.py +1226 -0
- chia/timelord/timelord_api.py +138 -0
- chia/timelord/timelord_launcher.py +190 -0
- chia/timelord/timelord_state.py +244 -0
- chia/timelord/types.py +22 -0
- chia/types/__init__.py +0 -0
- chia/types/aliases.py +35 -0
- chia/types/block_protocol.py +20 -0
- chia/types/blockchain_format/__init__.py +0 -0
- chia/types/blockchain_format/classgroup.py +5 -0
- chia/types/blockchain_format/coin.py +28 -0
- chia/types/blockchain_format/foliage.py +8 -0
- chia/types/blockchain_format/pool_target.py +5 -0
- chia/types/blockchain_format/program.py +269 -0
- chia/types/blockchain_format/proof_of_space.py +135 -0
- chia/types/blockchain_format/reward_chain_block.py +6 -0
- chia/types/blockchain_format/serialized_program.py +5 -0
- chia/types/blockchain_format/sized_bytes.py +11 -0
- chia/types/blockchain_format/slots.py +9 -0
- chia/types/blockchain_format/sub_epoch_summary.py +5 -0
- chia/types/blockchain_format/tree_hash.py +72 -0
- chia/types/blockchain_format/vdf.py +86 -0
- chia/types/clvm_cost.py +13 -0
- chia/types/coin_record.py +43 -0
- chia/types/coin_spend.py +115 -0
- chia/types/condition_opcodes.py +73 -0
- chia/types/condition_with_args.py +16 -0
- chia/types/eligible_coin_spends.py +365 -0
- chia/types/end_of_slot_bundle.py +5 -0
- chia/types/fee_rate.py +38 -0
- chia/types/full_block.py +5 -0
- chia/types/generator_types.py +13 -0
- chia/types/header_block.py +5 -0
- chia/types/internal_mempool_item.py +18 -0
- chia/types/mempool_inclusion_status.py +9 -0
- chia/types/mempool_item.py +85 -0
- chia/types/mempool_submission_status.py +30 -0
- chia/types/mojos.py +7 -0
- chia/types/peer_info.py +64 -0
- chia/types/signing_mode.py +29 -0
- chia/types/spend_bundle.py +30 -0
- chia/types/spend_bundle_conditions.py +7 -0
- chia/types/transaction_queue_entry.py +55 -0
- chia/types/unfinished_block.py +5 -0
- chia/types/unfinished_header_block.py +37 -0
- chia/types/validation_state.py +14 -0
- chia/types/weight_proof.py +49 -0
- chia/util/__init__.py +0 -0
- chia/util/action_scope.py +168 -0
- chia/util/async_pool.py +226 -0
- chia/util/augmented_chain.py +134 -0
- chia/util/batches.py +42 -0
- chia/util/bech32m.py +126 -0
- chia/util/beta_metrics.py +119 -0
- chia/util/block_cache.py +56 -0
- chia/util/byte_types.py +12 -0
- chia/util/check_fork_next_block.py +33 -0
- chia/util/chia_logging.py +144 -0
- chia/util/chia_version.py +33 -0
- chia/util/collection.py +17 -0
- chia/util/condition_tools.py +201 -0
- chia/util/config.py +367 -0
- chia/util/cpu.py +22 -0
- chia/util/db_synchronous.py +23 -0
- chia/util/db_version.py +32 -0
- chia/util/db_wrapper.py +430 -0
- chia/util/default_root.py +27 -0
- chia/util/dump_keyring.py +93 -0
- chia/util/english.txt +2048 -0
- chia/util/errors.py +353 -0
- chia/util/file_keyring.py +469 -0
- chia/util/files.py +97 -0
- chia/util/full_block_utils.py +345 -0
- chia/util/generator_tools.py +72 -0
- chia/util/hash.py +31 -0
- chia/util/initial-config.yaml +694 -0
- chia/util/inline_executor.py +26 -0
- chia/util/ints.py +19 -0
- chia/util/ip_address.py +39 -0
- chia/util/json_util.py +37 -0
- chia/util/keychain.py +676 -0
- chia/util/keyring_wrapper.py +327 -0
- chia/util/limited_semaphore.py +41 -0
- chia/util/lock.py +49 -0
- chia/util/log_exceptions.py +32 -0
- chia/util/logging.py +36 -0
- chia/util/lru_cache.py +31 -0
- chia/util/math.py +20 -0
- chia/util/network.py +182 -0
- chia/util/paginator.py +48 -0
- chia/util/path.py +31 -0
- chia/util/permissions.py +20 -0
- chia/util/prev_transaction_block.py +21 -0
- chia/util/priority_mutex.py +95 -0
- chia/util/profiler.py +197 -0
- chia/util/recursive_replace.py +24 -0
- chia/util/safe_cancel_task.py +16 -0
- chia/util/service_groups.py +47 -0
- chia/util/setproctitle.py +22 -0
- chia/util/significant_bits.py +32 -0
- chia/util/ssl_check.py +213 -0
- chia/util/streamable.py +642 -0
- chia/util/task_referencer.py +59 -0
- chia/util/task_timing.py +382 -0
- chia/util/timing.py +67 -0
- chia/util/vdf_prover.py +30 -0
- chia/util/virtual_project_analysis.py +540 -0
- chia/util/ws_message.py +66 -0
- chia/wallet/__init__.py +0 -0
- chia/wallet/cat_wallet/__init__.py +0 -0
- chia/wallet/cat_wallet/cat_constants.py +75 -0
- chia/wallet/cat_wallet/cat_info.py +47 -0
- chia/wallet/cat_wallet/cat_outer_puzzle.py +120 -0
- chia/wallet/cat_wallet/cat_utils.py +164 -0
- chia/wallet/cat_wallet/cat_wallet.py +855 -0
- chia/wallet/cat_wallet/dao_cat_info.py +28 -0
- chia/wallet/cat_wallet/dao_cat_wallet.py +669 -0
- chia/wallet/cat_wallet/lineage_store.py +74 -0
- chia/wallet/cat_wallet/puzzles/__init__.py +0 -0
- chia/wallet/cat_wallet/puzzles/cat_truths.clib +31 -0
- chia/wallet/cat_wallet/puzzles/cat_v2.clsp +397 -0
- chia/wallet/cat_wallet/puzzles/cat_v2.clsp.hex +1 -0
- chia/wallet/cat_wallet/puzzles/delegated_tail.clsp +25 -0
- chia/wallet/cat_wallet/puzzles/delegated_tail.clsp.hex +1 -0
- chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp +15 -0
- chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp.hex +1 -0
- chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp +26 -0
- chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp.hex +1 -0
- chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp +42 -0
- chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp.hex +1 -0
- chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp +24 -0
- chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp.hex +1 -0
- chia/wallet/coin_selection.py +188 -0
- chia/wallet/conditions.py +1512 -0
- chia/wallet/dao_wallet/__init__.py +0 -0
- chia/wallet/dao_wallet/dao_info.py +61 -0
- chia/wallet/dao_wallet/dao_utils.py +811 -0
- chia/wallet/dao_wallet/dao_wallet.py +2119 -0
- chia/wallet/db_wallet/__init__.py +0 -0
- chia/wallet/db_wallet/db_wallet_puzzles.py +111 -0
- chia/wallet/derivation_record.py +30 -0
- chia/wallet/derive_keys.py +146 -0
- chia/wallet/did_wallet/__init__.py +0 -0
- chia/wallet/did_wallet/did_info.py +39 -0
- chia/wallet/did_wallet/did_wallet.py +1494 -0
- chia/wallet/did_wallet/did_wallet_puzzles.py +221 -0
- chia/wallet/did_wallet/puzzles/__init__.py +0 -0
- chia/wallet/did_wallet/puzzles/did_innerpuz.clsp +135 -0
- chia/wallet/did_wallet/puzzles/did_innerpuz.clsp.hex +1 -0
- chia/wallet/driver_protocol.py +26 -0
- chia/wallet/key_val_store.py +55 -0
- chia/wallet/lineage_proof.py +58 -0
- chia/wallet/nft_wallet/__init__.py +0 -0
- chia/wallet/nft_wallet/metadata_outer_puzzle.py +92 -0
- chia/wallet/nft_wallet/nft_info.py +120 -0
- chia/wallet/nft_wallet/nft_puzzles.py +305 -0
- chia/wallet/nft_wallet/nft_wallet.py +1687 -0
- chia/wallet/nft_wallet/ownership_outer_puzzle.py +101 -0
- chia/wallet/nft_wallet/puzzles/__init__.py +0 -0
- chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp +6 -0
- chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp.hex +1 -0
- chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp +6 -0
- chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp.hex +1 -0
- chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp +30 -0
- chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp.hex +1 -0
- chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp +28 -0
- chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp.hex +1 -0
- chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp +100 -0
- chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp.hex +1 -0
- chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp +78 -0
- chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp.hex +1 -0
- chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp +74 -0
- chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp.hex +1 -0
- chia/wallet/nft_wallet/singleton_outer_puzzle.py +101 -0
- chia/wallet/nft_wallet/transfer_program_puzzle.py +82 -0
- chia/wallet/nft_wallet/uncurry_nft.py +217 -0
- chia/wallet/notification_manager.py +117 -0
- chia/wallet/notification_store.py +178 -0
- chia/wallet/outer_puzzles.py +84 -0
- chia/wallet/payment.py +33 -0
- chia/wallet/puzzle_drivers.py +118 -0
- chia/wallet/puzzles/__init__.py +0 -0
- chia/wallet/puzzles/augmented_condition.clsp +13 -0
- chia/wallet/puzzles/augmented_condition.clsp.hex +1 -0
- chia/wallet/puzzles/clawback/__init__.py +0 -0
- chia/wallet/puzzles/clawback/drivers.py +188 -0
- chia/wallet/puzzles/clawback/metadata.py +38 -0
- chia/wallet/puzzles/clawback/puzzle_decorator.py +67 -0
- chia/wallet/puzzles/condition_codes.clib +77 -0
- chia/wallet/puzzles/curry-and-treehash.clib +102 -0
- chia/wallet/puzzles/curry.clib +135 -0
- chia/wallet/puzzles/curry_by_index.clib +16 -0
- chia/wallet/puzzles/dao_cat_eve.clsp +17 -0
- chia/wallet/puzzles/dao_cat_eve.clsp.hex +1 -0
- chia/wallet/puzzles/dao_cat_launcher.clsp +36 -0
- chia/wallet/puzzles/dao_cat_launcher.clsp.hex +1 -0
- chia/wallet/puzzles/dao_finished_state.clsp +35 -0
- chia/wallet/puzzles/dao_finished_state.clsp.hex +1 -0
- chia/wallet/puzzles/dao_finished_state.clsp.hex.sha256tree +1 -0
- chia/wallet/puzzles/dao_lockup.clsp +288 -0
- chia/wallet/puzzles/dao_lockup.clsp.hex +1 -0
- chia/wallet/puzzles/dao_lockup.clsp.hex.sha256tree +1 -0
- chia/wallet/puzzles/dao_proposal.clsp +377 -0
- chia/wallet/puzzles/dao_proposal.clsp.hex +1 -0
- chia/wallet/puzzles/dao_proposal.clsp.hex.sha256tree +1 -0
- chia/wallet/puzzles/dao_proposal_timer.clsp +78 -0
- chia/wallet/puzzles/dao_proposal_timer.clsp.hex +1 -0
- chia/wallet/puzzles/dao_proposal_timer.clsp.hex.sha256tree +1 -0
- chia/wallet/puzzles/dao_proposal_validator.clsp +87 -0
- chia/wallet/puzzles/dao_proposal_validator.clsp.hex +1 -0
- chia/wallet/puzzles/dao_proposal_validator.clsp.hex.sha256tree +1 -0
- chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp +240 -0
- chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex +1 -0
- chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex.sha256tree +1 -0
- chia/wallet/puzzles/dao_treasury.clsp +115 -0
- chia/wallet/puzzles/dao_treasury.clsp.hex +1 -0
- chia/wallet/puzzles/dao_update_proposal.clsp +44 -0
- chia/wallet/puzzles/dao_update_proposal.clsp.hex +1 -0
- chia/wallet/puzzles/deployed_puzzle_hashes.json +67 -0
- chia/wallet/puzzles/json.clib +25 -0
- chia/wallet/puzzles/load_clvm.py +161 -0
- chia/wallet/puzzles/merkle_utils.clib +18 -0
- chia/wallet/puzzles/notification.clsp +7 -0
- chia/wallet/puzzles/notification.clsp.hex +1 -0
- chia/wallet/puzzles/p2_1_of_n.clsp +22 -0
- chia/wallet/puzzles/p2_1_of_n.clsp.hex +1 -0
- chia/wallet/puzzles/p2_conditions.clsp +3 -0
- chia/wallet/puzzles/p2_conditions.clsp.hex +1 -0
- chia/wallet/puzzles/p2_conditions.py +26 -0
- chia/wallet/puzzles/p2_delegated_conditions.clsp +18 -0
- chia/wallet/puzzles/p2_delegated_conditions.clsp.hex +1 -0
- chia/wallet/puzzles/p2_delegated_conditions.py +21 -0
- chia/wallet/puzzles/p2_delegated_puzzle.clsp +19 -0
- chia/wallet/puzzles/p2_delegated_puzzle.clsp.hex +1 -0
- chia/wallet/puzzles/p2_delegated_puzzle.py +34 -0
- chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp +91 -0
- chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp.hex +1 -0
- chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +160 -0
- chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp +108 -0
- chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp.hex +1 -0
- chia/wallet/puzzles/p2_m_of_n_delegate_direct.py +21 -0
- chia/wallet/puzzles/p2_parent.clsp +19 -0
- chia/wallet/puzzles/p2_parent.clsp.hex +1 -0
- chia/wallet/puzzles/p2_puzzle_hash.clsp +18 -0
- chia/wallet/puzzles/p2_puzzle_hash.clsp.hex +1 -0
- chia/wallet/puzzles/p2_puzzle_hash.py +27 -0
- chia/wallet/puzzles/p2_singleton.clsp +30 -0
- chia/wallet/puzzles/p2_singleton.clsp.hex +1 -0
- chia/wallet/puzzles/p2_singleton_aggregator.clsp +81 -0
- chia/wallet/puzzles/p2_singleton_aggregator.clsp.hex +1 -0
- chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp +50 -0
- chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp.hex +1 -0
- chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp +47 -0
- chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp.hex +1 -0
- chia/wallet/puzzles/puzzle_utils.py +34 -0
- chia/wallet/puzzles/settlement_payments.clsp +49 -0
- chia/wallet/puzzles/settlement_payments.clsp.hex +1 -0
- chia/wallet/puzzles/sha256tree.clib +11 -0
- chia/wallet/puzzles/singleton_launcher.clsp +16 -0
- chia/wallet/puzzles/singleton_launcher.clsp.hex +1 -0
- chia/wallet/puzzles/singleton_top_layer.clsp +177 -0
- chia/wallet/puzzles/singleton_top_layer.clsp.hex +1 -0
- chia/wallet/puzzles/singleton_top_layer.py +296 -0
- chia/wallet/puzzles/singleton_top_layer_v1_1.clsp +107 -0
- chia/wallet/puzzles/singleton_top_layer_v1_1.clsp.hex +1 -0
- chia/wallet/puzzles/singleton_top_layer_v1_1.py +345 -0
- chia/wallet/puzzles/singleton_truths.clib +21 -0
- chia/wallet/puzzles/tails.py +348 -0
- chia/wallet/puzzles/utility_macros.clib +48 -0
- chia/wallet/signer_protocol.py +125 -0
- chia/wallet/singleton.py +106 -0
- chia/wallet/singleton_record.py +30 -0
- chia/wallet/trade_manager.py +1102 -0
- chia/wallet/trade_record.py +67 -0
- chia/wallet/trading/__init__.py +0 -0
- chia/wallet/trading/offer.py +702 -0
- chia/wallet/trading/trade_status.py +13 -0
- chia/wallet/trading/trade_store.py +526 -0
- chia/wallet/transaction_record.py +158 -0
- chia/wallet/transaction_sorting.py +14 -0
- chia/wallet/uncurried_puzzle.py +17 -0
- chia/wallet/util/__init__.py +0 -0
- chia/wallet/util/address_type.py +55 -0
- chia/wallet/util/blind_signer_tl.py +164 -0
- chia/wallet/util/clvm_streamable.py +203 -0
- chia/wallet/util/compute_hints.py +66 -0
- chia/wallet/util/compute_memos.py +43 -0
- chia/wallet/util/curry_and_treehash.py +91 -0
- chia/wallet/util/debug_spend_bundle.py +232 -0
- chia/wallet/util/merkle_tree.py +100 -0
- chia/wallet/util/merkle_utils.py +102 -0
- chia/wallet/util/new_peak_queue.py +82 -0
- chia/wallet/util/notifications.py +12 -0
- chia/wallet/util/peer_request_cache.py +174 -0
- chia/wallet/util/pprint.py +39 -0
- chia/wallet/util/puzzle_compression.py +95 -0
- chia/wallet/util/puzzle_decorator.py +100 -0
- chia/wallet/util/puzzle_decorator_type.py +7 -0
- chia/wallet/util/query_filter.py +59 -0
- chia/wallet/util/transaction_type.py +23 -0
- chia/wallet/util/tx_config.py +158 -0
- chia/wallet/util/wallet_sync_utils.py +351 -0
- chia/wallet/util/wallet_types.py +72 -0
- chia/wallet/vc_wallet/__init__.py +0 -0
- chia/wallet/vc_wallet/cr_cat_drivers.py +664 -0
- chia/wallet/vc_wallet/cr_cat_wallet.py +877 -0
- chia/wallet/vc_wallet/cr_outer_puzzle.py +102 -0
- chia/wallet/vc_wallet/cr_puzzles/__init__.py +0 -0
- chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp +3 -0
- chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp.hex +1 -0
- chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp +304 -0
- chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp.hex +1 -0
- chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp +45 -0
- chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_drivers.py +838 -0
- chia/wallet/vc_wallet/vc_puzzles/__init__.py +0 -0
- chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp +30 -0
- chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp +75 -0
- chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp +32 -0
- chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp +80 -0
- chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp +163 -0
- chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp +16 -0
- chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp +74 -0
- chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp +23 -0
- chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp +64 -0
- chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_store.py +263 -0
- chia/wallet/vc_wallet/vc_wallet.py +638 -0
- chia/wallet/wallet.py +698 -0
- chia/wallet/wallet_action_scope.py +96 -0
- chia/wallet/wallet_blockchain.py +244 -0
- chia/wallet/wallet_coin_record.py +72 -0
- chia/wallet/wallet_coin_store.py +351 -0
- chia/wallet/wallet_info.py +35 -0
- chia/wallet/wallet_interested_store.py +188 -0
- chia/wallet/wallet_nft_store.py +279 -0
- chia/wallet/wallet_node.py +1765 -0
- chia/wallet/wallet_node_api.py +207 -0
- chia/wallet/wallet_pool_store.py +119 -0
- chia/wallet/wallet_protocol.py +90 -0
- chia/wallet/wallet_puzzle_store.py +396 -0
- chia/wallet/wallet_retry_store.py +70 -0
- chia/wallet/wallet_singleton_store.py +259 -0
- chia/wallet/wallet_spend_bundle.py +25 -0
- chia/wallet/wallet_state_manager.py +2819 -0
- chia/wallet/wallet_transaction_store.py +496 -0
- chia/wallet/wallet_user_store.py +110 -0
- chia/wallet/wallet_weight_proof_handler.py +126 -0
- chia_blockchain-2.5.1rc1.dist-info/LICENSE +201 -0
- chia_blockchain-2.5.1rc1.dist-info/METADATA +156 -0
- chia_blockchain-2.5.1rc1.dist-info/RECORD +1042 -0
- chia_blockchain-2.5.1rc1.dist-info/WHEEL +4 -0
- chia_blockchain-2.5.1rc1.dist-info/entry_points.txt +17 -0
- mozilla-ca/cacert.pem +3611 -0
|
@@ -0,0 +1,1692 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import contextlib
|
|
5
|
+
import functools
|
|
6
|
+
import logging
|
|
7
|
+
from collections.abc import Awaitable
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import Callable, Optional
|
|
10
|
+
from unittest.mock import MagicMock
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
from aiosqlite import Error as AIOSqliteError
|
|
14
|
+
from chia_rs import G2Element, confirm_not_included_already_hashed
|
|
15
|
+
from chiabip158 import PyBIP158
|
|
16
|
+
from colorlog import getLogger
|
|
17
|
+
|
|
18
|
+
from chia._tests.connection_utils import connect_and_get_peer, disconnect_all, disconnect_all_and_reconnect
|
|
19
|
+
from chia._tests.util.blockchain_mock import BlockchainMock
|
|
20
|
+
from chia._tests.util.misc import patch_request_handler, wallet_height_at_least
|
|
21
|
+
from chia._tests.util.setup_nodes import OldSimulatorsAndWallets
|
|
22
|
+
from chia._tests.util.time_out_assert import time_out_assert, time_out_assert_not_none
|
|
23
|
+
from chia._tests.weight_proof.test_weight_proof import load_blocks_dont_validate
|
|
24
|
+
from chia.consensus.block_body_validation import ForkInfo
|
|
25
|
+
from chia.consensus.block_record import BlockRecord
|
|
26
|
+
from chia.consensus.block_rewards import calculate_base_farmer_reward, calculate_pool_reward
|
|
27
|
+
from chia.consensus.constants import ConsensusConstants
|
|
28
|
+
from chia.consensus.difficulty_adjustment import get_next_sub_slot_iters_and_difficulty
|
|
29
|
+
from chia.full_node.full_node_api import FullNodeAPI
|
|
30
|
+
from chia.full_node.weight_proof import WeightProofHandler
|
|
31
|
+
from chia.protocols import full_node_protocol, wallet_protocol
|
|
32
|
+
from chia.protocols.protocol_message_types import ProtocolMessageTypes
|
|
33
|
+
from chia.protocols.shared_protocol import Capability
|
|
34
|
+
from chia.protocols.wallet_protocol import (
|
|
35
|
+
CoinState,
|
|
36
|
+
RequestAdditions,
|
|
37
|
+
RespondAdditions,
|
|
38
|
+
RespondBlockHeader,
|
|
39
|
+
RespondBlockHeaders,
|
|
40
|
+
SendTransaction,
|
|
41
|
+
)
|
|
42
|
+
from chia.server.outbound_message import Message, make_msg
|
|
43
|
+
from chia.server.server import ChiaServer
|
|
44
|
+
from chia.server.ws_connection import WSChiaConnection
|
|
45
|
+
from chia.simulator.add_blocks_in_batches import add_blocks_in_batches
|
|
46
|
+
from chia.simulator.block_tools import BlockTools
|
|
47
|
+
from chia.simulator.full_node_simulator import FullNodeSimulator
|
|
48
|
+
from chia.simulator.simulator_protocol import FarmNewBlockProtocol
|
|
49
|
+
from chia.types.blockchain_format.program import Program
|
|
50
|
+
from chia.types.blockchain_format.serialized_program import SerializedProgram
|
|
51
|
+
from chia.types.blockchain_format.sized_bytes import bytes32
|
|
52
|
+
from chia.types.coin_spend import make_spend
|
|
53
|
+
from chia.types.condition_opcodes import ConditionOpcode
|
|
54
|
+
from chia.types.full_block import FullBlock
|
|
55
|
+
from chia.types.peer_info import PeerInfo
|
|
56
|
+
from chia.types.spend_bundle import SpendBundle
|
|
57
|
+
from chia.types.validation_state import ValidationState
|
|
58
|
+
from chia.util.hash import std_hash
|
|
59
|
+
from chia.util.ints import uint32, uint64, uint128
|
|
60
|
+
from chia.wallet.nft_wallet.nft_wallet import NFTWallet
|
|
61
|
+
from chia.wallet.payment import Payment
|
|
62
|
+
from chia.wallet.util.compute_memos import compute_memos
|
|
63
|
+
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
|
|
64
|
+
from chia.wallet.util.wallet_sync_utils import PeerRequestException
|
|
65
|
+
from chia.wallet.util.wallet_types import WalletIdentifier
|
|
66
|
+
from chia.wallet.wallet_state_manager import WalletStateManager
|
|
67
|
+
from chia.wallet.wallet_weight_proof_handler import get_wp_fork_point
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
async def get_tx_count(wsm: WalletStateManager, wallet_id: int) -> int:
|
|
71
|
+
txs = await wsm.get_all_transactions(wallet_id)
|
|
72
|
+
return len(txs)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
async def get_nft_count(wallet: NFTWallet) -> int:
|
|
76
|
+
return await wallet.get_nft_count()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
log = getLogger(__name__)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
pytestmark = pytest.mark.standard_block_tools
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@pytest.mark.limit_consensus_modes(reason="save time")
|
|
86
|
+
@pytest.mark.anyio
|
|
87
|
+
async def test_request_block_headers(
|
|
88
|
+
simulator_and_wallet: OldSimulatorsAndWallets, default_400_blocks: list[FullBlock]
|
|
89
|
+
) -> None:
|
|
90
|
+
# Tests the edge case of receiving funds right before the recent blocks in weight proof
|
|
91
|
+
[full_node_api], [(wallet_node, _)], bt = simulator_and_wallet
|
|
92
|
+
|
|
93
|
+
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
94
|
+
ph = await wallet.get_new_puzzlehash()
|
|
95
|
+
await add_blocks_in_batches(default_400_blocks[:100], full_node_api.full_node)
|
|
96
|
+
|
|
97
|
+
msg = await full_node_api.request_block_headers(wallet_protocol.RequestBlockHeaders(uint32(10), uint32(15), False))
|
|
98
|
+
assert msg is not None
|
|
99
|
+
assert msg.type == ProtocolMessageTypes.respond_block_headers.value
|
|
100
|
+
res_block_headers = RespondBlockHeaders.from_bytes(msg.data)
|
|
101
|
+
bh = res_block_headers.header_blocks
|
|
102
|
+
assert len(bh) == 6
|
|
103
|
+
assert [x.reward_chain_block.height for x in default_400_blocks[10:16]] == [x.reward_chain_block.height for x in bh]
|
|
104
|
+
assert [x.foliage for x in default_400_blocks[10:16]] == [x.foliage for x in bh]
|
|
105
|
+
assert [x.transactions_filter for x in bh] == [b"\x00"] * 6
|
|
106
|
+
|
|
107
|
+
num_blocks = 20
|
|
108
|
+
new_blocks = bt.get_consecutive_blocks(num_blocks, block_list_input=default_400_blocks, pool_reward_puzzle_hash=ph)
|
|
109
|
+
await add_blocks_in_batches(new_blocks, full_node_api.full_node)
|
|
110
|
+
msg = await full_node_api.request_block_headers(wallet_protocol.RequestBlockHeaders(uint32(110), uint32(115), True))
|
|
111
|
+
assert msg is not None
|
|
112
|
+
res_block_headers = RespondBlockHeaders.from_bytes(msg.data)
|
|
113
|
+
bh = res_block_headers.header_blocks
|
|
114
|
+
assert len(bh) == 6
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@pytest.mark.limit_consensus_modes(reason="save time")
|
|
118
|
+
@pytest.mark.anyio
|
|
119
|
+
@pytest.mark.parametrize("rewards_only_tx_block", [True, False])
|
|
120
|
+
async def test_request_block_headers_transactions_filter(
|
|
121
|
+
one_node_one_block: tuple[FullNodeSimulator, ChiaServer, BlockTools], rewards_only_tx_block: bool
|
|
122
|
+
) -> None:
|
|
123
|
+
"""
|
|
124
|
+
Tests that `request_block_headers` returns a transactions filter that
|
|
125
|
+
correctly reflects the blocks transactions.
|
|
126
|
+
|
|
127
|
+
We use `rewards_only_tx_block` to control whether the test transaction
|
|
128
|
+
block contains our test spend as well, or just the reward coins.
|
|
129
|
+
|
|
130
|
+
For completeness, we're also comparing the outcome of
|
|
131
|
+
`request_block_headers` in this regard, to `request_header_blocks` as
|
|
132
|
+
well as `request_block_header`.
|
|
133
|
+
"""
|
|
134
|
+
full_node_api, _, bt = one_node_one_block
|
|
135
|
+
ph = SerializedProgram.to(1).get_tree_hash()
|
|
136
|
+
for _ in range(2):
|
|
137
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
138
|
+
if rewards_only_tx_block:
|
|
139
|
+
# Generate a transaction block without any spends
|
|
140
|
+
sb = None
|
|
141
|
+
else:
|
|
142
|
+
# Generate a transaction block with our test spend
|
|
143
|
+
coins = await full_node_api.full_node.coin_store.get_coin_records_by_puzzle_hash(False, ph)
|
|
144
|
+
[parent_coin] = [c.coin for c in coins if c.coin.amount == 250_000_000_000]
|
|
145
|
+
sb = SpendBundle(
|
|
146
|
+
[
|
|
147
|
+
make_spend(
|
|
148
|
+
parent_coin, SerializedProgram.to(1), SerializedProgram.to([[ConditionOpcode.CREATE_COIN, ph, 42]])
|
|
149
|
+
)
|
|
150
|
+
],
|
|
151
|
+
G2Element(),
|
|
152
|
+
)
|
|
153
|
+
blocks = await full_node_api.get_all_full_blocks()
|
|
154
|
+
blocks = bt.get_consecutive_blocks(1, blocks, guarantee_transaction_block=True, transaction_data=sb)
|
|
155
|
+
new_block = blocks[-1]
|
|
156
|
+
await full_node_api.full_node.add_block(new_block)
|
|
157
|
+
# Compute the expected transactions filter
|
|
158
|
+
if rewards_only_tx_block:
|
|
159
|
+
byte_array_tx = [bytearray(coin.puzzle_hash) for coin in new_block.get_included_reward_coins()]
|
|
160
|
+
else:
|
|
161
|
+
assert sb is not None
|
|
162
|
+
[test_spend] = sb.additions()
|
|
163
|
+
byte_array_tx = (
|
|
164
|
+
[bytearray(test_spend.puzzle_hash)]
|
|
165
|
+
+ [bytearray(coin.puzzle_hash) for coin in new_block.get_included_reward_coins()]
|
|
166
|
+
+ [bytearray(parent_coin.name())]
|
|
167
|
+
)
|
|
168
|
+
expected_transactions_filter = bytes(PyBIP158(byte_array_tx).GetEncoded())
|
|
169
|
+
# Perform the request and check the transactions filter
|
|
170
|
+
msg = await full_node_api.request_block_headers(
|
|
171
|
+
wallet_protocol.RequestBlockHeaders(uint32(new_block.height), uint32(new_block.height), True)
|
|
172
|
+
)
|
|
173
|
+
assert msg is not None
|
|
174
|
+
res_block_headers = RespondBlockHeaders.from_bytes(msg.data)
|
|
175
|
+
block_headers = res_block_headers.header_blocks
|
|
176
|
+
assert len(block_headers) == 1
|
|
177
|
+
block_header = block_headers[0]
|
|
178
|
+
assert block_header.transactions_filter == expected_transactions_filter
|
|
179
|
+
# Go further and compare this to the outcome of request_header_blocks
|
|
180
|
+
msg = await full_node_api.request_header_blocks(
|
|
181
|
+
wallet_protocol.RequestHeaderBlocks(uint32(new_block.height), uint32(new_block.height))
|
|
182
|
+
)
|
|
183
|
+
assert msg is not None
|
|
184
|
+
block_headers_res = RespondBlockHeaders.from_bytes(msg.data)
|
|
185
|
+
assert block_headers_res.header_blocks == block_headers
|
|
186
|
+
assert block_headers_res.header_blocks[0].transactions_filter == expected_transactions_filter
|
|
187
|
+
# Go even further and compare this to the outcome of request_block_header
|
|
188
|
+
msg = await full_node_api.request_block_header(wallet_protocol.RequestBlockHeader(uint32(new_block.height)))
|
|
189
|
+
assert msg is not None
|
|
190
|
+
block_header_res = RespondBlockHeader.from_bytes(msg.data)
|
|
191
|
+
assert block_header_res.header_block == block_header
|
|
192
|
+
assert block_header_res.header_block.transactions_filter == expected_transactions_filter
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# @pytest.mark.parametrize(
|
|
196
|
+
# "test_case",
|
|
197
|
+
# [(1_000_000, 10_000_010, False, ProtocolMessageTypes.reject_block_headers)],
|
|
198
|
+
# [(80, 99, False, ProtocolMessageTypes.respond_block_headers)],
|
|
199
|
+
# [(10, 8, False, None)],
|
|
200
|
+
# )
|
|
201
|
+
@pytest.mark.anyio
|
|
202
|
+
async def test_request_block_headers_rejected(
|
|
203
|
+
simulator_and_wallet: OldSimulatorsAndWallets, default_400_blocks: list[FullBlock]
|
|
204
|
+
) -> None:
|
|
205
|
+
# Tests the edge case of receiving funds right before the recent blocks in weight proof
|
|
206
|
+
[full_node_api], _, _ = simulator_and_wallet
|
|
207
|
+
|
|
208
|
+
# start_height, end_height, return_filter, expected_res = test_case
|
|
209
|
+
|
|
210
|
+
msg = await full_node_api.request_block_headers(
|
|
211
|
+
wallet_protocol.RequestBlockHeaders(uint32(1_000_000), uint32(1_000_010), False)
|
|
212
|
+
)
|
|
213
|
+
assert msg is not None
|
|
214
|
+
assert msg.type == ProtocolMessageTypes.reject_block_headers.value
|
|
215
|
+
|
|
216
|
+
await add_blocks_in_batches(default_400_blocks[:150], full_node_api.full_node)
|
|
217
|
+
msg = await full_node_api.request_block_headers(wallet_protocol.RequestBlockHeaders(uint32(80), uint32(99), False))
|
|
218
|
+
assert msg is not None
|
|
219
|
+
assert msg.type == ProtocolMessageTypes.respond_block_headers.value
|
|
220
|
+
msg = await full_node_api.request_block_headers(wallet_protocol.RequestBlockHeaders(uint32(10), uint32(8), False))
|
|
221
|
+
assert msg is not None
|
|
222
|
+
assert msg.type == ProtocolMessageTypes.reject_block_headers.value
|
|
223
|
+
|
|
224
|
+
msg = await full_node_api.request_block_headers(wallet_protocol.RequestBlockHeaders(uint32(10), uint32(8), True))
|
|
225
|
+
assert msg is not None
|
|
226
|
+
assert msg.type == ProtocolMessageTypes.reject_block_headers.value
|
|
227
|
+
|
|
228
|
+
# test for 128 blocks to fetch at once limit
|
|
229
|
+
msg = await full_node_api.request_block_headers(wallet_protocol.RequestBlockHeaders(uint32(10), uint32(140), True))
|
|
230
|
+
assert msg is not None
|
|
231
|
+
assert msg.type == ProtocolMessageTypes.reject_block_headers.value
|
|
232
|
+
|
|
233
|
+
msg = await full_node_api.request_block_headers(wallet_protocol.RequestBlockHeaders(uint32(90), uint32(160), False))
|
|
234
|
+
assert msg is not None
|
|
235
|
+
assert msg.type == ProtocolMessageTypes.reject_block_headers.value
|
|
236
|
+
msg = await full_node_api.request_block_headers(wallet_protocol.RequestBlockHeaders(uint32(90), uint32(160), True))
|
|
237
|
+
assert msg is not None
|
|
238
|
+
assert msg.type == ProtocolMessageTypes.reject_block_headers.value
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
@pytest.mark.parametrize(
|
|
242
|
+
"two_wallet_nodes",
|
|
243
|
+
[dict(disable_capabilities=[Capability.BLOCK_HEADERS]), dict(disable_capabilities=[Capability.BASE])],
|
|
244
|
+
indirect=True,
|
|
245
|
+
)
|
|
246
|
+
@pytest.mark.limit_consensus_modes(reason="save time")
|
|
247
|
+
@pytest.mark.anyio
|
|
248
|
+
async def test_basic_sync_wallet(
|
|
249
|
+
two_wallet_nodes: OldSimulatorsAndWallets,
|
|
250
|
+
default_400_blocks: list[FullBlock],
|
|
251
|
+
self_hostname: str,
|
|
252
|
+
use_delta_sync: bool,
|
|
253
|
+
) -> None:
|
|
254
|
+
[full_node_api], wallets, bt = two_wallet_nodes
|
|
255
|
+
full_node = full_node_api.full_node
|
|
256
|
+
full_node_server = full_node.server
|
|
257
|
+
|
|
258
|
+
# Trusted node sync
|
|
259
|
+
wallets[0][0].config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
|
|
260
|
+
wallets[0][0].config["use_delta_sync"] = use_delta_sync
|
|
261
|
+
|
|
262
|
+
# Untrusted node sync
|
|
263
|
+
wallets[1][0].config["trusted_peers"] = {}
|
|
264
|
+
wallets[1][0].config["use_delta_sync"] = use_delta_sync
|
|
265
|
+
|
|
266
|
+
await add_blocks_in_batches(default_400_blocks, full_node)
|
|
267
|
+
for wallet_node, wallet_server in wallets:
|
|
268
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
|
|
269
|
+
|
|
270
|
+
for wallet_node, wallet_server in wallets:
|
|
271
|
+
await time_out_assert(100, wallet_height_at_least, True, wallet_node, len(default_400_blocks) - 1)
|
|
272
|
+
|
|
273
|
+
# Tests a reorg with the wallet
|
|
274
|
+
num_blocks = 30
|
|
275
|
+
blocks_reorg = bt.get_consecutive_blocks(num_blocks - 1, block_list_input=default_400_blocks[:-5])
|
|
276
|
+
blocks_reorg = bt.get_consecutive_blocks(1, blocks_reorg, guarantee_transaction_block=True, current_time=True)
|
|
277
|
+
|
|
278
|
+
await add_blocks_in_batches(blocks_reorg[1:], full_node)
|
|
279
|
+
|
|
280
|
+
for wallet_node, wallet_server in wallets:
|
|
281
|
+
await time_out_assert(
|
|
282
|
+
100, wallet_height_at_least, True, wallet_node, len(default_400_blocks) + num_blocks - 5 - 1
|
|
283
|
+
)
|
|
284
|
+
await time_out_assert(20, wallet_node.wallet_state_manager.synced)
|
|
285
|
+
await disconnect_all(wallet_server)
|
|
286
|
+
assert not (await wallet_node.wallet_state_manager.synced())
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
@pytest.mark.parametrize(
|
|
290
|
+
"two_wallet_nodes",
|
|
291
|
+
[dict(disable_capabilities=[Capability.BLOCK_HEADERS]), dict(disable_capabilities=[Capability.BASE])],
|
|
292
|
+
indirect=True,
|
|
293
|
+
)
|
|
294
|
+
@pytest.mark.limit_consensus_modes(reason="save time")
|
|
295
|
+
@pytest.mark.anyio
|
|
296
|
+
async def test_almost_recent(
|
|
297
|
+
two_wallet_nodes: OldSimulatorsAndWallets,
|
|
298
|
+
default_400_blocks: list[FullBlock],
|
|
299
|
+
self_hostname: str,
|
|
300
|
+
blockchain_constants: ConsensusConstants,
|
|
301
|
+
use_delta_sync: bool,
|
|
302
|
+
) -> None:
|
|
303
|
+
# Tests the edge case of receiving funds right before the recent blocks in weight proof
|
|
304
|
+
[full_node_api], wallets, bt = two_wallet_nodes
|
|
305
|
+
full_node = full_node_api.full_node
|
|
306
|
+
full_node_server = full_node.server
|
|
307
|
+
|
|
308
|
+
# Trusted node sync
|
|
309
|
+
wallets[0][0].config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
|
|
310
|
+
wallets[0][0].config["use_delta_sync"] = use_delta_sync
|
|
311
|
+
|
|
312
|
+
# Untrusted node sync
|
|
313
|
+
wallets[1][0].config["trusted_peers"] = {}
|
|
314
|
+
wallets[1][0].config["use_delta_sync"] = use_delta_sync
|
|
315
|
+
|
|
316
|
+
base_num_blocks = 400
|
|
317
|
+
await add_blocks_in_batches(default_400_blocks, full_node)
|
|
318
|
+
|
|
319
|
+
all_blocks = default_400_blocks
|
|
320
|
+
both_phs = []
|
|
321
|
+
for wallet_node, wallet_server in wallets:
|
|
322
|
+
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
323
|
+
both_phs.append(await wallet.get_new_puzzlehash())
|
|
324
|
+
|
|
325
|
+
for i in range(20):
|
|
326
|
+
# Tests a reorg with the wallet
|
|
327
|
+
ph = both_phs[i % 2]
|
|
328
|
+
all_blocks = bt.get_consecutive_blocks(1, block_list_input=all_blocks, pool_reward_puzzle_hash=ph)
|
|
329
|
+
await full_node.add_block(all_blocks[-1])
|
|
330
|
+
|
|
331
|
+
new_blocks = bt.get_consecutive_blocks(
|
|
332
|
+
blockchain_constants.WEIGHT_PROOF_RECENT_BLOCKS + 10, block_list_input=all_blocks
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
await add_blocks_in_batches(new_blocks[base_num_blocks + 20 :], full_node)
|
|
336
|
+
|
|
337
|
+
for wallet_node, wallet_server in wallets:
|
|
338
|
+
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
339
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
|
|
340
|
+
await time_out_assert(30, wallet.get_confirmed_balance, 10 * calculate_pool_reward(uint32(1000)))
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
@pytest.mark.anyio
|
|
344
|
+
async def test_backtrack_sync_wallet(
|
|
345
|
+
two_wallet_nodes: OldSimulatorsAndWallets,
|
|
346
|
+
default_400_blocks: list[FullBlock],
|
|
347
|
+
self_hostname: str,
|
|
348
|
+
use_delta_sync: bool,
|
|
349
|
+
) -> None:
|
|
350
|
+
full_nodes, wallets, _ = two_wallet_nodes
|
|
351
|
+
full_node_api = full_nodes[0]
|
|
352
|
+
full_node_server = full_node_api.full_node.server
|
|
353
|
+
|
|
354
|
+
# Trusted node sync
|
|
355
|
+
wallets[0][0].config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
|
|
356
|
+
wallets[0][0].config["use_delta_sync"] = use_delta_sync
|
|
357
|
+
|
|
358
|
+
# Untrusted node sync
|
|
359
|
+
wallets[1][0].config["trusted_peers"] = {}
|
|
360
|
+
wallets[1][0].config["use_delta_sync"] = use_delta_sync
|
|
361
|
+
|
|
362
|
+
for block in default_400_blocks[:20]:
|
|
363
|
+
await full_node_api.full_node.add_block(block)
|
|
364
|
+
|
|
365
|
+
for wallet_node, wallet_server in wallets:
|
|
366
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
|
|
367
|
+
|
|
368
|
+
for wallet_node, wallet_server in wallets:
|
|
369
|
+
await time_out_assert(100, wallet_height_at_least, True, wallet_node, 19)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
# Tests a reorg with the wallet
|
|
373
|
+
@pytest.mark.anyio
|
|
374
|
+
async def test_short_batch_sync_wallet(
|
|
375
|
+
two_wallet_nodes: OldSimulatorsAndWallets,
|
|
376
|
+
default_400_blocks: list[FullBlock],
|
|
377
|
+
self_hostname: str,
|
|
378
|
+
use_delta_sync: bool,
|
|
379
|
+
) -> None:
|
|
380
|
+
[full_node_api], wallets, _ = two_wallet_nodes
|
|
381
|
+
full_node = full_node_api.full_node
|
|
382
|
+
full_node_server = full_node.server
|
|
383
|
+
|
|
384
|
+
# Trusted node sync
|
|
385
|
+
wallets[0][0].config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
|
|
386
|
+
wallets[0][0].config["use_delta_sync"] = use_delta_sync
|
|
387
|
+
|
|
388
|
+
# Untrusted node sync
|
|
389
|
+
wallets[1][0].config["trusted_peers"] = {}
|
|
390
|
+
wallets[1][0].config["use_delta_sync"] = use_delta_sync
|
|
391
|
+
|
|
392
|
+
await add_blocks_in_batches(default_400_blocks[:200], full_node)
|
|
393
|
+
|
|
394
|
+
for wallet_node, wallet_server in wallets:
|
|
395
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
|
|
396
|
+
|
|
397
|
+
for wallet_node, wallet_server in wallets:
|
|
398
|
+
await time_out_assert(100, wallet_height_at_least, True, wallet_node, 199)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
@pytest.mark.limit_consensus_modes(reason="save time")
|
|
402
|
+
@pytest.mark.anyio
|
|
403
|
+
async def test_long_sync_wallet(
|
|
404
|
+
two_wallet_nodes: OldSimulatorsAndWallets,
|
|
405
|
+
default_1000_blocks: list[FullBlock],
|
|
406
|
+
default_400_blocks: list[FullBlock],
|
|
407
|
+
self_hostname: str,
|
|
408
|
+
use_delta_sync: bool,
|
|
409
|
+
) -> None:
|
|
410
|
+
[full_node_api], wallets, bt = two_wallet_nodes
|
|
411
|
+
full_node = full_node_api.full_node
|
|
412
|
+
full_node_server = full_node.server
|
|
413
|
+
|
|
414
|
+
# Trusted node sync
|
|
415
|
+
wallets[0][0].config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
|
|
416
|
+
wallets[0][0].config["use_delta_sync"] = use_delta_sync
|
|
417
|
+
|
|
418
|
+
# Untrusted node sync
|
|
419
|
+
wallets[1][0].config["trusted_peers"] = {}
|
|
420
|
+
wallets[1][0].config["use_delta_sync"] = use_delta_sync
|
|
421
|
+
await add_blocks_in_batches(default_400_blocks, full_node)
|
|
422
|
+
|
|
423
|
+
for wallet_node, wallet_server in wallets:
|
|
424
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
|
|
425
|
+
|
|
426
|
+
for wallet_node, wallet_server in wallets:
|
|
427
|
+
await time_out_assert(600, wallet_height_at_least, True, wallet_node, len(default_400_blocks) - 1)
|
|
428
|
+
|
|
429
|
+
# Tests a long reorg
|
|
430
|
+
await add_blocks_in_batches(default_1000_blocks, full_node)
|
|
431
|
+
|
|
432
|
+
# ony the wallet with untrusted sync needs to reconnect
|
|
433
|
+
await disconnect_all_and_reconnect(wallets[1][1], full_node_server, self_hostname)
|
|
434
|
+
for wallet_node, wallet_server in wallets:
|
|
435
|
+
log.info(f"wallet node height is {await wallet_node.wallet_state_manager.blockchain.get_finished_sync_up_to()}")
|
|
436
|
+
await time_out_assert(200, wallet_height_at_least, True, wallet_node, len(default_1000_blocks) - 1)
|
|
437
|
+
|
|
438
|
+
# Tests a short reorg
|
|
439
|
+
num_blocks = 30
|
|
440
|
+
blocks_reorg = bt.get_consecutive_blocks(num_blocks, block_list_input=default_1000_blocks[:-5])
|
|
441
|
+
|
|
442
|
+
block_record = await full_node.blockchain.get_block_record_from_db(blocks_reorg[-num_blocks - 10].header_hash)
|
|
443
|
+
sub_slot_iters, difficulty = get_next_sub_slot_iters_and_difficulty(
|
|
444
|
+
full_node.constants, True, block_record, full_node.blockchain
|
|
445
|
+
)
|
|
446
|
+
fork_height = blocks_reorg[-num_blocks - 10].height - 1
|
|
447
|
+
await full_node.add_block_batch(
|
|
448
|
+
blocks_reorg[-num_blocks - 10 : -1],
|
|
449
|
+
PeerInfo("0.0.0.0", 0),
|
|
450
|
+
ForkInfo(fork_height, fork_height, blocks_reorg[-num_blocks - 10].prev_header_hash),
|
|
451
|
+
ValidationState(sub_slot_iters, difficulty, None),
|
|
452
|
+
)
|
|
453
|
+
await full_node.add_block(blocks_reorg[-1])
|
|
454
|
+
|
|
455
|
+
for wallet_node, wallet_server in wallets:
|
|
456
|
+
await time_out_assert(
|
|
457
|
+
120, wallet_height_at_least, True, wallet_node, len(default_1000_blocks) + num_blocks - 5 - 1
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
@pytest.mark.limit_consensus_modes(reason="save time")
|
|
462
|
+
@pytest.mark.anyio
|
|
463
|
+
async def test_wallet_reorg_sync(
|
|
464
|
+
two_wallet_nodes: OldSimulatorsAndWallets,
|
|
465
|
+
default_400_blocks: list[FullBlock],
|
|
466
|
+
self_hostname: str,
|
|
467
|
+
use_delta_sync: bool,
|
|
468
|
+
) -> None:
|
|
469
|
+
num_blocks = 5
|
|
470
|
+
[full_node_api], wallets, bt = two_wallet_nodes
|
|
471
|
+
full_node = full_node_api.full_node
|
|
472
|
+
full_node_server = full_node.server
|
|
473
|
+
|
|
474
|
+
# Trusted node sync
|
|
475
|
+
wallets[0][0].config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
|
|
476
|
+
wallets[0][0].config["use_delta_sync"] = use_delta_sync
|
|
477
|
+
|
|
478
|
+
# Untrusted node sync
|
|
479
|
+
wallets[1][0].config["trusted_peers"] = {}
|
|
480
|
+
wallets[1][0].config["use_delta_sync"] = use_delta_sync
|
|
481
|
+
|
|
482
|
+
phs = []
|
|
483
|
+
for wallet_node, wallet_server in wallets:
|
|
484
|
+
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
485
|
+
phs.append(await wallet.get_new_puzzlehash())
|
|
486
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
|
|
487
|
+
|
|
488
|
+
# Insert 400 blocks
|
|
489
|
+
await add_blocks_in_batches(default_400_blocks, full_node)
|
|
490
|
+
# Farm few more with reward
|
|
491
|
+
|
|
492
|
+
wallet_node1, _ = wallets[0]
|
|
493
|
+
wallet1 = wallet_node.wallet_state_manager.main_wallet
|
|
494
|
+
wallet_node2, _ = wallets[1]
|
|
495
|
+
wallet2 = wallet_node2.wallet_state_manager.main_wallet
|
|
496
|
+
|
|
497
|
+
await time_out_assert(60, wallet_height_at_least, True, wallet1, 399)
|
|
498
|
+
await time_out_assert(60, wallet_height_at_least, True, wallet2, 399)
|
|
499
|
+
|
|
500
|
+
for _ in range(num_blocks - 1):
|
|
501
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(phs[0]))
|
|
502
|
+
for _ in range(num_blocks):
|
|
503
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(phs[1]))
|
|
504
|
+
|
|
505
|
+
# Confirm we have the funds
|
|
506
|
+
funds = sum(
|
|
507
|
+
calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
await time_out_assert(60, wallet_height_at_least, True, wallet1, 408)
|
|
511
|
+
await time_out_assert(60, wallet1.get_confirmed_balance, funds)
|
|
512
|
+
await time_out_assert(60, get_tx_count, 2 * (num_blocks - 1), wallet_node1.wallet_state_manager, 1)
|
|
513
|
+
|
|
514
|
+
await time_out_assert(60, wallet_height_at_least, True, wallet2, 408)
|
|
515
|
+
await time_out_assert(60, wallet2.get_confirmed_balance, funds)
|
|
516
|
+
await time_out_assert(60, get_tx_count, 2 * (num_blocks - 1), wallet_node2.wallet_state_manager, 1)
|
|
517
|
+
|
|
518
|
+
# Reorg blocks that carry reward
|
|
519
|
+
num_blocks = 30
|
|
520
|
+
blocks_reorg = bt.get_consecutive_blocks(num_blocks, block_list_input=default_400_blocks[:-5])
|
|
521
|
+
|
|
522
|
+
await add_blocks_in_batches(blocks_reorg[-30:], full_node)
|
|
523
|
+
|
|
524
|
+
for wallet_node, wallet_server in wallets:
|
|
525
|
+
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
526
|
+
await time_out_assert(60, get_tx_count, 0, wallet_node.wallet_state_manager, 1)
|
|
527
|
+
await time_out_assert(60, wallet.get_confirmed_balance, 0)
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
@pytest.mark.limit_consensus_modes(reason="save time")
|
|
531
|
+
@pytest.mark.anyio
|
|
532
|
+
async def test_wallet_reorg_get_coinbase(
|
|
533
|
+
two_wallet_nodes: OldSimulatorsAndWallets, default_400_blocks: list[FullBlock], self_hostname: str
|
|
534
|
+
) -> None:
|
|
535
|
+
[full_node_api], wallets, bt = two_wallet_nodes
|
|
536
|
+
full_node = full_node_api.full_node
|
|
537
|
+
full_node_server = full_node.server
|
|
538
|
+
|
|
539
|
+
# Trusted node sync
|
|
540
|
+
wallets[0][0].config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
|
|
541
|
+
|
|
542
|
+
# Untrusted node sync
|
|
543
|
+
wallets[1][0].config["trusted_peers"] = {}
|
|
544
|
+
|
|
545
|
+
for wallet_node, wallet_server in wallets:
|
|
546
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
|
|
547
|
+
|
|
548
|
+
# Insert 400 blocks
|
|
549
|
+
await add_blocks_in_batches(default_400_blocks, full_node)
|
|
550
|
+
|
|
551
|
+
# Reorg blocks that carry reward
|
|
552
|
+
num_blocks_reorg = 30
|
|
553
|
+
blocks_reorg = bt.get_consecutive_blocks(num_blocks_reorg, block_list_input=default_400_blocks[:-5])
|
|
554
|
+
await add_blocks_in_batches(blocks_reorg[:-6], full_node)
|
|
555
|
+
|
|
556
|
+
await full_node.add_block(blocks_reorg[-6])
|
|
557
|
+
|
|
558
|
+
for wallet_node, wallet_server in wallets:
|
|
559
|
+
await time_out_assert(30, get_tx_count, 0, wallet_node.wallet_state_manager, 1)
|
|
560
|
+
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=30)
|
|
561
|
+
|
|
562
|
+
num_blocks_reorg_1 = 40
|
|
563
|
+
all_blocks_reorg_2 = blocks_reorg[:-30]
|
|
564
|
+
for wallet_node, wallet_server in wallets:
|
|
565
|
+
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
566
|
+
ph = await wallet.get_new_puzzlehash()
|
|
567
|
+
all_blocks_reorg_2 = bt.get_consecutive_blocks(
|
|
568
|
+
1, pool_reward_puzzle_hash=ph, farmer_reward_puzzle_hash=ph, block_list_input=all_blocks_reorg_2
|
|
569
|
+
)
|
|
570
|
+
blocks_reorg_2 = bt.get_consecutive_blocks(num_blocks_reorg_1, block_list_input=all_blocks_reorg_2)
|
|
571
|
+
block_record = await full_node.blockchain.get_block_record_from_db(blocks_reorg_2[-45].header_hash)
|
|
572
|
+
sub_slot_iters, difficulty = get_next_sub_slot_iters_and_difficulty(
|
|
573
|
+
full_node.constants, True, block_record, full_node.blockchain
|
|
574
|
+
)
|
|
575
|
+
await full_node.add_block_batch(
|
|
576
|
+
blocks_reorg_2[-44:],
|
|
577
|
+
PeerInfo("0.0.0.0", 0),
|
|
578
|
+
ForkInfo(blocks_reorg_2[-45].height, blocks_reorg_2[-45].height, blocks_reorg_2[-45].header_hash),
|
|
579
|
+
ValidationState(sub_slot_iters, difficulty, None),
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
for wallet_node, wallet_server in wallets:
|
|
583
|
+
await disconnect_all_and_reconnect(wallet_server, full_node_server, self_hostname)
|
|
584
|
+
|
|
585
|
+
# Confirm we have the funds
|
|
586
|
+
funds = calculate_pool_reward(uint32(len(all_blocks_reorg_2))) + calculate_base_farmer_reward(
|
|
587
|
+
uint32(len(all_blocks_reorg_2))
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
for wallet_node, wallet_server in wallets:
|
|
591
|
+
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
592
|
+
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=60)
|
|
593
|
+
|
|
594
|
+
await time_out_assert(20, get_tx_count, 2, wallet_node.wallet_state_manager, 1)
|
|
595
|
+
await time_out_assert(20, wallet.get_confirmed_balance, funds)
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
@pytest.mark.anyio
|
|
599
|
+
async def test_request_additions_errors(simulator_and_wallet: OldSimulatorsAndWallets, self_hostname: str) -> None:
|
|
600
|
+
full_nodes, wallets, _ = simulator_and_wallet
|
|
601
|
+
wallet_node, wallet_server = wallets[0]
|
|
602
|
+
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
603
|
+
ph = await wallet.get_new_puzzlehash()
|
|
604
|
+
|
|
605
|
+
full_node_api = full_nodes[0]
|
|
606
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_api.full_node.server.get_port()), None)
|
|
607
|
+
|
|
608
|
+
for _ in range(2):
|
|
609
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
610
|
+
|
|
611
|
+
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
|
|
612
|
+
|
|
613
|
+
last_block: Optional[BlockRecord] = full_node_api.full_node.blockchain.get_peak()
|
|
614
|
+
assert last_block is not None
|
|
615
|
+
|
|
616
|
+
# Invalid height
|
|
617
|
+
with pytest.raises(ValueError):
|
|
618
|
+
await full_node_api.request_additions(RequestAdditions(uint32(100), last_block.header_hash, [ph]))
|
|
619
|
+
|
|
620
|
+
# Invalid header hash
|
|
621
|
+
with pytest.raises(ValueError):
|
|
622
|
+
await full_node_api.request_additions(RequestAdditions(last_block.height, std_hash(b""), [ph]))
|
|
623
|
+
|
|
624
|
+
# No results
|
|
625
|
+
fake_coin = std_hash(b"")
|
|
626
|
+
assert ph != fake_coin
|
|
627
|
+
res1 = await full_node_api.request_additions(
|
|
628
|
+
RequestAdditions(last_block.height, last_block.header_hash, [fake_coin])
|
|
629
|
+
)
|
|
630
|
+
assert res1 is not None
|
|
631
|
+
response = RespondAdditions.from_bytes(res1.data)
|
|
632
|
+
assert response.height == last_block.height
|
|
633
|
+
assert response.header_hash == last_block.header_hash
|
|
634
|
+
assert response.proofs is not None
|
|
635
|
+
assert len(response.proofs) == 1
|
|
636
|
+
assert len(response.coins) == 1
|
|
637
|
+
full_block = await full_node_api.full_node.block_store.get_full_block(last_block.header_hash)
|
|
638
|
+
assert full_block is not None
|
|
639
|
+
assert full_block.foliage_transaction_block is not None
|
|
640
|
+
root = full_block.foliage_transaction_block.additions_root
|
|
641
|
+
assert confirm_not_included_already_hashed(root, response.proofs[0][0], response.proofs[0][1])
|
|
642
|
+
# proofs is a tuple of (puzzlehash, proof, proof_2)
|
|
643
|
+
# proof is a proof of inclusion (or exclusion) of that puzzlehash
|
|
644
|
+
# proof_2 is a proof of all the coins with that puzzlehash
|
|
645
|
+
# all coin names are concatenated and hashed into one entry in the merkle set for proof_2
|
|
646
|
+
# the response contains the list of coins so you can check the proof_2
|
|
647
|
+
|
|
648
|
+
assert response.proofs[0][0] == std_hash(b"")
|
|
649
|
+
assert response.proofs[0][1] is not None
|
|
650
|
+
assert response.proofs[0][2] is None
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
@pytest.mark.anyio
|
|
654
|
+
async def test_request_additions_success(simulator_and_wallet: OldSimulatorsAndWallets, self_hostname: str) -> None:
|
|
655
|
+
full_nodes, wallets, _ = simulator_and_wallet
|
|
656
|
+
wallet_node, wallet_server = wallets[0]
|
|
657
|
+
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
658
|
+
ph = await wallet.get_new_puzzlehash()
|
|
659
|
+
|
|
660
|
+
full_node_api = full_nodes[0]
|
|
661
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_api.full_node.server.get_port()), None)
|
|
662
|
+
|
|
663
|
+
for _ in range(2):
|
|
664
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
665
|
+
|
|
666
|
+
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
|
|
667
|
+
|
|
668
|
+
payees: list[Payment] = []
|
|
669
|
+
for i in range(10):
|
|
670
|
+
payee_ph = await wallet.get_new_puzzlehash()
|
|
671
|
+
payees.append(Payment(payee_ph, uint64(i + 100)))
|
|
672
|
+
payees.append(Payment(payee_ph, uint64(i + 200)))
|
|
673
|
+
|
|
674
|
+
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
675
|
+
await wallet.generate_signed_transaction(uint64(0), ph, action_scope, primaries=payees)
|
|
676
|
+
[tx] = action_scope.side_effects.transactions
|
|
677
|
+
assert tx.spend_bundle is not None
|
|
678
|
+
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
|
|
679
|
+
await full_node_api.wait_transaction_records_entered_mempool([tx])
|
|
680
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
681
|
+
|
|
682
|
+
last_block = full_node_api.full_node.blockchain.get_peak()
|
|
683
|
+
assert last_block is not None
|
|
684
|
+
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
|
|
685
|
+
|
|
686
|
+
res2 = await full_node_api.request_additions(
|
|
687
|
+
RequestAdditions(last_block.height, None, [payees[0].puzzle_hash, payees[2].puzzle_hash, std_hash(b"1")])
|
|
688
|
+
)
|
|
689
|
+
|
|
690
|
+
assert res2 is not None
|
|
691
|
+
response = RespondAdditions.from_bytes(res2.data)
|
|
692
|
+
assert response.height == last_block.height
|
|
693
|
+
assert response.header_hash == last_block.header_hash
|
|
694
|
+
assert response.proofs is not None
|
|
695
|
+
assert len(response.proofs) == 3
|
|
696
|
+
|
|
697
|
+
# First two PHs are included
|
|
698
|
+
for i in range(2):
|
|
699
|
+
assert response.proofs[i][0] in {payees[j].puzzle_hash for j in (0, 2)}
|
|
700
|
+
assert response.proofs[i][1] is not None
|
|
701
|
+
assert response.proofs[i][2] is not None
|
|
702
|
+
|
|
703
|
+
# Third PH is not included
|
|
704
|
+
assert response.proofs[2][2] is None
|
|
705
|
+
|
|
706
|
+
coin_list_dict = {p: coin_list for p, coin_list in response.coins}
|
|
707
|
+
|
|
708
|
+
assert len(coin_list_dict) == 3
|
|
709
|
+
for p, coin_list in coin_list_dict.items():
|
|
710
|
+
if p == std_hash(b"1"):
|
|
711
|
+
# this is the one that is not included
|
|
712
|
+
assert len(coin_list) == 0
|
|
713
|
+
else:
|
|
714
|
+
for coin in coin_list:
|
|
715
|
+
assert coin.puzzle_hash == p
|
|
716
|
+
# The other ones are included
|
|
717
|
+
assert len(coin_list) == 2
|
|
718
|
+
|
|
719
|
+
# None for puzzle hashes returns all coins and no proofs
|
|
720
|
+
res3 = await full_node_api.request_additions(RequestAdditions(last_block.height, last_block.header_hash, None))
|
|
721
|
+
|
|
722
|
+
assert res3 is not None
|
|
723
|
+
response = RespondAdditions.from_bytes(res3.data)
|
|
724
|
+
assert response.height == last_block.height
|
|
725
|
+
assert response.header_hash == last_block.header_hash
|
|
726
|
+
assert response.proofs is None
|
|
727
|
+
assert len(response.coins) == 12
|
|
728
|
+
assert sum(len(c_list) for _, c_list in response.coins) == 24
|
|
729
|
+
|
|
730
|
+
# [] for puzzle hashes returns nothing
|
|
731
|
+
res4 = await full_node_api.request_additions(RequestAdditions(last_block.height, last_block.header_hash, []))
|
|
732
|
+
assert res4 is not None
|
|
733
|
+
response = RespondAdditions.from_bytes(res4.data)
|
|
734
|
+
assert response.proofs == []
|
|
735
|
+
assert len(response.coins) == 0
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
@pytest.mark.anyio
|
|
739
|
+
async def test_get_wp_fork_point(
|
|
740
|
+
default_10000_blocks: list[FullBlock], blockchain_constants: ConsensusConstants
|
|
741
|
+
) -> None:
|
|
742
|
+
blocks = default_10000_blocks
|
|
743
|
+
header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks, blockchain_constants)
|
|
744
|
+
wpf = WeightProofHandler(blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries))
|
|
745
|
+
wp1 = await wpf.get_proof_of_weight(header_cache[height_to_hash[uint32(9_000)]].header_hash)
|
|
746
|
+
assert wp1 is not None
|
|
747
|
+
wp2 = await wpf.get_proof_of_weight(header_cache[height_to_hash[uint32(9_030)]].header_hash)
|
|
748
|
+
assert wp2 is not None
|
|
749
|
+
wp3 = await wpf.get_proof_of_weight(header_cache[height_to_hash[uint32(7_500)]].header_hash)
|
|
750
|
+
assert wp3 is not None
|
|
751
|
+
wp4 = await wpf.get_proof_of_weight(header_cache[height_to_hash[uint32(8_700)]].header_hash)
|
|
752
|
+
assert wp4 is not None
|
|
753
|
+
wp5 = await wpf.get_proof_of_weight(header_cache[height_to_hash[uint32(9_700)]].header_hash)
|
|
754
|
+
assert wp5 is not None
|
|
755
|
+
wp6 = await wpf.get_proof_of_weight(header_cache[height_to_hash[uint32(9_010)]].header_hash)
|
|
756
|
+
assert wp6 is not None
|
|
757
|
+
fork12 = get_wp_fork_point(blockchain_constants, wp1, wp2)
|
|
758
|
+
fork13 = get_wp_fork_point(blockchain_constants, wp3, wp1)
|
|
759
|
+
fork14 = get_wp_fork_point(blockchain_constants, wp4, wp1)
|
|
760
|
+
fork23 = get_wp_fork_point(blockchain_constants, wp3, wp2)
|
|
761
|
+
fork24 = get_wp_fork_point(blockchain_constants, wp4, wp2)
|
|
762
|
+
fork34 = get_wp_fork_point(blockchain_constants, wp3, wp4)
|
|
763
|
+
fork45 = get_wp_fork_point(blockchain_constants, wp4, wp5)
|
|
764
|
+
fork16 = get_wp_fork_point(blockchain_constants, wp1, wp6)
|
|
765
|
+
|
|
766
|
+
# overlap between recent chain in wps, fork point is the tip of the shorter wp
|
|
767
|
+
assert fork12 == wp1.recent_chain_data[-1].height
|
|
768
|
+
assert fork16 == wp1.recent_chain_data[-1].height
|
|
769
|
+
|
|
770
|
+
# if there is an overlap between the recent chains we can find the exact fork point
|
|
771
|
+
# if not we should get the latest block with a sub epoch summary that exists in both wp's
|
|
772
|
+
# this can happen in fork24 and fork14 since they are not very far and also not very close
|
|
773
|
+
|
|
774
|
+
if wp2.recent_chain_data[0].height > wp4.recent_chain_data[-1].height:
|
|
775
|
+
assert fork24 in summaries.keys()
|
|
776
|
+
assert fork24 < wp4.recent_chain_data[-1].height
|
|
777
|
+
else:
|
|
778
|
+
assert fork24 == wp4.recent_chain_data[-1].height
|
|
779
|
+
|
|
780
|
+
if wp1.recent_chain_data[0].height > wp4.recent_chain_data[-1].height:
|
|
781
|
+
assert fork14 in summaries.keys()
|
|
782
|
+
assert fork14 < wp4.recent_chain_data[-1].height
|
|
783
|
+
else:
|
|
784
|
+
assert fork14 == wp4.recent_chain_data[-1].height
|
|
785
|
+
|
|
786
|
+
# no overlap between recent chain in wps, fork point
|
|
787
|
+
# is the latest block with a sub epoch summary that exists in both wp's
|
|
788
|
+
assert fork13 in summaries.keys()
|
|
789
|
+
assert fork13 < wp3.recent_chain_data[-1].height
|
|
790
|
+
assert fork23 in summaries.keys()
|
|
791
|
+
assert fork23 < wp3.recent_chain_data[-1].height
|
|
792
|
+
assert fork34 in summaries.keys()
|
|
793
|
+
assert fork23 < wp3.recent_chain_data[-1].height
|
|
794
|
+
assert fork45 in summaries.keys()
|
|
795
|
+
assert fork45 < wp4.recent_chain_data[-1].height
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
"""
|
|
799
|
+
This tests that a wallet filters out the dust properly.
|
|
800
|
+
It runs in seven phases:
|
|
801
|
+
1. Create a single dust coin.
|
|
802
|
+
Typically (though there are edge cases), this coin will not be filtered.
|
|
803
|
+
2. Create dust coins until the filter threshold has been reached.
|
|
804
|
+
At this point, none of the dust should be filtered.
|
|
805
|
+
3. Create 10 coins that are exactly the size of the filter threshold.
|
|
806
|
+
These should not be filtered because they are not dust.
|
|
807
|
+
4. Create one more dust coin. This coin should be filtered.
|
|
808
|
+
5. Create 5 coins below the threshold and 5 at or above.
|
|
809
|
+
Those below the threshold should get filtered, and those above should not.
|
|
810
|
+
6. Clear all coins from the dust wallet.
|
|
811
|
+
Send to the dust wallet "spam_filter_after_n_txs" coins that are equal in value to "xch_spam_amount".
|
|
812
|
+
Send 1 mojo from the dust wallet. The dust wallet should receive a change coin valued at "xch_spam_amount-1".
|
|
813
|
+
7: Create an NFT wallet for the farmer wallet, and generate an NFT in that wallet.
|
|
814
|
+
Create an NFT wallet for the dust wallet.
|
|
815
|
+
Send the NFT to the dust wallet. The NFT should not be filtered.
|
|
816
|
+
"""
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
@pytest.mark.anyio
|
|
820
|
+
@pytest.mark.parametrize(
|
|
821
|
+
"spam_filter_after_n_txs, xch_spam_amount, dust_value",
|
|
822
|
+
[
|
|
823
|
+
# In the following tests, the filter is run right away:
|
|
824
|
+
(0, 1, 1), # nothing is filtered
|
|
825
|
+
# In the following tests, 1 coin will be created in part 1, and 9 in part 2:
|
|
826
|
+
(10, 10_000_000_000, 1), # everything is dust
|
|
827
|
+
(10, 10_000_000_000, 10_000_000_000), # max dust threshold, dust is same size so not filtered
|
|
828
|
+
# Test with more coins
|
|
829
|
+
(105, 1_000_000, 1), # default filter level (1m mojos), default dust size (1)
|
|
830
|
+
],
|
|
831
|
+
)
|
|
832
|
+
async def test_dusted_wallet(
|
|
833
|
+
self_hostname: str,
|
|
834
|
+
two_wallet_nodes_custom_spam_filtering: OldSimulatorsAndWallets,
|
|
835
|
+
spam_filter_after_n_txs: int,
|
|
836
|
+
xch_spam_amount: int,
|
|
837
|
+
dust_value: int,
|
|
838
|
+
use_delta_sync: bool,
|
|
839
|
+
) -> None:
|
|
840
|
+
full_nodes, wallets, _ = two_wallet_nodes_custom_spam_filtering
|
|
841
|
+
|
|
842
|
+
farm_wallet_node, farm_wallet_server = wallets[0]
|
|
843
|
+
farm_wallet_node.config["use_delta_sync"] = use_delta_sync
|
|
844
|
+
dust_wallet_node, dust_wallet_server = wallets[1]
|
|
845
|
+
dust_wallet_node.config["use_delta_sync"] = use_delta_sync
|
|
846
|
+
|
|
847
|
+
# Create two wallets, one for farming (not used for testing), and one for testing dust.
|
|
848
|
+
farm_wallet = farm_wallet_node.wallet_state_manager.main_wallet
|
|
849
|
+
dust_wallet = dust_wallet_node.wallet_state_manager.main_wallet
|
|
850
|
+
ph = await farm_wallet.get_new_puzzlehash()
|
|
851
|
+
|
|
852
|
+
full_node_api = full_nodes[0]
|
|
853
|
+
|
|
854
|
+
# It's also possible to obtain the current settings for spam_filter_after_n_txs and xch_spam_amount
|
|
855
|
+
# spam_filter_after_n_txs = wallets[0][0].config["spam_filter_after_n_txs"]
|
|
856
|
+
# xch_spam_amount = wallets[0][0].config["xch_spam_amount"]
|
|
857
|
+
# dust_value=1
|
|
858
|
+
|
|
859
|
+
# Verify legal values for the settings to be tested
|
|
860
|
+
# If spam_filter_after_n_txs is greater than 250, this test will take a long time to run.
|
|
861
|
+
# Current max value for xch_spam_amount is 0.01 XCH.
|
|
862
|
+
# If needed, this could be increased but we would need to farm more blocks.
|
|
863
|
+
# The max dust_value could be increased, but would require farming more blocks.
|
|
864
|
+
assert spam_filter_after_n_txs >= 0
|
|
865
|
+
assert spam_filter_after_n_txs <= 250
|
|
866
|
+
assert xch_spam_amount >= 1
|
|
867
|
+
assert xch_spam_amount <= 10_000_000_000
|
|
868
|
+
assert dust_value >= 1
|
|
869
|
+
assert dust_value <= 10_000_000_000
|
|
870
|
+
|
|
871
|
+
# start both clients
|
|
872
|
+
await farm_wallet_server.start_client(PeerInfo(self_hostname, full_node_api.full_node.server.get_port()), None)
|
|
873
|
+
await dust_wallet_server.start_client(PeerInfo(self_hostname, full_node_api.full_node.server.get_port()), None)
|
|
874
|
+
|
|
875
|
+
# Farm two blocks
|
|
876
|
+
for _ in range(2):
|
|
877
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
878
|
+
|
|
879
|
+
# sync both nodes
|
|
880
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
881
|
+
|
|
882
|
+
# Part 1: create a single dust coin
|
|
883
|
+
payees: list[Payment] = []
|
|
884
|
+
payee_ph = await dust_wallet.get_new_puzzlehash()
|
|
885
|
+
payees.append(Payment(payee_ph, uint64(dust_value)))
|
|
886
|
+
|
|
887
|
+
# construct and send tx
|
|
888
|
+
async with farm_wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
889
|
+
await farm_wallet.generate_signed_transaction(uint64(0), ph, action_scope, primaries=payees)
|
|
890
|
+
[tx] = action_scope.side_effects.transactions
|
|
891
|
+
assert tx.spend_bundle is not None
|
|
892
|
+
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
|
|
893
|
+
await full_node_api.wait_transaction_records_entered_mempool([tx])
|
|
894
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
895
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
896
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
897
|
+
|
|
898
|
+
# The dust is only filtered at this point if spam_filter_after_n_txs is 0 and xch_spam_amount is > dust_value.
|
|
899
|
+
if spam_filter_after_n_txs > 0:
|
|
900
|
+
dust_coins = 1
|
|
901
|
+
large_dust_coins = 0
|
|
902
|
+
large_dust_balance = 0
|
|
903
|
+
elif xch_spam_amount <= dust_value:
|
|
904
|
+
dust_coins = 0
|
|
905
|
+
large_dust_coins = 1
|
|
906
|
+
large_dust_balance = dust_value
|
|
907
|
+
else:
|
|
908
|
+
dust_coins = 0
|
|
909
|
+
large_dust_coins = 0
|
|
910
|
+
large_dust_balance = 0
|
|
911
|
+
|
|
912
|
+
# Obtain and log important values
|
|
913
|
+
all_unspent = await dust_wallet_node.wallet_state_manager.coin_store.get_all_unspent_coins()
|
|
914
|
+
log.info(f"all_unspent is {all_unspent}")
|
|
915
|
+
small_unspent_count = len([r for r in all_unspent if r.coin.amount < xch_spam_amount])
|
|
916
|
+
balance = await dust_wallet.get_confirmed_balance()
|
|
917
|
+
async with dust_wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=False) as action_scope:
|
|
918
|
+
num_coins = len(await dust_wallet.select_coins(uint64(balance), action_scope))
|
|
919
|
+
|
|
920
|
+
log.info(f"Small coin count is {small_unspent_count}")
|
|
921
|
+
log.info(f"Wallet balance is {balance}")
|
|
922
|
+
log.info(f"Number of coins is {num_coins}")
|
|
923
|
+
|
|
924
|
+
log.info(f"spam_filter_after_n_txs {spam_filter_after_n_txs}")
|
|
925
|
+
log.info(f"xch_spam_amount {xch_spam_amount}")
|
|
926
|
+
log.info(f"dust_value {dust_value}")
|
|
927
|
+
|
|
928
|
+
# Verify balance and number of coins not filtered.
|
|
929
|
+
assert balance == dust_coins * dust_value + large_dust_balance
|
|
930
|
+
assert num_coins == dust_coins + large_dust_coins
|
|
931
|
+
|
|
932
|
+
# Part 2: Create dust coins until the filter threshold has been reached.
|
|
933
|
+
# Nothing should be filtered yet (unless spam_filter_after_n_txs is 0).
|
|
934
|
+
payees = []
|
|
935
|
+
|
|
936
|
+
# Determine how much dust to create, recalling that there already is one dust coin.
|
|
937
|
+
new_dust = spam_filter_after_n_txs - 1
|
|
938
|
+
dust_remaining = new_dust
|
|
939
|
+
|
|
940
|
+
while dust_remaining > 0:
|
|
941
|
+
payee_ph = await dust_wallet.get_new_puzzlehash()
|
|
942
|
+
payees.append(Payment(payee_ph, uint64(dust_value)))
|
|
943
|
+
|
|
944
|
+
# After every 100 (at most) coins added, push the tx and advance the chain
|
|
945
|
+
# This greatly speeds up the overall process
|
|
946
|
+
if dust_remaining % 100 == 0 and dust_remaining != new_dust:
|
|
947
|
+
# construct and send tx
|
|
948
|
+
async with farm_wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
949
|
+
await farm_wallet.generate_signed_transaction(uint64(0), ph, action_scope, primaries=payees)
|
|
950
|
+
[tx] = action_scope.side_effects.transactions
|
|
951
|
+
assert tx.spend_bundle is not None
|
|
952
|
+
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
|
|
953
|
+
|
|
954
|
+
# advance the chain and sync both wallets
|
|
955
|
+
await full_node_api.wait_transaction_records_entered_mempool([tx])
|
|
956
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
957
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
958
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
959
|
+
# reset payees
|
|
960
|
+
payees = []
|
|
961
|
+
|
|
962
|
+
dust_remaining -= 1
|
|
963
|
+
|
|
964
|
+
# Only need to create tx if there was new dust to be added
|
|
965
|
+
if new_dust >= 1:
|
|
966
|
+
# construct and send tx
|
|
967
|
+
async with farm_wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
968
|
+
await farm_wallet.generate_signed_transaction(uint64(0), ph, action_scope, primaries=payees)
|
|
969
|
+
[tx] = action_scope.side_effects.transactions
|
|
970
|
+
assert tx.spend_bundle is not None
|
|
971
|
+
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
|
|
972
|
+
|
|
973
|
+
# advance the chain and sync both wallets
|
|
974
|
+
await full_node_api.wait_transaction_records_entered_mempool([tx])
|
|
975
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
976
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
977
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
978
|
+
|
|
979
|
+
# Obtain and log important values
|
|
980
|
+
all_unspent = await dust_wallet_node.wallet_state_manager.coin_store.get_all_unspent_coins()
|
|
981
|
+
small_unspent_count = len([r for r in all_unspent if r.coin.amount < xch_spam_amount])
|
|
982
|
+
balance = await dust_wallet.get_confirmed_balance()
|
|
983
|
+
# Selecting coins by using the wallet's coin selection algorithm won't work for large
|
|
984
|
+
# numbers of coins, so we'll use the state manager for the rest of the test
|
|
985
|
+
spendable_coins = await dust_wallet_node.wallet_state_manager.get_spendable_coins_for_wallet(1)
|
|
986
|
+
num_coins = len(spendable_coins)
|
|
987
|
+
|
|
988
|
+
log.info(f"Small coin count is {small_unspent_count}")
|
|
989
|
+
log.info(f"Wallet balance is {balance}")
|
|
990
|
+
log.info(f"Number of coins is {num_coins}")
|
|
991
|
+
|
|
992
|
+
# obtain the total expected coins (new_dust could be negative)
|
|
993
|
+
if new_dust > 0:
|
|
994
|
+
dust_coins += new_dust
|
|
995
|
+
|
|
996
|
+
# Make sure the number of coins matches the expected number.
|
|
997
|
+
# At this point, nothing should be getting filtered unless spam_filter_after_n_txs is 0.
|
|
998
|
+
assert dust_coins == spam_filter_after_n_txs
|
|
999
|
+
assert balance == dust_coins * dust_value + large_dust_balance
|
|
1000
|
+
assert num_coins == dust_coins + large_dust_coins
|
|
1001
|
+
|
|
1002
|
+
# Part 3: Create 10 coins that are exactly the size of the filter threshold.
|
|
1003
|
+
# These should not get filtered.
|
|
1004
|
+
large_coins = 10
|
|
1005
|
+
|
|
1006
|
+
payees = []
|
|
1007
|
+
|
|
1008
|
+
for _ in range(large_coins):
|
|
1009
|
+
payee_ph = await dust_wallet.get_new_puzzlehash()
|
|
1010
|
+
payees.append(Payment(payee_ph, uint64(xch_spam_amount)))
|
|
1011
|
+
|
|
1012
|
+
# construct and send tx
|
|
1013
|
+
async with farm_wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
1014
|
+
await farm_wallet.generate_signed_transaction(uint64(0), ph, action_scope, primaries=payees)
|
|
1015
|
+
[tx] = action_scope.side_effects.transactions
|
|
1016
|
+
assert tx.spend_bundle is not None
|
|
1017
|
+
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
|
|
1018
|
+
|
|
1019
|
+
# advance the chain and sync both wallets
|
|
1020
|
+
await full_node_api.wait_transaction_records_entered_mempool([tx])
|
|
1021
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1022
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
1023
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1024
|
+
|
|
1025
|
+
# Obtain and log important values
|
|
1026
|
+
all_unspent = await dust_wallet_node.wallet_state_manager.coin_store.get_all_unspent_coins()
|
|
1027
|
+
small_unspent_count = len([r for r in all_unspent if r.coin.amount < xch_spam_amount])
|
|
1028
|
+
balance = await dust_wallet.get_confirmed_balance()
|
|
1029
|
+
spendable_coins = await dust_wallet_node.wallet_state_manager.get_spendable_coins_for_wallet(1)
|
|
1030
|
+
num_coins = len(spendable_coins)
|
|
1031
|
+
|
|
1032
|
+
log.info(f"Small coin count is {small_unspent_count}")
|
|
1033
|
+
log.info(f"Wallet balance is {balance}")
|
|
1034
|
+
log.info(f"Number of coins is {num_coins}")
|
|
1035
|
+
|
|
1036
|
+
large_coin_balance = large_coins * xch_spam_amount
|
|
1037
|
+
|
|
1038
|
+
# Determine whether the filter should have been activated.
|
|
1039
|
+
# Make sure the number of coins matches the expected number.
|
|
1040
|
+
# At this point, nothing should be getting filtered unless spam_filter_after_n_txs is 0.
|
|
1041
|
+
assert dust_coins == spam_filter_after_n_txs
|
|
1042
|
+
assert balance == dust_coins * dust_value + large_coins * xch_spam_amount + large_dust_balance
|
|
1043
|
+
assert num_coins == dust_coins + large_coins + large_dust_coins
|
|
1044
|
+
|
|
1045
|
+
# Part 4: Create one more dust coin to test the threshold
|
|
1046
|
+
payees = []
|
|
1047
|
+
|
|
1048
|
+
payee_ph = await dust_wallet.get_new_puzzlehash()
|
|
1049
|
+
payees.append(Payment(payee_ph, uint64(dust_value)))
|
|
1050
|
+
|
|
1051
|
+
# construct and send tx
|
|
1052
|
+
async with farm_wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
1053
|
+
await farm_wallet.generate_signed_transaction(uint64(0), ph, action_scope, primaries=payees)
|
|
1054
|
+
[tx] = action_scope.side_effects.transactions
|
|
1055
|
+
assert tx.spend_bundle is not None
|
|
1056
|
+
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
|
|
1057
|
+
|
|
1058
|
+
# advance the chain and sync both wallets
|
|
1059
|
+
await full_node_api.wait_transaction_records_entered_mempool([tx])
|
|
1060
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1061
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
1062
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1063
|
+
|
|
1064
|
+
# Obtain and log important values
|
|
1065
|
+
all_unspent = await dust_wallet_node.wallet_state_manager.coin_store.get_all_unspent_coins()
|
|
1066
|
+
small_unspent_count = len([r for r in all_unspent if r.coin.amount < xch_spam_amount])
|
|
1067
|
+
balance = await dust_wallet.get_confirmed_balance()
|
|
1068
|
+
spendable_coins = await dust_wallet_node.wallet_state_manager.get_spendable_coins_for_wallet(1)
|
|
1069
|
+
num_coins = len(spendable_coins)
|
|
1070
|
+
|
|
1071
|
+
log.info(f"Small coin count is {small_unspent_count}")
|
|
1072
|
+
log.info(f"Wallet balance is {balance}")
|
|
1073
|
+
log.info(f"Number of coins is {num_coins}")
|
|
1074
|
+
|
|
1075
|
+
# In the edge case where the new "dust" is larger than the threshold,
|
|
1076
|
+
# then it is actually a large dust coin that won't get filtered.
|
|
1077
|
+
if dust_value >= xch_spam_amount:
|
|
1078
|
+
large_dust_coins += 1
|
|
1079
|
+
large_dust_balance += dust_value
|
|
1080
|
+
|
|
1081
|
+
assert dust_coins == spam_filter_after_n_txs
|
|
1082
|
+
assert balance == dust_coins * dust_value + large_coins * xch_spam_amount + large_dust_balance
|
|
1083
|
+
assert num_coins == dust_coins + large_dust_coins + large_coins
|
|
1084
|
+
|
|
1085
|
+
# Part 5: Create 5 coins below the threshold and 5 at or above.
|
|
1086
|
+
# Those below the threshold should get filtered, and those above should not.
|
|
1087
|
+
payees = []
|
|
1088
|
+
|
|
1089
|
+
for i in range(5):
|
|
1090
|
+
payee_ph = await dust_wallet.get_new_puzzlehash()
|
|
1091
|
+
|
|
1092
|
+
# Create a large coin and add on the appropriate balance.
|
|
1093
|
+
payees.append(Payment(payee_ph, uint64(xch_spam_amount + i)))
|
|
1094
|
+
large_coins += 1
|
|
1095
|
+
large_coin_balance += xch_spam_amount + i
|
|
1096
|
+
|
|
1097
|
+
payee_ph = await dust_wallet.get_new_puzzlehash()
|
|
1098
|
+
|
|
1099
|
+
# Make sure we are always creating coins with a positive value.
|
|
1100
|
+
if xch_spam_amount - dust_value - i > 0:
|
|
1101
|
+
payees.append(Payment(payee_ph, uint64(xch_spam_amount - dust_value - i)))
|
|
1102
|
+
else:
|
|
1103
|
+
payees.append(Payment(payee_ph, uint64(dust_value)))
|
|
1104
|
+
# In cases where xch_spam_amount is sufficiently low,
|
|
1105
|
+
# the new dust should be considered a large coina and not be filtered.
|
|
1106
|
+
if xch_spam_amount <= dust_value:
|
|
1107
|
+
large_dust_coins += 1
|
|
1108
|
+
large_dust_balance += dust_value
|
|
1109
|
+
|
|
1110
|
+
# construct and send tx
|
|
1111
|
+
async with farm_wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
1112
|
+
await farm_wallet.generate_signed_transaction(uint64(0), ph, action_scope, primaries=payees)
|
|
1113
|
+
[tx] = action_scope.side_effects.transactions
|
|
1114
|
+
assert tx.spend_bundle is not None
|
|
1115
|
+
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
|
|
1116
|
+
|
|
1117
|
+
# advance the chain and sync both wallets
|
|
1118
|
+
await full_node_api.wait_transaction_records_entered_mempool([tx])
|
|
1119
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1120
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
1121
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1122
|
+
|
|
1123
|
+
# Obtain and log important values
|
|
1124
|
+
all_unspent = await dust_wallet_node.wallet_state_manager.coin_store.get_all_unspent_coins()
|
|
1125
|
+
small_unspent_count = len([r for r in all_unspent if r.coin.amount < xch_spam_amount])
|
|
1126
|
+
balance = await dust_wallet.get_confirmed_balance()
|
|
1127
|
+
spendable_coins = await dust_wallet_node.wallet_state_manager.get_spendable_coins_for_wallet(1)
|
|
1128
|
+
num_coins = len(spendable_coins)
|
|
1129
|
+
|
|
1130
|
+
log.info(f"Small coin count is {small_unspent_count}")
|
|
1131
|
+
log.info(f"Wallet balance is {balance}")
|
|
1132
|
+
log.info(f"Number of coins is {num_coins}")
|
|
1133
|
+
|
|
1134
|
+
# The filter should have automatically been activated by now, regardless of filter value
|
|
1135
|
+
assert dust_coins == spam_filter_after_n_txs
|
|
1136
|
+
assert balance == dust_coins * dust_value + large_coin_balance + large_dust_balance
|
|
1137
|
+
assert num_coins == dust_coins + large_dust_coins + large_coins
|
|
1138
|
+
|
|
1139
|
+
# Part 6: Clear all coins from the dust wallet.
|
|
1140
|
+
# Send to the dust wallet "spam_filter_after_n_txs" coins that are equal in value to "xch_spam_amount".
|
|
1141
|
+
# Send 1 mojo from the dust wallet. The dust wallet should receive a change coin valued at "xch_spam_amount-1".
|
|
1142
|
+
|
|
1143
|
+
payee_ph = await farm_wallet.get_new_puzzlehash()
|
|
1144
|
+
payees = [Payment(payee_ph, uint64(balance))]
|
|
1145
|
+
|
|
1146
|
+
# construct and send tx
|
|
1147
|
+
async with dust_wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
1148
|
+
await dust_wallet.generate_signed_transaction(uint64(0), ph, action_scope, primaries=payees)
|
|
1149
|
+
[tx] = action_scope.side_effects.transactions
|
|
1150
|
+
assert tx.spend_bundle is not None
|
|
1151
|
+
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
|
|
1152
|
+
|
|
1153
|
+
# advance the chain and sync both wallets
|
|
1154
|
+
await full_node_api.wait_transaction_records_entered_mempool([tx])
|
|
1155
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1156
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
1157
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1158
|
+
|
|
1159
|
+
# Obtain and log important values
|
|
1160
|
+
all_unspent = await dust_wallet_node.wallet_state_manager.coin_store.get_all_unspent_coins()
|
|
1161
|
+
unspent_count = len(all_unspent)
|
|
1162
|
+
balance = await dust_wallet.get_confirmed_balance()
|
|
1163
|
+
|
|
1164
|
+
# Make sure the dust wallet is empty
|
|
1165
|
+
assert unspent_count == 0
|
|
1166
|
+
assert balance == 0
|
|
1167
|
+
|
|
1168
|
+
# create the same number of dust coins as the filter
|
|
1169
|
+
if spam_filter_after_n_txs > 0:
|
|
1170
|
+
coins_remaining = spam_filter_after_n_txs
|
|
1171
|
+
else:
|
|
1172
|
+
# in the edge case, create one coin
|
|
1173
|
+
coins_remaining = 1
|
|
1174
|
+
|
|
1175
|
+
# The size of the coin to send the dust wallet is the same as xch_spam_amount
|
|
1176
|
+
if xch_spam_amount > 1:
|
|
1177
|
+
coin_value = xch_spam_amount
|
|
1178
|
+
else:
|
|
1179
|
+
# Handle the edge case to make sure the coin is at least 2 mojos
|
|
1180
|
+
# This is needed to receive change
|
|
1181
|
+
coin_value = 2
|
|
1182
|
+
|
|
1183
|
+
while coins_remaining > 0:
|
|
1184
|
+
payee_ph = await dust_wallet.get_new_puzzlehash()
|
|
1185
|
+
payees.append(Payment(payee_ph, uint64(coin_value)))
|
|
1186
|
+
|
|
1187
|
+
# After every 100 (at most) coins added, push the tx and advance the chain
|
|
1188
|
+
# This greatly speeds up the overall process
|
|
1189
|
+
if coins_remaining % 100 == 0 and coins_remaining != spam_filter_after_n_txs:
|
|
1190
|
+
# construct and send tx
|
|
1191
|
+
async with farm_wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
1192
|
+
await farm_wallet.generate_signed_transaction(uint64(0), ph, action_scope, primaries=payees)
|
|
1193
|
+
[tx] = action_scope.side_effects.transactions
|
|
1194
|
+
assert tx.spend_bundle is not None
|
|
1195
|
+
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
|
|
1196
|
+
await full_node_api.wait_transaction_records_entered_mempool([tx])
|
|
1197
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1198
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
1199
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1200
|
+
# reset payees
|
|
1201
|
+
payees = []
|
|
1202
|
+
|
|
1203
|
+
coins_remaining -= 1
|
|
1204
|
+
|
|
1205
|
+
# construct and send tx
|
|
1206
|
+
async with farm_wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
1207
|
+
await farm_wallet.generate_signed_transaction(uint64(0), ph, action_scope, primaries=payees)
|
|
1208
|
+
[tx] = action_scope.side_effects.transactions
|
|
1209
|
+
assert tx.spend_bundle is not None
|
|
1210
|
+
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
|
|
1211
|
+
|
|
1212
|
+
# advance the chain and sync both wallets
|
|
1213
|
+
await full_node_api.wait_transaction_records_entered_mempool([tx])
|
|
1214
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1215
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
1216
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1217
|
+
|
|
1218
|
+
# Obtain and log important values
|
|
1219
|
+
all_unspent = await dust_wallet_node.wallet_state_manager.coin_store.get_all_unspent_coins()
|
|
1220
|
+
unspent_count = len(all_unspent)
|
|
1221
|
+
balance = await dust_wallet.get_confirmed_balance()
|
|
1222
|
+
|
|
1223
|
+
# Verify the number of coins and value
|
|
1224
|
+
if spam_filter_after_n_txs > 0:
|
|
1225
|
+
assert unspent_count == spam_filter_after_n_txs
|
|
1226
|
+
else:
|
|
1227
|
+
# in the edge case there should be 1 coin
|
|
1228
|
+
assert unspent_count == 1
|
|
1229
|
+
assert balance == unspent_count * coin_value
|
|
1230
|
+
|
|
1231
|
+
# Send a 1 mojo coin from the dust wallet to the farm wallet
|
|
1232
|
+
payee_ph = await farm_wallet.get_new_puzzlehash()
|
|
1233
|
+
payees = [Payment(payee_ph, uint64(1))]
|
|
1234
|
+
|
|
1235
|
+
# construct and send tx
|
|
1236
|
+
async with dust_wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
1237
|
+
await dust_wallet.generate_signed_transaction(uint64(0), ph, action_scope, primaries=payees)
|
|
1238
|
+
[tx] = action_scope.side_effects.transactions
|
|
1239
|
+
assert tx.spend_bundle is not None
|
|
1240
|
+
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
|
|
1241
|
+
|
|
1242
|
+
# advance the chain and sync both wallets
|
|
1243
|
+
await full_node_api.wait_transaction_records_entered_mempool([tx])
|
|
1244
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1245
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
1246
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1247
|
+
|
|
1248
|
+
# Obtain and log important values
|
|
1249
|
+
all_unspent = await dust_wallet_node.wallet_state_manager.coin_store.get_all_unspent_coins()
|
|
1250
|
+
unspent_count = len(all_unspent)
|
|
1251
|
+
balance = await dust_wallet.get_confirmed_balance()
|
|
1252
|
+
|
|
1253
|
+
# Make sure the dust wallet received a change coin worth 1 mojo less than the original coin size
|
|
1254
|
+
if spam_filter_after_n_txs > 0:
|
|
1255
|
+
assert unspent_count == spam_filter_after_n_txs
|
|
1256
|
+
else:
|
|
1257
|
+
# in the edge case there should be 1 coin
|
|
1258
|
+
assert unspent_count == 1
|
|
1259
|
+
assert balance == (unspent_count * coin_value) - 1
|
|
1260
|
+
|
|
1261
|
+
# Part 7: Create NFT wallets for the farmer and dust wallets.
|
|
1262
|
+
# Generate an NFT in the farmer wallet.
|
|
1263
|
+
# Send the NFT to the dust wallet, which already has enough coins to trigger the dust filter.
|
|
1264
|
+
# The NFT should not be filtered.
|
|
1265
|
+
|
|
1266
|
+
# Start with new puzzlehashes for each wallet
|
|
1267
|
+
farm_ph = await farm_wallet.get_new_puzzlehash()
|
|
1268
|
+
dust_ph = await dust_wallet.get_new_puzzlehash()
|
|
1269
|
+
|
|
1270
|
+
# Create an NFT wallet for the farmer and dust wallet
|
|
1271
|
+
farm_nft_wallet = await NFTWallet.create_new_nft_wallet(
|
|
1272
|
+
farm_wallet_node.wallet_state_manager, farm_wallet, name="FARM NFT WALLET"
|
|
1273
|
+
)
|
|
1274
|
+
dust_nft_wallet = await NFTWallet.create_new_nft_wallet(
|
|
1275
|
+
dust_wallet_node.wallet_state_manager, dust_wallet, name="DUST NFT WALLET"
|
|
1276
|
+
)
|
|
1277
|
+
|
|
1278
|
+
# Create a new NFT and send it to the farmer's NFT wallet
|
|
1279
|
+
metadata = Program.to(
|
|
1280
|
+
[("u", ["https://www.chia.net/img/branding/chia-logo.svg"]), ("h", "0xD4584AD463139FA8C0D9F68F4B59F185")]
|
|
1281
|
+
)
|
|
1282
|
+
async with farm_nft_wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
1283
|
+
await farm_nft_wallet.generate_new_nft(metadata, action_scope)
|
|
1284
|
+
for tx in action_scope.side_effects.transactions:
|
|
1285
|
+
if tx.spend_bundle is not None:
|
|
1286
|
+
assert len(compute_memos(tx.spend_bundle)) > 0
|
|
1287
|
+
await time_out_assert_not_none(
|
|
1288
|
+
20, full_node_api.full_node.mempool_manager.get_spendbundle, tx.spend_bundle.name()
|
|
1289
|
+
)
|
|
1290
|
+
|
|
1291
|
+
# Farm a new block
|
|
1292
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1293
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(farm_ph))
|
|
1294
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1295
|
+
|
|
1296
|
+
# Make sure the dust wallet has enough unspent coins in that the next coin would be filtered
|
|
1297
|
+
# if it were a normal dust coin (and not an NFT)
|
|
1298
|
+
all_unspent = await dust_wallet_node.wallet_state_manager.coin_store.get_all_unspent_coins()
|
|
1299
|
+
assert len(all_unspent) >= spam_filter_after_n_txs
|
|
1300
|
+
|
|
1301
|
+
# Make sure the NFT is in the farmer's NFT wallet, and the dust NFT wallet is empty
|
|
1302
|
+
await time_out_assert(15, get_nft_count, 1, farm_nft_wallet)
|
|
1303
|
+
await time_out_assert(15, get_nft_count, 0, dust_nft_wallet)
|
|
1304
|
+
|
|
1305
|
+
nft_coins = await farm_nft_wallet.get_current_nfts()
|
|
1306
|
+
# Send the NFT to the dust wallet
|
|
1307
|
+
async with farm_nft_wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
1308
|
+
await farm_nft_wallet.generate_signed_transaction(
|
|
1309
|
+
[uint64(nft_coins[0].coin.amount)], [dust_ph], action_scope, coins={nft_coins[0].coin}
|
|
1310
|
+
)
|
|
1311
|
+
assert len(action_scope.side_effects.transactions) == 1
|
|
1312
|
+
txs = await farm_wallet_node.wallet_state_manager.add_pending_transactions(action_scope.side_effects.transactions)
|
|
1313
|
+
assert txs[0].spend_bundle is not None
|
|
1314
|
+
assert len(compute_memos(txs[0].spend_bundle)) > 0
|
|
1315
|
+
|
|
1316
|
+
# Farm a new block.
|
|
1317
|
+
await full_node_api.wait_transaction_records_entered_mempool(txs)
|
|
1318
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1319
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(farm_ph))
|
|
1320
|
+
await full_node_api.wait_for_wallets_synced(wallet_nodes=[farm_wallet_node, dust_wallet_node], timeout=20)
|
|
1321
|
+
|
|
1322
|
+
# Make sure the dust wallet has enough unspent coins in that the next coin would be filtered
|
|
1323
|
+
# if it were a normal dust coin (and not an NFT)
|
|
1324
|
+
all_unspent = await dust_wallet_node.wallet_state_manager.coin_store.get_all_unspent_coins()
|
|
1325
|
+
assert len(all_unspent) >= spam_filter_after_n_txs
|
|
1326
|
+
|
|
1327
|
+
# The dust wallet should now hold the NFT. It should not be filtered
|
|
1328
|
+
await time_out_assert(15, get_nft_count, 0, farm_nft_wallet)
|
|
1329
|
+
await time_out_assert(15, get_nft_count, 1, dust_nft_wallet)
|
|
1330
|
+
|
|
1331
|
+
|
|
1332
|
+
@pytest.mark.anyio
|
|
1333
|
+
async def test_retry_store(
|
|
1334
|
+
two_wallet_nodes: OldSimulatorsAndWallets, self_hostname: str, monkeypatch: pytest.MonkeyPatch
|
|
1335
|
+
) -> None:
|
|
1336
|
+
full_nodes, wallets, _ = two_wallet_nodes
|
|
1337
|
+
full_node_api = full_nodes[0]
|
|
1338
|
+
full_node_server = full_node_api.full_node.server
|
|
1339
|
+
|
|
1340
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32.zeros))
|
|
1341
|
+
|
|
1342
|
+
# Trusted node sync
|
|
1343
|
+
wallets[0][0].config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
|
|
1344
|
+
|
|
1345
|
+
# Untrusted node sync
|
|
1346
|
+
wallets[1][0].config["trusted_peers"] = {}
|
|
1347
|
+
|
|
1348
|
+
@dataclass
|
|
1349
|
+
class FlakinessInfo:
|
|
1350
|
+
coin_state_flaky: bool = True
|
|
1351
|
+
fetch_children_flaky: bool = True
|
|
1352
|
+
get_timestamp_flaky: bool = True
|
|
1353
|
+
db_flaky: bool = True
|
|
1354
|
+
|
|
1355
|
+
def flaky_get_coin_state(
|
|
1356
|
+
flakiness_info: FlakinessInfo,
|
|
1357
|
+
func: Callable[[list[bytes32], WSChiaConnection, Optional[uint32]], Awaitable[list[CoinState]]],
|
|
1358
|
+
) -> Callable[[list[bytes32], WSChiaConnection, Optional[uint32]], Awaitable[list[CoinState]]]:
|
|
1359
|
+
async def new_func(
|
|
1360
|
+
coin_names: list[bytes32], peer: WSChiaConnection, fork_height: Optional[uint32] = None
|
|
1361
|
+
) -> list[CoinState]:
|
|
1362
|
+
if flakiness_info.coin_state_flaky:
|
|
1363
|
+
flakiness_info.coin_state_flaky = False
|
|
1364
|
+
raise PeerRequestException()
|
|
1365
|
+
else:
|
|
1366
|
+
return await func(coin_names, peer, fork_height)
|
|
1367
|
+
|
|
1368
|
+
return new_func
|
|
1369
|
+
|
|
1370
|
+
request_puzzle_solution_failure_tested = False
|
|
1371
|
+
|
|
1372
|
+
def flaky_request_puzzle_solution(
|
|
1373
|
+
func: Callable[[FullNodeAPI, wallet_protocol.RequestPuzzleSolution], Awaitable[Optional[Message]]],
|
|
1374
|
+
) -> Callable[[FullNodeAPI, wallet_protocol.RequestPuzzleSolution], Awaitable[Optional[Message]]]:
|
|
1375
|
+
@functools.wraps(func)
|
|
1376
|
+
async def new_func(self: FullNodeAPI, request: wallet_protocol.RequestPuzzleSolution) -> Optional[Message]:
|
|
1377
|
+
nonlocal request_puzzle_solution_failure_tested
|
|
1378
|
+
if not request_puzzle_solution_failure_tested:
|
|
1379
|
+
request_puzzle_solution_failure_tested = True
|
|
1380
|
+
# This can just return None if we have `none_response` enabled.
|
|
1381
|
+
reject = wallet_protocol.RejectPuzzleSolution(bytes32.zeros, uint32(0))
|
|
1382
|
+
return make_msg(ProtocolMessageTypes.reject_puzzle_solution, reject)
|
|
1383
|
+
else:
|
|
1384
|
+
return await func(self, request)
|
|
1385
|
+
|
|
1386
|
+
return new_func
|
|
1387
|
+
|
|
1388
|
+
def flaky_fetch_children(
|
|
1389
|
+
flakiness_info: FlakinessInfo,
|
|
1390
|
+
func: Callable[[bytes32, WSChiaConnection, Optional[uint32]], Awaitable[list[CoinState]]],
|
|
1391
|
+
) -> Callable[[bytes32, WSChiaConnection, Optional[uint32]], Awaitable[list[CoinState]]]:
|
|
1392
|
+
async def new_func(
|
|
1393
|
+
coin_name: bytes32, peer: WSChiaConnection, fork_height: Optional[uint32] = None
|
|
1394
|
+
) -> list[CoinState]:
|
|
1395
|
+
if flakiness_info.fetch_children_flaky:
|
|
1396
|
+
flakiness_info.fetch_children_flaky = False
|
|
1397
|
+
raise PeerRequestException()
|
|
1398
|
+
else:
|
|
1399
|
+
return await func(coin_name, peer, fork_height)
|
|
1400
|
+
|
|
1401
|
+
return new_func
|
|
1402
|
+
|
|
1403
|
+
def flaky_get_timestamp(
|
|
1404
|
+
flakiness_info: FlakinessInfo, func: Callable[[uint32], Awaitable[uint64]]
|
|
1405
|
+
) -> Callable[[uint32], Awaitable[uint64]]:
|
|
1406
|
+
async def new_func(height: uint32) -> uint64:
|
|
1407
|
+
if flakiness_info.get_timestamp_flaky:
|
|
1408
|
+
flakiness_info.get_timestamp_flaky = False
|
|
1409
|
+
raise PeerRequestException()
|
|
1410
|
+
else:
|
|
1411
|
+
return await func(height)
|
|
1412
|
+
|
|
1413
|
+
return new_func
|
|
1414
|
+
|
|
1415
|
+
def flaky_info_for_puzhash(
|
|
1416
|
+
flakiness_info: FlakinessInfo, func: Callable[[bytes32], Awaitable[Optional[WalletIdentifier]]]
|
|
1417
|
+
) -> Callable[[bytes32], Awaitable[Optional[WalletIdentifier]]]:
|
|
1418
|
+
async def new_func(puzzle_hash: bytes32) -> Optional[WalletIdentifier]:
|
|
1419
|
+
if flakiness_info.db_flaky:
|
|
1420
|
+
flakiness_info.db_flaky = False
|
|
1421
|
+
raise AIOSqliteError()
|
|
1422
|
+
else:
|
|
1423
|
+
return await func(puzzle_hash)
|
|
1424
|
+
|
|
1425
|
+
return new_func
|
|
1426
|
+
|
|
1427
|
+
with contextlib.ExitStack() as exit_stack:
|
|
1428
|
+
exit_stack.enter_context(
|
|
1429
|
+
patch_request_handler(
|
|
1430
|
+
api=full_node_api,
|
|
1431
|
+
handler=flaky_request_puzzle_solution(FullNodeAPI.request_puzzle_solution),
|
|
1432
|
+
request_type=ProtocolMessageTypes.request_puzzle_solution,
|
|
1433
|
+
)
|
|
1434
|
+
)
|
|
1435
|
+
m = exit_stack.enter_context(monkeypatch.context())
|
|
1436
|
+
|
|
1437
|
+
for wallet_node, wallet_server in wallets:
|
|
1438
|
+
wallet_node.coin_state_retry_seconds = 1
|
|
1439
|
+
request_puzzle_solution_failure_tested = False
|
|
1440
|
+
flakiness_info = FlakinessInfo()
|
|
1441
|
+
m.setattr(wallet_node, "get_coin_state", flaky_get_coin_state(flakiness_info, wallet_node.get_coin_state))
|
|
1442
|
+
m.setattr(wallet_node, "fetch_children", flaky_fetch_children(flakiness_info, wallet_node.fetch_children))
|
|
1443
|
+
m.setattr(
|
|
1444
|
+
wallet_node,
|
|
1445
|
+
"get_timestamp_for_height",
|
|
1446
|
+
flaky_get_timestamp(flakiness_info, wallet_node.get_timestamp_for_height),
|
|
1447
|
+
)
|
|
1448
|
+
m.setattr(
|
|
1449
|
+
wallet_node.wallet_state_manager.puzzle_store,
|
|
1450
|
+
"get_wallet_identifier_for_puzzle_hash",
|
|
1451
|
+
flaky_info_for_puzhash(
|
|
1452
|
+
flakiness_info, wallet_node.wallet_state_manager.puzzle_store.get_wallet_identifier_for_puzzle_hash
|
|
1453
|
+
),
|
|
1454
|
+
)
|
|
1455
|
+
|
|
1456
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
|
|
1457
|
+
|
|
1458
|
+
wallet = wallet_node.wallet_state_manager.main_wallet
|
|
1459
|
+
ph = await wallet.get_new_puzzlehash()
|
|
1460
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
1461
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32.zeros))
|
|
1462
|
+
|
|
1463
|
+
async def retry_store_empty() -> bool:
|
|
1464
|
+
return len(await wallet_node.wallet_state_manager.retry_store.get_all_states_to_retry()) == 0
|
|
1465
|
+
|
|
1466
|
+
async def assert_coin_state_retry() -> None:
|
|
1467
|
+
# Wait for retry coin states to show up
|
|
1468
|
+
await time_out_assert(15, retry_store_empty, False)
|
|
1469
|
+
# And become retried/removed
|
|
1470
|
+
await time_out_assert(30, retry_store_empty, True)
|
|
1471
|
+
|
|
1472
|
+
await assert_coin_state_retry()
|
|
1473
|
+
|
|
1474
|
+
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
1475
|
+
await wallet.generate_signed_transaction(
|
|
1476
|
+
uint64(1_000_000_000_000), bytes32.zeros, action_scope, memos=[ph]
|
|
1477
|
+
)
|
|
1478
|
+
[tx] = action_scope.side_effects.transactions
|
|
1479
|
+
await time_out_assert(30, wallet.get_confirmed_balance, 2_000_000_000_000)
|
|
1480
|
+
|
|
1481
|
+
async def tx_in_mempool() -> bool:
|
|
1482
|
+
return full_node_api.full_node.mempool_manager.get_spendbundle(tx.name) is not None
|
|
1483
|
+
|
|
1484
|
+
await time_out_assert(15, tx_in_mempool)
|
|
1485
|
+
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32.zeros))
|
|
1486
|
+
|
|
1487
|
+
await assert_coin_state_retry()
|
|
1488
|
+
|
|
1489
|
+
assert not flakiness_info.coin_state_flaky
|
|
1490
|
+
assert request_puzzle_solution_failure_tested
|
|
1491
|
+
assert not flakiness_info.fetch_children_flaky
|
|
1492
|
+
assert not flakiness_info.get_timestamp_flaky
|
|
1493
|
+
assert not flakiness_info.db_flaky
|
|
1494
|
+
await time_out_assert(30, wallet.get_confirmed_balance, 1_000_000_000_000)
|
|
1495
|
+
|
|
1496
|
+
|
|
1497
|
+
# TODO: fix this test
|
|
1498
|
+
@pytest.mark.limit_consensus_modes(reason="save time")
|
|
1499
|
+
@pytest.mark.anyio
|
|
1500
|
+
@pytest.mark.skip("the test fails with 'wallet_state_manager not assigned'. This test doesn't work, skip it for now")
|
|
1501
|
+
async def test_bad_peak_mismatch(
|
|
1502
|
+
two_wallet_nodes: OldSimulatorsAndWallets,
|
|
1503
|
+
default_1000_blocks: list[FullBlock],
|
|
1504
|
+
self_hostname: str,
|
|
1505
|
+
blockchain_constants: ConsensusConstants,
|
|
1506
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
1507
|
+
) -> None:
|
|
1508
|
+
[full_node_api], [(wallet_node, wallet_server), _], _ = two_wallet_nodes
|
|
1509
|
+
full_node = full_node_api.full_node
|
|
1510
|
+
full_node_server = full_node.server
|
|
1511
|
+
blocks = default_1000_blocks
|
|
1512
|
+
header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks, blockchain_constants)
|
|
1513
|
+
wpf = WeightProofHandler(blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries))
|
|
1514
|
+
|
|
1515
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
|
|
1516
|
+
|
|
1517
|
+
await add_blocks_in_batches(blocks, full_node)
|
|
1518
|
+
|
|
1519
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
|
|
1520
|
+
|
|
1521
|
+
# make wp for lower height
|
|
1522
|
+
wp = await wpf.get_proof_of_weight(height_to_hash[uint32(800)])
|
|
1523
|
+
assert wp is not None
|
|
1524
|
+
# create the node respond with the lighter proof
|
|
1525
|
+
wp_msg = make_msg(
|
|
1526
|
+
ProtocolMessageTypes.respond_proof_of_weight,
|
|
1527
|
+
full_node_protocol.RespondProofOfWeight(wp, wp.recent_chain_data[-1].header_hash),
|
|
1528
|
+
)
|
|
1529
|
+
with monkeypatch.context() as m:
|
|
1530
|
+
f: asyncio.Future[Optional[Message]] = asyncio.Future()
|
|
1531
|
+
f.set_result(wp_msg)
|
|
1532
|
+
m.setattr(full_node_api, "request_proof_of_weight", MagicMock(return_value=f))
|
|
1533
|
+
|
|
1534
|
+
# create the node respond with the lighter header block
|
|
1535
|
+
header_block_msg = make_msg(
|
|
1536
|
+
ProtocolMessageTypes.respond_block_header,
|
|
1537
|
+
wallet_protocol.RespondBlockHeader(wp.recent_chain_data[-1]),
|
|
1538
|
+
)
|
|
1539
|
+
f2: asyncio.Future[Optional[Message]] = asyncio.Future()
|
|
1540
|
+
f2.set_result(header_block_msg)
|
|
1541
|
+
m.setattr(full_node_api, "request_block_header", MagicMock(return_value=f2))
|
|
1542
|
+
|
|
1543
|
+
# create new fake peak msg
|
|
1544
|
+
fake_peak_height = uint32(11_000)
|
|
1545
|
+
fake_peak_weight = uint128(1_000_000_000)
|
|
1546
|
+
msg = wallet_protocol.NewPeakWallet(
|
|
1547
|
+
blocks[-1].header_hash, fake_peak_height, fake_peak_weight, uint32(max(blocks[-1].height - 1, uint32(0)))
|
|
1548
|
+
)
|
|
1549
|
+
await asyncio.sleep(3)
|
|
1550
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
|
|
1551
|
+
await wallet_node.new_peak_wallet(msg, wallet_server.all_connections.popitem()[1])
|
|
1552
|
+
await asyncio.sleep(3)
|
|
1553
|
+
peak = await wallet_node.wallet_state_manager.blockchain.get_peak_block()
|
|
1554
|
+
assert peak is not None
|
|
1555
|
+
assert peak.height != fake_peak_height
|
|
1556
|
+
|
|
1557
|
+
|
|
1558
|
+
@pytest.mark.limit_consensus_modes(reason="save time")
|
|
1559
|
+
@pytest.mark.anyio
|
|
1560
|
+
async def test_long_sync_untrusted_break(
|
|
1561
|
+
setup_two_nodes_and_wallet: OldSimulatorsAndWallets,
|
|
1562
|
+
default_1000_blocks: list[FullBlock],
|
|
1563
|
+
default_400_blocks: list[FullBlock],
|
|
1564
|
+
self_hostname: str,
|
|
1565
|
+
caplog: pytest.LogCaptureFixture,
|
|
1566
|
+
use_delta_sync: bool,
|
|
1567
|
+
) -> None:
|
|
1568
|
+
[trusted_full_node_api, untrusted_full_node_api], [(wallet_node, wallet_server)], _ = setup_two_nodes_and_wallet
|
|
1569
|
+
trusted_full_node_server = trusted_full_node_api.full_node.server
|
|
1570
|
+
untrusted_full_node_server = untrusted_full_node_api.full_node.server
|
|
1571
|
+
wallet_node.config["trusted_peers"] = {trusted_full_node_server.node_id.hex(): None}
|
|
1572
|
+
wallet_node.config["use_delta_sync"] = use_delta_sync
|
|
1573
|
+
|
|
1574
|
+
sync_canceled = False
|
|
1575
|
+
|
|
1576
|
+
async def register_for_ph_updates(
|
|
1577
|
+
self: object,
|
|
1578
|
+
request: wallet_protocol.RegisterForPhUpdates,
|
|
1579
|
+
peer: WSChiaConnection,
|
|
1580
|
+
) -> None:
|
|
1581
|
+
nonlocal sync_canceled
|
|
1582
|
+
# Just sleep a long time here to simulate a long-running untrusted sync
|
|
1583
|
+
try:
|
|
1584
|
+
await asyncio.sleep(120)
|
|
1585
|
+
except Exception:
|
|
1586
|
+
sync_canceled = True
|
|
1587
|
+
raise
|
|
1588
|
+
|
|
1589
|
+
def wallet_syncing() -> bool:
|
|
1590
|
+
return wallet_node.wallet_state_manager.sync_mode
|
|
1591
|
+
|
|
1592
|
+
def check_sync_canceled() -> bool:
|
|
1593
|
+
return sync_canceled
|
|
1594
|
+
|
|
1595
|
+
def synced_to_trusted() -> bool:
|
|
1596
|
+
return trusted_full_node_server.node_id in wallet_node.synced_peers
|
|
1597
|
+
|
|
1598
|
+
def only_trusted_peer() -> bool:
|
|
1599
|
+
trusted_peers = sum(wallet_node.is_trusted(peer) for peer in wallet_server.all_connections.values())
|
|
1600
|
+
untrusted_peers = sum(not wallet_node.is_trusted(peer) for peer in wallet_server.all_connections.values())
|
|
1601
|
+
return trusted_peers == 1 and untrusted_peers == 0
|
|
1602
|
+
|
|
1603
|
+
await add_blocks_in_batches(default_400_blocks, trusted_full_node_api.full_node)
|
|
1604
|
+
|
|
1605
|
+
await add_blocks_in_batches(default_1000_blocks[:400], untrusted_full_node_api.full_node)
|
|
1606
|
+
|
|
1607
|
+
with patch_request_handler(api=untrusted_full_node_api, handler=register_for_ph_updates):
|
|
1608
|
+
# Connect to the untrusted peer and wait until the long sync started
|
|
1609
|
+
await wallet_server.start_client(PeerInfo(self_hostname, untrusted_full_node_server.get_port()), None)
|
|
1610
|
+
await time_out_assert(30, wallet_syncing)
|
|
1611
|
+
with caplog.at_level(logging.INFO):
|
|
1612
|
+
# Connect to the trusted peer and make sure the running untrusted long sync gets interrupted via disconnect
|
|
1613
|
+
await wallet_server.start_client(PeerInfo(self_hostname, trusted_full_node_server.get_port()), None)
|
|
1614
|
+
await time_out_assert(600, wallet_height_at_least, True, wallet_node, len(default_400_blocks) - 1)
|
|
1615
|
+
assert time_out_assert(10, synced_to_trusted)
|
|
1616
|
+
assert untrusted_full_node_server.node_id not in wallet_node.synced_peers
|
|
1617
|
+
assert "Connected to a synced trusted peer, disconnecting from all untrusted nodes." in caplog.text
|
|
1618
|
+
|
|
1619
|
+
# Make sure the sync was interrupted
|
|
1620
|
+
assert time_out_assert(30, check_sync_canceled)
|
|
1621
|
+
# And that we only have a trusted peer left
|
|
1622
|
+
assert time_out_assert(30, only_trusted_peer)
|
|
1623
|
+
|
|
1624
|
+
|
|
1625
|
+
@pytest.mark.anyio
|
|
1626
|
+
@pytest.mark.parametrize("chain_length", [0, 100])
|
|
1627
|
+
@pytest.mark.parametrize("fork_point", [500, 1500])
|
|
1628
|
+
async def test_long_reorg_nodes_and_wallet(
|
|
1629
|
+
chain_length: int,
|
|
1630
|
+
fork_point: int,
|
|
1631
|
+
three_nodes: list[FullNodeAPI],
|
|
1632
|
+
simulator_and_wallet: OldSimulatorsAndWallets,
|
|
1633
|
+
default_10000_blocks: list[FullBlock],
|
|
1634
|
+
test_long_reorg_blocks: list[FullBlock],
|
|
1635
|
+
test_long_reorg_1500_blocks: list[FullBlock],
|
|
1636
|
+
self_hostname: str,
|
|
1637
|
+
) -> None:
|
|
1638
|
+
full_node_1, full_node_2, _ = three_nodes
|
|
1639
|
+
_, [wallet], _ = simulator_and_wallet
|
|
1640
|
+
wallet_node = wallet[0]
|
|
1641
|
+
wallet_server = wallet[1]
|
|
1642
|
+
# Trusted node sync
|
|
1643
|
+
wallet_node.config["trusted_peers"] = {full_node_1.server.node_id.hex(): full_node_1.server.node_id.hex()}
|
|
1644
|
+
|
|
1645
|
+
if fork_point == 1500:
|
|
1646
|
+
blocks = default_10000_blocks[: 3600 - chain_length]
|
|
1647
|
+
else:
|
|
1648
|
+
blocks = default_10000_blocks[: 1600 - chain_length]
|
|
1649
|
+
if fork_point == 1500:
|
|
1650
|
+
reorg_blocks = test_long_reorg_1500_blocks[: 3100 - chain_length]
|
|
1651
|
+
else:
|
|
1652
|
+
reorg_blocks = test_long_reorg_blocks[: 1200 - chain_length]
|
|
1653
|
+
pytest.skip("We rely on the light-blocks test for a 0 forkpoint")
|
|
1654
|
+
|
|
1655
|
+
last_blk = blocks[-1]
|
|
1656
|
+
last_reorg_blk = reorg_blocks[-1]
|
|
1657
|
+
assert last_blk.header_hash != last_reorg_blk.header_hash
|
|
1658
|
+
assert last_blk.weight < last_reorg_blk.weight
|
|
1659
|
+
|
|
1660
|
+
await wallet_server.start_client(PeerInfo(self_hostname, full_node_1.server.get_port()), None)
|
|
1661
|
+
assert len(wallet_server.all_connections) == 1
|
|
1662
|
+
assert len(full_node_1.server.all_connections) == 1
|
|
1663
|
+
|
|
1664
|
+
await add_blocks_in_batches(blocks, full_node_1.full_node)
|
|
1665
|
+
node_1_peak = full_node_1.full_node.blockchain.get_peak()
|
|
1666
|
+
assert node_1_peak is not None
|
|
1667
|
+
await time_out_assert(600, wallet_height_at_least, True, wallet_node, node_1_peak.height)
|
|
1668
|
+
log.info(f"wallet node height is {node_1_peak.height}")
|
|
1669
|
+
# full node 2 has the reorg-chain
|
|
1670
|
+
await add_blocks_in_batches(reorg_blocks[:-1], full_node_2.full_node)
|
|
1671
|
+
await connect_and_get_peer(full_node_1.full_node.server, full_node_2.full_node.server, self_hostname)
|
|
1672
|
+
|
|
1673
|
+
# # TODO: There appears to be an issue where the node with the lighter chain
|
|
1674
|
+
# # fails to initiate the reorg until there's a new block farmed onto the
|
|
1675
|
+
# # heavier chain.
|
|
1676
|
+
await full_node_2.full_node.add_block(reorg_blocks[-1])
|
|
1677
|
+
|
|
1678
|
+
def check_nodes_in_sync() -> bool:
|
|
1679
|
+
p1 = full_node_1.full_node.blockchain.get_peak()
|
|
1680
|
+
p2 = full_node_2.full_node.blockchain.get_peak()
|
|
1681
|
+
return p1 is not None and p1 == p2
|
|
1682
|
+
|
|
1683
|
+
await time_out_assert(600, check_nodes_in_sync)
|
|
1684
|
+
node_2_peak = full_node_2.full_node.blockchain.get_peak()
|
|
1685
|
+
assert node_2_peak is not None
|
|
1686
|
+
print(f"peak: {str(node_2_peak.header_hash)[:6]}")
|
|
1687
|
+
await time_out_assert(600, wallet_height_at_least, True, wallet_node, node_2_peak.height)
|
|
1688
|
+
# reorg1_timing = time.monotonic() - start
|
|
1689
|
+
# we already checked p1==p2
|
|
1690
|
+
p1 = full_node_2.full_node.blockchain.get_peak()
|
|
1691
|
+
assert p1 is not None
|
|
1692
|
+
assert p1.header_hash == last_reorg_blk.header_hash
|