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,2700 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import contextlib
|
|
5
|
+
import dataclasses
|
|
6
|
+
import logging
|
|
7
|
+
import random
|
|
8
|
+
import time
|
|
9
|
+
from collections.abc import Awaitable, Coroutine
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
from chia_rs import (
|
|
14
|
+
AugSchemeMPL,
|
|
15
|
+
G2Element,
|
|
16
|
+
PrivateKey,
|
|
17
|
+
SpendBundleConditions,
|
|
18
|
+
additions_and_removals,
|
|
19
|
+
get_flags_for_height_and_constants,
|
|
20
|
+
)
|
|
21
|
+
from clvm.casts import int_to_bytes
|
|
22
|
+
from packaging.version import Version
|
|
23
|
+
|
|
24
|
+
from chia._tests.blockchain.blockchain_test_utils import _validate_and_add_block, _validate_and_add_block_no_error
|
|
25
|
+
from chia._tests.conftest import ConsensusMode
|
|
26
|
+
from chia._tests.connection_utils import add_dummy_connection, connect_and_get_peer
|
|
27
|
+
from chia._tests.core.full_node.stores.test_coin_store import get_future_reward_coins
|
|
28
|
+
from chia._tests.core.make_block_generator import make_spend_bundle
|
|
29
|
+
from chia._tests.core.node_height import node_height_at_least
|
|
30
|
+
from chia._tests.util.misc import wallet_height_at_least
|
|
31
|
+
from chia._tests.util.setup_nodes import SimulatorsAndWalletsServices
|
|
32
|
+
from chia._tests.util.time_out_assert import time_out_assert, time_out_assert_custom_interval, time_out_messages
|
|
33
|
+
from chia.consensus.block_body_validation import ForkInfo
|
|
34
|
+
from chia.consensus.multiprocess_validation import PreValidationResult, pre_validate_block
|
|
35
|
+
from chia.consensus.pot_iterations import is_overflow_block
|
|
36
|
+
from chia.full_node.coin_store import CoinStore
|
|
37
|
+
from chia.full_node.full_node import WalletUpdate
|
|
38
|
+
from chia.full_node.full_node_api import FullNodeAPI
|
|
39
|
+
from chia.full_node.signage_point import SignagePoint
|
|
40
|
+
from chia.full_node.sync_store import Peak
|
|
41
|
+
from chia.protocols import full_node_protocol, timelord_protocol, wallet_protocol
|
|
42
|
+
from chia.protocols import full_node_protocol as fnp
|
|
43
|
+
from chia.protocols.full_node_protocol import RespondTransaction
|
|
44
|
+
from chia.protocols.protocol_message_types import ProtocolMessageTypes
|
|
45
|
+
from chia.protocols.shared_protocol import Capability, default_capabilities
|
|
46
|
+
from chia.protocols.wallet_protocol import SendTransaction, TransactionAck
|
|
47
|
+
from chia.server.address_manager import AddressManager
|
|
48
|
+
from chia.server.outbound_message import Message, NodeType
|
|
49
|
+
from chia.server.server import ChiaServer
|
|
50
|
+
from chia.simulator.add_blocks_in_batches import add_blocks_in_batches
|
|
51
|
+
from chia.simulator.block_tools import (
|
|
52
|
+
BlockTools,
|
|
53
|
+
create_block_tools_async,
|
|
54
|
+
get_signage_point,
|
|
55
|
+
make_unfinished_block,
|
|
56
|
+
test_constants,
|
|
57
|
+
)
|
|
58
|
+
from chia.simulator.full_node_simulator import FullNodeSimulator
|
|
59
|
+
from chia.simulator.keyring import TempKeyring
|
|
60
|
+
from chia.simulator.setup_services import setup_full_node
|
|
61
|
+
from chia.simulator.simulator_protocol import FarmNewBlockProtocol
|
|
62
|
+
from chia.simulator.wallet_tools import WalletTool
|
|
63
|
+
from chia.types.blockchain_format.classgroup import ClassgroupElement
|
|
64
|
+
from chia.types.blockchain_format.foliage import Foliage, FoliageTransactionBlock, TransactionsInfo
|
|
65
|
+
from chia.types.blockchain_format.program import Program
|
|
66
|
+
from chia.types.blockchain_format.proof_of_space import ProofOfSpace, calculate_plot_id_pk, calculate_pos_challenge
|
|
67
|
+
from chia.types.blockchain_format.reward_chain_block import RewardChainBlockUnfinished
|
|
68
|
+
from chia.types.blockchain_format.serialized_program import SerializedProgram
|
|
69
|
+
from chia.types.blockchain_format.sized_bytes import bytes32
|
|
70
|
+
from chia.types.blockchain_format.vdf import CompressibleVDFField, VDFProof
|
|
71
|
+
from chia.types.coin_record import CoinRecord
|
|
72
|
+
from chia.types.coin_spend import make_spend
|
|
73
|
+
from chia.types.condition_opcodes import ConditionOpcode
|
|
74
|
+
from chia.types.condition_with_args import ConditionWithArgs
|
|
75
|
+
from chia.types.full_block import FullBlock
|
|
76
|
+
from chia.types.mempool_inclusion_status import MempoolInclusionStatus
|
|
77
|
+
from chia.types.peer_info import PeerInfo, TimestampedPeerInfo
|
|
78
|
+
from chia.types.spend_bundle import SpendBundle, estimate_fees
|
|
79
|
+
from chia.types.unfinished_block import UnfinishedBlock
|
|
80
|
+
from chia.types.validation_state import ValidationState
|
|
81
|
+
from chia.util.augmented_chain import AugmentedBlockchain
|
|
82
|
+
from chia.util.errors import ConsensusError, Err
|
|
83
|
+
from chia.util.hash import std_hash
|
|
84
|
+
from chia.util.ints import uint8, uint16, uint32, uint64, uint128
|
|
85
|
+
from chia.util.limited_semaphore import LimitedSemaphore
|
|
86
|
+
from chia.util.recursive_replace import recursive_replace
|
|
87
|
+
from chia.util.task_referencer import create_referenced_task
|
|
88
|
+
from chia.util.vdf_prover import get_vdf_info_and_proof
|
|
89
|
+
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
|
|
90
|
+
from chia.wallet.wallet_spend_bundle import WalletSpendBundle
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_pre_validation_result() -> None:
|
|
94
|
+
conds = SpendBundleConditions([], 0, 0, 0, None, None, [], 0, 0, 0, True, 0, 0)
|
|
95
|
+
results = PreValidationResult(None, uint64(1), conds, uint32(0))
|
|
96
|
+
assert results.validated_signature is True
|
|
97
|
+
|
|
98
|
+
conds = SpendBundleConditions([], 0, 0, 0, None, None, [], 0, 0, 0, False, 0, 0)
|
|
99
|
+
results = PreValidationResult(None, uint64(1), conds, uint32(0))
|
|
100
|
+
assert results.validated_signature is False
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
async def new_transaction_not_requested(incoming, new_spend):
|
|
104
|
+
await asyncio.sleep(3)
|
|
105
|
+
while not incoming.empty():
|
|
106
|
+
response = await incoming.get()
|
|
107
|
+
if (
|
|
108
|
+
response is not None
|
|
109
|
+
and isinstance(response, Message)
|
|
110
|
+
and response.type == ProtocolMessageTypes.request_transaction.value
|
|
111
|
+
):
|
|
112
|
+
request = full_node_protocol.RequestTransaction.from_bytes(response.data)
|
|
113
|
+
if request.transaction_id == new_spend.transaction_id:
|
|
114
|
+
return False
|
|
115
|
+
return True
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
async def new_transaction_requested(incoming, new_spend):
|
|
119
|
+
await asyncio.sleep(1)
|
|
120
|
+
while not incoming.empty():
|
|
121
|
+
response = await incoming.get()
|
|
122
|
+
if (
|
|
123
|
+
response is not None
|
|
124
|
+
and isinstance(response, Message)
|
|
125
|
+
and response.type == ProtocolMessageTypes.request_transaction.value
|
|
126
|
+
):
|
|
127
|
+
request = full_node_protocol.RequestTransaction.from_bytes(response.data)
|
|
128
|
+
if request.transaction_id == new_spend.transaction_id:
|
|
129
|
+
return True
|
|
130
|
+
return False
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
async def get_block_path(full_node: FullNodeAPI):
|
|
134
|
+
blocks_list = [await full_node.full_node.blockchain.get_full_peak()]
|
|
135
|
+
assert blocks_list[0] is not None
|
|
136
|
+
while blocks_list[0].height != 0:
|
|
137
|
+
b = await full_node.full_node.block_store.get_full_block(blocks_list[0].prev_header_hash)
|
|
138
|
+
assert b is not None
|
|
139
|
+
blocks_list.insert(0, b)
|
|
140
|
+
return blocks_list
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@pytest.mark.anyio
|
|
144
|
+
async def test_sync_no_farmer(
|
|
145
|
+
setup_two_nodes_and_wallet,
|
|
146
|
+
default_1000_blocks: list[FullBlock],
|
|
147
|
+
self_hostname: str,
|
|
148
|
+
seeded_random: random.Random,
|
|
149
|
+
):
|
|
150
|
+
nodes, _wallets, _bt = setup_two_nodes_and_wallet
|
|
151
|
+
server_1 = nodes[0].full_node.server
|
|
152
|
+
server_2 = nodes[1].full_node.server
|
|
153
|
+
full_node_1 = nodes[0]
|
|
154
|
+
full_node_2 = nodes[1]
|
|
155
|
+
|
|
156
|
+
blocks = default_1000_blocks
|
|
157
|
+
|
|
158
|
+
# full node 1 has the complete chain
|
|
159
|
+
await add_blocks_in_batches(blocks, full_node_1.full_node)
|
|
160
|
+
target_peak = full_node_1.full_node.blockchain.get_peak()
|
|
161
|
+
|
|
162
|
+
# full node 2 is behind by 800 blocks
|
|
163
|
+
await add_blocks_in_batches(blocks[:-800], full_node_2.full_node)
|
|
164
|
+
# connect the nodes and wait for node 2 to sync up to node 1
|
|
165
|
+
await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
166
|
+
|
|
167
|
+
def check_nodes_in_sync():
|
|
168
|
+
p1 = full_node_2.full_node.blockchain.get_peak()
|
|
169
|
+
p2 = full_node_1.full_node.blockchain.get_peak()
|
|
170
|
+
return p1 == p2
|
|
171
|
+
|
|
172
|
+
await time_out_assert(120, check_nodes_in_sync)
|
|
173
|
+
|
|
174
|
+
assert full_node_1.full_node.blockchain.get_peak() == target_peak
|
|
175
|
+
assert full_node_2.full_node.blockchain.get_peak() == target_peak
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@pytest.mark.anyio
|
|
179
|
+
@pytest.mark.parametrize("tx_size", [3000000000000])
|
|
180
|
+
async def test_block_compression(setup_two_nodes_and_wallet, empty_blockchain, tx_size, self_hostname):
|
|
181
|
+
nodes, wallets, bt = setup_two_nodes_and_wallet
|
|
182
|
+
server_1 = nodes[0].full_node.server
|
|
183
|
+
server_2 = nodes[1].full_node.server
|
|
184
|
+
server_3 = wallets[0][1]
|
|
185
|
+
full_node_1 = nodes[0]
|
|
186
|
+
full_node_2 = nodes[1]
|
|
187
|
+
wallet_node_1 = wallets[0][0]
|
|
188
|
+
wallet = wallet_node_1.wallet_state_manager.main_wallet
|
|
189
|
+
|
|
190
|
+
# Avoid retesting the slow reorg portion, not necessary more than once
|
|
191
|
+
test_reorgs = True
|
|
192
|
+
_ = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
193
|
+
_ = await connect_and_get_peer(server_1, server_3, self_hostname)
|
|
194
|
+
|
|
195
|
+
ph = await wallet.get_new_puzzlehash()
|
|
196
|
+
|
|
197
|
+
for i in range(4):
|
|
198
|
+
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
199
|
+
|
|
200
|
+
await time_out_assert(30, wallet_height_at_least, True, wallet_node_1, 4)
|
|
201
|
+
await time_out_assert(30, node_height_at_least, True, full_node_1, 4)
|
|
202
|
+
await time_out_assert(30, node_height_at_least, True, full_node_2, 4)
|
|
203
|
+
await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
|
|
204
|
+
|
|
205
|
+
# Send a transaction to mempool
|
|
206
|
+
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
207
|
+
await wallet.generate_signed_transaction(
|
|
208
|
+
tx_size,
|
|
209
|
+
ph,
|
|
210
|
+
action_scope,
|
|
211
|
+
)
|
|
212
|
+
[tr] = action_scope.side_effects.transactions
|
|
213
|
+
await time_out_assert(
|
|
214
|
+
10,
|
|
215
|
+
full_node_2.full_node.mempool_manager.get_spendbundle,
|
|
216
|
+
tr.spend_bundle,
|
|
217
|
+
tr.name,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# Farm a block
|
|
221
|
+
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
222
|
+
await time_out_assert(30, node_height_at_least, True, full_node_1, 5)
|
|
223
|
+
await time_out_assert(30, node_height_at_least, True, full_node_2, 5)
|
|
224
|
+
await time_out_assert(30, wallet_height_at_least, True, wallet_node_1, 5)
|
|
225
|
+
await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
|
|
226
|
+
|
|
227
|
+
async def check_transaction_confirmed(transaction) -> bool:
|
|
228
|
+
tx = await wallet_node_1.wallet_state_manager.get_transaction(transaction.name)
|
|
229
|
+
return tx.confirmed
|
|
230
|
+
|
|
231
|
+
await time_out_assert(30, check_transaction_confirmed, True, tr)
|
|
232
|
+
|
|
233
|
+
# Confirm generator is not compressed
|
|
234
|
+
program: Optional[SerializedProgram] = (await full_node_1.get_all_full_blocks())[-1].transactions_generator
|
|
235
|
+
assert program is not None
|
|
236
|
+
assert len((await full_node_1.get_all_full_blocks())[-1].transactions_generator_ref_list) == 0
|
|
237
|
+
|
|
238
|
+
# Send another tx
|
|
239
|
+
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
240
|
+
await wallet.generate_signed_transaction(
|
|
241
|
+
20000,
|
|
242
|
+
ph,
|
|
243
|
+
action_scope,
|
|
244
|
+
)
|
|
245
|
+
[tr] = action_scope.side_effects.transactions
|
|
246
|
+
await time_out_assert(
|
|
247
|
+
10,
|
|
248
|
+
full_node_2.full_node.mempool_manager.get_spendbundle,
|
|
249
|
+
tr.spend_bundle,
|
|
250
|
+
tr.name,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
# Farm a block
|
|
254
|
+
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
255
|
+
await time_out_assert(10, node_height_at_least, True, full_node_1, 6)
|
|
256
|
+
await time_out_assert(10, node_height_at_least, True, full_node_2, 6)
|
|
257
|
+
await time_out_assert(10, wallet_height_at_least, True, wallet_node_1, 6)
|
|
258
|
+
await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
|
|
259
|
+
|
|
260
|
+
await time_out_assert(10, check_transaction_confirmed, True, tr)
|
|
261
|
+
|
|
262
|
+
# Confirm generator is compressed
|
|
263
|
+
program: Optional[SerializedProgram] = (await full_node_1.get_all_full_blocks())[-1].transactions_generator
|
|
264
|
+
assert program is not None
|
|
265
|
+
num_blocks = len((await full_node_1.get_all_full_blocks())[-1].transactions_generator_ref_list)
|
|
266
|
+
# since the hard fork, we don't use this compression mechanism
|
|
267
|
+
# anymore, we use CLVM backrefs in the encoding instead
|
|
268
|
+
assert num_blocks == 0
|
|
269
|
+
|
|
270
|
+
# Farm two empty blocks
|
|
271
|
+
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
272
|
+
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
273
|
+
await time_out_assert(10, node_height_at_least, True, full_node_1, 8)
|
|
274
|
+
await time_out_assert(10, node_height_at_least, True, full_node_2, 8)
|
|
275
|
+
await time_out_assert(10, wallet_height_at_least, True, wallet_node_1, 8)
|
|
276
|
+
await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
|
|
277
|
+
|
|
278
|
+
# Send another 2 tx
|
|
279
|
+
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
280
|
+
await wallet.generate_signed_transaction(
|
|
281
|
+
30000,
|
|
282
|
+
ph,
|
|
283
|
+
action_scope,
|
|
284
|
+
)
|
|
285
|
+
[tr] = action_scope.side_effects.transactions
|
|
286
|
+
await time_out_assert(
|
|
287
|
+
10,
|
|
288
|
+
full_node_2.full_node.mempool_manager.get_spendbundle,
|
|
289
|
+
tr.spend_bundle,
|
|
290
|
+
tr.name,
|
|
291
|
+
)
|
|
292
|
+
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
293
|
+
await wallet.generate_signed_transaction(
|
|
294
|
+
40000,
|
|
295
|
+
ph,
|
|
296
|
+
action_scope,
|
|
297
|
+
)
|
|
298
|
+
[tr] = action_scope.side_effects.transactions
|
|
299
|
+
await time_out_assert(
|
|
300
|
+
10,
|
|
301
|
+
full_node_2.full_node.mempool_manager.get_spendbundle,
|
|
302
|
+
tr.spend_bundle,
|
|
303
|
+
tr.name,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
307
|
+
await wallet.generate_signed_transaction(
|
|
308
|
+
50000,
|
|
309
|
+
ph,
|
|
310
|
+
action_scope,
|
|
311
|
+
)
|
|
312
|
+
[tr] = action_scope.side_effects.transactions
|
|
313
|
+
await time_out_assert(
|
|
314
|
+
10,
|
|
315
|
+
full_node_2.full_node.mempool_manager.get_spendbundle,
|
|
316
|
+
tr.spend_bundle,
|
|
317
|
+
tr.name,
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
321
|
+
await wallet.generate_signed_transaction(
|
|
322
|
+
3000000000000,
|
|
323
|
+
ph,
|
|
324
|
+
action_scope,
|
|
325
|
+
)
|
|
326
|
+
[tr] = action_scope.side_effects.transactions
|
|
327
|
+
await time_out_assert(
|
|
328
|
+
10,
|
|
329
|
+
full_node_2.full_node.mempool_manager.get_spendbundle,
|
|
330
|
+
tr.spend_bundle,
|
|
331
|
+
tr.name,
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
# Farm a block
|
|
335
|
+
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
336
|
+
await time_out_assert(10, node_height_at_least, True, full_node_1, 9)
|
|
337
|
+
await time_out_assert(10, node_height_at_least, True, full_node_2, 9)
|
|
338
|
+
await time_out_assert(10, wallet_height_at_least, True, wallet_node_1, 9)
|
|
339
|
+
await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
|
|
340
|
+
|
|
341
|
+
await time_out_assert(10, check_transaction_confirmed, True, tr)
|
|
342
|
+
|
|
343
|
+
# Confirm generator is compressed
|
|
344
|
+
program: Optional[SerializedProgram] = (await full_node_1.get_all_full_blocks())[-1].transactions_generator
|
|
345
|
+
assert program is not None
|
|
346
|
+
num_blocks = len((await full_node_1.get_all_full_blocks())[-1].transactions_generator_ref_list)
|
|
347
|
+
# since the hard fork, we don't use this compression mechanism
|
|
348
|
+
# anymore, we use CLVM backrefs in the encoding instead
|
|
349
|
+
assert num_blocks == 0
|
|
350
|
+
|
|
351
|
+
# Creates a standard_transaction and an anyone-can-spend tx
|
|
352
|
+
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=False) as action_scope:
|
|
353
|
+
await wallet.generate_signed_transaction(
|
|
354
|
+
30000,
|
|
355
|
+
Program.to(1).get_tree_hash(),
|
|
356
|
+
action_scope,
|
|
357
|
+
)
|
|
358
|
+
[tr] = action_scope.side_effects.transactions
|
|
359
|
+
extra_spend = WalletSpendBundle(
|
|
360
|
+
[
|
|
361
|
+
make_spend(
|
|
362
|
+
next(coin for coin in tr.additions if coin.puzzle_hash == Program.to(1).get_tree_hash()),
|
|
363
|
+
Program.to(1),
|
|
364
|
+
Program.to([[51, ph, 30000]]),
|
|
365
|
+
)
|
|
366
|
+
],
|
|
367
|
+
G2Element(),
|
|
368
|
+
)
|
|
369
|
+
new_spend_bundle = WalletSpendBundle.aggregate([tr.spend_bundle, extra_spend])
|
|
370
|
+
new_tr = dataclasses.replace(
|
|
371
|
+
tr,
|
|
372
|
+
spend_bundle=new_spend_bundle,
|
|
373
|
+
additions=new_spend_bundle.additions(),
|
|
374
|
+
removals=new_spend_bundle.removals(),
|
|
375
|
+
)
|
|
376
|
+
[new_tr] = await wallet.wallet_state_manager.add_pending_transactions([new_tr])
|
|
377
|
+
await time_out_assert(
|
|
378
|
+
10,
|
|
379
|
+
full_node_2.full_node.mempool_manager.get_spendbundle,
|
|
380
|
+
new_tr.spend_bundle,
|
|
381
|
+
new_tr.spend_bundle.name(),
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
# Farm a block
|
|
385
|
+
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
386
|
+
await time_out_assert(10, node_height_at_least, True, full_node_1, 10)
|
|
387
|
+
await time_out_assert(10, node_height_at_least, True, full_node_2, 10)
|
|
388
|
+
await time_out_assert(10, wallet_height_at_least, True, wallet_node_1, 10)
|
|
389
|
+
await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
|
|
390
|
+
|
|
391
|
+
await time_out_assert(10, check_transaction_confirmed, True, new_tr)
|
|
392
|
+
|
|
393
|
+
# Confirm generator is not compressed, #CAT creation has a cat spend
|
|
394
|
+
all_blocks = await full_node_1.get_all_full_blocks()
|
|
395
|
+
program: Optional[SerializedProgram] = all_blocks[-1].transactions_generator
|
|
396
|
+
assert program is not None
|
|
397
|
+
assert len(all_blocks[-1].transactions_generator_ref_list) == 0
|
|
398
|
+
|
|
399
|
+
# Make a standard transaction and an anyone-can-spend transaction
|
|
400
|
+
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=False) as action_scope:
|
|
401
|
+
await wallet.generate_signed_transaction(
|
|
402
|
+
30000,
|
|
403
|
+
Program.to(1).get_tree_hash(),
|
|
404
|
+
action_scope,
|
|
405
|
+
)
|
|
406
|
+
[tr] = action_scope.side_effects.transactions
|
|
407
|
+
extra_spend = WalletSpendBundle(
|
|
408
|
+
[
|
|
409
|
+
make_spend(
|
|
410
|
+
next(coin for coin in tr.additions if coin.puzzle_hash == Program.to(1).get_tree_hash()),
|
|
411
|
+
Program.to(1),
|
|
412
|
+
Program.to([[51, ph, 30000]]),
|
|
413
|
+
)
|
|
414
|
+
],
|
|
415
|
+
G2Element(),
|
|
416
|
+
)
|
|
417
|
+
new_spend_bundle = WalletSpendBundle.aggregate([tr.spend_bundle, extra_spend])
|
|
418
|
+
new_tr = dataclasses.replace(
|
|
419
|
+
tr,
|
|
420
|
+
spend_bundle=new_spend_bundle,
|
|
421
|
+
additions=new_spend_bundle.additions(),
|
|
422
|
+
removals=new_spend_bundle.removals(),
|
|
423
|
+
)
|
|
424
|
+
[new_tr] = await wallet.wallet_state_manager.add_pending_transactions([new_tr])
|
|
425
|
+
await time_out_assert(
|
|
426
|
+
10,
|
|
427
|
+
full_node_2.full_node.mempool_manager.get_spendbundle,
|
|
428
|
+
new_tr.spend_bundle,
|
|
429
|
+
new_tr.spend_bundle.name(),
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
# Farm a block
|
|
433
|
+
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
434
|
+
await time_out_assert(10, node_height_at_least, True, full_node_1, 11)
|
|
435
|
+
await time_out_assert(10, node_height_at_least, True, full_node_2, 11)
|
|
436
|
+
await time_out_assert(10, wallet_height_at_least, True, wallet_node_1, 11)
|
|
437
|
+
await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
|
|
438
|
+
|
|
439
|
+
# Confirm generator is not compressed
|
|
440
|
+
program: Optional[SerializedProgram] = (await full_node_1.get_all_full_blocks())[-1].transactions_generator
|
|
441
|
+
assert program is not None
|
|
442
|
+
assert len((await full_node_1.get_all_full_blocks())[-1].transactions_generator_ref_list) == 0
|
|
443
|
+
|
|
444
|
+
height = full_node_1.full_node.blockchain.get_peak().height
|
|
445
|
+
|
|
446
|
+
blockchain = empty_blockchain
|
|
447
|
+
all_blocks: list[FullBlock] = await full_node_1.get_all_full_blocks()
|
|
448
|
+
assert height == len(all_blocks) - 1
|
|
449
|
+
|
|
450
|
+
if test_reorgs:
|
|
451
|
+
ssi = bt.constants.SUB_SLOT_ITERS_STARTING
|
|
452
|
+
diff = bt.constants.DIFFICULTY_STARTING
|
|
453
|
+
reog_blocks = bt.get_consecutive_blocks(14)
|
|
454
|
+
for r in range(0, len(reog_blocks), 3):
|
|
455
|
+
fork_info = ForkInfo(-1, -1, bt.constants.GENESIS_CHALLENGE)
|
|
456
|
+
for reorg_block in reog_blocks[:r]:
|
|
457
|
+
await _validate_and_add_block_no_error(blockchain, reorg_block, fork_info=fork_info)
|
|
458
|
+
for i in range(1, height):
|
|
459
|
+
vs = ValidationState(ssi, diff, None)
|
|
460
|
+
chain = AugmentedBlockchain(blockchain)
|
|
461
|
+
futures: list[Awaitable[PreValidationResult]] = []
|
|
462
|
+
for block in all_blocks[:i]:
|
|
463
|
+
futures.append(
|
|
464
|
+
await pre_validate_block(
|
|
465
|
+
blockchain.constants,
|
|
466
|
+
chain,
|
|
467
|
+
block,
|
|
468
|
+
blockchain.pool,
|
|
469
|
+
None,
|
|
470
|
+
vs,
|
|
471
|
+
)
|
|
472
|
+
)
|
|
473
|
+
results: list[PreValidationResult] = list(await asyncio.gather(*futures))
|
|
474
|
+
for result in results:
|
|
475
|
+
assert result.error is None
|
|
476
|
+
|
|
477
|
+
for r in range(0, len(all_blocks), 3):
|
|
478
|
+
fork_info = ForkInfo(-1, -1, bt.constants.GENESIS_CHALLENGE)
|
|
479
|
+
for block in all_blocks[:r]:
|
|
480
|
+
await _validate_and_add_block_no_error(blockchain, block, fork_info=fork_info)
|
|
481
|
+
for i in range(1, height):
|
|
482
|
+
vs = ValidationState(ssi, diff, None)
|
|
483
|
+
chain = AugmentedBlockchain(blockchain)
|
|
484
|
+
futures = []
|
|
485
|
+
for block in all_blocks[:i]:
|
|
486
|
+
futures.append(
|
|
487
|
+
await pre_validate_block(blockchain.constants, chain, block, blockchain.pool, None, vs)
|
|
488
|
+
)
|
|
489
|
+
results = list(await asyncio.gather(*futures))
|
|
490
|
+
for result in results:
|
|
491
|
+
assert result.error is None
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
@pytest.mark.anyio
|
|
495
|
+
async def test_spendbundle_serialization():
|
|
496
|
+
sb: SpendBundle = make_spend_bundle(1)
|
|
497
|
+
protocol_message = RespondTransaction(sb)
|
|
498
|
+
assert bytes(sb) == bytes(protocol_message)
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
@pytest.mark.anyio
|
|
502
|
+
async def test_inbound_connection_limit(setup_four_nodes, self_hostname):
|
|
503
|
+
nodes, _, _ = setup_four_nodes
|
|
504
|
+
server_1 = nodes[0].full_node.server
|
|
505
|
+
server_1.config["target_peer_count"] = 2
|
|
506
|
+
server_1.config["target_outbound_peer_count"] = 0
|
|
507
|
+
for i in range(1, 4):
|
|
508
|
+
full_node_i = nodes[i]
|
|
509
|
+
server_i = full_node_i.full_node.server
|
|
510
|
+
await server_i.start_client(PeerInfo(self_hostname, server_1.get_port()))
|
|
511
|
+
assert len(server_1.get_connections(NodeType.FULL_NODE)) == 2
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
@pytest.mark.anyio
|
|
515
|
+
async def test_request_peers(wallet_nodes, self_hostname):
|
|
516
|
+
full_node_1, full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, _ = wallet_nodes
|
|
517
|
+
full_node_2.full_node.full_node_peers.address_manager.make_private_subnets_valid()
|
|
518
|
+
await server_2.start_client(PeerInfo(self_hostname, server_1.get_port()))
|
|
519
|
+
|
|
520
|
+
async def have_msgs():
|
|
521
|
+
await full_node_2.full_node.full_node_peers.address_manager.add_to_new_table(
|
|
522
|
+
[TimestampedPeerInfo("127.0.0.1", uint16(1000), uint64(int(time.time())) - 1000)],
|
|
523
|
+
None,
|
|
524
|
+
)
|
|
525
|
+
msg_bytes = await full_node_2.full_node.full_node_peers.request_peers(PeerInfo("::1", server_2._port))
|
|
526
|
+
msg = fnp.RespondPeers.from_bytes(msg_bytes.data)
|
|
527
|
+
if msg is not None and not (len(msg.peer_list) == 1):
|
|
528
|
+
return False
|
|
529
|
+
peer = msg.peer_list[0]
|
|
530
|
+
return (peer.host in {self_hostname, "127.0.0.1"}) and peer.port == 1000
|
|
531
|
+
|
|
532
|
+
await time_out_assert_custom_interval(10, 1, have_msgs, True)
|
|
533
|
+
full_node_1.full_node.full_node_peers.address_manager = AddressManager()
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
@pytest.mark.anyio
|
|
537
|
+
async def test_basic_chain(wallet_nodes, self_hostname):
|
|
538
|
+
full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
|
|
539
|
+
|
|
540
|
+
incoming_queue, _ = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
541
|
+
expected_requests = 0
|
|
542
|
+
if await full_node_1.full_node.synced():
|
|
543
|
+
expected_requests = 1
|
|
544
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
|
|
545
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
546
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
547
|
+
for block in blocks[:1]:
|
|
548
|
+
await full_node_1.full_node.add_block(block, peer)
|
|
549
|
+
|
|
550
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "new_peak", 1))
|
|
551
|
+
|
|
552
|
+
assert full_node_1.full_node.blockchain.get_peak().height == 0
|
|
553
|
+
|
|
554
|
+
fork_info = ForkInfo(-1, -1, bt.constants.GENESIS_CHALLENGE)
|
|
555
|
+
for block in bt.get_consecutive_blocks(30):
|
|
556
|
+
await full_node_1.full_node.add_block(block, peer, fork_info=fork_info)
|
|
557
|
+
|
|
558
|
+
assert full_node_1.full_node.blockchain.get_peak().height == 29
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
@pytest.mark.anyio
|
|
562
|
+
async def test_respond_end_of_sub_slot(wallet_nodes, self_hostname):
|
|
563
|
+
full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
|
|
564
|
+
|
|
565
|
+
incoming_queue, _dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
566
|
+
expected_requests = 0
|
|
567
|
+
if await full_node_1.full_node.synced():
|
|
568
|
+
expected_requests = 1
|
|
569
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
|
|
570
|
+
|
|
571
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
572
|
+
|
|
573
|
+
# Create empty slots
|
|
574
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
575
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=6)
|
|
576
|
+
|
|
577
|
+
# Add empty slots successful
|
|
578
|
+
for slot in blocks[-1].finished_sub_slots[:-2]:
|
|
579
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
580
|
+
num_sub_slots_added = len(blocks[-1].finished_sub_slots[:-2])
|
|
581
|
+
await time_out_assert(
|
|
582
|
+
10,
|
|
583
|
+
time_out_messages(
|
|
584
|
+
incoming_queue,
|
|
585
|
+
"new_signage_point_or_end_of_sub_slot",
|
|
586
|
+
num_sub_slots_added,
|
|
587
|
+
),
|
|
588
|
+
)
|
|
589
|
+
# Already have sub slot
|
|
590
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(blocks[-1].finished_sub_slots[-3]), peer)
|
|
591
|
+
await asyncio.sleep(2)
|
|
592
|
+
assert incoming_queue.qsize() == 0
|
|
593
|
+
|
|
594
|
+
# Add empty slots unsuccessful
|
|
595
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(blocks[-1].finished_sub_slots[-1]), peer)
|
|
596
|
+
await asyncio.sleep(2)
|
|
597
|
+
assert incoming_queue.qsize() == 0
|
|
598
|
+
|
|
599
|
+
# Add some blocks
|
|
600
|
+
blocks = bt.get_consecutive_blocks(4, block_list_input=blocks)
|
|
601
|
+
for block in blocks[-5:]:
|
|
602
|
+
await full_node_1.full_node.add_block(block, peer)
|
|
603
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "new_peak", 5))
|
|
604
|
+
blocks = bt.get_consecutive_blocks(1, skip_slots=2, block_list_input=blocks)
|
|
605
|
+
|
|
606
|
+
# Add empty slots successful
|
|
607
|
+
for slot in blocks[-1].finished_sub_slots:
|
|
608
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
609
|
+
num_sub_slots_added = len(blocks[-1].finished_sub_slots)
|
|
610
|
+
await time_out_assert(
|
|
611
|
+
10,
|
|
612
|
+
time_out_messages(
|
|
613
|
+
incoming_queue,
|
|
614
|
+
"new_signage_point_or_end_of_sub_slot",
|
|
615
|
+
num_sub_slots_added,
|
|
616
|
+
),
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
@pytest.mark.anyio
|
|
621
|
+
async def test_respond_end_of_sub_slot_no_reorg(wallet_nodes, self_hostname):
|
|
622
|
+
full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
|
|
623
|
+
|
|
624
|
+
incoming_queue, _dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
625
|
+
expected_requests = 0
|
|
626
|
+
if await full_node_1.full_node.synced():
|
|
627
|
+
expected_requests = 1
|
|
628
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
|
|
629
|
+
|
|
630
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
631
|
+
|
|
632
|
+
# First get two blocks in the same sub slot
|
|
633
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
634
|
+
|
|
635
|
+
for i in range(0, 9999999):
|
|
636
|
+
blocks = bt.get_consecutive_blocks(5, block_list_input=blocks, skip_slots=1, seed=i.to_bytes(4, "big"))
|
|
637
|
+
if len(blocks[-1].finished_sub_slots) == 0:
|
|
638
|
+
break
|
|
639
|
+
|
|
640
|
+
# Then create a fork after the first block.
|
|
641
|
+
blocks_alt_1 = bt.get_consecutive_blocks(1, block_list_input=blocks[:-1], skip_slots=1)
|
|
642
|
+
for slot in blocks[-1].finished_sub_slots[:-2]:
|
|
643
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
644
|
+
|
|
645
|
+
# Add all blocks
|
|
646
|
+
for block in blocks:
|
|
647
|
+
await full_node_1.full_node.add_block(block, peer)
|
|
648
|
+
|
|
649
|
+
original_ss = full_node_1.full_node.full_node_store.finished_sub_slots[:]
|
|
650
|
+
|
|
651
|
+
# Add subslot for first alternative
|
|
652
|
+
for slot in blocks_alt_1[-1].finished_sub_slots:
|
|
653
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
654
|
+
|
|
655
|
+
assert full_node_1.full_node.full_node_store.finished_sub_slots == original_ss
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
@pytest.mark.anyio
|
|
659
|
+
async def test_respond_end_of_sub_slot_race(wallet_nodes, self_hostname):
|
|
660
|
+
full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
|
|
661
|
+
|
|
662
|
+
incoming_queue, _dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
663
|
+
expected_requests = 0
|
|
664
|
+
if await full_node_1.full_node.synced():
|
|
665
|
+
expected_requests = 1
|
|
666
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
|
|
667
|
+
|
|
668
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
669
|
+
|
|
670
|
+
# First get two blocks in the same sub slot
|
|
671
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
672
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
673
|
+
|
|
674
|
+
await full_node_1.full_node.add_block(blocks[-1], peer)
|
|
675
|
+
|
|
676
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
|
|
677
|
+
|
|
678
|
+
original_ss = full_node_1.full_node.full_node_store.finished_sub_slots[:].copy()
|
|
679
|
+
# Add the block
|
|
680
|
+
await full_node_1.full_node.add_block(blocks[-1], peer)
|
|
681
|
+
|
|
682
|
+
# Replace with original SS in order to imitate race condition (block added but subslot not yet added)
|
|
683
|
+
full_node_1.full_node.full_node_store.finished_sub_slots = original_ss
|
|
684
|
+
|
|
685
|
+
for slot in blocks[-1].finished_sub_slots:
|
|
686
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
@pytest.mark.anyio
|
|
690
|
+
async def test_respond_unfinished(wallet_nodes, self_hostname):
|
|
691
|
+
full_node_1, _full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
692
|
+
|
|
693
|
+
incoming_queue, _dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
694
|
+
expected_requests = 0
|
|
695
|
+
if await full_node_1.full_node.synced():
|
|
696
|
+
expected_requests = 1
|
|
697
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
|
|
698
|
+
|
|
699
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
700
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
701
|
+
|
|
702
|
+
# Create empty slots
|
|
703
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=6)
|
|
704
|
+
block = blocks[-1]
|
|
705
|
+
unf = make_unfinished_block(block, bt.constants)
|
|
706
|
+
|
|
707
|
+
# Can't add because no sub slots
|
|
708
|
+
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is None
|
|
709
|
+
|
|
710
|
+
# Add empty slots successful
|
|
711
|
+
for slot in blocks[-1].finished_sub_slots:
|
|
712
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
713
|
+
|
|
714
|
+
await full_node_1.full_node.add_unfinished_block(unf, None)
|
|
715
|
+
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is not None
|
|
716
|
+
|
|
717
|
+
# Do the same thing but with non-genesis
|
|
718
|
+
await full_node_1.full_node.add_block(block)
|
|
719
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=3)
|
|
720
|
+
|
|
721
|
+
block = blocks[-1]
|
|
722
|
+
unf = make_unfinished_block(block, bt.constants)
|
|
723
|
+
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is None
|
|
724
|
+
|
|
725
|
+
for slot in blocks[-1].finished_sub_slots:
|
|
726
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
727
|
+
|
|
728
|
+
await full_node_1.full_node.add_unfinished_block(unf, None)
|
|
729
|
+
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is not None
|
|
730
|
+
|
|
731
|
+
# Do the same thing one more time, with overflow
|
|
732
|
+
await full_node_1.full_node.add_block(block)
|
|
733
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=3, force_overflow=True)
|
|
734
|
+
|
|
735
|
+
block = blocks[-1]
|
|
736
|
+
unf = make_unfinished_block(block, bt.constants, force_overflow=True)
|
|
737
|
+
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is None
|
|
738
|
+
|
|
739
|
+
for slot in blocks[-1].finished_sub_slots:
|
|
740
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
741
|
+
|
|
742
|
+
await full_node_1.full_node.add_unfinished_block(unf, None)
|
|
743
|
+
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is not None
|
|
744
|
+
|
|
745
|
+
# This next section tests making unfinished block with transactions, and then submitting the finished block
|
|
746
|
+
ph = wallet_a.get_new_puzzlehash()
|
|
747
|
+
ph_receiver = wallet_receiver.get_new_puzzlehash()
|
|
748
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
749
|
+
blocks = bt.get_consecutive_blocks(
|
|
750
|
+
2,
|
|
751
|
+
block_list_input=blocks,
|
|
752
|
+
guarantee_transaction_block=True,
|
|
753
|
+
farmer_reward_puzzle_hash=ph,
|
|
754
|
+
pool_reward_puzzle_hash=ph,
|
|
755
|
+
)
|
|
756
|
+
await full_node_1.full_node.add_block(blocks[-2])
|
|
757
|
+
await full_node_1.full_node.add_block(blocks[-1])
|
|
758
|
+
coin_to_spend = blocks[-1].get_included_reward_coins()[0]
|
|
759
|
+
|
|
760
|
+
spend_bundle = wallet_a.generate_signed_transaction(coin_to_spend.amount, ph_receiver, coin_to_spend)
|
|
761
|
+
|
|
762
|
+
blocks = bt.get_consecutive_blocks(
|
|
763
|
+
1,
|
|
764
|
+
block_list_input=blocks,
|
|
765
|
+
guarantee_transaction_block=True,
|
|
766
|
+
transaction_data=spend_bundle,
|
|
767
|
+
force_overflow=True,
|
|
768
|
+
seed=b"random seed",
|
|
769
|
+
)
|
|
770
|
+
block = blocks[-1]
|
|
771
|
+
unf = make_unfinished_block(block, bt.constants, force_overflow=True)
|
|
772
|
+
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is None
|
|
773
|
+
await full_node_1.full_node.add_unfinished_block(unf, None)
|
|
774
|
+
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is not None
|
|
775
|
+
entry = full_node_1.full_node.full_node_store.get_unfinished_block_result(
|
|
776
|
+
unf.partial_hash, unf.foliage.foliage_transaction_block_hash
|
|
777
|
+
)
|
|
778
|
+
assert entry is not None
|
|
779
|
+
result = entry.result
|
|
780
|
+
assert result is not None
|
|
781
|
+
assert result.conds is not None
|
|
782
|
+
assert result.conds.cost > 0
|
|
783
|
+
|
|
784
|
+
assert not full_node_1.full_node.blockchain.contains_block(block.header_hash)
|
|
785
|
+
assert block.transactions_generator is not None
|
|
786
|
+
block_no_transactions = block.replace(transactions_generator=None)
|
|
787
|
+
assert block_no_transactions.transactions_generator is None
|
|
788
|
+
|
|
789
|
+
await full_node_1.full_node.add_block(block_no_transactions)
|
|
790
|
+
assert full_node_1.full_node.blockchain.contains_block(block.header_hash)
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
@pytest.mark.anyio
|
|
794
|
+
async def test_new_peak(wallet_nodes, self_hostname):
|
|
795
|
+
full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
|
|
796
|
+
|
|
797
|
+
incoming_queue, dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
798
|
+
dummy_peer = server_1.all_connections[dummy_node_id]
|
|
799
|
+
expected_requests = 0
|
|
800
|
+
if await full_node_1.full_node.synced():
|
|
801
|
+
expected_requests = 1
|
|
802
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
|
|
803
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
804
|
+
|
|
805
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
806
|
+
blocks = bt.get_consecutive_blocks(3, block_list_input=blocks) # Alternate chain
|
|
807
|
+
|
|
808
|
+
blocks_reorg = bt.get_consecutive_blocks(3, block_list_input=blocks[:-1], seed=b"214") # Alternate chain
|
|
809
|
+
for block in blocks[-3:]:
|
|
810
|
+
new_peak = fnp.NewPeak(
|
|
811
|
+
block.header_hash,
|
|
812
|
+
block.height,
|
|
813
|
+
block.weight,
|
|
814
|
+
uint32(0),
|
|
815
|
+
block.reward_chain_block.get_unfinished().get_hash(),
|
|
816
|
+
)
|
|
817
|
+
task_1 = create_referenced_task(full_node_1.new_peak(new_peak, dummy_peer))
|
|
818
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 1))
|
|
819
|
+
task_1.cancel()
|
|
820
|
+
|
|
821
|
+
await full_node_1.full_node.add_block(block, peer)
|
|
822
|
+
# Ignores, already have
|
|
823
|
+
task_2 = create_referenced_task(full_node_1.new_peak(new_peak, dummy_peer))
|
|
824
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 0))
|
|
825
|
+
task_2.cancel()
|
|
826
|
+
|
|
827
|
+
async def suppress_value_error(coro: Coroutine) -> None:
|
|
828
|
+
with contextlib.suppress(ValueError):
|
|
829
|
+
await coro
|
|
830
|
+
|
|
831
|
+
# Ignores low weight
|
|
832
|
+
new_peak = fnp.NewPeak(
|
|
833
|
+
blocks_reorg[-2].header_hash,
|
|
834
|
+
blocks_reorg[-2].height,
|
|
835
|
+
blocks_reorg[-2].weight,
|
|
836
|
+
uint32(0),
|
|
837
|
+
blocks_reorg[-2].reward_chain_block.get_unfinished().get_hash(),
|
|
838
|
+
)
|
|
839
|
+
create_referenced_task(suppress_value_error(full_node_1.new_peak(new_peak, dummy_peer)))
|
|
840
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 0))
|
|
841
|
+
|
|
842
|
+
# Does not ignore equal weight
|
|
843
|
+
new_peak = fnp.NewPeak(
|
|
844
|
+
blocks_reorg[-1].header_hash,
|
|
845
|
+
blocks_reorg[-1].height,
|
|
846
|
+
blocks_reorg[-1].weight,
|
|
847
|
+
uint32(0),
|
|
848
|
+
blocks_reorg[-1].reward_chain_block.get_unfinished().get_hash(),
|
|
849
|
+
)
|
|
850
|
+
create_referenced_task(suppress_value_error(full_node_1.new_peak(new_peak, dummy_peer)))
|
|
851
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 1))
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
@pytest.mark.anyio
|
|
855
|
+
async def test_new_transaction_and_mempool(wallet_nodes, self_hostname, seeded_random: random.Random):
|
|
856
|
+
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
857
|
+
wallet_ph = wallet_a.get_new_puzzlehash()
|
|
858
|
+
blocks = bt.get_consecutive_blocks(
|
|
859
|
+
3,
|
|
860
|
+
guarantee_transaction_block=True,
|
|
861
|
+
farmer_reward_puzzle_hash=wallet_ph,
|
|
862
|
+
pool_reward_puzzle_hash=wallet_ph,
|
|
863
|
+
)
|
|
864
|
+
for block in blocks:
|
|
865
|
+
await full_node_1.full_node.add_block(block)
|
|
866
|
+
|
|
867
|
+
start_height = (
|
|
868
|
+
full_node_1.full_node.blockchain.get_peak().height
|
|
869
|
+
if full_node_1.full_node.blockchain.get_peak() is not None
|
|
870
|
+
else -1
|
|
871
|
+
)
|
|
872
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
873
|
+
incoming_queue, node_id = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
874
|
+
fake_peer = server_1.all_connections[node_id]
|
|
875
|
+
puzzle_hashes = []
|
|
876
|
+
|
|
877
|
+
# Makes a bunch of coins
|
|
878
|
+
conditions_dict: dict = {ConditionOpcode.CREATE_COIN: []}
|
|
879
|
+
# This should fit in one transaction
|
|
880
|
+
for _ in range(100):
|
|
881
|
+
receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
|
|
882
|
+
puzzle_hashes.append(receiver_puzzlehash)
|
|
883
|
+
output = ConditionWithArgs(ConditionOpcode.CREATE_COIN, [receiver_puzzlehash, int_to_bytes(10000000000)])
|
|
884
|
+
|
|
885
|
+
conditions_dict[ConditionOpcode.CREATE_COIN].append(output)
|
|
886
|
+
|
|
887
|
+
spend_bundle = wallet_a.generate_signed_transaction(
|
|
888
|
+
100,
|
|
889
|
+
puzzle_hashes[0],
|
|
890
|
+
get_future_reward_coins(blocks[1])[0],
|
|
891
|
+
condition_dic=conditions_dict,
|
|
892
|
+
)
|
|
893
|
+
assert spend_bundle is not None
|
|
894
|
+
new_transaction = fnp.NewTransaction(spend_bundle.get_hash(), uint64(100), uint64(100))
|
|
895
|
+
|
|
896
|
+
await full_node_1.new_transaction(new_transaction, fake_peer)
|
|
897
|
+
await time_out_assert(10, new_transaction_requested, True, incoming_queue, new_transaction)
|
|
898
|
+
|
|
899
|
+
respond_transaction_2 = fnp.RespondTransaction(spend_bundle)
|
|
900
|
+
await full_node_1.respond_transaction(respond_transaction_2, peer)
|
|
901
|
+
|
|
902
|
+
blocks = bt.get_consecutive_blocks(
|
|
903
|
+
1,
|
|
904
|
+
block_list_input=blocks,
|
|
905
|
+
guarantee_transaction_block=True,
|
|
906
|
+
transaction_data=spend_bundle,
|
|
907
|
+
)
|
|
908
|
+
await full_node_1.full_node.add_block(blocks[-1], None)
|
|
909
|
+
|
|
910
|
+
# Already seen
|
|
911
|
+
await full_node_1.new_transaction(new_transaction, fake_peer)
|
|
912
|
+
await time_out_assert(10, new_transaction_not_requested, True, incoming_queue, new_transaction)
|
|
913
|
+
|
|
914
|
+
await time_out_assert(10, node_height_at_least, True, full_node_1, start_height + 1)
|
|
915
|
+
await time_out_assert(10, node_height_at_least, True, full_node_2, start_height + 1)
|
|
916
|
+
|
|
917
|
+
included_tx = 0
|
|
918
|
+
not_included_tx = 0
|
|
919
|
+
seen_bigger_transaction_has_high_fee = False
|
|
920
|
+
successful_bundle: Optional[WalletSpendBundle] = None
|
|
921
|
+
|
|
922
|
+
# Fill mempool
|
|
923
|
+
receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
|
|
924
|
+
random.seed(b"123465")
|
|
925
|
+
group_size = 3 # We will generate transaction bundles of this size (* standard transaction of around 3-4M cost)
|
|
926
|
+
for i in range(1, len(puzzle_hashes), group_size):
|
|
927
|
+
phs_to_use = [puzzle_hashes[i + j] for j in range(group_size) if (i + j) < len(puzzle_hashes)]
|
|
928
|
+
coin_records = [
|
|
929
|
+
(await full_node_1.full_node.coin_store.get_coin_records_by_puzzle_hash(True, puzzle_hash))[0]
|
|
930
|
+
for puzzle_hash in phs_to_use
|
|
931
|
+
]
|
|
932
|
+
|
|
933
|
+
last_iteration = (i == len(puzzle_hashes) - group_size) or len(phs_to_use) < group_size
|
|
934
|
+
if last_iteration:
|
|
935
|
+
force_high_fee = True
|
|
936
|
+
fee = 100000000 * group_size # 100 million * group_size (20 fee per cost)
|
|
937
|
+
else:
|
|
938
|
+
force_high_fee = False
|
|
939
|
+
fee = random.randint(1, 100000000 * group_size)
|
|
940
|
+
spend_bundles = [
|
|
941
|
+
wallet_receiver.generate_signed_transaction(uint64(500), receiver_puzzlehash, coin_record.coin, fee=0)
|
|
942
|
+
for coin_record in coin_records[1:]
|
|
943
|
+
] + [
|
|
944
|
+
wallet_receiver.generate_signed_transaction(uint64(500), receiver_puzzlehash, coin_records[0].coin, fee=fee)
|
|
945
|
+
]
|
|
946
|
+
spend_bundle = WalletSpendBundle.aggregate(spend_bundles)
|
|
947
|
+
assert estimate_fees(spend_bundle) == fee
|
|
948
|
+
respond_transaction = wallet_protocol.SendTransaction(spend_bundle)
|
|
949
|
+
|
|
950
|
+
await full_node_1.send_transaction(respond_transaction)
|
|
951
|
+
|
|
952
|
+
request = fnp.RequestTransaction(spend_bundle.get_hash())
|
|
953
|
+
req = await full_node_1.request_transaction(request)
|
|
954
|
+
|
|
955
|
+
fee_rate_for_med = full_node_1.full_node.mempool_manager.mempool.get_min_fee_rate(5000000)
|
|
956
|
+
fee_rate_for_large = full_node_1.full_node.mempool_manager.mempool.get_min_fee_rate(50000000)
|
|
957
|
+
if fee_rate_for_large > fee_rate_for_med:
|
|
958
|
+
seen_bigger_transaction_has_high_fee = True
|
|
959
|
+
|
|
960
|
+
if req is not None and req.data == bytes(fnp.RespondTransaction(spend_bundle)):
|
|
961
|
+
included_tx += 1
|
|
962
|
+
spend_bundles.append(spend_bundle)
|
|
963
|
+
assert not full_node_1.full_node.mempool_manager.mempool.at_full_capacity(0)
|
|
964
|
+
assert full_node_1.full_node.mempool_manager.mempool.get_min_fee_rate(0) == 0
|
|
965
|
+
if force_high_fee:
|
|
966
|
+
successful_bundle = spend_bundle
|
|
967
|
+
else:
|
|
968
|
+
assert full_node_1.full_node.mempool_manager.mempool.at_full_capacity(10500000 * group_size)
|
|
969
|
+
assert full_node_1.full_node.mempool_manager.mempool.get_min_fee_rate(10500000 * group_size) > 0
|
|
970
|
+
assert not force_high_fee
|
|
971
|
+
not_included_tx += 1
|
|
972
|
+
assert successful_bundle is not None
|
|
973
|
+
assert full_node_1.full_node.mempool_manager.mempool.at_full_capacity(10000000 * group_size)
|
|
974
|
+
|
|
975
|
+
# these numbers reflect the capacity of the mempool. In these
|
|
976
|
+
# tests MEMPOOL_BLOCK_BUFFER is 1. The other factors are COST_PER_BYTE
|
|
977
|
+
# and MAX_BLOCK_COST_CLVM
|
|
978
|
+
assert included_tx == 23
|
|
979
|
+
assert not_included_tx == 10
|
|
980
|
+
assert seen_bigger_transaction_has_high_fee
|
|
981
|
+
|
|
982
|
+
# Mempool is full
|
|
983
|
+
new_transaction = fnp.NewTransaction(bytes32.random(seeded_random), uint64(10000000), uint64(1))
|
|
984
|
+
await full_node_1.new_transaction(new_transaction, fake_peer)
|
|
985
|
+
assert full_node_1.full_node.mempool_manager.mempool.at_full_capacity(10000000 * group_size)
|
|
986
|
+
await time_out_assert(
|
|
987
|
+
30, full_node_2.full_node.mempool_manager.mempool.at_full_capacity, True, 10000000 * group_size
|
|
988
|
+
)
|
|
989
|
+
|
|
990
|
+
await time_out_assert(10, new_transaction_not_requested, True, incoming_queue, new_transaction)
|
|
991
|
+
|
|
992
|
+
# Idempotence in resubmission
|
|
993
|
+
status, err = await full_node_1.full_node.add_transaction(
|
|
994
|
+
successful_bundle, successful_bundle.name(), peer, test=True
|
|
995
|
+
)
|
|
996
|
+
assert status == MempoolInclusionStatus.SUCCESS
|
|
997
|
+
assert err is None
|
|
998
|
+
|
|
999
|
+
# Resubmission through wallet is also fine
|
|
1000
|
+
response_msg = await full_node_1.send_transaction(SendTransaction(successful_bundle), test=True)
|
|
1001
|
+
assert TransactionAck.from_bytes(response_msg.data).status == MempoolInclusionStatus.SUCCESS.value
|
|
1002
|
+
|
|
1003
|
+
# Farm one block to clear mempool
|
|
1004
|
+
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(receiver_puzzlehash))
|
|
1005
|
+
|
|
1006
|
+
# No longer full
|
|
1007
|
+
new_transaction = fnp.NewTransaction(bytes32.random(seeded_random), uint64(1000000), uint64(1))
|
|
1008
|
+
await full_node_1.new_transaction(new_transaction, fake_peer)
|
|
1009
|
+
|
|
1010
|
+
# Cannot resubmit transaction, but not because of ALREADY_INCLUDING
|
|
1011
|
+
status, err = await full_node_1.full_node.add_transaction(
|
|
1012
|
+
successful_bundle, successful_bundle.name(), peer, test=True
|
|
1013
|
+
)
|
|
1014
|
+
assert status == MempoolInclusionStatus.FAILED
|
|
1015
|
+
assert err != Err.ALREADY_INCLUDING_TRANSACTION
|
|
1016
|
+
|
|
1017
|
+
await time_out_assert(10, new_transaction_requested, True, incoming_queue, new_transaction)
|
|
1018
|
+
|
|
1019
|
+
# Reorg the blockchain
|
|
1020
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
1021
|
+
blocks = bt.get_consecutive_blocks(
|
|
1022
|
+
2,
|
|
1023
|
+
block_list_input=blocks[:-1],
|
|
1024
|
+
guarantee_transaction_block=True,
|
|
1025
|
+
)
|
|
1026
|
+
await add_blocks_in_batches(blocks[-2:], full_node_1.full_node)
|
|
1027
|
+
# Can now resubmit a transaction after the reorg
|
|
1028
|
+
status, err = await full_node_1.full_node.add_transaction(
|
|
1029
|
+
successful_bundle, successful_bundle.name(), peer, test=True
|
|
1030
|
+
)
|
|
1031
|
+
assert err is None
|
|
1032
|
+
assert status == MempoolInclusionStatus.SUCCESS
|
|
1033
|
+
|
|
1034
|
+
|
|
1035
|
+
@pytest.mark.anyio
|
|
1036
|
+
async def test_request_respond_transaction(wallet_nodes, self_hostname, seeded_random: random.Random):
|
|
1037
|
+
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1038
|
+
wallet_ph = wallet_a.get_new_puzzlehash()
|
|
1039
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
1040
|
+
|
|
1041
|
+
blocks = bt.get_consecutive_blocks(
|
|
1042
|
+
3,
|
|
1043
|
+
block_list_input=blocks,
|
|
1044
|
+
guarantee_transaction_block=True,
|
|
1045
|
+
farmer_reward_puzzle_hash=wallet_ph,
|
|
1046
|
+
pool_reward_puzzle_hash=wallet_ph,
|
|
1047
|
+
)
|
|
1048
|
+
|
|
1049
|
+
incoming_queue, _dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
1050
|
+
|
|
1051
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1052
|
+
|
|
1053
|
+
for block in blocks[-3:]:
|
|
1054
|
+
await full_node_1.full_node.add_block(block, peer)
|
|
1055
|
+
await full_node_2.full_node.add_block(block, peer)
|
|
1056
|
+
|
|
1057
|
+
# Farm another block to clear mempool
|
|
1058
|
+
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(wallet_ph))
|
|
1059
|
+
|
|
1060
|
+
tx_id = bytes32.random(seeded_random)
|
|
1061
|
+
request_transaction = fnp.RequestTransaction(tx_id)
|
|
1062
|
+
msg = await full_node_1.request_transaction(request_transaction)
|
|
1063
|
+
assert msg is None
|
|
1064
|
+
|
|
1065
|
+
receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
|
|
1066
|
+
|
|
1067
|
+
spend_bundle = wallet_a.generate_signed_transaction(
|
|
1068
|
+
100, receiver_puzzlehash, blocks[-1].get_included_reward_coins()[0]
|
|
1069
|
+
)
|
|
1070
|
+
assert spend_bundle is not None
|
|
1071
|
+
respond_transaction = fnp.RespondTransaction(spend_bundle)
|
|
1072
|
+
res = await full_node_1.respond_transaction(respond_transaction, peer)
|
|
1073
|
+
assert res is None
|
|
1074
|
+
|
|
1075
|
+
# Check broadcast
|
|
1076
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "new_transaction"))
|
|
1077
|
+
|
|
1078
|
+
request_transaction = fnp.RequestTransaction(spend_bundle.get_hash())
|
|
1079
|
+
msg = await full_node_1.request_transaction(request_transaction)
|
|
1080
|
+
assert msg is not None
|
|
1081
|
+
assert msg.data == bytes(fnp.RespondTransaction(spend_bundle))
|
|
1082
|
+
|
|
1083
|
+
|
|
1084
|
+
@pytest.mark.anyio
|
|
1085
|
+
async def test_respond_transaction_fail(wallet_nodes, self_hostname, seeded_random: random.Random):
|
|
1086
|
+
full_node_1, _full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1087
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
1088
|
+
cb_ph = wallet_a.get_new_puzzlehash()
|
|
1089
|
+
|
|
1090
|
+
incoming_queue, _dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
1091
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1092
|
+
|
|
1093
|
+
tx_id = bytes32.random(seeded_random)
|
|
1094
|
+
request_transaction = fnp.RequestTransaction(tx_id)
|
|
1095
|
+
msg = await full_node_1.request_transaction(request_transaction)
|
|
1096
|
+
assert msg is None
|
|
1097
|
+
|
|
1098
|
+
receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
|
|
1099
|
+
|
|
1100
|
+
blocks_new = bt.get_consecutive_blocks(
|
|
1101
|
+
3,
|
|
1102
|
+
block_list_input=blocks,
|
|
1103
|
+
guarantee_transaction_block=True,
|
|
1104
|
+
farmer_reward_puzzle_hash=cb_ph,
|
|
1105
|
+
pool_reward_puzzle_hash=cb_ph,
|
|
1106
|
+
)
|
|
1107
|
+
await asyncio.sleep(1)
|
|
1108
|
+
while incoming_queue.qsize() > 0:
|
|
1109
|
+
await incoming_queue.get()
|
|
1110
|
+
|
|
1111
|
+
await full_node_1.full_node.add_block(blocks_new[-3], peer)
|
|
1112
|
+
await full_node_1.full_node.add_block(blocks_new[-2], peer)
|
|
1113
|
+
await full_node_1.full_node.add_block(blocks_new[-1], peer)
|
|
1114
|
+
|
|
1115
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "new_peak", 3))
|
|
1116
|
+
# Invalid transaction does not propagate
|
|
1117
|
+
spend_bundle = wallet_a.generate_signed_transaction(
|
|
1118
|
+
100000000000000,
|
|
1119
|
+
receiver_puzzlehash,
|
|
1120
|
+
blocks_new[-1].get_included_reward_coins()[0],
|
|
1121
|
+
)
|
|
1122
|
+
|
|
1123
|
+
assert spend_bundle is not None
|
|
1124
|
+
respond_transaction = fnp.RespondTransaction(spend_bundle)
|
|
1125
|
+
msg = await full_node_1.respond_transaction(respond_transaction, peer)
|
|
1126
|
+
assert msg is None
|
|
1127
|
+
|
|
1128
|
+
await asyncio.sleep(1)
|
|
1129
|
+
assert incoming_queue.qsize() == 0
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
@pytest.mark.anyio
|
|
1133
|
+
async def test_request_block(wallet_nodes):
|
|
1134
|
+
full_node_1, _full_node_2, _server_1, _server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1135
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
1136
|
+
|
|
1137
|
+
blocks = bt.get_consecutive_blocks(
|
|
1138
|
+
3,
|
|
1139
|
+
block_list_input=blocks,
|
|
1140
|
+
guarantee_transaction_block=True,
|
|
1141
|
+
farmer_reward_puzzle_hash=wallet_a.get_new_puzzlehash(),
|
|
1142
|
+
pool_reward_puzzle_hash=wallet_a.get_new_puzzlehash(),
|
|
1143
|
+
)
|
|
1144
|
+
spend_bundle = wallet_a.generate_signed_transaction(
|
|
1145
|
+
1123,
|
|
1146
|
+
wallet_receiver.get_new_puzzlehash(),
|
|
1147
|
+
blocks[-1].get_included_reward_coins()[0],
|
|
1148
|
+
)
|
|
1149
|
+
blocks = bt.get_consecutive_blocks(
|
|
1150
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=spend_bundle
|
|
1151
|
+
)
|
|
1152
|
+
|
|
1153
|
+
for block in blocks:
|
|
1154
|
+
await full_node_1.full_node.add_block(block)
|
|
1155
|
+
|
|
1156
|
+
# Don't have height
|
|
1157
|
+
res = await full_node_1.request_block(fnp.RequestBlock(uint32(1248921), False))
|
|
1158
|
+
assert res.type == ProtocolMessageTypes.reject_block.value
|
|
1159
|
+
|
|
1160
|
+
# Ask without transactions
|
|
1161
|
+
res = await full_node_1.request_block(fnp.RequestBlock(blocks[-1].height, False))
|
|
1162
|
+
assert res.type != ProtocolMessageTypes.reject_block.value
|
|
1163
|
+
assert fnp.RespondBlock.from_bytes(res.data).block.transactions_generator is None
|
|
1164
|
+
|
|
1165
|
+
# Ask with transactions
|
|
1166
|
+
res = await full_node_1.request_block(fnp.RequestBlock(blocks[-1].height, True))
|
|
1167
|
+
assert res.type != ProtocolMessageTypes.reject_block.value
|
|
1168
|
+
assert fnp.RespondBlock.from_bytes(res.data).block.transactions_generator is not None
|
|
1169
|
+
|
|
1170
|
+
# Ask for another one
|
|
1171
|
+
res = await full_node_1.request_block(fnp.RequestBlock(blocks[-1].height - 1, True))
|
|
1172
|
+
assert res.type != ProtocolMessageTypes.reject_block.value
|
|
1173
|
+
|
|
1174
|
+
|
|
1175
|
+
@pytest.mark.anyio
|
|
1176
|
+
async def test_request_blocks(wallet_nodes):
|
|
1177
|
+
full_node_1, _full_node_2, _server_1, _server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1178
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
1179
|
+
|
|
1180
|
+
# create more blocks than constants.MAX_BLOCK_COUNT_PER_REQUEST (32)
|
|
1181
|
+
blocks = bt.get_consecutive_blocks(
|
|
1182
|
+
33,
|
|
1183
|
+
block_list_input=blocks,
|
|
1184
|
+
guarantee_transaction_block=True,
|
|
1185
|
+
farmer_reward_puzzle_hash=wallet_a.get_new_puzzlehash(),
|
|
1186
|
+
pool_reward_puzzle_hash=wallet_a.get_new_puzzlehash(),
|
|
1187
|
+
)
|
|
1188
|
+
|
|
1189
|
+
spend_bundle = wallet_a.generate_signed_transaction(
|
|
1190
|
+
1123,
|
|
1191
|
+
wallet_receiver.get_new_puzzlehash(),
|
|
1192
|
+
blocks[-1].get_included_reward_coins()[0],
|
|
1193
|
+
)
|
|
1194
|
+
blocks_t = bt.get_consecutive_blocks(
|
|
1195
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=spend_bundle
|
|
1196
|
+
)
|
|
1197
|
+
|
|
1198
|
+
for block in blocks_t:
|
|
1199
|
+
await full_node_1.full_node.add_block(block)
|
|
1200
|
+
|
|
1201
|
+
peak_height = blocks_t[-1].height
|
|
1202
|
+
|
|
1203
|
+
# Start >= End
|
|
1204
|
+
res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(4), uint32(4), False))
|
|
1205
|
+
assert res is not None
|
|
1206
|
+
fetched_blocks = fnp.RespondBlocks.from_bytes(res.data).blocks
|
|
1207
|
+
assert len(fetched_blocks) == 1
|
|
1208
|
+
assert fetched_blocks[0].header_hash == blocks[4].header_hash
|
|
1209
|
+
res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(5), uint32(4), False))
|
|
1210
|
+
assert res.type == ProtocolMessageTypes.reject_blocks.value
|
|
1211
|
+
# Invalid range
|
|
1212
|
+
res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(peak_height - 5), uint32(peak_height + 5), False))
|
|
1213
|
+
assert res.type == ProtocolMessageTypes.reject_blocks.value
|
|
1214
|
+
|
|
1215
|
+
# Try fetching more blocks than constants.MAX_BLOCK_COUNT_PER_REQUESTS
|
|
1216
|
+
res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(0), uint32(33), False))
|
|
1217
|
+
assert res.type == ProtocolMessageTypes.reject_blocks.value
|
|
1218
|
+
|
|
1219
|
+
# Ask without transactions
|
|
1220
|
+
res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(peak_height - 5), uint32(peak_height), False))
|
|
1221
|
+
|
|
1222
|
+
fetched_blocks = fnp.RespondBlocks.from_bytes(res.data).blocks
|
|
1223
|
+
assert len(fetched_blocks) == 6
|
|
1224
|
+
for b in fetched_blocks:
|
|
1225
|
+
assert b.transactions_generator is None
|
|
1226
|
+
|
|
1227
|
+
# Ask with transactions
|
|
1228
|
+
res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(peak_height - 5), uint32(peak_height), True))
|
|
1229
|
+
fetched_blocks = fnp.RespondBlocks.from_bytes(res.data).blocks
|
|
1230
|
+
assert len(fetched_blocks) == 6
|
|
1231
|
+
assert fetched_blocks[-1].transactions_generator is not None
|
|
1232
|
+
assert std_hash(fetched_blocks[-1]) == std_hash(blocks_t[-1])
|
|
1233
|
+
|
|
1234
|
+
|
|
1235
|
+
@pytest.mark.anyio
|
|
1236
|
+
@pytest.mark.parametrize("peer_version", ["0.0.35", "0.0.36"])
|
|
1237
|
+
@pytest.mark.parametrize("requesting", [0, 1, 2])
|
|
1238
|
+
async def test_new_unfinished_block(wallet_nodes, peer_version: str, requesting: int, self_hostname: str):
|
|
1239
|
+
full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
|
|
1240
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
1241
|
+
|
|
1242
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1243
|
+
assert peer in server_1.all_connections.values()
|
|
1244
|
+
|
|
1245
|
+
blocks = bt.get_consecutive_blocks(2, block_list_input=blocks)
|
|
1246
|
+
block: FullBlock = blocks[-1]
|
|
1247
|
+
unf = make_unfinished_block(block, bt.constants)
|
|
1248
|
+
|
|
1249
|
+
# Don't have
|
|
1250
|
+
if requesting == 1:
|
|
1251
|
+
full_node_1.full_node.full_node_store.mark_requesting_unfinished_block(unf.partial_hash, None)
|
|
1252
|
+
res = await full_node_1.new_unfinished_block(fnp.NewUnfinishedBlock(unf.partial_hash))
|
|
1253
|
+
assert res is None
|
|
1254
|
+
elif requesting == 2:
|
|
1255
|
+
full_node_1.full_node.full_node_store.mark_requesting_unfinished_block(
|
|
1256
|
+
unf.partial_hash, unf.foliage.foliage_transaction_block_hash
|
|
1257
|
+
)
|
|
1258
|
+
res = await full_node_1.new_unfinished_block(fnp.NewUnfinishedBlock(unf.partial_hash))
|
|
1259
|
+
assert res is None
|
|
1260
|
+
else:
|
|
1261
|
+
res = await full_node_1.new_unfinished_block(fnp.NewUnfinishedBlock(unf.partial_hash))
|
|
1262
|
+
assert res is not None
|
|
1263
|
+
assert res is not None and res.data == bytes(fnp.RequestUnfinishedBlock(unf.partial_hash))
|
|
1264
|
+
|
|
1265
|
+
# when we receive a new unfinished block, we advertize it to our peers.
|
|
1266
|
+
# We send new_unfinished_blocks to old peers (0.0.35 and earlier) and we
|
|
1267
|
+
# send new_unfinishe_blocks2 to new peers (0.0.6 and later). Test both
|
|
1268
|
+
peer.protocol_version = Version(peer_version)
|
|
1269
|
+
|
|
1270
|
+
await full_node_1.full_node.add_block(blocks[-2])
|
|
1271
|
+
await full_node_1.full_node.add_unfinished_block(unf, None)
|
|
1272
|
+
|
|
1273
|
+
msg = peer.outgoing_queue.get_nowait()
|
|
1274
|
+
assert msg.type == ProtocolMessageTypes.new_peak.value
|
|
1275
|
+
msg = peer.outgoing_queue.get_nowait()
|
|
1276
|
+
if peer_version == "0.0.35":
|
|
1277
|
+
assert msg.type == ProtocolMessageTypes.new_unfinished_block.value
|
|
1278
|
+
assert msg.data == bytes(fnp.NewUnfinishedBlock(unf.partial_hash))
|
|
1279
|
+
elif peer_version == "0.0.36":
|
|
1280
|
+
assert msg.type == ProtocolMessageTypes.new_unfinished_block2.value
|
|
1281
|
+
assert msg.data == bytes(fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash))
|
|
1282
|
+
else: # pragma: no cover
|
|
1283
|
+
# the test parameters must have been updated, update the test too!
|
|
1284
|
+
assert False
|
|
1285
|
+
|
|
1286
|
+
# Have
|
|
1287
|
+
res = await full_node_1.new_unfinished_block(fnp.NewUnfinishedBlock(unf.partial_hash))
|
|
1288
|
+
assert res is None
|
|
1289
|
+
|
|
1290
|
+
|
|
1291
|
+
@pytest.mark.anyio
|
|
1292
|
+
@pytest.mark.parametrize("requesting", [0, 1, 2])
|
|
1293
|
+
async def test_new_unfinished_block2(wallet_nodes, requesting: int, self_hostname: str):
|
|
1294
|
+
full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
|
|
1295
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
1296
|
+
|
|
1297
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1298
|
+
|
|
1299
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1300
|
+
block: FullBlock = blocks[-1]
|
|
1301
|
+
unf = make_unfinished_block(block, bt.constants)
|
|
1302
|
+
|
|
1303
|
+
# Don't have
|
|
1304
|
+
if requesting == 1:
|
|
1305
|
+
full_node_1.full_node.full_node_store.mark_requesting_unfinished_block(unf.partial_hash, None)
|
|
1306
|
+
|
|
1307
|
+
if requesting == 2:
|
|
1308
|
+
full_node_1.full_node.full_node_store.mark_requesting_unfinished_block(
|
|
1309
|
+
unf.partial_hash, unf.foliage.foliage_transaction_block_hash
|
|
1310
|
+
)
|
|
1311
|
+
res = await full_node_1.new_unfinished_block2(
|
|
1312
|
+
fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1313
|
+
)
|
|
1314
|
+
assert res is None
|
|
1315
|
+
else:
|
|
1316
|
+
res = await full_node_1.new_unfinished_block2(
|
|
1317
|
+
fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1318
|
+
)
|
|
1319
|
+
assert res is not None and res.data == bytes(
|
|
1320
|
+
fnp.RequestUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1321
|
+
)
|
|
1322
|
+
|
|
1323
|
+
await full_node_1.full_node.add_unfinished_block(unf, peer)
|
|
1324
|
+
|
|
1325
|
+
# Have
|
|
1326
|
+
res = await full_node_1.new_unfinished_block2(
|
|
1327
|
+
fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1328
|
+
)
|
|
1329
|
+
assert res is None
|
|
1330
|
+
|
|
1331
|
+
|
|
1332
|
+
@pytest.mark.anyio
|
|
1333
|
+
async def test_new_unfinished_block2_forward_limit(wallet_nodes, self_hostname: str):
|
|
1334
|
+
full_node_1, _full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1335
|
+
blocks = bt.get_consecutive_blocks(3, guarantee_transaction_block=True)
|
|
1336
|
+
for block in blocks:
|
|
1337
|
+
await full_node_1.full_node.add_block(block)
|
|
1338
|
+
coin = blocks[-1].get_included_reward_coins()[0]
|
|
1339
|
+
puzzle_hash = wallet_receiver.get_new_puzzlehash()
|
|
1340
|
+
|
|
1341
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1342
|
+
|
|
1343
|
+
# notify the node of unfinished blocks for this reward block hash
|
|
1344
|
+
# we forward 3 different blocks with the same reward block hash, but no
|
|
1345
|
+
# more (it's configurable)
|
|
1346
|
+
# also, we don't forward unfinished blocks that are "worse" than the
|
|
1347
|
+
# best block we've already seen, so we may need to send more than 3
|
|
1348
|
+
# blocks to the node for it to forward 3
|
|
1349
|
+
|
|
1350
|
+
unf_blocks: list[UnfinishedBlock] = []
|
|
1351
|
+
|
|
1352
|
+
last_reward_hash: Optional[bytes32] = None
|
|
1353
|
+
for idx in range(0, 6):
|
|
1354
|
+
# we include a different transaction in each block. This makes the
|
|
1355
|
+
# foliage different in each of them, but the reward block (plot) the same
|
|
1356
|
+
tx = wallet_a.generate_signed_transaction(100 * (idx + 1), puzzle_hash, coin)
|
|
1357
|
+
|
|
1358
|
+
# note that we use the same chain to build the new block on top of every time
|
|
1359
|
+
block = bt.get_consecutive_blocks(
|
|
1360
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
1361
|
+
)[-1]
|
|
1362
|
+
unf = make_unfinished_block(block, bt.constants)
|
|
1363
|
+
unf_blocks.append(unf)
|
|
1364
|
+
|
|
1365
|
+
if last_reward_hash is None:
|
|
1366
|
+
last_reward_hash = unf.partial_hash
|
|
1367
|
+
else:
|
|
1368
|
+
assert last_reward_hash == unf.partial_hash
|
|
1369
|
+
|
|
1370
|
+
# sort the blocks from worst -> best
|
|
1371
|
+
def sort_key(b: UnfinishedBlock) -> bytes32:
|
|
1372
|
+
assert b.foliage.foliage_transaction_block_hash is not None
|
|
1373
|
+
return b.foliage.foliage_transaction_block_hash
|
|
1374
|
+
|
|
1375
|
+
unf_blocks.sort(reverse=True, key=sort_key)
|
|
1376
|
+
|
|
1377
|
+
for idx, unf in enumerate(unf_blocks):
|
|
1378
|
+
res = await full_node_1.new_unfinished_block2(
|
|
1379
|
+
fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1380
|
+
)
|
|
1381
|
+
# 3 is the default number of different unfinished blocks we forward
|
|
1382
|
+
if idx < 3:
|
|
1383
|
+
# Don't have
|
|
1384
|
+
assert res is not None and res.data == bytes(
|
|
1385
|
+
fnp.RequestUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1386
|
+
)
|
|
1387
|
+
else:
|
|
1388
|
+
# too many UnfinishedBlocks with the same reward hash
|
|
1389
|
+
assert res is None
|
|
1390
|
+
await full_node_1.full_node.add_unfinished_block(unf, peer)
|
|
1391
|
+
|
|
1392
|
+
|
|
1393
|
+
@pytest.mark.anyio
|
|
1394
|
+
@pytest.mark.parametrize(
|
|
1395
|
+
"committment,expected",
|
|
1396
|
+
[
|
|
1397
|
+
(0, Err.INVALID_TRANSACTIONS_GENERATOR_HASH),
|
|
1398
|
+
(1, Err.INVALID_TRANSACTIONS_INFO_HASH),
|
|
1399
|
+
(2, Err.INVALID_FOLIAGE_BLOCK_HASH),
|
|
1400
|
+
(3, Err.INVALID_PLOT_SIGNATURE),
|
|
1401
|
+
(4, Err.INVALID_PLOT_SIGNATURE),
|
|
1402
|
+
(5, Err.INVALID_POSPACE),
|
|
1403
|
+
(6, Err.INVALID_POSPACE),
|
|
1404
|
+
(7, Err.TOO_MANY_GENERATOR_REFS),
|
|
1405
|
+
],
|
|
1406
|
+
)
|
|
1407
|
+
async def test_unfinished_block_with_replaced_generator(wallet_nodes, self_hostname, committment, expected):
|
|
1408
|
+
full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
|
|
1409
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
1410
|
+
|
|
1411
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1412
|
+
|
|
1413
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1414
|
+
block: FullBlock = blocks[0]
|
|
1415
|
+
overflow = is_overflow_block(bt.constants, block.reward_chain_block.signage_point_index)
|
|
1416
|
+
|
|
1417
|
+
replaced_generator = SerializedProgram.from_bytes(b"\x80")
|
|
1418
|
+
|
|
1419
|
+
if committment > 0:
|
|
1420
|
+
tr = block.transactions_info
|
|
1421
|
+
transactions_info = TransactionsInfo(
|
|
1422
|
+
std_hash(bytes(replaced_generator)),
|
|
1423
|
+
tr.generator_refs_root,
|
|
1424
|
+
tr.aggregated_signature,
|
|
1425
|
+
tr.fees,
|
|
1426
|
+
tr.cost,
|
|
1427
|
+
tr.reward_claims_incorporated,
|
|
1428
|
+
)
|
|
1429
|
+
else:
|
|
1430
|
+
transactions_info = block.transactions_info
|
|
1431
|
+
|
|
1432
|
+
if committment > 1:
|
|
1433
|
+
tb = block.foliage_transaction_block
|
|
1434
|
+
transaction_block = FoliageTransactionBlock(
|
|
1435
|
+
tb.prev_transaction_block_hash,
|
|
1436
|
+
tb.timestamp,
|
|
1437
|
+
tb.filter_hash,
|
|
1438
|
+
tb.additions_root,
|
|
1439
|
+
tb.removals_root,
|
|
1440
|
+
transactions_info.get_hash(),
|
|
1441
|
+
)
|
|
1442
|
+
else:
|
|
1443
|
+
transaction_block = block.foliage_transaction_block
|
|
1444
|
+
|
|
1445
|
+
if committment > 2:
|
|
1446
|
+
fl = block.foliage
|
|
1447
|
+
foliage = Foliage(
|
|
1448
|
+
fl.prev_block_hash,
|
|
1449
|
+
fl.reward_block_hash,
|
|
1450
|
+
fl.foliage_block_data,
|
|
1451
|
+
fl.foliage_block_data_signature,
|
|
1452
|
+
transaction_block.get_hash(),
|
|
1453
|
+
fl.foliage_transaction_block_signature,
|
|
1454
|
+
)
|
|
1455
|
+
else:
|
|
1456
|
+
foliage = block.foliage
|
|
1457
|
+
|
|
1458
|
+
if committment > 3:
|
|
1459
|
+
fl = block.foliage
|
|
1460
|
+
|
|
1461
|
+
secret_key: PrivateKey = AugSchemeMPL.key_gen(bytes([2] * 32))
|
|
1462
|
+
public_key = secret_key.get_g1()
|
|
1463
|
+
signature = AugSchemeMPL.sign(secret_key, transaction_block.get_hash())
|
|
1464
|
+
|
|
1465
|
+
foliage = Foliage(
|
|
1466
|
+
fl.prev_block_hash,
|
|
1467
|
+
fl.reward_block_hash,
|
|
1468
|
+
fl.foliage_block_data,
|
|
1469
|
+
fl.foliage_block_data_signature,
|
|
1470
|
+
transaction_block.get_hash(),
|
|
1471
|
+
signature,
|
|
1472
|
+
)
|
|
1473
|
+
|
|
1474
|
+
if committment > 4:
|
|
1475
|
+
pos = block.reward_chain_block.proof_of_space
|
|
1476
|
+
|
|
1477
|
+
if committment > 5:
|
|
1478
|
+
if pos.pool_public_key is None:
|
|
1479
|
+
plot_id = calculate_plot_id_pk(pos.pool_contract_puzzle_hash, public_key)
|
|
1480
|
+
else:
|
|
1481
|
+
plot_id = calculate_plot_id_pk(pos.pool_public_key, public_key)
|
|
1482
|
+
original_challenge_hash = block.reward_chain_block.pos_ss_cc_challenge_hash
|
|
1483
|
+
|
|
1484
|
+
if block.reward_chain_block.challenge_chain_sp_vdf is None:
|
|
1485
|
+
# Edge case of first sp (start of slot), where sp_iters == 0
|
|
1486
|
+
cc_sp_hash = original_challenge_hash
|
|
1487
|
+
else:
|
|
1488
|
+
cc_sp_hash = block.reward_chain_block.challenge_chain_sp_vdf.output.get_hash()
|
|
1489
|
+
challenge = calculate_pos_challenge(plot_id, original_challenge_hash, cc_sp_hash)
|
|
1490
|
+
|
|
1491
|
+
else:
|
|
1492
|
+
challenge = pos.challenge
|
|
1493
|
+
|
|
1494
|
+
proof_of_space = ProofOfSpace(
|
|
1495
|
+
challenge,
|
|
1496
|
+
pos.pool_public_key,
|
|
1497
|
+
pos.pool_contract_puzzle_hash,
|
|
1498
|
+
public_key,
|
|
1499
|
+
pos.size,
|
|
1500
|
+
pos.proof,
|
|
1501
|
+
)
|
|
1502
|
+
|
|
1503
|
+
rcb = block.reward_chain_block.get_unfinished()
|
|
1504
|
+
reward_chain_block = RewardChainBlockUnfinished(
|
|
1505
|
+
rcb.total_iters,
|
|
1506
|
+
rcb.signage_point_index,
|
|
1507
|
+
rcb.pos_ss_cc_challenge_hash,
|
|
1508
|
+
proof_of_space,
|
|
1509
|
+
rcb.challenge_chain_sp_vdf,
|
|
1510
|
+
rcb.challenge_chain_sp_signature,
|
|
1511
|
+
rcb.reward_chain_sp_vdf,
|
|
1512
|
+
rcb.reward_chain_sp_signature,
|
|
1513
|
+
)
|
|
1514
|
+
else:
|
|
1515
|
+
reward_chain_block = block.reward_chain_block.get_unfinished()
|
|
1516
|
+
|
|
1517
|
+
else:
|
|
1518
|
+
reward_chain_block = block.reward_chain_block.get_unfinished()
|
|
1519
|
+
|
|
1520
|
+
generator_refs: list[uint32] = []
|
|
1521
|
+
if committment > 6:
|
|
1522
|
+
generator_refs = [uint32(n) for n in range(600)]
|
|
1523
|
+
|
|
1524
|
+
unf = UnfinishedBlock(
|
|
1525
|
+
block.finished_sub_slots[:] if not overflow else block.finished_sub_slots[:-1],
|
|
1526
|
+
reward_chain_block,
|
|
1527
|
+
block.challenge_chain_sp_proof,
|
|
1528
|
+
block.reward_chain_sp_proof,
|
|
1529
|
+
foliage,
|
|
1530
|
+
transaction_block,
|
|
1531
|
+
transactions_info,
|
|
1532
|
+
replaced_generator,
|
|
1533
|
+
generator_refs,
|
|
1534
|
+
)
|
|
1535
|
+
|
|
1536
|
+
_, header_error = await full_node_1.full_node.blockchain.validate_unfinished_block_header(unf)
|
|
1537
|
+
assert header_error == expected
|
|
1538
|
+
|
|
1539
|
+
# tampered-with generator
|
|
1540
|
+
res = await full_node_1.new_unfinished_block(fnp.NewUnfinishedBlock(unf.partial_hash))
|
|
1541
|
+
assert res is not None
|
|
1542
|
+
with pytest.raises(ConsensusError, match=f"{str(expected).split('.')[1]}"):
|
|
1543
|
+
await full_node_1.full_node.add_unfinished_block(unf, peer)
|
|
1544
|
+
|
|
1545
|
+
|
|
1546
|
+
@pytest.mark.anyio
|
|
1547
|
+
async def test_double_blocks_same_pospace(wallet_nodes, self_hostname):
|
|
1548
|
+
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1549
|
+
|
|
1550
|
+
incoming_queue, dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12315)
|
|
1551
|
+
dummy_peer = server_1.all_connections[dummy_node_id]
|
|
1552
|
+
_ = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1553
|
+
|
|
1554
|
+
ph = wallet_a.get_new_puzzlehash()
|
|
1555
|
+
|
|
1556
|
+
for i in range(2):
|
|
1557
|
+
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
1558
|
+
blocks: list[FullBlock] = await full_node_1.get_all_full_blocks()
|
|
1559
|
+
|
|
1560
|
+
coin = blocks[-1].get_included_reward_coins()[0]
|
|
1561
|
+
tx = wallet_a.generate_signed_transaction(10000, wallet_receiver.get_new_puzzlehash(), coin)
|
|
1562
|
+
|
|
1563
|
+
blocks = bt.get_consecutive_blocks(
|
|
1564
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
1565
|
+
)
|
|
1566
|
+
|
|
1567
|
+
block: FullBlock = blocks[-1]
|
|
1568
|
+
unf = make_unfinished_block(block, bt.constants)
|
|
1569
|
+
await full_node_1.full_node.add_unfinished_block(unf, dummy_peer)
|
|
1570
|
+
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash)
|
|
1571
|
+
|
|
1572
|
+
block_2 = recursive_replace(
|
|
1573
|
+
blocks[-1], "foliage_transaction_block.timestamp", unf.foliage_transaction_block.timestamp + 1
|
|
1574
|
+
)
|
|
1575
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
1576
|
+
new_fbh_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
|
|
1577
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fbh_sig)
|
|
1578
|
+
block_2 = recursive_replace(block_2, "transactions_generator", None)
|
|
1579
|
+
|
|
1580
|
+
rb_task = create_referenced_task(full_node_2.full_node.add_block(block_2, dummy_peer))
|
|
1581
|
+
|
|
1582
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 1))
|
|
1583
|
+
rb_task.cancel()
|
|
1584
|
+
|
|
1585
|
+
|
|
1586
|
+
@pytest.mark.anyio
|
|
1587
|
+
async def test_request_unfinished_block(wallet_nodes, self_hostname):
|
|
1588
|
+
full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
|
|
1589
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
1590
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1591
|
+
blocks = bt.get_consecutive_blocks(10, block_list_input=blocks, seed=b"12345")
|
|
1592
|
+
for block in blocks[:-1]:
|
|
1593
|
+
await full_node_1.full_node.add_block(block)
|
|
1594
|
+
block: FullBlock = blocks[-1]
|
|
1595
|
+
unf = make_unfinished_block(block, bt.constants)
|
|
1596
|
+
|
|
1597
|
+
# Don't have
|
|
1598
|
+
res = await full_node_1.request_unfinished_block(fnp.RequestUnfinishedBlock(unf.partial_hash))
|
|
1599
|
+
assert res is None
|
|
1600
|
+
await full_node_1.full_node.add_unfinished_block(unf, peer)
|
|
1601
|
+
# Have
|
|
1602
|
+
res = await full_node_1.request_unfinished_block(fnp.RequestUnfinishedBlock(unf.partial_hash))
|
|
1603
|
+
assert res is not None
|
|
1604
|
+
|
|
1605
|
+
|
|
1606
|
+
@pytest.mark.anyio
|
|
1607
|
+
async def test_request_unfinished_block2(wallet_nodes, self_hostname):
|
|
1608
|
+
full_node_1, _full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1609
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
1610
|
+
blocks = bt.get_consecutive_blocks(3, guarantee_transaction_block=True)
|
|
1611
|
+
for block in blocks:
|
|
1612
|
+
await full_node_1.full_node.add_block(block)
|
|
1613
|
+
coin = blocks[-1].get_included_reward_coins()[0]
|
|
1614
|
+
puzzle_hash = wallet_receiver.get_new_puzzlehash()
|
|
1615
|
+
|
|
1616
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1617
|
+
|
|
1618
|
+
# the "best" unfinished block according to the metric we use to pick one
|
|
1619
|
+
# deterministically
|
|
1620
|
+
best_unf: Optional[UnfinishedBlock] = None
|
|
1621
|
+
|
|
1622
|
+
for idx in range(0, 6):
|
|
1623
|
+
# we include a different transaction in each block. This makes the
|
|
1624
|
+
# foliage different in each of them, but the reward block (plot) the same
|
|
1625
|
+
tx = wallet_a.generate_signed_transaction(100 * (idx + 1), puzzle_hash, coin)
|
|
1626
|
+
|
|
1627
|
+
# note that we use the same chain to build the new block on top of every time
|
|
1628
|
+
block = bt.get_consecutive_blocks(
|
|
1629
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
1630
|
+
)[-1]
|
|
1631
|
+
unf = make_unfinished_block(block, bt.constants)
|
|
1632
|
+
assert unf.foliage.foliage_transaction_block_hash is not None
|
|
1633
|
+
|
|
1634
|
+
if best_unf is None:
|
|
1635
|
+
best_unf = unf
|
|
1636
|
+
elif (
|
|
1637
|
+
unf.foliage.foliage_transaction_block_hash is not None
|
|
1638
|
+
and unf.foliage.foliage_transaction_block_hash < best_unf.foliage.foliage_transaction_block_hash
|
|
1639
|
+
):
|
|
1640
|
+
best_unf = unf
|
|
1641
|
+
|
|
1642
|
+
# Don't have
|
|
1643
|
+
res = await full_node_1.request_unfinished_block2(
|
|
1644
|
+
fnp.RequestUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1645
|
+
)
|
|
1646
|
+
assert res is None
|
|
1647
|
+
|
|
1648
|
+
await full_node_1.full_node.add_unfinished_block(unf, peer)
|
|
1649
|
+
# Have
|
|
1650
|
+
res = await full_node_1.request_unfinished_block2(
|
|
1651
|
+
fnp.RequestUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1652
|
+
)
|
|
1653
|
+
assert res.data == bytes(fnp.RespondUnfinishedBlock(unf))
|
|
1654
|
+
|
|
1655
|
+
res = await full_node_1.request_unfinished_block(fnp.RequestUnfinishedBlock(unf.partial_hash))
|
|
1656
|
+
assert res.data == bytes(fnp.RespondUnfinishedBlock(best_unf))
|
|
1657
|
+
|
|
1658
|
+
res = await full_node_1.request_unfinished_block2(fnp.RequestUnfinishedBlock2(unf.partial_hash, None))
|
|
1659
|
+
assert res.data == bytes(fnp.RespondUnfinishedBlock(best_unf))
|
|
1660
|
+
|
|
1661
|
+
|
|
1662
|
+
@pytest.mark.anyio
|
|
1663
|
+
async def test_new_signage_point_or_end_of_sub_slot(wallet_nodes, self_hostname):
|
|
1664
|
+
full_node_1, full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
|
|
1665
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
1666
|
+
|
|
1667
|
+
blocks = bt.get_consecutive_blocks(3, block_list_input=blocks, skip_slots=2)
|
|
1668
|
+
await full_node_1.full_node.add_block(blocks[-3])
|
|
1669
|
+
await full_node_1.full_node.add_block(blocks[-2])
|
|
1670
|
+
await full_node_1.full_node.add_block(blocks[-1])
|
|
1671
|
+
|
|
1672
|
+
blockchain = full_node_1.full_node.blockchain
|
|
1673
|
+
peak = blockchain.get_peak()
|
|
1674
|
+
|
|
1675
|
+
sp = get_signage_point(
|
|
1676
|
+
bt.constants,
|
|
1677
|
+
blockchain,
|
|
1678
|
+
peak,
|
|
1679
|
+
peak.ip_sub_slot_total_iters(bt.constants),
|
|
1680
|
+
uint8(11),
|
|
1681
|
+
[],
|
|
1682
|
+
peak.sub_slot_iters,
|
|
1683
|
+
)
|
|
1684
|
+
|
|
1685
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1686
|
+
res = await full_node_1.new_signage_point_or_end_of_sub_slot(
|
|
1687
|
+
fnp.NewSignagePointOrEndOfSubSlot(None, sp.cc_vdf.challenge, uint8(11), sp.rc_vdf.challenge), peer
|
|
1688
|
+
)
|
|
1689
|
+
assert res.type == ProtocolMessageTypes.request_signage_point_or_end_of_sub_slot.value
|
|
1690
|
+
assert fnp.RequestSignagePointOrEndOfSubSlot.from_bytes(res.data).index_from_challenge == uint8(11)
|
|
1691
|
+
|
|
1692
|
+
for block in blocks:
|
|
1693
|
+
await full_node_2.full_node.add_block(block)
|
|
1694
|
+
|
|
1695
|
+
num_slots = 20
|
|
1696
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=num_slots)
|
|
1697
|
+
slots = blocks[-1].finished_sub_slots
|
|
1698
|
+
|
|
1699
|
+
assert len(full_node_2.full_node.full_node_store.finished_sub_slots) <= 2
|
|
1700
|
+
assert len(full_node_2.full_node.full_node_store.finished_sub_slots) <= 2
|
|
1701
|
+
|
|
1702
|
+
for slot in slots[:-1]:
|
|
1703
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
1704
|
+
assert len(full_node_1.full_node.full_node_store.finished_sub_slots) >= num_slots - 1
|
|
1705
|
+
|
|
1706
|
+
_incoming_queue, dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12315)
|
|
1707
|
+
dummy_peer = server_1.all_connections[dummy_node_id]
|
|
1708
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slots[-1]), dummy_peer)
|
|
1709
|
+
|
|
1710
|
+
assert len(full_node_1.full_node.full_node_store.finished_sub_slots) >= num_slots
|
|
1711
|
+
|
|
1712
|
+
def caught_up_slots():
|
|
1713
|
+
return len(full_node_2.full_node.full_node_store.finished_sub_slots) >= num_slots
|
|
1714
|
+
|
|
1715
|
+
await time_out_assert(20, caught_up_slots)
|
|
1716
|
+
|
|
1717
|
+
|
|
1718
|
+
@pytest.mark.anyio
|
|
1719
|
+
async def test_new_signage_point_caching(wallet_nodes, empty_blockchain, self_hostname):
|
|
1720
|
+
full_node_1, _full_node_2, server_1, server_2, _wallet_a, _wallet_receiver, bt = wallet_nodes
|
|
1721
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
1722
|
+
|
|
1723
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1724
|
+
blocks = bt.get_consecutive_blocks(3, block_list_input=blocks, skip_slots=2)
|
|
1725
|
+
await full_node_1.full_node.add_block(blocks[-3])
|
|
1726
|
+
await full_node_1.full_node.add_block(blocks[-2])
|
|
1727
|
+
await full_node_1.full_node.add_block(blocks[-1])
|
|
1728
|
+
|
|
1729
|
+
blockchain = full_node_1.full_node.blockchain
|
|
1730
|
+
|
|
1731
|
+
# Submit the sub slot, but not the last block
|
|
1732
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1, force_overflow=True)
|
|
1733
|
+
for ss in blocks[-1].finished_sub_slots:
|
|
1734
|
+
challenge_chain = ss.challenge_chain.replace(
|
|
1735
|
+
new_difficulty=20,
|
|
1736
|
+
)
|
|
1737
|
+
slot2 = ss.replace(
|
|
1738
|
+
challenge_chain=challenge_chain,
|
|
1739
|
+
)
|
|
1740
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot2), peer)
|
|
1741
|
+
|
|
1742
|
+
second_blockchain = empty_blockchain
|
|
1743
|
+
for block in blocks:
|
|
1744
|
+
await _validate_and_add_block(second_blockchain, block)
|
|
1745
|
+
|
|
1746
|
+
# Creates a signage point based on the last block
|
|
1747
|
+
peak_2 = second_blockchain.get_peak()
|
|
1748
|
+
sp: SignagePoint = get_signage_point(
|
|
1749
|
+
bt.constants,
|
|
1750
|
+
blockchain,
|
|
1751
|
+
peak_2,
|
|
1752
|
+
peak_2.ip_sub_slot_total_iters(bt.constants),
|
|
1753
|
+
uint8(4),
|
|
1754
|
+
[],
|
|
1755
|
+
peak_2.sub_slot_iters,
|
|
1756
|
+
)
|
|
1757
|
+
# Submits the signage point, cannot add because don't have block
|
|
1758
|
+
await full_node_1.respond_signage_point(
|
|
1759
|
+
fnp.RespondSignagePoint(4, sp.cc_vdf, sp.cc_proof, sp.rc_vdf, sp.rc_proof), peer
|
|
1760
|
+
)
|
|
1761
|
+
# Should not add duplicates to cache though
|
|
1762
|
+
await full_node_1.respond_signage_point(
|
|
1763
|
+
fnp.RespondSignagePoint(4, sp.cc_vdf, sp.cc_proof, sp.rc_vdf, sp.rc_proof), peer
|
|
1764
|
+
)
|
|
1765
|
+
assert full_node_1.full_node.full_node_store.get_signage_point(sp.cc_vdf.output.get_hash()) is None
|
|
1766
|
+
assert len(full_node_1.full_node.full_node_store.future_sp_cache[sp.rc_vdf.challenge]) == 1
|
|
1767
|
+
|
|
1768
|
+
# Add block
|
|
1769
|
+
await full_node_1.full_node.add_block(blocks[-1], peer)
|
|
1770
|
+
|
|
1771
|
+
# Now signage point should be added
|
|
1772
|
+
sp = full_node_1.full_node.full_node_store.get_signage_point(sp.cc_vdf.output.get_hash())
|
|
1773
|
+
assert sp is not None
|
|
1774
|
+
|
|
1775
|
+
|
|
1776
|
+
@pytest.mark.anyio
|
|
1777
|
+
async def test_slot_catch_up_genesis(setup_two_nodes_fixture, self_hostname):
|
|
1778
|
+
nodes, _, bt = setup_two_nodes_fixture
|
|
1779
|
+
server_1 = nodes[0].full_node.server
|
|
1780
|
+
server_2 = nodes[1].full_node.server
|
|
1781
|
+
full_node_1 = nodes[0]
|
|
1782
|
+
full_node_2 = nodes[1]
|
|
1783
|
+
|
|
1784
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1785
|
+
num_slots = 20
|
|
1786
|
+
blocks = bt.get_consecutive_blocks(1, skip_slots=num_slots)
|
|
1787
|
+
slots = blocks[-1].finished_sub_slots
|
|
1788
|
+
|
|
1789
|
+
assert len(full_node_2.full_node.full_node_store.finished_sub_slots) <= 2
|
|
1790
|
+
assert len(full_node_2.full_node.full_node_store.finished_sub_slots) <= 2
|
|
1791
|
+
|
|
1792
|
+
for slot in slots[:-1]:
|
|
1793
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
1794
|
+
assert len(full_node_1.full_node.full_node_store.finished_sub_slots) >= num_slots - 1
|
|
1795
|
+
|
|
1796
|
+
_incoming_queue, dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12315)
|
|
1797
|
+
dummy_peer = server_1.all_connections[dummy_node_id]
|
|
1798
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slots[-1]), dummy_peer)
|
|
1799
|
+
|
|
1800
|
+
assert len(full_node_1.full_node.full_node_store.finished_sub_slots) >= num_slots
|
|
1801
|
+
|
|
1802
|
+
def caught_up_slots():
|
|
1803
|
+
return len(full_node_2.full_node.full_node_store.finished_sub_slots) >= num_slots
|
|
1804
|
+
|
|
1805
|
+
await time_out_assert(20, caught_up_slots)
|
|
1806
|
+
|
|
1807
|
+
|
|
1808
|
+
@pytest.mark.anyio
|
|
1809
|
+
async def test_compact_protocol(setup_two_nodes_fixture):
|
|
1810
|
+
nodes, _, bt = setup_two_nodes_fixture
|
|
1811
|
+
full_node_1 = nodes[0]
|
|
1812
|
+
full_node_2 = nodes[1]
|
|
1813
|
+
blocks = bt.get_consecutive_blocks(num_blocks=10, skip_slots=3)
|
|
1814
|
+
block = blocks[0]
|
|
1815
|
+
for b in blocks:
|
|
1816
|
+
await full_node_1.full_node.add_block(b)
|
|
1817
|
+
timelord_protocol_finished = []
|
|
1818
|
+
cc_eos_count = 0
|
|
1819
|
+
for sub_slot in block.finished_sub_slots:
|
|
1820
|
+
vdf_info, vdf_proof = get_vdf_info_and_proof(
|
|
1821
|
+
bt.constants,
|
|
1822
|
+
ClassgroupElement.get_default_element(),
|
|
1823
|
+
sub_slot.challenge_chain.challenge_chain_end_of_slot_vdf.challenge,
|
|
1824
|
+
sub_slot.challenge_chain.challenge_chain_end_of_slot_vdf.number_of_iterations,
|
|
1825
|
+
True,
|
|
1826
|
+
)
|
|
1827
|
+
cc_eos_count += 1
|
|
1828
|
+
timelord_protocol_finished.append(
|
|
1829
|
+
timelord_protocol.RespondCompactProofOfTime(
|
|
1830
|
+
vdf_info,
|
|
1831
|
+
vdf_proof,
|
|
1832
|
+
block.header_hash,
|
|
1833
|
+
block.height,
|
|
1834
|
+
CompressibleVDFField.CC_EOS_VDF,
|
|
1835
|
+
)
|
|
1836
|
+
)
|
|
1837
|
+
blocks_2 = bt.get_consecutive_blocks(num_blocks=10, block_list_input=blocks, skip_slots=3)
|
|
1838
|
+
block = blocks_2[-10]
|
|
1839
|
+
for b in blocks_2[-11:]:
|
|
1840
|
+
await full_node_1.full_node.add_block(b)
|
|
1841
|
+
icc_eos_count = 0
|
|
1842
|
+
for sub_slot in block.finished_sub_slots:
|
|
1843
|
+
if sub_slot.infused_challenge_chain is not None:
|
|
1844
|
+
icc_eos_count += 1
|
|
1845
|
+
vdf_info, vdf_proof = get_vdf_info_and_proof(
|
|
1846
|
+
bt.constants,
|
|
1847
|
+
ClassgroupElement.get_default_element(),
|
|
1848
|
+
sub_slot.infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.challenge,
|
|
1849
|
+
sub_slot.infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.number_of_iterations,
|
|
1850
|
+
True,
|
|
1851
|
+
)
|
|
1852
|
+
timelord_protocol_finished.append(
|
|
1853
|
+
timelord_protocol.RespondCompactProofOfTime(
|
|
1854
|
+
vdf_info,
|
|
1855
|
+
vdf_proof,
|
|
1856
|
+
block.header_hash,
|
|
1857
|
+
block.height,
|
|
1858
|
+
CompressibleVDFField.ICC_EOS_VDF,
|
|
1859
|
+
)
|
|
1860
|
+
)
|
|
1861
|
+
assert block.reward_chain_block.challenge_chain_sp_vdf is not None
|
|
1862
|
+
vdf_info, vdf_proof = get_vdf_info_and_proof(
|
|
1863
|
+
bt.constants,
|
|
1864
|
+
ClassgroupElement.get_default_element(),
|
|
1865
|
+
block.reward_chain_block.challenge_chain_sp_vdf.challenge,
|
|
1866
|
+
block.reward_chain_block.challenge_chain_sp_vdf.number_of_iterations,
|
|
1867
|
+
True,
|
|
1868
|
+
)
|
|
1869
|
+
timelord_protocol_finished.append(
|
|
1870
|
+
timelord_protocol.RespondCompactProofOfTime(
|
|
1871
|
+
vdf_info,
|
|
1872
|
+
vdf_proof,
|
|
1873
|
+
block.header_hash,
|
|
1874
|
+
block.height,
|
|
1875
|
+
CompressibleVDFField.CC_SP_VDF,
|
|
1876
|
+
)
|
|
1877
|
+
)
|
|
1878
|
+
vdf_info, vdf_proof = get_vdf_info_and_proof(
|
|
1879
|
+
bt.constants,
|
|
1880
|
+
ClassgroupElement.get_default_element(),
|
|
1881
|
+
block.reward_chain_block.challenge_chain_ip_vdf.challenge,
|
|
1882
|
+
block.reward_chain_block.challenge_chain_ip_vdf.number_of_iterations,
|
|
1883
|
+
True,
|
|
1884
|
+
)
|
|
1885
|
+
timelord_protocol_finished.append(
|
|
1886
|
+
timelord_protocol.RespondCompactProofOfTime(
|
|
1887
|
+
vdf_info,
|
|
1888
|
+
vdf_proof,
|
|
1889
|
+
block.header_hash,
|
|
1890
|
+
block.height,
|
|
1891
|
+
CompressibleVDFField.CC_IP_VDF,
|
|
1892
|
+
)
|
|
1893
|
+
)
|
|
1894
|
+
|
|
1895
|
+
# Note: the below numbers depend on the block cache, so might need to be updated
|
|
1896
|
+
assert cc_eos_count == 3 and icc_eos_count == 3
|
|
1897
|
+
for compact_proof in timelord_protocol_finished:
|
|
1898
|
+
await full_node_1.full_node.add_compact_proof_of_time(compact_proof)
|
|
1899
|
+
stored_blocks = await full_node_1.get_all_full_blocks()
|
|
1900
|
+
cc_eos_compact_count = 0
|
|
1901
|
+
icc_eos_compact_count = 0
|
|
1902
|
+
has_compact_cc_sp_vdf = False
|
|
1903
|
+
has_compact_cc_ip_vdf = False
|
|
1904
|
+
for block in stored_blocks:
|
|
1905
|
+
for sub_slot in block.finished_sub_slots:
|
|
1906
|
+
if sub_slot.proofs.challenge_chain_slot_proof.normalized_to_identity:
|
|
1907
|
+
cc_eos_compact_count += 1
|
|
1908
|
+
if (
|
|
1909
|
+
sub_slot.proofs.infused_challenge_chain_slot_proof is not None
|
|
1910
|
+
and sub_slot.proofs.infused_challenge_chain_slot_proof.normalized_to_identity
|
|
1911
|
+
):
|
|
1912
|
+
icc_eos_compact_count += 1
|
|
1913
|
+
if block.challenge_chain_sp_proof is not None and block.challenge_chain_sp_proof.normalized_to_identity:
|
|
1914
|
+
has_compact_cc_sp_vdf = True
|
|
1915
|
+
if block.challenge_chain_ip_proof.normalized_to_identity:
|
|
1916
|
+
has_compact_cc_ip_vdf = True
|
|
1917
|
+
# Note: the below numbers depend on the block cache, so might need to be updated
|
|
1918
|
+
assert cc_eos_compact_count == 3
|
|
1919
|
+
assert icc_eos_compact_count == 3
|
|
1920
|
+
assert has_compact_cc_sp_vdf
|
|
1921
|
+
assert has_compact_cc_ip_vdf
|
|
1922
|
+
for height, block in enumerate(stored_blocks):
|
|
1923
|
+
await full_node_2.full_node.add_block(block)
|
|
1924
|
+
assert full_node_2.full_node.blockchain.get_peak().height == height
|
|
1925
|
+
|
|
1926
|
+
|
|
1927
|
+
@pytest.mark.anyio
|
|
1928
|
+
async def test_compact_protocol_invalid_messages(setup_two_nodes_fixture, self_hostname):
|
|
1929
|
+
nodes, _, bt = setup_two_nodes_fixture
|
|
1930
|
+
full_node_1 = nodes[0]
|
|
1931
|
+
full_node_2 = nodes[1]
|
|
1932
|
+
blocks = bt.get_consecutive_blocks(num_blocks=1, skip_slots=3)
|
|
1933
|
+
blocks_2 = bt.get_consecutive_blocks(num_blocks=3, block_list_input=blocks, skip_slots=3)
|
|
1934
|
+
for block in blocks_2[:2]:
|
|
1935
|
+
await full_node_1.full_node.add_block(block)
|
|
1936
|
+
assert full_node_1.full_node.blockchain.get_peak().height == 1
|
|
1937
|
+
# (wrong_vdf_info, wrong_vdf_proof) pair verifies, but it's not present in the blockchain at all.
|
|
1938
|
+
block = blocks_2[2]
|
|
1939
|
+
wrong_vdf_info, wrong_vdf_proof = get_vdf_info_and_proof(
|
|
1940
|
+
bt.constants,
|
|
1941
|
+
ClassgroupElement.get_default_element(),
|
|
1942
|
+
block.reward_chain_block.challenge_chain_ip_vdf.challenge,
|
|
1943
|
+
block.reward_chain_block.challenge_chain_ip_vdf.number_of_iterations,
|
|
1944
|
+
True,
|
|
1945
|
+
)
|
|
1946
|
+
timelord_protocol_invalid_messages = []
|
|
1947
|
+
full_node_protocol_invalid_messaages = []
|
|
1948
|
+
for block in blocks_2[:2]:
|
|
1949
|
+
for sub_slot in block.finished_sub_slots:
|
|
1950
|
+
vdf_info, correct_vdf_proof = get_vdf_info_and_proof(
|
|
1951
|
+
bt.constants,
|
|
1952
|
+
ClassgroupElement.get_default_element(),
|
|
1953
|
+
sub_slot.challenge_chain.challenge_chain_end_of_slot_vdf.challenge,
|
|
1954
|
+
sub_slot.challenge_chain.challenge_chain_end_of_slot_vdf.number_of_iterations,
|
|
1955
|
+
True,
|
|
1956
|
+
)
|
|
1957
|
+
assert wrong_vdf_proof != correct_vdf_proof
|
|
1958
|
+
timelord_protocol_invalid_messages.append(
|
|
1959
|
+
timelord_protocol.RespondCompactProofOfTime(
|
|
1960
|
+
vdf_info,
|
|
1961
|
+
wrong_vdf_proof,
|
|
1962
|
+
block.header_hash,
|
|
1963
|
+
block.height,
|
|
1964
|
+
CompressibleVDFField.CC_EOS_VDF,
|
|
1965
|
+
)
|
|
1966
|
+
)
|
|
1967
|
+
full_node_protocol_invalid_messaages.append(
|
|
1968
|
+
fnp.RespondCompactVDF(
|
|
1969
|
+
block.height,
|
|
1970
|
+
block.header_hash,
|
|
1971
|
+
CompressibleVDFField.CC_EOS_VDF,
|
|
1972
|
+
vdf_info,
|
|
1973
|
+
wrong_vdf_proof,
|
|
1974
|
+
)
|
|
1975
|
+
)
|
|
1976
|
+
if sub_slot.infused_challenge_chain is not None:
|
|
1977
|
+
vdf_info, correct_vdf_proof = get_vdf_info_and_proof(
|
|
1978
|
+
bt.constants,
|
|
1979
|
+
ClassgroupElement.get_default_element(),
|
|
1980
|
+
sub_slot.infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.challenge,
|
|
1981
|
+
sub_slot.infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.number_of_iterations,
|
|
1982
|
+
True,
|
|
1983
|
+
)
|
|
1984
|
+
assert wrong_vdf_proof != correct_vdf_proof
|
|
1985
|
+
timelord_protocol_invalid_messages.append(
|
|
1986
|
+
timelord_protocol.RespondCompactProofOfTime(
|
|
1987
|
+
vdf_info,
|
|
1988
|
+
wrong_vdf_proof,
|
|
1989
|
+
block.header_hash,
|
|
1990
|
+
block.height,
|
|
1991
|
+
CompressibleVDFField.ICC_EOS_VDF,
|
|
1992
|
+
)
|
|
1993
|
+
)
|
|
1994
|
+
full_node_protocol_invalid_messaages.append(
|
|
1995
|
+
fnp.RespondCompactVDF(
|
|
1996
|
+
block.height,
|
|
1997
|
+
block.header_hash,
|
|
1998
|
+
CompressibleVDFField.ICC_EOS_VDF,
|
|
1999
|
+
vdf_info,
|
|
2000
|
+
wrong_vdf_proof,
|
|
2001
|
+
)
|
|
2002
|
+
)
|
|
2003
|
+
|
|
2004
|
+
if block.reward_chain_block.challenge_chain_sp_vdf is not None:
|
|
2005
|
+
vdf_info, correct_vdf_proof = get_vdf_info_and_proof(
|
|
2006
|
+
bt.constants,
|
|
2007
|
+
ClassgroupElement.get_default_element(),
|
|
2008
|
+
block.reward_chain_block.challenge_chain_sp_vdf.challenge,
|
|
2009
|
+
block.reward_chain_block.challenge_chain_sp_vdf.number_of_iterations,
|
|
2010
|
+
True,
|
|
2011
|
+
)
|
|
2012
|
+
sp_vdf_proof = wrong_vdf_proof
|
|
2013
|
+
if wrong_vdf_proof == correct_vdf_proof:
|
|
2014
|
+
# This can actually happen...
|
|
2015
|
+
sp_vdf_proof = VDFProof(uint8(0), b"1239819023890", True)
|
|
2016
|
+
timelord_protocol_invalid_messages.append(
|
|
2017
|
+
timelord_protocol.RespondCompactProofOfTime(
|
|
2018
|
+
vdf_info,
|
|
2019
|
+
sp_vdf_proof,
|
|
2020
|
+
block.header_hash,
|
|
2021
|
+
block.height,
|
|
2022
|
+
CompressibleVDFField.CC_SP_VDF,
|
|
2023
|
+
)
|
|
2024
|
+
)
|
|
2025
|
+
full_node_protocol_invalid_messaages.append(
|
|
2026
|
+
fnp.RespondCompactVDF(
|
|
2027
|
+
block.height,
|
|
2028
|
+
block.header_hash,
|
|
2029
|
+
CompressibleVDFField.CC_SP_VDF,
|
|
2030
|
+
vdf_info,
|
|
2031
|
+
sp_vdf_proof,
|
|
2032
|
+
)
|
|
2033
|
+
)
|
|
2034
|
+
|
|
2035
|
+
vdf_info, correct_vdf_proof = get_vdf_info_and_proof(
|
|
2036
|
+
bt.constants,
|
|
2037
|
+
ClassgroupElement.get_default_element(),
|
|
2038
|
+
block.reward_chain_block.challenge_chain_ip_vdf.challenge,
|
|
2039
|
+
block.reward_chain_block.challenge_chain_ip_vdf.number_of_iterations,
|
|
2040
|
+
True,
|
|
2041
|
+
)
|
|
2042
|
+
ip_vdf_proof = wrong_vdf_proof
|
|
2043
|
+
if wrong_vdf_proof == correct_vdf_proof:
|
|
2044
|
+
# This can actually happen...
|
|
2045
|
+
ip_vdf_proof = VDFProof(uint8(0), b"1239819023890", True)
|
|
2046
|
+
timelord_protocol_invalid_messages.append(
|
|
2047
|
+
timelord_protocol.RespondCompactProofOfTime(
|
|
2048
|
+
vdf_info,
|
|
2049
|
+
ip_vdf_proof,
|
|
2050
|
+
block.header_hash,
|
|
2051
|
+
block.height,
|
|
2052
|
+
CompressibleVDFField.CC_IP_VDF,
|
|
2053
|
+
)
|
|
2054
|
+
)
|
|
2055
|
+
full_node_protocol_invalid_messaages.append(
|
|
2056
|
+
fnp.RespondCompactVDF(
|
|
2057
|
+
block.height,
|
|
2058
|
+
block.header_hash,
|
|
2059
|
+
CompressibleVDFField.CC_IP_VDF,
|
|
2060
|
+
vdf_info,
|
|
2061
|
+
ip_vdf_proof,
|
|
2062
|
+
)
|
|
2063
|
+
)
|
|
2064
|
+
|
|
2065
|
+
timelord_protocol_invalid_messages.append(
|
|
2066
|
+
timelord_protocol.RespondCompactProofOfTime(
|
|
2067
|
+
wrong_vdf_info,
|
|
2068
|
+
wrong_vdf_proof,
|
|
2069
|
+
block.header_hash,
|
|
2070
|
+
block.height,
|
|
2071
|
+
CompressibleVDFField.CC_EOS_VDF,
|
|
2072
|
+
)
|
|
2073
|
+
)
|
|
2074
|
+
timelord_protocol_invalid_messages.append(
|
|
2075
|
+
timelord_protocol.RespondCompactProofOfTime(
|
|
2076
|
+
wrong_vdf_info,
|
|
2077
|
+
wrong_vdf_proof,
|
|
2078
|
+
block.header_hash,
|
|
2079
|
+
block.height,
|
|
2080
|
+
CompressibleVDFField.ICC_EOS_VDF,
|
|
2081
|
+
)
|
|
2082
|
+
)
|
|
2083
|
+
timelord_protocol_invalid_messages.append(
|
|
2084
|
+
timelord_protocol.RespondCompactProofOfTime(
|
|
2085
|
+
wrong_vdf_info,
|
|
2086
|
+
wrong_vdf_proof,
|
|
2087
|
+
block.header_hash,
|
|
2088
|
+
block.height,
|
|
2089
|
+
CompressibleVDFField.CC_SP_VDF,
|
|
2090
|
+
)
|
|
2091
|
+
)
|
|
2092
|
+
timelord_protocol_invalid_messages.append(
|
|
2093
|
+
timelord_protocol.RespondCompactProofOfTime(
|
|
2094
|
+
wrong_vdf_info,
|
|
2095
|
+
wrong_vdf_proof,
|
|
2096
|
+
block.header_hash,
|
|
2097
|
+
block.height,
|
|
2098
|
+
CompressibleVDFField.CC_IP_VDF,
|
|
2099
|
+
)
|
|
2100
|
+
)
|
|
2101
|
+
full_node_protocol_invalid_messaages.append(
|
|
2102
|
+
fnp.RespondCompactVDF(
|
|
2103
|
+
block.height,
|
|
2104
|
+
block.header_hash,
|
|
2105
|
+
CompressibleVDFField.CC_EOS_VDF,
|
|
2106
|
+
wrong_vdf_info,
|
|
2107
|
+
wrong_vdf_proof,
|
|
2108
|
+
)
|
|
2109
|
+
)
|
|
2110
|
+
full_node_protocol_invalid_messaages.append(
|
|
2111
|
+
fnp.RespondCompactVDF(
|
|
2112
|
+
block.height,
|
|
2113
|
+
block.header_hash,
|
|
2114
|
+
CompressibleVDFField.ICC_EOS_VDF,
|
|
2115
|
+
wrong_vdf_info,
|
|
2116
|
+
wrong_vdf_proof,
|
|
2117
|
+
)
|
|
2118
|
+
)
|
|
2119
|
+
full_node_protocol_invalid_messaages.append(
|
|
2120
|
+
fnp.RespondCompactVDF(
|
|
2121
|
+
block.height,
|
|
2122
|
+
block.header_hash,
|
|
2123
|
+
CompressibleVDFField.CC_SP_VDF,
|
|
2124
|
+
wrong_vdf_info,
|
|
2125
|
+
wrong_vdf_proof,
|
|
2126
|
+
)
|
|
2127
|
+
)
|
|
2128
|
+
full_node_protocol_invalid_messaages.append(
|
|
2129
|
+
fnp.RespondCompactVDF(
|
|
2130
|
+
block.height,
|
|
2131
|
+
block.header_hash,
|
|
2132
|
+
CompressibleVDFField.CC_IP_VDF,
|
|
2133
|
+
wrong_vdf_info,
|
|
2134
|
+
wrong_vdf_proof,
|
|
2135
|
+
)
|
|
2136
|
+
)
|
|
2137
|
+
server_1 = full_node_1.full_node.server
|
|
2138
|
+
server_2 = full_node_2.full_node.server
|
|
2139
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
2140
|
+
for invalid_compact_proof in timelord_protocol_invalid_messages:
|
|
2141
|
+
await full_node_1.full_node.add_compact_proof_of_time(invalid_compact_proof)
|
|
2142
|
+
for invalid_compact_proof in full_node_protocol_invalid_messaages:
|
|
2143
|
+
await full_node_1.full_node.add_compact_vdf(invalid_compact_proof, peer)
|
|
2144
|
+
stored_blocks = await full_node_1.get_all_full_blocks()
|
|
2145
|
+
for block in stored_blocks:
|
|
2146
|
+
for sub_slot in block.finished_sub_slots:
|
|
2147
|
+
assert not sub_slot.proofs.challenge_chain_slot_proof.normalized_to_identity
|
|
2148
|
+
if sub_slot.proofs.infused_challenge_chain_slot_proof is not None:
|
|
2149
|
+
assert not sub_slot.proofs.infused_challenge_chain_slot_proof.normalized_to_identity
|
|
2150
|
+
if block.challenge_chain_sp_proof is not None:
|
|
2151
|
+
assert not block.challenge_chain_sp_proof.normalized_to_identity
|
|
2152
|
+
assert not block.challenge_chain_ip_proof.normalized_to_identity
|
|
2153
|
+
|
|
2154
|
+
|
|
2155
|
+
@pytest.mark.anyio
|
|
2156
|
+
async def test_respond_compact_proof_message_limit(setup_two_nodes_fixture):
|
|
2157
|
+
nodes, _, bt = setup_two_nodes_fixture
|
|
2158
|
+
full_node_1 = nodes[0]
|
|
2159
|
+
full_node_2 = nodes[1]
|
|
2160
|
+
NUM_BLOCKS = 20
|
|
2161
|
+
# We don't compactify the last 5 blocks.
|
|
2162
|
+
EXPECTED_COMPACTIFIED = NUM_BLOCKS - 5
|
|
2163
|
+
blocks = bt.get_consecutive_blocks(num_blocks=NUM_BLOCKS)
|
|
2164
|
+
finished_compact_proofs = []
|
|
2165
|
+
for block in blocks:
|
|
2166
|
+
await full_node_1.full_node.add_block(block)
|
|
2167
|
+
await full_node_2.full_node.add_block(block)
|
|
2168
|
+
vdf_info, vdf_proof = get_vdf_info_and_proof(
|
|
2169
|
+
bt.constants,
|
|
2170
|
+
ClassgroupElement.get_default_element(),
|
|
2171
|
+
block.reward_chain_block.challenge_chain_ip_vdf.challenge,
|
|
2172
|
+
block.reward_chain_block.challenge_chain_ip_vdf.number_of_iterations,
|
|
2173
|
+
True,
|
|
2174
|
+
)
|
|
2175
|
+
finished_compact_proofs.append(
|
|
2176
|
+
timelord_protocol.RespondCompactProofOfTime(
|
|
2177
|
+
vdf_info,
|
|
2178
|
+
vdf_proof,
|
|
2179
|
+
block.header_hash,
|
|
2180
|
+
block.height,
|
|
2181
|
+
CompressibleVDFField.CC_IP_VDF,
|
|
2182
|
+
)
|
|
2183
|
+
)
|
|
2184
|
+
|
|
2185
|
+
async def coro(full_node, compact_proof):
|
|
2186
|
+
await full_node.respond_compact_proof_of_time(compact_proof)
|
|
2187
|
+
|
|
2188
|
+
full_node_1.full_node._compact_vdf_sem = LimitedSemaphore.create(active_limit=1, waiting_limit=2)
|
|
2189
|
+
tasks = asyncio.gather(
|
|
2190
|
+
*[coro(full_node_1, respond_compact_proof) for respond_compact_proof in finished_compact_proofs]
|
|
2191
|
+
)
|
|
2192
|
+
await tasks
|
|
2193
|
+
stored_blocks = await full_node_1.get_all_full_blocks()
|
|
2194
|
+
compactified = 0
|
|
2195
|
+
for block in stored_blocks:
|
|
2196
|
+
if block.challenge_chain_ip_proof.normalized_to_identity:
|
|
2197
|
+
compactified += 1
|
|
2198
|
+
assert compactified == 3
|
|
2199
|
+
|
|
2200
|
+
# The other full node receives the compact messages one at a time.
|
|
2201
|
+
for respond_compact_proof in finished_compact_proofs:
|
|
2202
|
+
await full_node_2.full_node.add_compact_proof_of_time(respond_compact_proof)
|
|
2203
|
+
stored_blocks = await full_node_2.get_all_full_blocks()
|
|
2204
|
+
compactified = 0
|
|
2205
|
+
for block in stored_blocks:
|
|
2206
|
+
if block.challenge_chain_ip_proof.normalized_to_identity:
|
|
2207
|
+
compactified += 1
|
|
2208
|
+
assert compactified == EXPECTED_COMPACTIFIED
|
|
2209
|
+
|
|
2210
|
+
|
|
2211
|
+
@pytest.mark.parametrize(
|
|
2212
|
+
argnames=["custom_capabilities", "expect_success"],
|
|
2213
|
+
argvalues=[
|
|
2214
|
+
# standard
|
|
2215
|
+
[default_capabilities[NodeType.FULL_NODE], True],
|
|
2216
|
+
# an additional enabled but unknown capability
|
|
2217
|
+
[[*default_capabilities[NodeType.FULL_NODE], (uint16(max(Capability) + 1), "1")], True],
|
|
2218
|
+
# no capability, not even Chia mainnet
|
|
2219
|
+
# TODO: shouldn't we fail without Capability.BASE?
|
|
2220
|
+
[[], True],
|
|
2221
|
+
# only an unknown capability
|
|
2222
|
+
# TODO: shouldn't we fail without Capability.BASE?
|
|
2223
|
+
[[(uint16(max(Capability) + 1), "1")], True],
|
|
2224
|
+
],
|
|
2225
|
+
)
|
|
2226
|
+
@pytest.mark.anyio
|
|
2227
|
+
async def test_invalid_capability_can_connect(
|
|
2228
|
+
two_nodes: tuple[FullNodeAPI, FullNodeAPI, ChiaServer, ChiaServer, BlockTools],
|
|
2229
|
+
self_hostname: str,
|
|
2230
|
+
custom_capabilities: list[tuple[uint16, str]],
|
|
2231
|
+
expect_success: bool,
|
|
2232
|
+
) -> None:
|
|
2233
|
+
# TODO: consider not testing this against both DB v1 and v2?
|
|
2234
|
+
|
|
2235
|
+
[
|
|
2236
|
+
_initiating_full_node_api,
|
|
2237
|
+
_listening_full_node_api,
|
|
2238
|
+
initiating_server,
|
|
2239
|
+
listening_server,
|
|
2240
|
+
_bt,
|
|
2241
|
+
] = two_nodes
|
|
2242
|
+
|
|
2243
|
+
initiating_server._local_capabilities_for_handshake = custom_capabilities
|
|
2244
|
+
|
|
2245
|
+
connected = await initiating_server.start_client(PeerInfo(self_hostname, listening_server.get_port()), None)
|
|
2246
|
+
assert connected == expect_success, custom_capabilities
|
|
2247
|
+
|
|
2248
|
+
|
|
2249
|
+
@pytest.mark.anyio
|
|
2250
|
+
async def test_node_start_with_existing_blocks(db_version: int) -> None:
|
|
2251
|
+
with TempKeyring(populate=True) as keychain:
|
|
2252
|
+
block_tools = await create_block_tools_async(keychain=keychain)
|
|
2253
|
+
|
|
2254
|
+
blocks_per_cycle = 5
|
|
2255
|
+
expected_height = 0
|
|
2256
|
+
|
|
2257
|
+
for cycle in range(2):
|
|
2258
|
+
async with setup_full_node(
|
|
2259
|
+
consensus_constants=block_tools.constants,
|
|
2260
|
+
db_name="node_restart_test.db",
|
|
2261
|
+
self_hostname=block_tools.config["self_hostname"],
|
|
2262
|
+
local_bt=block_tools,
|
|
2263
|
+
simulator=True,
|
|
2264
|
+
db_version=db_version,
|
|
2265
|
+
reuse_db=True,
|
|
2266
|
+
) as service:
|
|
2267
|
+
simulator_api = service._api
|
|
2268
|
+
assert isinstance(simulator_api, FullNodeSimulator)
|
|
2269
|
+
await simulator_api.farm_blocks_to_puzzlehash(count=blocks_per_cycle)
|
|
2270
|
+
|
|
2271
|
+
expected_height += blocks_per_cycle
|
|
2272
|
+
assert simulator_api.full_node._blockchain is not None
|
|
2273
|
+
block_record = simulator_api.full_node._blockchain.get_peak()
|
|
2274
|
+
|
|
2275
|
+
assert block_record is not None, f"block_record is None on cycle {cycle + 1}"
|
|
2276
|
+
assert block_record.height == expected_height, f"wrong height on cycle {cycle + 1}"
|
|
2277
|
+
|
|
2278
|
+
|
|
2279
|
+
@pytest.mark.anyio
|
|
2280
|
+
async def test_wallet_sync_task_failure(
|
|
2281
|
+
one_node: SimulatorsAndWalletsServices, caplog: pytest.LogCaptureFixture
|
|
2282
|
+
) -> None:
|
|
2283
|
+
[full_node_service], _, _ = one_node
|
|
2284
|
+
full_node = full_node_service._node
|
|
2285
|
+
assert full_node.wallet_sync_task is not None
|
|
2286
|
+
caplog.set_level(logging.DEBUG)
|
|
2287
|
+
peak = Peak(bytes32(32 * b"0"), uint32(0), uint128(0))
|
|
2288
|
+
# WalletUpdate with invalid args to force an exception in FullNode.update_wallets / FullNode.wallet_sync_task
|
|
2289
|
+
bad_wallet_update = WalletUpdate(-10, peak, [], {}) # type: ignore[arg-type]
|
|
2290
|
+
await full_node.wallet_sync_queue.put(bad_wallet_update)
|
|
2291
|
+
await time_out_assert(30, full_node.wallet_sync_queue.empty)
|
|
2292
|
+
assert "update_wallets - fork_height: -10, peak_height: 0" in caplog.text
|
|
2293
|
+
assert "Wallet sync task failure" in caplog.text
|
|
2294
|
+
assert not full_node.wallet_sync_task.done()
|
|
2295
|
+
caplog.clear()
|
|
2296
|
+
# WalletUpdate with valid args to test continued processing after failure
|
|
2297
|
+
good_wallet_update = WalletUpdate(uint32(10), peak, [], {})
|
|
2298
|
+
await full_node.wallet_sync_queue.put(good_wallet_update)
|
|
2299
|
+
await time_out_assert(30, full_node.wallet_sync_queue.empty)
|
|
2300
|
+
assert "update_wallets - fork_height: 10, peak_height: 0" in caplog.text
|
|
2301
|
+
assert "Wallet sync task failure" not in caplog.text
|
|
2302
|
+
assert not full_node.wallet_sync_task.done()
|
|
2303
|
+
|
|
2304
|
+
|
|
2305
|
+
def print_coin_records(records: dict[bytes32, CoinRecord]) -> None: # pragma: no cover
|
|
2306
|
+
print("found unexpected coins in database")
|
|
2307
|
+
for rec in records.values():
|
|
2308
|
+
print(f"{rec}")
|
|
2309
|
+
|
|
2310
|
+
|
|
2311
|
+
async def validate_coin_set(coin_store: CoinStore, blocks: list[FullBlock]) -> None:
|
|
2312
|
+
prev_height = blocks[0].height - 1
|
|
2313
|
+
prev_hash = blocks[0].prev_header_hash
|
|
2314
|
+
for block in blocks:
|
|
2315
|
+
assert block.height == prev_height + 1
|
|
2316
|
+
assert block.prev_header_hash == prev_hash
|
|
2317
|
+
prev_height = int(block.height)
|
|
2318
|
+
prev_hash = block.header_hash
|
|
2319
|
+
rewards = block.get_included_reward_coins()
|
|
2320
|
+
records = {rec.coin.name(): rec for rec in await coin_store.get_coins_added_at_height(block.height)}
|
|
2321
|
+
|
|
2322
|
+
# validate reward coins
|
|
2323
|
+
for reward in rewards:
|
|
2324
|
+
rec = records.pop(reward.name())
|
|
2325
|
+
assert rec is not None
|
|
2326
|
+
assert rec.confirmed_block_index == block.height
|
|
2327
|
+
assert rec.coin == reward
|
|
2328
|
+
assert rec.coinbase
|
|
2329
|
+
|
|
2330
|
+
if block.transactions_generator is None:
|
|
2331
|
+
if len(records) > 0: # pragma: no cover
|
|
2332
|
+
print(f"height: {block.height} unexpected coins in the DB: {records} TX: No")
|
|
2333
|
+
print_coin_records(records)
|
|
2334
|
+
assert records == {}
|
|
2335
|
+
continue
|
|
2336
|
+
|
|
2337
|
+
if len(block.transactions_generator_ref_list) > 0: # pragma: no cover
|
|
2338
|
+
# TODO: Support block references
|
|
2339
|
+
assert False
|
|
2340
|
+
|
|
2341
|
+
flags = get_flags_for_height_and_constants(block.height, test_constants)
|
|
2342
|
+
additions, removals = additions_and_removals(bytes(block.transactions_generator), [], flags, test_constants)
|
|
2343
|
+
|
|
2344
|
+
for add, hint in additions:
|
|
2345
|
+
rec = records.pop(add.name())
|
|
2346
|
+
assert rec is not None
|
|
2347
|
+
assert rec.confirmed_block_index == block.height
|
|
2348
|
+
assert rec.coin == add
|
|
2349
|
+
assert not rec.coinbase
|
|
2350
|
+
|
|
2351
|
+
if len(records) > 0: # pragma: no cover
|
|
2352
|
+
print(f"height: {block.height} unexpected coins in the DB: {records} TX: Yes")
|
|
2353
|
+
print_coin_records(records)
|
|
2354
|
+
assert records == {}
|
|
2355
|
+
|
|
2356
|
+
records = {rec.coin.name(): rec for rec in await coin_store.get_coins_removed_at_height(block.height)}
|
|
2357
|
+
for rem in removals:
|
|
2358
|
+
rec = records.pop(rem.name())
|
|
2359
|
+
assert rec is not None
|
|
2360
|
+
assert rec.spent_block_index == block.height
|
|
2361
|
+
assert rec.coin == rem
|
|
2362
|
+
|
|
2363
|
+
if len(records) > 0: # pragma: no cover
|
|
2364
|
+
print(f"height: {block.height} unexpected removals: {records} TX: Yes")
|
|
2365
|
+
print_coin_records(records)
|
|
2366
|
+
assert records == {}
|
|
2367
|
+
|
|
2368
|
+
|
|
2369
|
+
@pytest.mark.anyio
|
|
2370
|
+
@pytest.mark.parametrize("light_blocks", [True, False])
|
|
2371
|
+
async def test_long_reorg(
|
|
2372
|
+
light_blocks: bool,
|
|
2373
|
+
one_node_one_block,
|
|
2374
|
+
default_10000_blocks: list[FullBlock],
|
|
2375
|
+
test_long_reorg_1500_blocks: list[FullBlock],
|
|
2376
|
+
test_long_reorg_1500_blocks_light: list[FullBlock],
|
|
2377
|
+
seeded_random: random.Random,
|
|
2378
|
+
):
|
|
2379
|
+
node, _server, _bt = one_node_one_block
|
|
2380
|
+
|
|
2381
|
+
fork_point = 1499
|
|
2382
|
+
blocks = default_10000_blocks[:3000]
|
|
2383
|
+
|
|
2384
|
+
if light_blocks:
|
|
2385
|
+
# if the blocks have lighter weight, we need more height to compensate,
|
|
2386
|
+
# to force a reorg
|
|
2387
|
+
reorg_blocks = test_long_reorg_1500_blocks_light[:3050]
|
|
2388
|
+
else:
|
|
2389
|
+
reorg_blocks = test_long_reorg_1500_blocks[:2700]
|
|
2390
|
+
|
|
2391
|
+
await add_blocks_in_batches(blocks, node.full_node)
|
|
2392
|
+
peak = node.full_node.blockchain.get_peak()
|
|
2393
|
+
chain_1_height = peak.height
|
|
2394
|
+
chain_1_weight = peak.weight
|
|
2395
|
+
chain_1_peak = peak.header_hash
|
|
2396
|
+
|
|
2397
|
+
assert reorg_blocks[fork_point] == default_10000_blocks[fork_point]
|
|
2398
|
+
assert reorg_blocks[fork_point + 1] != default_10000_blocks[fork_point + 1]
|
|
2399
|
+
|
|
2400
|
+
await validate_coin_set(node.full_node._coin_store, blocks)
|
|
2401
|
+
|
|
2402
|
+
# one aspect of this test is to make sure we can reorg blocks that are
|
|
2403
|
+
# not in the cache. We need to explicitly prune the cache to get that
|
|
2404
|
+
# effect.
|
|
2405
|
+
node.full_node.blockchain.clean_block_records()
|
|
2406
|
+
await add_blocks_in_batches(reorg_blocks, node.full_node)
|
|
2407
|
+
# if these asserts fires, there was no reorg
|
|
2408
|
+
peak = node.full_node.blockchain.get_peak()
|
|
2409
|
+
assert peak.header_hash != chain_1_peak
|
|
2410
|
+
assert peak.weight > chain_1_weight
|
|
2411
|
+
chain_2_weight = peak.weight
|
|
2412
|
+
chain_2_peak = peak.header_hash
|
|
2413
|
+
|
|
2414
|
+
await validate_coin_set(node.full_node._coin_store, reorg_blocks)
|
|
2415
|
+
|
|
2416
|
+
# if the reorg chain has lighter blocks, once we've re-orged onto it, we
|
|
2417
|
+
# have a greater block height. If the reorg chain has heavier blocks, we
|
|
2418
|
+
# end up with a lower height than the original chain (but greater weight)
|
|
2419
|
+
if light_blocks:
|
|
2420
|
+
assert peak.height > chain_1_height
|
|
2421
|
+
else:
|
|
2422
|
+
assert peak.height < chain_1_height
|
|
2423
|
+
# now reorg back to the original chain
|
|
2424
|
+
# this exercises the case where we have some of the blocks in the DB already
|
|
2425
|
+
node.full_node.blockchain.clean_block_records()
|
|
2426
|
+
# when using add_block manualy we must warmup the cache
|
|
2427
|
+
await node.full_node.blockchain.warmup(fork_point - 100)
|
|
2428
|
+
if light_blocks:
|
|
2429
|
+
blocks = default_10000_blocks[fork_point - 100 : 3200]
|
|
2430
|
+
else:
|
|
2431
|
+
blocks = default_10000_blocks[fork_point - 100 : 5500]
|
|
2432
|
+
await add_blocks_in_batches(blocks, node.full_node)
|
|
2433
|
+
# if these asserts fires, there was no reorg back to the original chain
|
|
2434
|
+
peak = node.full_node.blockchain.get_peak()
|
|
2435
|
+
assert peak.header_hash != chain_2_peak
|
|
2436
|
+
assert peak.weight > chain_2_weight
|
|
2437
|
+
|
|
2438
|
+
await validate_coin_set(node.full_node._coin_store, blocks)
|
|
2439
|
+
|
|
2440
|
+
|
|
2441
|
+
@pytest.mark.anyio
|
|
2442
|
+
@pytest.mark.parametrize("light_blocks", [True, False])
|
|
2443
|
+
@pytest.mark.parametrize("chain_length", [0, 100])
|
|
2444
|
+
@pytest.mark.parametrize("fork_point", [500, 1500])
|
|
2445
|
+
@pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.HARD_FORK_2_0], reason="save time")
|
|
2446
|
+
async def test_long_reorg_nodes(
|
|
2447
|
+
light_blocks: bool,
|
|
2448
|
+
chain_length: int,
|
|
2449
|
+
fork_point: int,
|
|
2450
|
+
three_nodes,
|
|
2451
|
+
default_10000_blocks: list[FullBlock],
|
|
2452
|
+
test_long_reorg_blocks: list[FullBlock],
|
|
2453
|
+
test_long_reorg_blocks_light: list[FullBlock],
|
|
2454
|
+
test_long_reorg_1500_blocks: list[FullBlock],
|
|
2455
|
+
test_long_reorg_1500_blocks_light: list[FullBlock],
|
|
2456
|
+
self_hostname: str,
|
|
2457
|
+
seeded_random: random.Random,
|
|
2458
|
+
):
|
|
2459
|
+
full_node_1, full_node_2, full_node_3 = three_nodes
|
|
2460
|
+
|
|
2461
|
+
if fork_point == 1500:
|
|
2462
|
+
blocks = default_10000_blocks[: 3600 - chain_length]
|
|
2463
|
+
else:
|
|
2464
|
+
blocks = default_10000_blocks[: 1600 - chain_length]
|
|
2465
|
+
|
|
2466
|
+
if light_blocks:
|
|
2467
|
+
if fork_point == 1500:
|
|
2468
|
+
reorg_blocks = test_long_reorg_1500_blocks_light[: 3600 - chain_length]
|
|
2469
|
+
reorg_height = 4000
|
|
2470
|
+
else:
|
|
2471
|
+
reorg_blocks = test_long_reorg_blocks_light[: 1600 - chain_length]
|
|
2472
|
+
reorg_height = 4000
|
|
2473
|
+
else:
|
|
2474
|
+
if fork_point == 1500:
|
|
2475
|
+
reorg_blocks = test_long_reorg_1500_blocks[: 3100 - chain_length]
|
|
2476
|
+
reorg_height = 10000
|
|
2477
|
+
else:
|
|
2478
|
+
reorg_blocks = test_long_reorg_blocks[: 1200 - chain_length]
|
|
2479
|
+
reorg_height = 4000
|
|
2480
|
+
pytest.skip("We rely on the light-blocks test for a 0 forkpoint")
|
|
2481
|
+
|
|
2482
|
+
await add_blocks_in_batches(blocks, full_node_1.full_node)
|
|
2483
|
+
|
|
2484
|
+
# full node 2 has the reorg-chain
|
|
2485
|
+
await add_blocks_in_batches(reorg_blocks[:-1], full_node_2.full_node)
|
|
2486
|
+
await connect_and_get_peer(full_node_1.full_node.server, full_node_2.full_node.server, self_hostname)
|
|
2487
|
+
|
|
2488
|
+
# TODO: There appears to be an issue where the node with the lighter chain
|
|
2489
|
+
# fails to initiate the reorg until there's a new block farmed onto the
|
|
2490
|
+
# heavier chain.
|
|
2491
|
+
await full_node_2.full_node.add_block(reorg_blocks[-1])
|
|
2492
|
+
|
|
2493
|
+
start = time.monotonic()
|
|
2494
|
+
|
|
2495
|
+
def check_nodes_in_sync():
|
|
2496
|
+
p1 = full_node_2.full_node.blockchain.get_peak()
|
|
2497
|
+
p2 = full_node_1.full_node.blockchain.get_peak()
|
|
2498
|
+
return p1 == p2
|
|
2499
|
+
|
|
2500
|
+
await time_out_assert(100, check_nodes_in_sync)
|
|
2501
|
+
peak = full_node_2.full_node.blockchain.get_peak()
|
|
2502
|
+
print(f"peak: {str(peak.header_hash)[:6]}")
|
|
2503
|
+
|
|
2504
|
+
reorg1_timing = time.monotonic() - start
|
|
2505
|
+
|
|
2506
|
+
p1 = full_node_1.full_node.blockchain.get_peak()
|
|
2507
|
+
p2 = full_node_2.full_node.blockchain.get_peak()
|
|
2508
|
+
|
|
2509
|
+
assert p1.header_hash == reorg_blocks[-1].header_hash
|
|
2510
|
+
assert p2.header_hash == reorg_blocks[-1].header_hash
|
|
2511
|
+
|
|
2512
|
+
await validate_coin_set(full_node_1.full_node._coin_store, reorg_blocks)
|
|
2513
|
+
await validate_coin_set(full_node_2.full_node._coin_store, reorg_blocks)
|
|
2514
|
+
|
|
2515
|
+
blocks = default_10000_blocks[:reorg_height]
|
|
2516
|
+
|
|
2517
|
+
# this is a pre-requisite for a reorg to happen
|
|
2518
|
+
assert blocks[-1].weight > p1.weight
|
|
2519
|
+
assert blocks[-1].weight > p2.weight
|
|
2520
|
+
|
|
2521
|
+
# full node 3 has the original chain, but even longer
|
|
2522
|
+
await add_blocks_in_batches(blocks, full_node_3.full_node)
|
|
2523
|
+
print("connecting node 3")
|
|
2524
|
+
await connect_and_get_peer(full_node_3.full_node.server, full_node_1.full_node.server, self_hostname)
|
|
2525
|
+
await connect_and_get_peer(full_node_3.full_node.server, full_node_2.full_node.server, self_hostname)
|
|
2526
|
+
|
|
2527
|
+
start = time.monotonic()
|
|
2528
|
+
|
|
2529
|
+
def check_nodes_in_sync2():
|
|
2530
|
+
p1 = full_node_1.full_node.blockchain.get_peak()
|
|
2531
|
+
p2 = full_node_2.full_node.blockchain.get_peak()
|
|
2532
|
+
p3 = full_node_3.full_node.blockchain.get_peak()
|
|
2533
|
+
return p1 == p3 and p1 == p2
|
|
2534
|
+
|
|
2535
|
+
await time_out_assert(900, check_nodes_in_sync2)
|
|
2536
|
+
|
|
2537
|
+
reorg2_timing = time.monotonic() - start
|
|
2538
|
+
|
|
2539
|
+
p1 = full_node_1.full_node.blockchain.get_peak()
|
|
2540
|
+
p2 = full_node_2.full_node.blockchain.get_peak()
|
|
2541
|
+
p3 = full_node_3.full_node.blockchain.get_peak()
|
|
2542
|
+
|
|
2543
|
+
assert p1.header_hash == blocks[-1].header_hash
|
|
2544
|
+
assert p2.header_hash == blocks[-1].header_hash
|
|
2545
|
+
assert p3.header_hash == blocks[-1].header_hash
|
|
2546
|
+
|
|
2547
|
+
print(f"reorg1 timing: {reorg1_timing:0.2f}s")
|
|
2548
|
+
print(f"reorg2 timing: {reorg2_timing:0.2f}s")
|
|
2549
|
+
|
|
2550
|
+
await validate_coin_set(full_node_1.full_node._coin_store, blocks)
|
|
2551
|
+
await validate_coin_set(full_node_2.full_node._coin_store, blocks)
|
|
2552
|
+
await validate_coin_set(full_node_3.full_node._coin_store, blocks)
|
|
2553
|
+
|
|
2554
|
+
|
|
2555
|
+
@pytest.mark.anyio
|
|
2556
|
+
async def test_shallow_reorg_nodes(
|
|
2557
|
+
three_nodes,
|
|
2558
|
+
self_hostname: str,
|
|
2559
|
+
bt: BlockTools,
|
|
2560
|
+
):
|
|
2561
|
+
full_node_1, full_node_2, _ = three_nodes
|
|
2562
|
+
|
|
2563
|
+
# node 1 has chan A, then we replace the top block and ensure
|
|
2564
|
+
# node 2 follows along correctly
|
|
2565
|
+
|
|
2566
|
+
await connect_and_get_peer(full_node_1.full_node.server, full_node_2.full_node.server, self_hostname)
|
|
2567
|
+
|
|
2568
|
+
wallet_a = WalletTool(bt.constants)
|
|
2569
|
+
WALLET_A_PUZZLE_HASHES = [wallet_a.get_new_puzzlehash() for _ in range(2)]
|
|
2570
|
+
coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
|
|
2571
|
+
receiver_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
|
|
2572
|
+
|
|
2573
|
+
chain = bt.get_consecutive_blocks(
|
|
2574
|
+
10,
|
|
2575
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
2576
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
2577
|
+
guarantee_transaction_block=True,
|
|
2578
|
+
)
|
|
2579
|
+
await add_blocks_in_batches(chain, full_node_1.full_node)
|
|
2580
|
+
|
|
2581
|
+
all_coins = []
|
|
2582
|
+
for spend_block in chain:
|
|
2583
|
+
for coin in spend_block.get_included_reward_coins():
|
|
2584
|
+
if coin.puzzle_hash == coinbase_puzzlehash:
|
|
2585
|
+
all_coins.append(coin)
|
|
2586
|
+
|
|
2587
|
+
def check_nodes_in_sync():
|
|
2588
|
+
p1 = full_node_2.full_node.blockchain.get_peak()
|
|
2589
|
+
p2 = full_node_1.full_node.blockchain.get_peak()
|
|
2590
|
+
return p1 == p2
|
|
2591
|
+
|
|
2592
|
+
await time_out_assert(10, check_nodes_in_sync)
|
|
2593
|
+
await validate_coin_set(full_node_1.full_node.blockchain.coin_store, chain)
|
|
2594
|
+
await validate_coin_set(full_node_2.full_node.blockchain.coin_store, chain)
|
|
2595
|
+
|
|
2596
|
+
# we spend a coin in the next block
|
|
2597
|
+
spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
|
|
2598
|
+
|
|
2599
|
+
# make a non transaction block with fewer iterations than a, which should
|
|
2600
|
+
# replace it
|
|
2601
|
+
chain_b = bt.get_consecutive_blocks(
|
|
2602
|
+
1,
|
|
2603
|
+
chain,
|
|
2604
|
+
guarantee_transaction_block=False,
|
|
2605
|
+
seed=b"{seed}",
|
|
2606
|
+
)
|
|
2607
|
+
|
|
2608
|
+
chain_a = bt.get_consecutive_blocks(
|
|
2609
|
+
1,
|
|
2610
|
+
chain,
|
|
2611
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
2612
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
2613
|
+
transaction_data=spend_bundle,
|
|
2614
|
+
guarantee_transaction_block=True,
|
|
2615
|
+
min_signage_point=chain_b[-1].reward_chain_block.signage_point_index,
|
|
2616
|
+
)
|
|
2617
|
+
|
|
2618
|
+
print(f"chain A: {chain_a[-1].header_hash.hex()}")
|
|
2619
|
+
print(f"chain B: {chain_b[-1].header_hash.hex()}")
|
|
2620
|
+
|
|
2621
|
+
assert chain_b[-1].total_iters < chain_a[-1].total_iters
|
|
2622
|
+
|
|
2623
|
+
await add_blocks_in_batches(chain_a[-1:], full_node_1.full_node)
|
|
2624
|
+
|
|
2625
|
+
await time_out_assert(10, check_nodes_in_sync)
|
|
2626
|
+
await validate_coin_set(full_node_1.full_node.blockchain.coin_store, chain_a)
|
|
2627
|
+
await validate_coin_set(full_node_2.full_node.blockchain.coin_store, chain_a)
|
|
2628
|
+
|
|
2629
|
+
await add_blocks_in_batches(chain_b[-1:], full_node_1.full_node)
|
|
2630
|
+
|
|
2631
|
+
# make sure node 1 reorged onto chain B
|
|
2632
|
+
assert full_node_1.full_node.blockchain.get_peak().header_hash == chain_b[-1].header_hash
|
|
2633
|
+
|
|
2634
|
+
await time_out_assert(10, check_nodes_in_sync)
|
|
2635
|
+
await validate_coin_set(full_node_1.full_node.blockchain.coin_store, chain_b)
|
|
2636
|
+
await validate_coin_set(full_node_2.full_node.blockchain.coin_store, chain_b)
|
|
2637
|
+
|
|
2638
|
+
# now continue building the chain on top of B
|
|
2639
|
+
# since spend_bundle was supposed to have been reorged-out, we should be
|
|
2640
|
+
# able to include it in another block, howerver, since we replaced a TX
|
|
2641
|
+
# block with a non-TX block, it won't be available immediately at height 11
|
|
2642
|
+
|
|
2643
|
+
# add a TX block, this will make spend_bundle valid in the next block
|
|
2644
|
+
chain = bt.get_consecutive_blocks(
|
|
2645
|
+
1,
|
|
2646
|
+
chain,
|
|
2647
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
2648
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
2649
|
+
guarantee_transaction_block=True,
|
|
2650
|
+
)
|
|
2651
|
+
for coin in chain[-1].get_included_reward_coins():
|
|
2652
|
+
if coin.puzzle_hash == coinbase_puzzlehash:
|
|
2653
|
+
all_coins.append(coin)
|
|
2654
|
+
|
|
2655
|
+
for i in range(3):
|
|
2656
|
+
chain = bt.get_consecutive_blocks(
|
|
2657
|
+
1,
|
|
2658
|
+
chain,
|
|
2659
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
2660
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
2661
|
+
transaction_data=spend_bundle,
|
|
2662
|
+
guarantee_transaction_block=True,
|
|
2663
|
+
)
|
|
2664
|
+
for coin in chain[-1].get_included_reward_coins():
|
|
2665
|
+
if coin.puzzle_hash == coinbase_puzzlehash:
|
|
2666
|
+
all_coins.append(coin)
|
|
2667
|
+
spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
|
|
2668
|
+
|
|
2669
|
+
await add_blocks_in_batches(chain[-4:], full_node_1.full_node)
|
|
2670
|
+
await time_out_assert(10, check_nodes_in_sync)
|
|
2671
|
+
await validate_coin_set(full_node_1.full_node.blockchain.coin_store, chain)
|
|
2672
|
+
await validate_coin_set(full_node_2.full_node.blockchain.coin_store, chain)
|
|
2673
|
+
|
|
2674
|
+
|
|
2675
|
+
@pytest.mark.anyio
|
|
2676
|
+
@pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.HARD_FORK_2_0], reason="save time")
|
|
2677
|
+
async def test_eviction_from_bls_cache(one_node_one_block: tuple[FullNodeSimulator, ChiaServer, BlockTools]) -> None:
|
|
2678
|
+
"""
|
|
2679
|
+
This test covers the case where adding a block to the blockchain evicts
|
|
2680
|
+
all its pk msg pairs from the BLS cache.
|
|
2681
|
+
"""
|
|
2682
|
+
full_node_1, _, bt = one_node_one_block
|
|
2683
|
+
blocks = bt.get_consecutive_blocks(
|
|
2684
|
+
3, guarantee_transaction_block=True, farmer_reward_puzzle_hash=bt.pool_ph, pool_reward_puzzle_hash=bt.pool_ph
|
|
2685
|
+
)
|
|
2686
|
+
await add_blocks_in_batches(blocks, full_node_1.full_node)
|
|
2687
|
+
wt = bt.get_pool_wallet_tool()
|
|
2688
|
+
reward_coins = blocks[-1].get_included_reward_coins()
|
|
2689
|
+
# Setup a test block with two pk msg pairs
|
|
2690
|
+
tx1 = wt.generate_signed_transaction(uint64(42), wt.get_new_puzzlehash(), reward_coins[0])
|
|
2691
|
+
tx2 = wt.generate_signed_transaction(uint64(1337), wt.get_new_puzzlehash(), reward_coins[1])
|
|
2692
|
+
tx = SpendBundle.aggregate([tx1, tx2])
|
|
2693
|
+
await full_node_1.full_node.add_transaction(tx, tx.name(), None, test=True)
|
|
2694
|
+
assert len(full_node_1.full_node._bls_cache.items()) == 2
|
|
2695
|
+
blocks = bt.get_consecutive_blocks(
|
|
2696
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
2697
|
+
)
|
|
2698
|
+
# Farming a block with this tx evicts those pk msg pairs from the BLS cache
|
|
2699
|
+
await full_node_1.full_node.add_block(blocks[-1], None, full_node_1.full_node._bls_cache)
|
|
2700
|
+
assert len(full_node_1.full_node._bls_cache.items()) == 0
|