chia-blockchain 2.5.0rc1__py3-none-any.whl → 2.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chia/_tests/README.md +1 -1
- chia/_tests/blockchain/blockchain_test_utils.py +24 -26
- chia/_tests/blockchain/test_augmented_chain.py +6 -8
- chia/_tests/blockchain/test_blockchain.py +409 -307
- chia/_tests/blockchain/test_blockchain_transactions.py +56 -75
- chia/_tests/blockchain/test_build_chains.py +11 -13
- chia/_tests/blockchain/test_get_block_generator.py +8 -8
- chia/_tests/blockchain/test_lookup_fork_chain.py +3 -4
- chia/_tests/build-init-files.py +3 -4
- chia/_tests/build-job-matrix.py +9 -9
- chia/_tests/check_sql_statements.py +2 -3
- chia/_tests/clvm/benchmark_costs.py +1 -1
- chia/_tests/clvm/coin_store.py +7 -5
- chia/_tests/clvm/test_chialisp_deserialization.py +8 -8
- chia/_tests/clvm/test_condition_codes.py +2 -2
- chia/_tests/clvm/test_curry_and_treehash.py +2 -4
- chia/_tests/clvm/test_message_conditions.py +184 -0
- chia/_tests/clvm/test_puzzle_compression.py +1 -2
- chia/_tests/clvm/test_puzzle_drivers.py +3 -3
- chia/_tests/clvm/test_puzzles.py +13 -18
- chia/_tests/clvm/test_singletons.py +17 -17
- chia/_tests/clvm/test_spend_sim.py +7 -7
- chia/_tests/cmds/cmd_test_utils.py +42 -45
- chia/_tests/cmds/conftest.py +2 -2
- chia/_tests/cmds/test_click_types.py +21 -16
- chia/_tests/cmds/test_cmd_framework.py +255 -35
- chia/_tests/cmds/test_cmds_util.py +2 -2
- chia/_tests/cmds/test_daemon.py +3 -3
- chia/_tests/cmds/test_dev_gh.py +131 -0
- chia/_tests/cmds/test_farm_cmd.py +1 -2
- chia/_tests/cmds/test_show.py +6 -6
- chia/_tests/cmds/test_tx_config_args.py +2 -1
- chia/_tests/cmds/wallet/test_dao.py +23 -23
- chia/_tests/cmds/wallet/test_did.py +29 -29
- chia/_tests/cmds/wallet/test_nft.py +24 -23
- chia/_tests/cmds/wallet/test_notifications.py +8 -8
- chia/_tests/cmds/wallet/test_tx_decorators.py +3 -3
- chia/_tests/cmds/wallet/test_vcs.py +97 -73
- chia/_tests/cmds/wallet/test_wallet.py +74 -75
- chia/_tests/cmds/wallet/test_wallet_check.py +5 -7
- chia/_tests/conftest.py +153 -38
- chia/_tests/connection_utils.py +7 -6
- chia/_tests/core/cmds/test_beta.py +3 -3
- chia/_tests/core/cmds/test_keys.py +6 -6
- chia/_tests/core/cmds/test_wallet.py +3 -3
- chia/_tests/core/consensus/test_block_creation.py +3 -5
- chia/_tests/core/custom_types/test_coin.py +1 -3
- chia/_tests/core/custom_types/test_spend_bundle.py +3 -4
- chia/_tests/core/daemon/test_daemon.py +58 -58
- chia/_tests/core/daemon/test_keychain_proxy.py +2 -1
- chia/_tests/core/data_layer/conftest.py +4 -3
- chia/_tests/core/data_layer/test_data_cli.py +1 -2
- chia/_tests/core/data_layer/test_data_layer.py +5 -5
- chia/_tests/core/data_layer/test_data_layer_util.py +8 -9
- chia/_tests/core/data_layer/test_data_rpc.py +75 -93
- chia/_tests/core/data_layer/test_data_store.py +38 -37
- chia/_tests/core/data_layer/test_data_store_schema.py +11 -11
- chia/_tests/core/data_layer/util.py +11 -10
- chia/_tests/core/farmer/test_farmer_api.py +6 -4
- chia/_tests/core/full_node/full_sync/test_full_sync.py +5 -10
- chia/_tests/core/full_node/ram_db.py +2 -2
- chia/_tests/core/full_node/stores/test_block_store.py +113 -11
- chia/_tests/core/full_node/stores/test_coin_store.py +37 -28
- chia/_tests/core/full_node/stores/test_full_node_store.py +34 -30
- chia/_tests/core/full_node/stores/test_hint_store.py +3 -4
- chia/_tests/core/full_node/test_address_manager.py +2 -2
- chia/_tests/core/full_node/test_block_height_map.py +1 -1
- chia/_tests/core/full_node/test_conditions.py +10 -12
- chia/_tests/core/full_node/test_full_node.py +2077 -1822
- chia/_tests/core/full_node/test_generator_tools.py +4 -4
- chia/_tests/core/full_node/test_hint_management.py +2 -2
- chia/_tests/core/full_node/test_performance.py +2 -5
- chia/_tests/core/full_node/test_subscriptions.py +4 -4
- chia/_tests/core/full_node/test_tx_processing_queue.py +5 -4
- chia/_tests/core/make_block_generator.py +5 -7
- chia/_tests/core/mempool/test_mempool.py +205 -208
- chia/_tests/core/mempool/test_mempool_fee_protocol.py +5 -5
- chia/_tests/core/mempool/test_mempool_item_queries.py +2 -4
- chia/_tests/core/mempool/test_mempool_manager.py +109 -80
- chia/_tests/core/mempool/test_mempool_performance.py +3 -4
- chia/_tests/core/mempool/test_singleton_fast_forward.py +12 -12
- chia/_tests/core/server/flood.py +6 -4
- chia/_tests/core/server/serve.py +10 -7
- chia/_tests/core/server/test_api_protocol.py +21 -0
- chia/_tests/core/server/test_capabilities.py +3 -5
- chia/_tests/core/server/test_dos.py +15 -16
- chia/_tests/core/server/test_loop.py +14 -10
- chia/_tests/core/server/test_node_discovery.py +1 -2
- chia/_tests/core/server/test_rate_limits.py +156 -44
- chia/_tests/core/server/test_server.py +8 -7
- chia/_tests/core/services/test_services.py +59 -37
- chia/_tests/core/ssl/test_ssl.py +5 -3
- chia/_tests/core/test_cost_calculation.py +5 -6
- chia/_tests/core/test_crawler.py +2 -2
- chia/_tests/core/test_db_conversion.py +5 -4
- chia/_tests/core/test_db_validation.py +6 -5
- chia/_tests/core/test_farmer_harvester_rpc.py +8 -7
- chia/_tests/core/test_filter.py +3 -5
- chia/_tests/core/test_full_node_rpc.py +64 -90
- chia/_tests/core/test_merkle_set.py +10 -10
- chia/_tests/core/test_program.py +2 -4
- chia/_tests/core/test_rpc_util.py +1 -2
- chia/_tests/core/test_seeder.py +124 -12
- chia/_tests/core/util/test_block_cache.py +5 -5
- chia/_tests/core/util/test_cached_bls.py +3 -3
- chia/_tests/core/util/test_config.py +13 -13
- chia/_tests/core/util/test_files.py +2 -2
- chia/_tests/core/util/test_jsonify.py +9 -9
- chia/_tests/core/util/test_keychain.py +13 -5
- chia/_tests/core/util/test_keyring_wrapper.py +6 -5
- chia/_tests/core/util/test_log_exceptions.py +3 -3
- chia/_tests/core/util/test_streamable.py +38 -38
- chia/_tests/db/test_db_wrapper.py +13 -12
- chia/_tests/environments/common.py +2 -2
- chia/_tests/environments/full_node.py +2 -2
- chia/_tests/environments/wallet.py +109 -48
- chia/_tests/farmer_harvester/test_farmer.py +35 -35
- chia/_tests/farmer_harvester/test_farmer_harvester.py +17 -17
- chia/_tests/farmer_harvester/test_filter_prefix_bits.py +6 -5
- chia/_tests/farmer_harvester/test_third_party_harvesters.py +73 -46
- chia/_tests/fee_estimation/test_fee_estimation_integration.py +8 -8
- chia/_tests/fee_estimation/test_fee_estimation_rpc.py +47 -47
- chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +6 -7
- chia/_tests/fee_estimation/test_mempoolitem_height_added.py +11 -11
- chia/_tests/generator/test_compression.py +13 -30
- chia/_tests/generator/test_generator_types.py +3 -3
- chia/_tests/generator/test_rom.py +7 -9
- chia/_tests/plot_sync/test_delta.py +2 -3
- chia/_tests/plot_sync/test_plot_sync.py +25 -24
- chia/_tests/plot_sync/test_receiver.py +9 -9
- chia/_tests/plot_sync/test_sender.py +1 -1
- chia/_tests/plot_sync/test_sync_simulated.py +27 -26
- chia/_tests/plot_sync/util.py +2 -1
- chia/_tests/plotting/test_plot_manager.py +54 -11
- chia/_tests/plotting/util.py +2 -3
- chia/_tests/pools/test_pool_cli_parsing.py +128 -0
- chia/_tests/pools/test_pool_cmdline.py +993 -15
- chia/_tests/pools/test_pool_config.py +3 -5
- chia/_tests/pools/test_pool_puzzles_lifecycle.py +10 -11
- chia/_tests/pools/test_pool_rpc.py +203 -90
- chia/_tests/pools/test_pool_wallet.py +12 -8
- chia/_tests/pools/test_wallet_pool_store.py +3 -3
- chia/_tests/process_junit.py +16 -17
- chia/_tests/rpc/test_rpc_client.py +59 -2
- chia/_tests/rpc/test_rpc_server.py +183 -0
- chia/_tests/simulation/test_simulation.py +5 -5
- chia/_tests/simulation/test_simulator.py +8 -10
- chia/_tests/simulation/test_start_simulator.py +5 -4
- chia/_tests/timelord/test_new_peak.py +19 -19
- chia/_tests/tools/test_run_block.py +1 -2
- chia/_tests/tools/test_virtual_project.py +591 -0
- chia/_tests/util/benchmark_cost.py +9 -9
- chia/_tests/util/benchmarks.py +1 -2
- chia/_tests/util/blockchain.py +12 -11
- chia/_tests/util/blockchain_mock.py +15 -15
- chia/_tests/util/build_network_protocol_files.py +12 -12
- chia/_tests/util/db_connection.py +3 -2
- chia/_tests/util/full_sync.py +14 -6
- chia/_tests/util/gen_ssl_certs.py +4 -5
- chia/_tests/util/generator_tools_testing.py +5 -7
- chia/_tests/util/get_name_puzzle_conditions.py +52 -0
- chia/_tests/util/key_tool.py +2 -3
- chia/_tests/util/misc.py +59 -106
- chia/_tests/util/network_protocol_data.py +7 -9
- chia/_tests/util/protocol_messages_json.py +112 -111
- chia/_tests/util/rpc.py +3 -0
- chia/_tests/util/run_block.py +16 -16
- chia/_tests/util/setup_nodes.py +25 -23
- chia/{clvm → _tests/util}/spend_sim.py +59 -55
- chia/_tests/util/split_managers.py +12 -9
- chia/_tests/util/temp_file.py +1 -1
- chia/_tests/util/test_action_scope.py +2 -1
- chia/_tests/util/test_async_pool.py +8 -8
- chia/_tests/util/test_build_job_matrix.py +2 -3
- chia/_tests/util/test_condition_tools.py +4 -6
- chia/_tests/util/test_config.py +5 -5
- chia/_tests/util/test_dump_keyring.py +1 -1
- chia/_tests/util/test_full_block_utils.py +19 -11
- chia/_tests/util/test_limited_semaphore.py +4 -3
- chia/_tests/util/test_logging_filter.py +2 -3
- chia/_tests/util/test_misc.py +29 -28
- chia/_tests/util/test_network.py +32 -31
- chia/_tests/util/test_network_protocol_files.py +2 -3
- chia/_tests/util/test_network_protocol_json.py +1 -0
- chia/_tests/util/test_network_protocol_test.py +18 -19
- chia/_tests/util/test_paginator.py +3 -4
- chia/_tests/util/test_pprint.py +1 -1
- chia/_tests/util/test_priority_mutex.py +18 -17
- chia/_tests/util/test_recursive_replace.py +2 -2
- chia/_tests/util/test_testnet_overrides.py +3 -3
- chia/_tests/util/test_timing.py +1 -1
- chia/_tests/util/test_trusted_peer.py +2 -2
- chia/_tests/util/time_out_assert.py +43 -6
- chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +13 -13
- chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +1 -1
- chia/_tests/wallet/cat_wallet/test_cat_wallet.py +117 -29
- chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +15 -15
- chia/_tests/wallet/cat_wallet/test_trades.py +50 -28
- chia/_tests/wallet/clawback/test_clawback_decorator.py +3 -5
- chia/_tests/wallet/clawback/test_clawback_lifecycle.py +6 -6
- chia/_tests/wallet/clawback/test_clawback_metadata.py +1 -2
- chia/_tests/wallet/conftest.py +135 -74
- chia/_tests/wallet/dao_wallet/test_dao_clvm.py +25 -17
- chia/_tests/wallet/dao_wallet/test_dao_wallets.py +75 -75
- chia/_tests/wallet/db_wallet/test_db_graftroot.py +10 -12
- chia/_tests/wallet/db_wallet/test_dl_offers.py +6 -6
- chia/_tests/wallet/db_wallet/test_dl_wallet.py +18 -18
- chia/_tests/wallet/did_wallet/test_did.py +1277 -474
- chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +12 -11
- chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +115 -105
- chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +6 -7
- chia/_tests/wallet/nft_wallet/test_nft_offers.py +16 -16
- chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +3 -3
- chia/_tests/wallet/nft_wallet/test_nft_wallet.py +38 -12
- chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +1 -1
- chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +31 -33
- chia/_tests/wallet/rpc/test_wallet_rpc.py +218 -171
- chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +36 -37
- chia/_tests/wallet/sync/test_wallet_sync.py +241 -78
- chia/_tests/wallet/test_address_type.py +20 -20
- chia/_tests/wallet/test_clvm_streamable.py +5 -5
- chia/_tests/wallet/test_coin_management.py +354 -0
- chia/_tests/wallet/test_coin_selection.py +34 -35
- chia/_tests/wallet/test_conditions.py +28 -16
- chia/_tests/wallet/test_debug_spend_bundle.py +156 -14
- chia/_tests/wallet/test_new_wallet_protocol.py +29 -31
- chia/_tests/wallet/test_nft_store.py +1 -2
- chia/_tests/wallet/test_notifications.py +2 -2
- chia/_tests/wallet/test_offer_parsing_performance.py +1 -1
- chia/_tests/wallet/test_puzzle_store.py +2 -3
- chia/_tests/wallet/test_sign_coin_spends.py +3 -3
- chia/_tests/wallet/test_signer_protocol.py +33 -34
- chia/_tests/wallet/test_singleton_lifecycle_fast.py +29 -29
- chia/_tests/wallet/test_taproot.py +1 -1
- chia/_tests/wallet/test_transaction_store.py +23 -19
- chia/_tests/wallet/test_util.py +36 -32
- chia/_tests/wallet/test_wallet.py +37 -37
- chia/_tests/wallet/test_wallet_action_scope.py +8 -8
- chia/_tests/wallet/test_wallet_blockchain.py +4 -6
- chia/_tests/wallet/test_wallet_coin_store.py +34 -34
- chia/_tests/wallet/test_wallet_node.py +69 -72
- chia/_tests/wallet/test_wallet_retry.py +3 -3
- chia/_tests/wallet/test_wallet_state_manager.py +12 -5
- chia/_tests/wallet/test_wallet_trade_store.py +2 -2
- chia/_tests/wallet/test_wallet_utils.py +5 -4
- chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +3 -3
- chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +18 -18
- chia/_tests/wallet/vc_wallet/test_vc_wallet.py +69 -40
- chia/_tests/wallet/wallet_block_tools.py +27 -27
- chia/_tests/weight_proof/test_weight_proof.py +30 -30
- chia/apis.py +19 -0
- chia/cmds/beta.py +8 -7
- chia/cmds/beta_funcs.py +15 -11
- chia/cmds/check_wallet_db.py +29 -27
- chia/cmds/chia.py +17 -9
- chia/cmds/cmd_classes.py +87 -79
- chia/cmds/cmd_helpers.py +242 -0
- chia/cmds/cmds_util.py +56 -66
- chia/cmds/coin_funcs.py +168 -153
- chia/cmds/coins.py +156 -194
- chia/cmds/configure.py +4 -3
- chia/cmds/dao.py +89 -33
- chia/cmds/dao_funcs.py +55 -33
- chia/cmds/data.py +7 -6
- chia/cmds/data_funcs.py +26 -21
- chia/cmds/db.py +4 -3
- chia/cmds/db_backup_func.py +2 -2
- chia/cmds/db_upgrade_func.py +3 -3
- chia/cmds/db_validate_func.py +2 -2
- chia/cmds/dev.py +2 -0
- chia/cmds/farm.py +18 -5
- chia/cmds/farm_funcs.py +17 -24
- chia/cmds/gh.py +275 -0
- chia/cmds/init.py +4 -11
- chia/cmds/init_funcs.py +9 -9
- chia/cmds/installers.py +5 -3
- chia/cmds/keys.py +56 -39
- chia/cmds/keys_funcs.py +30 -31
- chia/cmds/netspace.py +6 -3
- chia/cmds/netspace_funcs.py +3 -2
- chia/cmds/param_types.py +16 -6
- chia/cmds/passphrase.py +8 -7
- chia/cmds/passphrase_funcs.py +7 -61
- chia/cmds/peer.py +2 -1
- chia/cmds/peer_funcs.py +5 -5
- chia/cmds/plotnft.py +207 -153
- chia/cmds/plotnft_funcs.py +205 -174
- chia/cmds/plots.py +14 -6
- chia/cmds/plotters.py +2 -1
- chia/cmds/rpc.py +48 -28
- chia/cmds/show.py +2 -1
- chia/cmds/show_funcs.py +7 -6
- chia/cmds/signer.py +50 -58
- chia/cmds/sim.py +22 -14
- chia/cmds/sim_funcs.py +11 -11
- chia/cmds/start.py +3 -3
- chia/cmds/start_funcs.py +9 -12
- chia/cmds/stop.py +4 -3
- chia/cmds/units.py +1 -3
- chia/cmds/wallet.py +252 -96
- chia/cmds/wallet_funcs.py +217 -143
- chia/consensus/block_body_validation.py +133 -86
- chia/consensus/block_creation.py +42 -21
- chia/consensus/block_header_validation.py +32 -37
- chia/consensus/block_record.py +1 -2
- chia/consensus/blockchain.py +167 -180
- chia/consensus/blockchain_interface.py +10 -10
- chia/consensus/constants.py +2 -2
- chia/consensus/default_constants.py +3 -4
- chia/consensus/difficulty_adjustment.py +5 -5
- chia/consensus/find_fork_point.py +5 -5
- chia/consensus/full_block_to_block_record.py +4 -4
- chia/consensus/get_block_challenge.py +2 -2
- chia/consensus/get_block_generator.py +4 -3
- chia/consensus/multiprocess_validation.py +207 -304
- chia/consensus/vdf_info_computation.py +3 -3
- chia/daemon/client.py +46 -27
- chia/daemon/keychain_proxy.py +10 -9
- chia/daemon/keychain_server.py +18 -18
- chia/daemon/server.py +103 -113
- chia/daemon/windows_signal.py +2 -2
- chia/data_layer/data_layer.py +64 -76
- chia/data_layer/data_layer_api.py +8 -0
- chia/data_layer/data_layer_errors.py +3 -3
- chia/data_layer/data_layer_server.py +2 -2
- chia/data_layer/data_layer_util.py +71 -71
- chia/data_layer/data_layer_wallet.py +63 -67
- chia/data_layer/data_store.py +72 -72
- chia/data_layer/dl_wallet_store.py +10 -10
- chia/data_layer/download_data.py +5 -5
- chia/data_layer/s3_plugin_service.py +9 -9
- chia/data_layer/util/benchmark.py +0 -1
- chia/data_layer/util/plugin.py +2 -3
- chia/farmer/farmer.py +46 -43
- chia/farmer/farmer_api.py +27 -21
- chia/full_node/block_height_map.py +6 -6
- chia/full_node/block_store.py +41 -35
- chia/full_node/coin_store.py +42 -41
- chia/full_node/fee_estimate.py +2 -2
- chia/full_node/fee_estimation.py +1 -2
- chia/full_node/fee_history.py +5 -6
- chia/full_node/fee_tracker.py +24 -24
- chia/full_node/full_node.py +574 -300
- chia/full_node/full_node_api.py +181 -130
- chia/full_node/full_node_store.py +43 -43
- chia/full_node/hint_management.py +4 -4
- chia/full_node/hint_store.py +9 -10
- chia/full_node/mempool.py +25 -19
- chia/full_node/mempool_check_conditions.py +11 -42
- chia/full_node/mempool_manager.py +48 -53
- chia/full_node/pending_tx_cache.py +9 -9
- chia/full_node/subscriptions.py +23 -24
- chia/full_node/sync_store.py +8 -7
- chia/full_node/tx_processing_queue.py +3 -3
- chia/full_node/util/__init__.py +0 -0
- chia/full_node/weight_proof.py +79 -78
- chia/harvester/harvester.py +9 -8
- chia/harvester/harvester_api.py +19 -13
- chia/introducer/introducer.py +7 -5
- chia/introducer/introducer_api.py +9 -3
- chia/legacy/keyring.py +6 -5
- chia/plot_sync/delta.py +8 -8
- chia/plot_sync/receiver.py +12 -11
- chia/plot_sync/sender.py +15 -12
- chia/plotters/bladebit.py +12 -12
- chia/plotters/chiapos.py +2 -2
- chia/plotters/madmax.py +8 -8
- chia/plotters/plotters.py +6 -6
- chia/plotters/plotters_util.py +6 -4
- chia/plotting/cache.py +8 -7
- chia/plotting/check_plots.py +8 -8
- chia/plotting/create_plots.py +6 -6
- chia/plotting/manager.py +22 -22
- chia/plotting/util.py +31 -19
- chia/pools/pool_config.py +7 -7
- chia/pools/pool_puzzles.py +16 -16
- chia/pools/pool_wallet.py +64 -57
- chia/pools/pool_wallet_info.py +3 -3
- chia/protocols/full_node_protocol.py +3 -3
- chia/protocols/harvester_protocol.py +12 -12
- chia/protocols/introducer_protocol.py +1 -2
- chia/protocols/protocol_message_types.py +4 -4
- chia/protocols/protocol_state_machine.py +2 -2
- chia/protocols/protocol_timing.py +1 -0
- chia/protocols/shared_protocol.py +3 -3
- chia/protocols/timelord_protocol.py +2 -2
- chia/protocols/wallet_protocol.py +33 -33
- chia/rpc/crawler_rpc_api.py +12 -7
- chia/rpc/data_layer_rpc_api.py +49 -44
- chia/rpc/data_layer_rpc_client.py +41 -41
- chia/rpc/data_layer_rpc_util.py +7 -11
- chia/rpc/farmer_rpc_api.py +32 -27
- chia/rpc/farmer_rpc_client.py +14 -14
- chia/rpc/full_node_rpc_api.py +53 -48
- chia/rpc/full_node_rpc_client.py +30 -30
- chia/rpc/harvester_rpc_api.py +16 -11
- chia/rpc/harvester_rpc_client.py +6 -6
- chia/rpc/rpc_client.py +34 -14
- chia/rpc/rpc_server.py +117 -43
- chia/rpc/timelord_rpc_api.py +9 -4
- chia/rpc/util.py +11 -211
- chia/rpc/wallet_request_types.py +276 -60
- chia/rpc/wallet_rpc_api.py +563 -399
- chia/rpc/wallet_rpc_client.py +220 -250
- chia/seeder/crawl_store.py +6 -8
- chia/seeder/crawler.py +23 -36
- chia/seeder/crawler_api.py +28 -22
- chia/seeder/dns_server.py +99 -50
- chia/seeder/start_crawler.py +13 -9
- chia/server/address_manager.py +19 -19
- chia/server/address_manager_store.py +17 -17
- chia/server/api_protocol.py +106 -1
- chia/server/capabilities.py +3 -3
- chia/server/chia_policy.py +17 -16
- chia/server/introducer_peers.py +3 -3
- chia/server/node_discovery.py +34 -38
- chia/server/rate_limit_numbers.py +26 -16
- chia/server/rate_limits.py +67 -27
- chia/server/server.py +52 -31
- chia/server/signal_handlers.py +6 -3
- chia/server/ssl_context.py +5 -5
- chia/server/start_data_layer.py +37 -23
- chia/server/start_farmer.py +28 -16
- chia/server/start_full_node.py +29 -23
- chia/server/start_harvester.py +28 -15
- chia/server/start_introducer.py +27 -15
- chia/server/start_service.py +17 -29
- chia/server/start_timelord.py +25 -18
- chia/server/start_wallet.py +22 -18
- chia/server/upnp.py +4 -3
- chia/server/ws_connection.py +68 -54
- chia/simulator/add_blocks_in_batches.py +54 -0
- chia/simulator/block_tools.py +65 -64
- chia/simulator/full_node_simulator.py +66 -74
- chia/simulator/setup_services.py +10 -9
- chia/simulator/simulator_full_node_rpc_api.py +12 -14
- chia/simulator/simulator_full_node_rpc_client.py +3 -5
- chia/simulator/simulator_test_tools.py +8 -7
- chia/simulator/socket.py +1 -4
- chia/simulator/ssl_certs.py +5 -5
- chia/simulator/ssl_certs_1.py +2 -4
- chia/simulator/ssl_certs_10.py +2 -4
- chia/simulator/ssl_certs_2.py +2 -4
- chia/simulator/ssl_certs_3.py +2 -4
- chia/simulator/ssl_certs_4.py +2 -4
- chia/simulator/ssl_certs_5.py +2 -4
- chia/simulator/ssl_certs_6.py +2 -4
- chia/simulator/ssl_certs_7.py +2 -4
- chia/simulator/ssl_certs_8.py +2 -4
- chia/simulator/ssl_certs_9.py +2 -4
- chia/simulator/start_simulator.py +14 -6
- chia/simulator/wallet_tools.py +21 -20
- chia/ssl/create_ssl.py +11 -11
- chia/timelord/iters_from_block.py +2 -2
- chia/timelord/timelord.py +57 -33
- chia/timelord/timelord_api.py +12 -6
- chia/timelord/timelord_launcher.py +10 -8
- chia/timelord/timelord_state.py +5 -5
- chia/types/block_protocol.py +2 -2
- chia/types/blockchain_format/coin.py +3 -3
- chia/types/blockchain_format/program.py +17 -18
- chia/types/blockchain_format/tree_hash.py +9 -9
- chia/types/coin_spend.py +8 -8
- chia/types/condition_with_args.py +1 -2
- chia/types/eligible_coin_spends.py +16 -15
- chia/types/generator_types.py +1 -2
- chia/types/internal_mempool_item.py +1 -2
- chia/types/mempool_item.py +7 -7
- chia/types/mempool_submission_status.py +2 -2
- chia/types/peer_info.py +1 -1
- chia/types/spend_bundle.py +1 -2
- chia/types/transaction_queue_entry.py +2 -2
- chia/types/unfinished_header_block.py +2 -2
- chia/types/validation_state.py +14 -0
- chia/types/weight_proof.py +5 -6
- chia/util/action_scope.py +8 -8
- chia/util/async_pool.py +6 -4
- chia/util/augmented_chain.py +13 -9
- chia/util/batches.py +5 -2
- chia/util/bech32m.py +14 -11
- chia/util/beta_metrics.py +5 -4
- chia/util/block_cache.py +5 -5
- chia/util/byte_types.py +2 -0
- chia/util/check_fork_next_block.py +3 -2
- chia/util/chia_logging.py +41 -21
- chia/util/collection.py +3 -3
- chia/util/condition_tools.py +18 -18
- chia/util/config.py +26 -25
- chia/util/cpu.py +2 -0
- chia/util/db_synchronous.py +2 -0
- chia/util/db_version.py +2 -0
- chia/util/db_wrapper.py +13 -10
- chia/util/default_root.py +17 -0
- chia/util/dump_keyring.py +6 -6
- chia/util/errors.py +5 -3
- chia/util/file_keyring.py +22 -33
- chia/util/files.py +2 -0
- chia/util/full_block_utils.py +31 -7
- chia/util/generator_tools.py +18 -8
- chia/util/hash.py +3 -1
- chia/util/initial-config.yaml +19 -0
- chia/util/inline_executor.py +2 -0
- chia/util/ip_address.py +39 -0
- chia/util/json_util.py +0 -4
- chia/util/keychain.py +27 -24
- chia/util/keyring_wrapper.py +65 -4
- chia/util/limited_semaphore.py +3 -1
- chia/util/lock.py +4 -2
- chia/util/log_exceptions.py +5 -2
- chia/util/logging.py +3 -1
- chia/util/lru_cache.py +2 -0
- chia/util/math.py +4 -4
- chia/util/network.py +15 -73
- chia/util/paginator.py +3 -1
- chia/util/path.py +2 -0
- chia/util/permissions.py +3 -2
- chia/util/prev_transaction_block.py +1 -3
- chia/util/priority_mutex.py +6 -3
- chia/util/profiler.py +7 -4
- chia/util/recursive_replace.py +2 -0
- chia/util/safe_cancel_task.py +2 -0
- chia/util/service_groups.py +2 -2
- chia/util/setproctitle.py +2 -0
- chia/util/significant_bits.py +2 -0
- chia/util/ssl_check.py +11 -11
- chia/util/streamable.py +44 -56
- chia/util/task_referencer.py +59 -0
- chia/util/task_timing.py +22 -18
- chia/util/timing.py +4 -1
- chia/util/vdf_prover.py +2 -3
- chia/util/virtual_project_analysis.py +540 -0
- chia/util/ws_message.py +6 -6
- chia/wallet/cat_wallet/cat_info.py +3 -3
- chia/wallet/cat_wallet/cat_outer_puzzle.py +3 -3
- chia/wallet/cat_wallet/cat_utils.py +5 -4
- chia/wallet/cat_wallet/cat_wallet.py +56 -70
- chia/wallet/cat_wallet/dao_cat_info.py +3 -3
- chia/wallet/cat_wallet/dao_cat_wallet.py +18 -18
- chia/wallet/cat_wallet/lineage_store.py +2 -2
- chia/wallet/coin_selection.py +15 -15
- chia/wallet/conditions.py +257 -71
- chia/wallet/dao_wallet/dao_info.py +4 -4
- chia/wallet/dao_wallet/dao_utils.py +43 -42
- chia/wallet/dao_wallet/dao_wallet.py +66 -68
- chia/wallet/db_wallet/db_wallet_puzzles.py +12 -8
- chia/wallet/derive_keys.py +11 -11
- chia/wallet/did_wallet/did_info.py +3 -3
- chia/wallet/did_wallet/did_wallet.py +56 -47
- chia/wallet/did_wallet/did_wallet_puzzles.py +7 -6
- chia/wallet/lineage_proof.py +4 -4
- chia/wallet/nft_wallet/metadata_outer_puzzle.py +2 -2
- chia/wallet/nft_wallet/nft_info.py +4 -4
- chia/wallet/nft_wallet/nft_puzzles.py +16 -16
- chia/wallet/nft_wallet/nft_wallet.py +90 -89
- chia/wallet/nft_wallet/ownership_outer_puzzle.py +2 -2
- chia/wallet/nft_wallet/singleton_outer_puzzle.py +2 -2
- chia/wallet/nft_wallet/transfer_program_puzzle.py +2 -2
- chia/wallet/nft_wallet/uncurry_nft.py +2 -2
- chia/wallet/notification_manager.py +5 -5
- chia/wallet/notification_store.py +6 -6
- chia/wallet/outer_puzzles.py +2 -2
- chia/wallet/payment.py +4 -5
- chia/wallet/puzzle_drivers.py +4 -4
- chia/wallet/puzzles/clawback/drivers.py +5 -5
- chia/wallet/puzzles/clawback/puzzle_decorator.py +7 -7
- chia/wallet/puzzles/load_clvm.py +2 -3
- chia/wallet/puzzles/p2_conditions.py +1 -2
- chia/wallet/puzzles/p2_delegated_conditions.py +1 -2
- chia/wallet/puzzles/p2_delegated_puzzle.py +2 -3
- chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +3 -4
- chia/wallet/puzzles/p2_m_of_n_delegate_direct.py +1 -2
- chia/wallet/puzzles/p2_puzzle_hash.py +1 -2
- chia/wallet/puzzles/puzzle_utils.py +7 -7
- chia/wallet/puzzles/singleton_top_layer.py +6 -5
- chia/wallet/puzzles/singleton_top_layer_v1_1.py +6 -5
- chia/wallet/puzzles/tails.py +34 -30
- chia/wallet/signer_protocol.py +7 -8
- chia/wallet/singleton.py +4 -4
- chia/wallet/trade_manager.py +155 -141
- chia/wallet/trade_record.py +5 -5
- chia/wallet/trading/offer.py +100 -101
- chia/wallet/trading/trade_store.py +14 -14
- chia/wallet/transaction_record.py +31 -16
- chia/wallet/util/address_type.py +4 -4
- chia/wallet/util/blind_signer_tl.py +8 -12
- chia/wallet/util/clvm_streamable.py +15 -15
- chia/wallet/util/compute_hints.py +5 -5
- chia/wallet/util/compute_memos.py +4 -6
- chia/wallet/util/curry_and_treehash.py +3 -2
- chia/wallet/util/debug_spend_bundle.py +6 -8
- chia/wallet/util/merkle_tree.py +10 -10
- chia/wallet/util/merkle_utils.py +10 -10
- chia/wallet/util/new_peak_queue.py +3 -3
- chia/wallet/util/peer_request_cache.py +8 -8
- chia/{util → wallet/util}/pprint.py +2 -3
- chia/wallet/util/puzzle_compression.py +3 -4
- chia/wallet/util/puzzle_decorator.py +10 -10
- chia/wallet/util/query_filter.py +9 -10
- chia/wallet/util/tx_config.py +12 -12
- chia/wallet/util/wallet_sync_utils.py +24 -21
- chia/wallet/util/wallet_types.py +9 -2
- chia/wallet/vc_wallet/cr_cat_drivers.py +28 -27
- chia/wallet/vc_wallet/cr_cat_wallet.py +42 -40
- chia/wallet/vc_wallet/cr_outer_puzzle.py +4 -4
- chia/wallet/vc_wallet/vc_drivers.py +16 -16
- chia/wallet/vc_wallet/vc_store.py +9 -9
- chia/wallet/vc_wallet/vc_wallet.py +35 -35
- chia/wallet/wallet.py +54 -54
- chia/wallet/wallet_action_scope.py +14 -13
- chia/wallet/wallet_blockchain.py +10 -10
- chia/wallet/wallet_coin_record.py +2 -2
- chia/wallet/wallet_coin_store.py +10 -10
- chia/wallet/wallet_info.py +1 -2
- chia/wallet/wallet_interested_store.py +5 -5
- chia/wallet/wallet_nft_store.py +6 -6
- chia/wallet/wallet_node.py +72 -76
- chia/wallet/wallet_node_api.py +33 -27
- chia/wallet/wallet_pool_store.py +1 -2
- chia/wallet/wallet_protocol.py +15 -15
- chia/wallet/wallet_puzzle_store.py +35 -4
- chia/wallet/wallet_retry_store.py +2 -2
- chia/wallet/wallet_singleton_store.py +10 -9
- chia/wallet/wallet_spend_bundle.py +4 -20
- chia/wallet/wallet_state_manager.py +223 -224
- chia/wallet/wallet_transaction_store.py +44 -18
- chia/wallet/wallet_user_store.py +2 -2
- chia/wallet/wallet_weight_proof_handler.py +2 -2
- {chia_blockchain-2.5.0rc1.dist-info → chia_blockchain-2.5.1.dist-info}/LICENSE +1 -1
- {chia_blockchain-2.5.0rc1.dist-info → chia_blockchain-2.5.1.dist-info}/METADATA +67 -72
- chia_blockchain-2.5.1.dist-info/RECORD +1042 -0
- {chia_blockchain-2.5.0rc1.dist-info → chia_blockchain-2.5.1.dist-info}/WHEEL +1 -1
- mozilla-ca/cacert.pem +32 -87
- chia/_tests/cmds/wallet/test_coins.py +0 -195
- chia/consensus/block_root_validation.py +0 -46
- chia/util/api_decorators.py +0 -89
- chia_blockchain-2.5.0rc1.dist-info/RECORD +0 -1028
- {chia_blockchain-2.5.0rc1.dist-info → chia_blockchain-2.5.1.dist-info}/entry_points.txt +0 -0
|
@@ -6,10 +6,18 @@ import dataclasses
|
|
|
6
6
|
import logging
|
|
7
7
|
import random
|
|
8
8
|
import time
|
|
9
|
-
from
|
|
9
|
+
from collections.abc import Awaitable, Coroutine
|
|
10
|
+
from typing import Optional
|
|
10
11
|
|
|
11
12
|
import pytest
|
|
12
|
-
from chia_rs import
|
|
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
|
+
)
|
|
13
21
|
from clvm.casts import int_to_bytes
|
|
14
22
|
from packaging.version import Version
|
|
15
23
|
|
|
@@ -19,19 +27,19 @@ from chia._tests.connection_utils import add_dummy_connection, connect_and_get_p
|
|
|
19
27
|
from chia._tests.core.full_node.stores.test_coin_store import get_future_reward_coins
|
|
20
28
|
from chia._tests.core.make_block_generator import make_spend_bundle
|
|
21
29
|
from chia._tests.core.node_height import node_height_at_least
|
|
22
|
-
from chia._tests.util.misc import
|
|
30
|
+
from chia._tests.util.misc import wallet_height_at_least
|
|
23
31
|
from chia._tests.util.setup_nodes import SimulatorsAndWalletsServices
|
|
24
32
|
from chia._tests.util.time_out_assert import time_out_assert, time_out_assert_custom_interval, time_out_messages
|
|
25
33
|
from chia.consensus.block_body_validation import ForkInfo
|
|
26
|
-
from chia.consensus.multiprocess_validation import
|
|
34
|
+
from chia.consensus.multiprocess_validation import PreValidationResult, pre_validate_block
|
|
27
35
|
from chia.consensus.pot_iterations import is_overflow_block
|
|
36
|
+
from chia.full_node.coin_store import CoinStore
|
|
28
37
|
from chia.full_node.full_node import WalletUpdate
|
|
29
38
|
from chia.full_node.full_node_api import FullNodeAPI
|
|
30
39
|
from chia.full_node.signage_point import SignagePoint
|
|
31
40
|
from chia.full_node.sync_store import Peak
|
|
32
|
-
from chia.protocols import full_node_protocol
|
|
41
|
+
from chia.protocols import full_node_protocol, timelord_protocol, wallet_protocol
|
|
33
42
|
from chia.protocols import full_node_protocol as fnp
|
|
34
|
-
from chia.protocols import timelord_protocol, wallet_protocol
|
|
35
43
|
from chia.protocols.full_node_protocol import RespondTransaction
|
|
36
44
|
from chia.protocols.protocol_message_types import ProtocolMessageTypes
|
|
37
45
|
from chia.protocols.shared_protocol import Capability, default_capabilities
|
|
@@ -39,11 +47,19 @@ from chia.protocols.wallet_protocol import SendTransaction, TransactionAck
|
|
|
39
47
|
from chia.server.address_manager import AddressManager
|
|
40
48
|
from chia.server.outbound_message import Message, NodeType
|
|
41
49
|
from chia.server.server import ChiaServer
|
|
42
|
-
from chia.simulator.
|
|
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
|
+
)
|
|
43
58
|
from chia.simulator.full_node_simulator import FullNodeSimulator
|
|
44
59
|
from chia.simulator.keyring import TempKeyring
|
|
45
60
|
from chia.simulator.setup_services import setup_full_node
|
|
46
61
|
from chia.simulator.simulator_protocol import FarmNewBlockProtocol
|
|
62
|
+
from chia.simulator.wallet_tools import WalletTool
|
|
47
63
|
from chia.types.blockchain_format.classgroup import ClassgroupElement
|
|
48
64
|
from chia.types.blockchain_format.foliage import Foliage, FoliageTransactionBlock, TransactionsInfo
|
|
49
65
|
from chia.types.blockchain_format.program import Program
|
|
@@ -52,6 +68,7 @@ from chia.types.blockchain_format.reward_chain_block import RewardChainBlockUnfi
|
|
|
52
68
|
from chia.types.blockchain_format.serialized_program import SerializedProgram
|
|
53
69
|
from chia.types.blockchain_format.sized_bytes import bytes32
|
|
54
70
|
from chia.types.blockchain_format.vdf import CompressibleVDFField, VDFProof
|
|
71
|
+
from chia.types.coin_record import CoinRecord
|
|
55
72
|
from chia.types.coin_spend import make_spend
|
|
56
73
|
from chia.types.condition_opcodes import ConditionOpcode
|
|
57
74
|
from chia.types.condition_with_args import ConditionWithArgs
|
|
@@ -60,16 +77,29 @@ from chia.types.mempool_inclusion_status import MempoolInclusionStatus
|
|
|
60
77
|
from chia.types.peer_info import PeerInfo, TimestampedPeerInfo
|
|
61
78
|
from chia.types.spend_bundle import SpendBundle, estimate_fees
|
|
62
79
|
from chia.types.unfinished_block import UnfinishedBlock
|
|
80
|
+
from chia.types.validation_state import ValidationState
|
|
81
|
+
from chia.util.augmented_chain import AugmentedBlockchain
|
|
63
82
|
from chia.util.errors import ConsensusError, Err
|
|
64
83
|
from chia.util.hash import std_hash
|
|
65
84
|
from chia.util.ints import uint8, uint16, uint32, uint64, uint128
|
|
66
85
|
from chia.util.limited_semaphore import LimitedSemaphore
|
|
67
86
|
from chia.util.recursive_replace import recursive_replace
|
|
87
|
+
from chia.util.task_referencer import create_referenced_task
|
|
68
88
|
from chia.util.vdf_prover import get_vdf_info_and_proof
|
|
69
89
|
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
|
|
70
90
|
from chia.wallet.wallet_spend_bundle import WalletSpendBundle
|
|
71
91
|
|
|
72
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
|
+
|
|
73
103
|
async def new_transaction_not_requested(incoming, new_spend):
|
|
74
104
|
await asyncio.sleep(3)
|
|
75
105
|
while not incoming.empty():
|
|
@@ -113,11 +143,11 @@ async def get_block_path(full_node: FullNodeAPI):
|
|
|
113
143
|
@pytest.mark.anyio
|
|
114
144
|
async def test_sync_no_farmer(
|
|
115
145
|
setup_two_nodes_and_wallet,
|
|
116
|
-
default_1000_blocks:
|
|
146
|
+
default_1000_blocks: list[FullBlock],
|
|
117
147
|
self_hostname: str,
|
|
118
148
|
seeded_random: random.Random,
|
|
119
149
|
):
|
|
120
|
-
nodes,
|
|
150
|
+
nodes, _wallets, _bt = setup_two_nodes_and_wallet
|
|
121
151
|
server_1 = nodes[0].full_node.server
|
|
122
152
|
server_2 = nodes[1].full_node.server
|
|
123
153
|
full_node_1 = nodes[0]
|
|
@@ -145,1766 +175,1810 @@ async def test_sync_no_farmer(
|
|
|
145
175
|
assert full_node_2.full_node.blockchain.get_peak() == target_peak
|
|
146
176
|
|
|
147
177
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
wallet = wallet_node_1.wallet_state_manager.main_wallet
|
|
160
|
-
|
|
161
|
-
# Avoid retesting the slow reorg portion, not necessary more than once
|
|
162
|
-
test_reorgs = True
|
|
163
|
-
_ = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
164
|
-
_ = await connect_and_get_peer(server_1, server_3, self_hostname)
|
|
165
|
-
|
|
166
|
-
ph = await wallet.get_new_puzzlehash()
|
|
167
|
-
|
|
168
|
-
for i in range(4):
|
|
169
|
-
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
170
|
-
|
|
171
|
-
await time_out_assert(30, wallet_height_at_least, True, wallet_node_1, 4)
|
|
172
|
-
await time_out_assert(30, node_height_at_least, True, full_node_1, 4)
|
|
173
|
-
await time_out_assert(30, node_height_at_least, True, full_node_2, 4)
|
|
174
|
-
await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
|
|
175
|
-
|
|
176
|
-
# Send a transaction to mempool
|
|
177
|
-
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
178
|
-
await wallet.generate_signed_transaction(
|
|
179
|
-
tx_size,
|
|
180
|
-
ph,
|
|
181
|
-
action_scope,
|
|
182
|
-
)
|
|
183
|
-
[tr] = action_scope.side_effects.transactions
|
|
184
|
-
await time_out_assert(
|
|
185
|
-
10,
|
|
186
|
-
full_node_2.full_node.mempool_manager.get_spendbundle,
|
|
187
|
-
tr.spend_bundle,
|
|
188
|
-
tr.name,
|
|
189
|
-
)
|
|
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
|
|
190
189
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
await time_out_assert(30, wallet_height_at_least, True, wallet_node_1, 5)
|
|
196
|
-
await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
|
|
197
|
-
|
|
198
|
-
async def check_transaction_confirmed(transaction) -> bool:
|
|
199
|
-
tx = await wallet_node_1.wallet_state_manager.get_transaction(transaction.name)
|
|
200
|
-
return tx.confirmed
|
|
201
|
-
|
|
202
|
-
await time_out_assert(30, check_transaction_confirmed, True, tr)
|
|
203
|
-
|
|
204
|
-
# Confirm generator is not compressed
|
|
205
|
-
program: Optional[SerializedProgram] = (await full_node_1.get_all_full_blocks())[-1].transactions_generator
|
|
206
|
-
assert program is not None
|
|
207
|
-
assert len((await full_node_1.get_all_full_blocks())[-1].transactions_generator_ref_list) == 0
|
|
208
|
-
|
|
209
|
-
# Send another tx
|
|
210
|
-
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
211
|
-
await wallet.generate_signed_transaction(
|
|
212
|
-
20000,
|
|
213
|
-
ph,
|
|
214
|
-
action_scope,
|
|
215
|
-
)
|
|
216
|
-
[tr] = action_scope.side_effects.transactions
|
|
217
|
-
await time_out_assert(
|
|
218
|
-
10,
|
|
219
|
-
full_node_2.full_node.mempool_manager.get_spendbundle,
|
|
220
|
-
tr.spend_bundle,
|
|
221
|
-
tr.name,
|
|
222
|
-
)
|
|
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)
|
|
223
194
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
await time_out_assert(10, node_height_at_least, True, full_node_2, 6)
|
|
228
|
-
await time_out_assert(10, wallet_height_at_least, True, wallet_node_1, 6)
|
|
229
|
-
await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
|
|
230
|
-
|
|
231
|
-
await time_out_assert(10, check_transaction_confirmed, True, tr)
|
|
232
|
-
|
|
233
|
-
# Confirm generator is compressed
|
|
234
|
-
program: Optional[SerializedProgram] = (await full_node_1.get_all_full_blocks())[-1].transactions_generator
|
|
235
|
-
assert program is not None
|
|
236
|
-
num_blocks = len((await full_node_1.get_all_full_blocks())[-1].transactions_generator_ref_list)
|
|
237
|
-
# since the hard fork, we don't use this compression mechanism
|
|
238
|
-
# anymore, we use CLVM backrefs in the encoding instead
|
|
239
|
-
assert num_blocks == 0
|
|
240
|
-
|
|
241
|
-
# Farm two empty blocks
|
|
242
|
-
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
195
|
+
ph = await wallet.get_new_puzzlehash()
|
|
196
|
+
|
|
197
|
+
for i in range(4):
|
|
243
198
|
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
244
|
-
await time_out_assert(10, node_height_at_least, True, full_node_1, 8)
|
|
245
|
-
await time_out_assert(10, node_height_at_least, True, full_node_2, 8)
|
|
246
|
-
await time_out_assert(10, wallet_height_at_least, True, wallet_node_1, 8)
|
|
247
|
-
await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
|
|
248
|
-
|
|
249
|
-
# Send another 2 tx
|
|
250
|
-
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
251
|
-
await wallet.generate_signed_transaction(
|
|
252
|
-
30000,
|
|
253
|
-
ph,
|
|
254
|
-
action_scope,
|
|
255
|
-
)
|
|
256
|
-
[tr] = action_scope.side_effects.transactions
|
|
257
|
-
await time_out_assert(
|
|
258
|
-
10,
|
|
259
|
-
full_node_2.full_node.mempool_manager.get_spendbundle,
|
|
260
|
-
tr.spend_bundle,
|
|
261
|
-
tr.name,
|
|
262
|
-
)
|
|
263
|
-
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
264
|
-
await wallet.generate_signed_transaction(
|
|
265
|
-
40000,
|
|
266
|
-
ph,
|
|
267
|
-
action_scope,
|
|
268
|
-
)
|
|
269
|
-
[tr] = action_scope.side_effects.transactions
|
|
270
|
-
await time_out_assert(
|
|
271
|
-
10,
|
|
272
|
-
full_node_2.full_node.mempool_manager.get_spendbundle,
|
|
273
|
-
tr.spend_bundle,
|
|
274
|
-
tr.name,
|
|
275
|
-
)
|
|
276
199
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
await
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
tr.name,
|
|
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,
|
|
289
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
|
+
)
|
|
290
219
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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,
|
|
303
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
|
+
)
|
|
304
252
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
)
|
|
337
|
-
],
|
|
338
|
-
G2Element(),
|
|
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,
|
|
339
284
|
)
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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,
|
|
346
297
|
)
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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,
|
|
353
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
|
+
)
|
|
354
319
|
|
|
355
|
-
|
|
356
|
-
await
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=30)
|
|
361
|
-
|
|
362
|
-
await time_out_assert(10, check_transaction_confirmed, True, new_tr)
|
|
363
|
-
|
|
364
|
-
# Confirm generator is not compressed, #CAT creation has a cat spend
|
|
365
|
-
all_blocks = await full_node_1.get_all_full_blocks()
|
|
366
|
-
program: Optional[SerializedProgram] = all_blocks[-1].transactions_generator
|
|
367
|
-
assert program is not None
|
|
368
|
-
assert len(all_blocks[-1].transactions_generator_ref_list) == 0
|
|
369
|
-
|
|
370
|
-
# Make a standard transaction and an anyone-can-spend transaction
|
|
371
|
-
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=False) as action_scope:
|
|
372
|
-
await wallet.generate_signed_transaction(
|
|
373
|
-
30000,
|
|
374
|
-
Program.to(1).get_tree_hash(),
|
|
375
|
-
action_scope,
|
|
376
|
-
)
|
|
377
|
-
[tr] = action_scope.side_effects.transactions
|
|
378
|
-
extra_spend = WalletSpendBundle(
|
|
379
|
-
[
|
|
380
|
-
make_spend(
|
|
381
|
-
next(coin for coin in tr.additions if coin.puzzle_hash == Program.to(1).get_tree_hash()),
|
|
382
|
-
Program.to(1),
|
|
383
|
-
Program.to([[51, ph, 30000]]),
|
|
384
|
-
)
|
|
385
|
-
],
|
|
386
|
-
G2Element(),
|
|
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,
|
|
387
325
|
)
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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,
|
|
394
357
|
)
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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,
|
|
401
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
|
+
)
|
|
402
431
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
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
|
+
)
|
|
439
472
|
)
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
difficulty=diff,
|
|
456
|
-
prev_ses_block=None,
|
|
457
|
-
validate_signatures=False,
|
|
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)
|
|
458
488
|
)
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
class TestFullNodeProtocol:
|
|
465
|
-
@pytest.mark.anyio
|
|
466
|
-
async def test_spendbundle_serialization(self):
|
|
467
|
-
sb: SpendBundle = make_spend_bundle(1)
|
|
468
|
-
protocol_message = RespondTransaction(sb)
|
|
469
|
-
assert bytes(sb) == bytes(protocol_message)
|
|
470
|
-
|
|
471
|
-
@pytest.mark.anyio
|
|
472
|
-
async def test_inbound_connection_limit(self, setup_four_nodes, self_hostname):
|
|
473
|
-
nodes, _, _ = setup_four_nodes
|
|
474
|
-
server_1 = nodes[0].full_node.server
|
|
475
|
-
server_1.config["target_peer_count"] = 2
|
|
476
|
-
server_1.config["target_outbound_peer_count"] = 0
|
|
477
|
-
for i in range(1, 4):
|
|
478
|
-
full_node_i = nodes[i]
|
|
479
|
-
server_i = full_node_i.full_node.server
|
|
480
|
-
await server_i.start_client(PeerInfo(self_hostname, server_1.get_port()))
|
|
481
|
-
assert len(server_1.get_connections(NodeType.FULL_NODE)) == 2
|
|
482
|
-
|
|
483
|
-
@pytest.mark.anyio
|
|
484
|
-
async def test_request_peers(self, wallet_nodes, self_hostname):
|
|
485
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, _ = wallet_nodes
|
|
486
|
-
full_node_2.full_node.full_node_peers.address_manager.make_private_subnets_valid()
|
|
487
|
-
await server_2.start_client(PeerInfo(self_hostname, server_1.get_port()))
|
|
488
|
-
|
|
489
|
-
async def have_msgs():
|
|
490
|
-
await full_node_2.full_node.full_node_peers.address_manager.add_to_new_table(
|
|
491
|
-
[TimestampedPeerInfo("127.0.0.1", uint16(1000), uint64(int(time.time())) - 1000)],
|
|
492
|
-
None,
|
|
493
|
-
)
|
|
494
|
-
msg_bytes = await full_node_2.full_node.full_node_peers.request_peers(PeerInfo("::1", server_2._port))
|
|
495
|
-
msg = fnp.RespondPeers.from_bytes(msg_bytes.data)
|
|
496
|
-
if msg is not None and not (len(msg.peer_list) == 1):
|
|
497
|
-
return False
|
|
498
|
-
peer = msg.peer_list[0]
|
|
499
|
-
return (peer.host == self_hostname or peer.host == "127.0.0.1") and peer.port == 1000
|
|
500
|
-
|
|
501
|
-
await time_out_assert_custom_interval(10, 1, have_msgs, True)
|
|
502
|
-
full_node_1.full_node.full_node_peers.address_manager = AddressManager()
|
|
503
|
-
|
|
504
|
-
@pytest.mark.anyio
|
|
505
|
-
async def test_basic_chain(self, wallet_nodes, self_hostname):
|
|
506
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
507
|
-
|
|
508
|
-
incoming_queue, _ = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
509
|
-
expected_requests = 0
|
|
510
|
-
if await full_node_1.full_node.synced():
|
|
511
|
-
expected_requests = 1
|
|
512
|
-
await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
|
|
513
|
-
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
514
|
-
blocks = bt.get_consecutive_blocks(1)
|
|
515
|
-
for block in blocks[:1]:
|
|
516
|
-
await full_node_1.full_node.add_block(block, peer)
|
|
517
|
-
|
|
518
|
-
await time_out_assert(10, time_out_messages(incoming_queue, "new_peak", 1))
|
|
519
|
-
|
|
520
|
-
assert full_node_1.full_node.blockchain.get_peak().height == 0
|
|
521
|
-
|
|
522
|
-
for block in bt.get_consecutive_blocks(30):
|
|
523
|
-
await full_node_1.full_node.add_block(block, peer)
|
|
524
|
-
|
|
525
|
-
assert full_node_1.full_node.blockchain.get_peak().height == 29
|
|
526
|
-
|
|
527
|
-
@pytest.mark.anyio
|
|
528
|
-
async def test_respond_end_of_sub_slot(self, wallet_nodes, self_hostname):
|
|
529
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
530
|
-
|
|
531
|
-
incoming_queue, dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
532
|
-
expected_requests = 0
|
|
533
|
-
if await full_node_1.full_node.synced():
|
|
534
|
-
expected_requests = 1
|
|
535
|
-
await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
|
|
536
|
-
|
|
537
|
-
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
538
|
-
|
|
539
|
-
# Create empty slots
|
|
540
|
-
blocks = await full_node_1.get_all_full_blocks()
|
|
541
|
-
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=6)
|
|
542
|
-
|
|
543
|
-
# Add empty slots successful
|
|
544
|
-
for slot in blocks[-1].finished_sub_slots[:-2]:
|
|
545
|
-
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
546
|
-
num_sub_slots_added = len(blocks[-1].finished_sub_slots[:-2])
|
|
547
|
-
await time_out_assert(
|
|
548
|
-
10,
|
|
549
|
-
time_out_messages(
|
|
550
|
-
incoming_queue,
|
|
551
|
-
"new_signage_point_or_end_of_sub_slot",
|
|
552
|
-
num_sub_slots_added,
|
|
553
|
-
),
|
|
554
|
-
)
|
|
555
|
-
# Already have sub slot
|
|
556
|
-
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(blocks[-1].finished_sub_slots[-3]), peer)
|
|
557
|
-
await asyncio.sleep(2)
|
|
558
|
-
assert incoming_queue.qsize() == 0
|
|
559
|
-
|
|
560
|
-
# Add empty slots unsuccessful
|
|
561
|
-
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(blocks[-1].finished_sub_slots[-1]), peer)
|
|
562
|
-
await asyncio.sleep(2)
|
|
563
|
-
assert incoming_queue.qsize() == 0
|
|
564
|
-
|
|
565
|
-
# Add some blocks
|
|
566
|
-
blocks = bt.get_consecutive_blocks(4, block_list_input=blocks)
|
|
567
|
-
for block in blocks[-5:]:
|
|
568
|
-
await full_node_1.full_node.add_block(block, peer)
|
|
569
|
-
await time_out_assert(10, time_out_messages(incoming_queue, "new_peak", 5))
|
|
570
|
-
blocks = bt.get_consecutive_blocks(1, skip_slots=2, block_list_input=blocks)
|
|
571
|
-
|
|
572
|
-
# Add empty slots successful
|
|
573
|
-
for slot in blocks[-1].finished_sub_slots:
|
|
574
|
-
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
575
|
-
num_sub_slots_added = len(blocks[-1].finished_sub_slots)
|
|
576
|
-
await time_out_assert(
|
|
577
|
-
10,
|
|
578
|
-
time_out_messages(
|
|
579
|
-
incoming_queue,
|
|
580
|
-
"new_signage_point_or_end_of_sub_slot",
|
|
581
|
-
num_sub_slots_added,
|
|
582
|
-
),
|
|
583
|
-
)
|
|
489
|
+
results = list(await asyncio.gather(*futures))
|
|
490
|
+
for result in results:
|
|
491
|
+
assert result.error is None
|
|
584
492
|
|
|
585
|
-
@pytest.mark.anyio
|
|
586
|
-
async def test_respond_end_of_sub_slot_no_reorg(self, wallet_nodes, self_hostname):
|
|
587
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
588
493
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
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)
|
|
594
499
|
|
|
595
|
-
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
596
500
|
|
|
597
|
-
|
|
598
|
-
|
|
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
|
|
599
512
|
|
|
600
|
-
for i in range(0, 9999999):
|
|
601
|
-
blocks = bt.get_consecutive_blocks(5, block_list_input=blocks, skip_slots=1, seed=i.to_bytes(4, "big"))
|
|
602
|
-
if len(blocks[-1].finished_sub_slots) == 0:
|
|
603
|
-
break
|
|
604
513
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
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
|
|
609
531
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
await full_node_1.full_node.add_block(block, peer)
|
|
532
|
+
await time_out_assert_custom_interval(10, 1, have_msgs, True)
|
|
533
|
+
full_node_1.full_node.full_node_peers.address_manager = AddressManager()
|
|
613
534
|
|
|
614
|
-
original_ss = full_node_1.full_node.full_node_store.finished_sub_slots[:]
|
|
615
535
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
|
619
539
|
|
|
620
|
-
|
|
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)
|
|
621
549
|
|
|
622
|
-
|
|
623
|
-
async def test_respond_end_of_sub_slot_race(self, wallet_nodes, self_hostname):
|
|
624
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
550
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "new_peak", 1))
|
|
625
551
|
|
|
626
|
-
|
|
627
|
-
expected_requests = 0
|
|
628
|
-
if await full_node_1.full_node.synced():
|
|
629
|
-
expected_requests = 1
|
|
630
|
-
await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
|
|
552
|
+
assert full_node_1.full_node.blockchain.get_peak().height == 0
|
|
631
553
|
|
|
632
|
-
|
|
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)
|
|
633
557
|
|
|
634
|
-
|
|
635
|
-
blocks = await full_node_1.get_all_full_blocks()
|
|
636
|
-
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
558
|
+
assert full_node_1.full_node.blockchain.get_peak().height == 29
|
|
637
559
|
|
|
638
|
-
await full_node_1.full_node.add_block(blocks[-1], peer)
|
|
639
560
|
|
|
640
|
-
|
|
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
|
+
)
|
|
641
618
|
|
|
642
|
-
original_ss = full_node_1.full_node.full_node_store.finished_sub_slots[:].copy()
|
|
643
|
-
# Add the block
|
|
644
|
-
await full_node_1.full_node.add_block(blocks[-1], peer)
|
|
645
619
|
|
|
646
|
-
|
|
647
|
-
|
|
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
|
|
648
623
|
|
|
649
|
-
|
|
650
|
-
|
|
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))
|
|
651
629
|
|
|
652
|
-
|
|
653
|
-
async def test_respond_unfinished(self, wallet_nodes, self_hostname):
|
|
654
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
630
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
655
631
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
if await full_node_1.full_node.synced():
|
|
659
|
-
expected_requests = 1
|
|
660
|
-
await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
|
|
632
|
+
# First get two blocks in the same sub slot
|
|
633
|
+
blocks = await full_node_1.get_all_full_blocks()
|
|
661
634
|
|
|
662
|
-
|
|
663
|
-
blocks =
|
|
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
|
|
664
639
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
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)
|
|
669
644
|
|
|
670
|
-
|
|
671
|
-
|
|
645
|
+
# Add all blocks
|
|
646
|
+
for block in blocks:
|
|
647
|
+
await full_node_1.full_node.add_block(block, peer)
|
|
672
648
|
|
|
673
|
-
|
|
674
|
-
for slot in blocks[-1].finished_sub_slots:
|
|
675
|
-
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
649
|
+
original_ss = full_node_1.full_node.full_node_store.finished_sub_slots[:]
|
|
676
650
|
|
|
677
|
-
|
|
678
|
-
|
|
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)
|
|
679
654
|
|
|
680
|
-
|
|
681
|
-
await full_node_1.full_node.add_block(block)
|
|
682
|
-
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=3)
|
|
655
|
+
assert full_node_1.full_node.full_node_store.finished_sub_slots == original_ss
|
|
683
656
|
|
|
684
|
-
block = blocks[-1]
|
|
685
|
-
unf = make_unfinished_block(block, bt.constants)
|
|
686
|
-
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is None
|
|
687
657
|
|
|
688
|
-
|
|
689
|
-
|
|
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
|
|
690
661
|
|
|
691
|
-
|
|
692
|
-
|
|
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))
|
|
693
667
|
|
|
694
|
-
|
|
695
|
-
await full_node_1.full_node.add_block(block)
|
|
696
|
-
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=3, force_overflow=True)
|
|
668
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
697
669
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
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)
|
|
701
673
|
|
|
702
|
-
|
|
703
|
-
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
674
|
+
await full_node_1.full_node.add_block(blocks[-1], peer)
|
|
704
675
|
|
|
705
|
-
|
|
706
|
-
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is not None
|
|
676
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
|
|
707
677
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
blocks = await full_node_1.get_all_full_blocks()
|
|
712
|
-
blocks = bt.get_consecutive_blocks(
|
|
713
|
-
2,
|
|
714
|
-
block_list_input=blocks,
|
|
715
|
-
guarantee_transaction_block=True,
|
|
716
|
-
farmer_reward_puzzle_hash=ph,
|
|
717
|
-
pool_reward_puzzle_hash=ph,
|
|
718
|
-
)
|
|
719
|
-
await full_node_1.full_node.add_block(blocks[-2])
|
|
720
|
-
await full_node_1.full_node.add_block(blocks[-1])
|
|
721
|
-
coin_to_spend = blocks[-1].get_included_reward_coins()[0]
|
|
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)
|
|
722
681
|
|
|
723
|
-
|
|
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
|
|
724
684
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
block_list_input=blocks,
|
|
728
|
-
guarantee_transaction_block=True,
|
|
729
|
-
transaction_data=spend_bundle,
|
|
730
|
-
force_overflow=True,
|
|
731
|
-
seed=b"random seed",
|
|
732
|
-
)
|
|
733
|
-
block = blocks[-1]
|
|
734
|
-
unf = make_unfinished_block(block, bt.constants, force_overflow=True)
|
|
735
|
-
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is None
|
|
736
|
-
await full_node_1.full_node.add_unfinished_block(unf, None)
|
|
737
|
-
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash) is not None
|
|
738
|
-
entry = full_node_1.full_node.full_node_store.get_unfinished_block_result(
|
|
739
|
-
unf.partial_hash, unf.foliage.foliage_transaction_block_hash
|
|
740
|
-
)
|
|
741
|
-
assert entry is not None
|
|
742
|
-
result = entry.result
|
|
743
|
-
assert result is not None
|
|
744
|
-
assert result.conds is not None
|
|
745
|
-
assert result.conds.cost > 0
|
|
746
|
-
|
|
747
|
-
assert not full_node_1.full_node.blockchain.contains_block(block.header_hash)
|
|
748
|
-
assert block.transactions_generator is not None
|
|
749
|
-
block_no_transactions = block.replace(transactions_generator=None)
|
|
750
|
-
assert block_no_transactions.transactions_generator is None
|
|
751
|
-
|
|
752
|
-
await full_node_1.full_node.add_block(block_no_transactions)
|
|
753
|
-
assert full_node_1.full_node.blockchain.contains_block(block.header_hash)
|
|
754
|
-
|
|
755
|
-
@pytest.mark.anyio
|
|
756
|
-
async def test_new_peak(self, wallet_nodes, self_hostname):
|
|
757
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
758
|
-
|
|
759
|
-
incoming_queue, dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
760
|
-
dummy_peer = server_1.all_connections[dummy_node_id]
|
|
761
|
-
expected_requests = 0
|
|
762
|
-
if await full_node_1.full_node.synced():
|
|
763
|
-
expected_requests = 1
|
|
764
|
-
await time_out_assert(10, time_out_messages(incoming_queue, "request_mempool_transactions", expected_requests))
|
|
765
|
-
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
766
|
-
|
|
767
|
-
blocks = await full_node_1.get_all_full_blocks()
|
|
768
|
-
blocks = bt.get_consecutive_blocks(3, block_list_input=blocks) # Alternate chain
|
|
769
|
-
|
|
770
|
-
blocks_reorg = bt.get_consecutive_blocks(3, block_list_input=blocks[:-1], seed=b"214") # Alternate chain
|
|
771
|
-
for block in blocks[-3:]:
|
|
772
|
-
new_peak = fnp.NewPeak(
|
|
773
|
-
block.header_hash,
|
|
774
|
-
block.height,
|
|
775
|
-
block.weight,
|
|
776
|
-
uint32(0),
|
|
777
|
-
block.reward_chain_block.get_unfinished().get_hash(),
|
|
778
|
-
)
|
|
779
|
-
task_1 = asyncio.create_task(full_node_1.new_peak(new_peak, dummy_peer))
|
|
780
|
-
await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 1))
|
|
781
|
-
task_1.cancel()
|
|
685
|
+
for slot in blocks[-1].finished_sub_slots:
|
|
686
|
+
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
782
687
|
|
|
783
|
-
await full_node_1.full_node.add_block(block, peer)
|
|
784
|
-
# Ignores, already have
|
|
785
|
-
task_2 = asyncio.create_task(full_node_1.new_peak(new_peak, dummy_peer))
|
|
786
|
-
await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 0))
|
|
787
|
-
task_2.cancel()
|
|
788
688
|
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
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
|
|
792
783
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
blocks_reorg[-2].weight,
|
|
798
|
-
uint32(0),
|
|
799
|
-
blocks_reorg[-2].reward_chain_block.get_unfinished().get_hash(),
|
|
800
|
-
)
|
|
801
|
-
asyncio.create_task(suppress_value_error(full_node_1.new_peak(new_peak, dummy_peer)))
|
|
802
|
-
await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 0))
|
|
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
|
|
803
788
|
|
|
804
|
-
|
|
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:]:
|
|
805
810
|
new_peak = fnp.NewPeak(
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
811
|
+
block.header_hash,
|
|
812
|
+
block.height,
|
|
813
|
+
block.weight,
|
|
809
814
|
uint32(0),
|
|
810
|
-
|
|
815
|
+
block.reward_chain_block.get_unfinished().get_hash(),
|
|
811
816
|
)
|
|
812
|
-
|
|
817
|
+
task_1 = create_referenced_task(full_node_1.new_peak(new_peak, dummy_peer))
|
|
813
818
|
await time_out_assert(10, time_out_messages(incoming_queue, "request_block", 1))
|
|
819
|
+
task_1.cancel()
|
|
814
820
|
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
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))
|
|
827
852
|
|
|
828
|
-
start_height = (
|
|
829
|
-
full_node_1.full_node.blockchain.get_peak().height
|
|
830
|
-
if full_node_1.full_node.blockchain.get_peak() is not None
|
|
831
|
-
else -1
|
|
832
|
-
)
|
|
833
|
-
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
834
|
-
incoming_queue, node_id = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
835
|
-
fake_peer = server_1.all_connections[node_id]
|
|
836
|
-
puzzle_hashes = []
|
|
837
|
-
|
|
838
|
-
# Makes a bunch of coins
|
|
839
|
-
conditions_dict: Dict = {ConditionOpcode.CREATE_COIN: []}
|
|
840
|
-
# This should fit in one transaction
|
|
841
|
-
for _ in range(100):
|
|
842
|
-
receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
|
|
843
|
-
puzzle_hashes.append(receiver_puzzlehash)
|
|
844
|
-
output = ConditionWithArgs(ConditionOpcode.CREATE_COIN, [receiver_puzzlehash, int_to_bytes(10000000000)])
|
|
845
|
-
|
|
846
|
-
conditions_dict[ConditionOpcode.CREATE_COIN].append(output)
|
|
847
|
-
|
|
848
|
-
spend_bundle = wallet_a.generate_signed_transaction(
|
|
849
|
-
100,
|
|
850
|
-
puzzle_hashes[0],
|
|
851
|
-
get_future_reward_coins(blocks[1])[0],
|
|
852
|
-
condition_dic=conditions_dict,
|
|
853
|
-
)
|
|
854
|
-
assert spend_bundle is not None
|
|
855
|
-
new_transaction = fnp.NewTransaction(spend_bundle.get_hash(), uint64(100), uint64(100))
|
|
856
853
|
|
|
857
|
-
|
|
858
|
-
|
|
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)
|
|
859
866
|
|
|
860
|
-
|
|
861
|
-
|
|
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)])
|
|
862
884
|
|
|
863
|
-
|
|
864
|
-
1,
|
|
865
|
-
block_list_input=blocks,
|
|
866
|
-
guarantee_transaction_block=True,
|
|
867
|
-
transaction_data=spend_bundle,
|
|
868
|
-
)
|
|
869
|
-
await full_node_1.full_node.add_block(blocks[-1], None)
|
|
885
|
+
conditions_dict[ConditionOpcode.CREATE_COIN].append(output)
|
|
870
886
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
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))
|
|
874
895
|
|
|
875
|
-
|
|
876
|
-
|
|
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)
|
|
877
898
|
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
seen_bigger_transaction_has_high_fee = False
|
|
881
|
-
successful_bundle: Optional[WalletSpendBundle] = None
|
|
899
|
+
respond_transaction_2 = fnp.RespondTransaction(spend_bundle)
|
|
900
|
+
await full_node_1.respond_transaction(respond_transaction_2, peer)
|
|
882
901
|
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
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
|
+
)
|
|
952
989
|
|
|
953
|
-
|
|
990
|
+
await time_out_assert(10, new_transaction_not_requested, True, incoming_queue, new_transaction)
|
|
954
991
|
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
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
|
|
961
998
|
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
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
|
|
965
1002
|
|
|
966
|
-
|
|
967
|
-
|
|
1003
|
+
# Farm one block to clear mempool
|
|
1004
|
+
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(receiver_puzzlehash))
|
|
968
1005
|
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
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)
|
|
972
1009
|
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
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
|
|
979
1016
|
|
|
980
|
-
|
|
1017
|
+
await time_out_assert(10, new_transaction_requested, True, incoming_queue, new_transaction)
|
|
981
1018
|
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
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
|
|
991
1033
|
|
|
992
|
-
# Can now resubmit a transaction after the reorg
|
|
993
|
-
status, err = await full_node_1.full_node.add_transaction(
|
|
994
|
-
successful_bundle, successful_bundle.name(), peer, test=True
|
|
995
|
-
)
|
|
996
|
-
assert err is None
|
|
997
|
-
assert status == MempoolInclusionStatus.SUCCESS
|
|
998
|
-
|
|
999
|
-
@pytest.mark.anyio
|
|
1000
|
-
async def test_request_respond_transaction(self, wallet_nodes, self_hostname, seeded_random: random.Random):
|
|
1001
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1002
|
-
wallet_ph = wallet_a.get_new_puzzlehash()
|
|
1003
|
-
blocks = await full_node_1.get_all_full_blocks()
|
|
1004
|
-
|
|
1005
|
-
blocks = bt.get_consecutive_blocks(
|
|
1006
|
-
3,
|
|
1007
|
-
block_list_input=blocks,
|
|
1008
|
-
guarantee_transaction_block=True,
|
|
1009
|
-
farmer_reward_puzzle_hash=wallet_ph,
|
|
1010
|
-
pool_reward_puzzle_hash=wallet_ph,
|
|
1011
|
-
)
|
|
1012
1034
|
|
|
1013
|
-
|
|
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
|
+
)
|
|
1014
1048
|
|
|
1015
|
-
|
|
1049
|
+
incoming_queue, _dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
1016
1050
|
|
|
1017
|
-
|
|
1018
|
-
await full_node_1.full_node.add_block(block, peer)
|
|
1019
|
-
await full_node_2.full_node.add_block(block, peer)
|
|
1051
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1020
1052
|
|
|
1021
|
-
|
|
1022
|
-
await full_node_1.
|
|
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)
|
|
1023
1056
|
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
msg = await full_node_1.request_transaction(request_transaction)
|
|
1027
|
-
assert msg is None
|
|
1057
|
+
# Farm another block to clear mempool
|
|
1058
|
+
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(wallet_ph))
|
|
1028
1059
|
|
|
1029
|
-
|
|
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
|
|
1030
1064
|
|
|
1031
|
-
|
|
1032
|
-
100, receiver_puzzlehash, blocks[-1].get_included_reward_coins()[0]
|
|
1033
|
-
)
|
|
1034
|
-
assert spend_bundle is not None
|
|
1035
|
-
respond_transaction = fnp.RespondTransaction(spend_bundle)
|
|
1036
|
-
res = await full_node_1.respond_transaction(respond_transaction, peer)
|
|
1037
|
-
assert res is None
|
|
1065
|
+
receiver_puzzlehash = wallet_receiver.get_new_puzzlehash()
|
|
1038
1066
|
|
|
1039
|
-
|
|
1040
|
-
|
|
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
|
|
1041
1074
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
assert msg is not None
|
|
1045
|
-
assert msg.data == bytes(fnp.RespondTransaction(spend_bundle))
|
|
1075
|
+
# Check broadcast
|
|
1076
|
+
await time_out_assert(10, time_out_messages(incoming_queue, "new_transaction"))
|
|
1046
1077
|
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
cb_ph = wallet_a.get_new_puzzlehash()
|
|
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))
|
|
1052
1082
|
|
|
1053
|
-
incoming_queue, dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12312)
|
|
1054
|
-
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1055
1083
|
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
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
|
+
)
|
|
1060
1122
|
|
|
1061
|
-
|
|
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
|
|
1062
1127
|
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
block_list_input=blocks,
|
|
1066
|
-
guarantee_transaction_block=True,
|
|
1067
|
-
farmer_reward_puzzle_hash=cb_ph,
|
|
1068
|
-
pool_reward_puzzle_hash=cb_ph,
|
|
1069
|
-
)
|
|
1070
|
-
await asyncio.sleep(1)
|
|
1071
|
-
while incoming_queue.qsize() > 0:
|
|
1072
|
-
await incoming_queue.get()
|
|
1073
|
-
|
|
1074
|
-
await full_node_1.full_node.add_block(blocks_new[-3], peer)
|
|
1075
|
-
await full_node_1.full_node.add_block(blocks_new[-2], peer)
|
|
1076
|
-
await full_node_1.full_node.add_block(blocks_new[-1], peer)
|
|
1077
|
-
|
|
1078
|
-
await time_out_assert(10, time_out_messages(incoming_queue, "new_peak", 3))
|
|
1079
|
-
# Invalid transaction does not propagate
|
|
1080
|
-
spend_bundle = wallet_a.generate_signed_transaction(
|
|
1081
|
-
100000000000000,
|
|
1082
|
-
receiver_puzzlehash,
|
|
1083
|
-
blocks_new[-1].get_included_reward_coins()[0],
|
|
1084
|
-
)
|
|
1128
|
+
await asyncio.sleep(1)
|
|
1129
|
+
assert incoming_queue.qsize() == 0
|
|
1085
1130
|
|
|
1086
|
-
assert spend_bundle is not None
|
|
1087
|
-
respond_transaction = fnp.RespondTransaction(spend_bundle)
|
|
1088
|
-
msg = await full_node_1.respond_transaction(respond_transaction, peer)
|
|
1089
|
-
assert msg is None
|
|
1090
1131
|
|
|
1091
|
-
|
|
1092
|
-
|
|
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
|
+
)
|
|
1093
1152
|
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1097
|
-
blocks = await full_node_1.get_all_full_blocks()
|
|
1153
|
+
for block in blocks:
|
|
1154
|
+
await full_node_1.full_node.add_block(block)
|
|
1098
1155
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
guarantee_transaction_block=True,
|
|
1103
|
-
farmer_reward_puzzle_hash=wallet_a.get_new_puzzlehash(),
|
|
1104
|
-
pool_reward_puzzle_hash=wallet_a.get_new_puzzlehash(),
|
|
1105
|
-
)
|
|
1106
|
-
spend_bundle = wallet_a.generate_signed_transaction(
|
|
1107
|
-
1123,
|
|
1108
|
-
wallet_receiver.get_new_puzzlehash(),
|
|
1109
|
-
blocks[-1].get_included_reward_coins()[0],
|
|
1110
|
-
)
|
|
1111
|
-
blocks = bt.get_consecutive_blocks(
|
|
1112
|
-
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=spend_bundle
|
|
1113
|
-
)
|
|
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
|
|
1114
1159
|
|
|
1115
|
-
|
|
1116
|
-
|
|
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
|
|
1117
1164
|
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
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
|
|
1121
1169
|
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
assert fnp.RespondBlock.from_bytes(res.data).block.transactions_generator is None
|
|
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
|
|
1126
1173
|
|
|
1127
|
-
# Ask with transactions
|
|
1128
|
-
res = await full_node_1.request_block(fnp.RequestBlock(blocks[-1].height, True))
|
|
1129
|
-
assert res.type != ProtocolMessageTypes.reject_block.value
|
|
1130
|
-
assert fnp.RespondBlock.from_bytes(res.data).block.transactions_generator is not None
|
|
1131
1174
|
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
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
|
+
)
|
|
1135
1188
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
blocks
|
|
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
|
+
)
|
|
1140
1197
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
33,
|
|
1144
|
-
block_list_input=blocks,
|
|
1145
|
-
guarantee_transaction_block=True,
|
|
1146
|
-
farmer_reward_puzzle_hash=wallet_a.get_new_puzzlehash(),
|
|
1147
|
-
pool_reward_puzzle_hash=wallet_a.get_new_puzzlehash(),
|
|
1148
|
-
)
|
|
1198
|
+
for block in blocks_t:
|
|
1199
|
+
await full_node_1.full_node.add_block(block)
|
|
1149
1200
|
|
|
1150
|
-
|
|
1151
|
-
1123,
|
|
1152
|
-
wallet_receiver.get_new_puzzlehash(),
|
|
1153
|
-
blocks[-1].get_included_reward_coins()[0],
|
|
1154
|
-
)
|
|
1155
|
-
blocks_t = bt.get_consecutive_blocks(
|
|
1156
|
-
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=spend_bundle
|
|
1157
|
-
)
|
|
1201
|
+
peak_height = blocks_t[-1].height
|
|
1158
1202
|
|
|
1159
|
-
|
|
1160
|
-
|
|
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
|
|
1161
1214
|
|
|
1162
|
-
|
|
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
|
|
1163
1218
|
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
assert res is not None
|
|
1167
|
-
fetched_blocks = fnp.RespondBlocks.from_bytes(res.data).blocks
|
|
1168
|
-
assert len(fetched_blocks) == 1
|
|
1169
|
-
assert fetched_blocks[0].header_hash == blocks[4].header_hash
|
|
1170
|
-
res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(5), uint32(4), False))
|
|
1171
|
-
assert res.type == ProtocolMessageTypes.reject_blocks.value
|
|
1172
|
-
# Invalid range
|
|
1173
|
-
res = await full_node_1.request_blocks(
|
|
1174
|
-
fnp.RequestBlocks(uint32(peak_height - 5), uint32(peak_height + 5), False)
|
|
1175
|
-
)
|
|
1176
|
-
assert res.type == ProtocolMessageTypes.reject_blocks.value
|
|
1177
|
-
|
|
1178
|
-
# Try fetching more blocks than constants.MAX_BLOCK_COUNT_PER_REQUESTS
|
|
1179
|
-
res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(0), uint32(33), False))
|
|
1180
|
-
assert res.type == ProtocolMessageTypes.reject_blocks.value
|
|
1181
|
-
|
|
1182
|
-
# Ask without transactions
|
|
1183
|
-
res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(peak_height - 5), uint32(peak_height), False))
|
|
1184
|
-
|
|
1185
|
-
fetched_blocks = fnp.RespondBlocks.from_bytes(res.data).blocks
|
|
1186
|
-
assert len(fetched_blocks) == 6
|
|
1187
|
-
for b in fetched_blocks:
|
|
1188
|
-
assert b.transactions_generator is None
|
|
1189
|
-
|
|
1190
|
-
# Ask with transactions
|
|
1191
|
-
res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(peak_height - 5), uint32(peak_height), True))
|
|
1192
|
-
fetched_blocks = fnp.RespondBlocks.from_bytes(res.data).blocks
|
|
1193
|
-
assert len(fetched_blocks) == 6
|
|
1194
|
-
assert fetched_blocks[-1].transactions_generator is not None
|
|
1195
|
-
assert std_hash(fetched_blocks[-1]) == std_hash(blocks_t[-1])
|
|
1196
|
-
|
|
1197
|
-
@pytest.mark.anyio
|
|
1198
|
-
@pytest.mark.parametrize("peer_version", ["0.0.35", "0.0.36"])
|
|
1199
|
-
@pytest.mark.parametrize("requesting", [0, 1, 2])
|
|
1200
|
-
async def test_new_unfinished_block(self, wallet_nodes, peer_version: str, requesting: int, self_hostname: str):
|
|
1201
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1202
|
-
blocks = await full_node_1.get_all_full_blocks()
|
|
1203
|
-
|
|
1204
|
-
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1205
|
-
assert peer in server_1.all_connections.values()
|
|
1206
|
-
|
|
1207
|
-
blocks = bt.get_consecutive_blocks(2, block_list_input=blocks)
|
|
1208
|
-
block: FullBlock = blocks[-1]
|
|
1209
|
-
unf = make_unfinished_block(block, bt.constants)
|
|
1219
|
+
# Ask without transactions
|
|
1220
|
+
res = await full_node_1.request_blocks(fnp.RequestBlocks(uint32(peak_height - 5), uint32(peak_height), False))
|
|
1210
1221
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
assert res is None
|
|
1216
|
-
elif requesting == 2:
|
|
1217
|
-
full_node_1.full_node.full_node_store.mark_requesting_unfinished_block(
|
|
1218
|
-
unf.partial_hash, unf.foliage.foliage_transaction_block_hash
|
|
1219
|
-
)
|
|
1220
|
-
res = await full_node_1.new_unfinished_block(fnp.NewUnfinishedBlock(unf.partial_hash))
|
|
1221
|
-
assert res is None
|
|
1222
|
-
else:
|
|
1223
|
-
res = await full_node_1.new_unfinished_block(fnp.NewUnfinishedBlock(unf.partial_hash))
|
|
1224
|
-
assert res is not None
|
|
1225
|
-
assert res is not None and res.data == bytes(fnp.RequestUnfinishedBlock(unf.partial_hash))
|
|
1226
|
-
|
|
1227
|
-
# when we receive a new unfinished block, we advertize it to our peers.
|
|
1228
|
-
# We send new_unfinished_blocks to old peers (0.0.35 and earlier) and we
|
|
1229
|
-
# send new_unfinishe_blocks2 to new peers (0.0.6 and later). Test both
|
|
1230
|
-
peer.protocol_version = Version(peer_version)
|
|
1231
|
-
|
|
1232
|
-
await full_node_1.full_node.add_block(blocks[-2])
|
|
1233
|
-
await full_node_1.full_node.add_unfinished_block(unf, None)
|
|
1234
|
-
|
|
1235
|
-
msg = peer.outgoing_queue.get_nowait()
|
|
1236
|
-
assert msg.type == ProtocolMessageTypes.new_peak.value
|
|
1237
|
-
msg = peer.outgoing_queue.get_nowait()
|
|
1238
|
-
if peer_version == "0.0.35":
|
|
1239
|
-
assert msg.type == ProtocolMessageTypes.new_unfinished_block.value
|
|
1240
|
-
assert msg.data == bytes(fnp.NewUnfinishedBlock(unf.partial_hash))
|
|
1241
|
-
elif peer_version == "0.0.36":
|
|
1242
|
-
assert msg.type == ProtocolMessageTypes.new_unfinished_block2.value
|
|
1243
|
-
assert msg.data == bytes(
|
|
1244
|
-
fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1245
|
-
)
|
|
1246
|
-
else: # pragma: no cover
|
|
1247
|
-
# the test parameters must have been updated, update the test too!
|
|
1248
|
-
assert False
|
|
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
|
|
1249
1226
|
|
|
1250
|
-
|
|
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)
|
|
1251
1252
|
res = await full_node_1.new_unfinished_block(fnp.NewUnfinishedBlock(unf.partial_hash))
|
|
1252
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
|
|
1253
1289
|
|
|
1254
|
-
@pytest.mark.anyio
|
|
1255
|
-
@pytest.mark.parametrize("requesting", [0, 1, 2])
|
|
1256
|
-
async def test_new_unfinished_block2(self, wallet_nodes, requesting: int, self_hostname: str):
|
|
1257
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1258
|
-
blocks = await full_node_1.get_all_full_blocks()
|
|
1259
|
-
|
|
1260
|
-
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1261
1290
|
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
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()
|
|
1265
1296
|
|
|
1266
|
-
|
|
1267
|
-
if requesting == 1:
|
|
1268
|
-
full_node_1.full_node.full_node_store.mark_requesting_unfinished_block(unf.partial_hash, None)
|
|
1297
|
+
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1269
1298
|
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
)
|
|
1274
|
-
res = await full_node_1.new_unfinished_block2(
|
|
1275
|
-
fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1276
|
-
)
|
|
1277
|
-
assert res is None
|
|
1278
|
-
else:
|
|
1279
|
-
res = await full_node_1.new_unfinished_block2(
|
|
1280
|
-
fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1281
|
-
)
|
|
1282
|
-
assert res is not None and res.data == bytes(
|
|
1283
|
-
fnp.RequestUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1284
|
-
)
|
|
1299
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1300
|
+
block: FullBlock = blocks[-1]
|
|
1301
|
+
unf = make_unfinished_block(block, bt.constants)
|
|
1285
1302
|
|
|
1286
|
-
|
|
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)
|
|
1287
1306
|
|
|
1288
|
-
|
|
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
|
+
)
|
|
1289
1311
|
res = await full_node_1.new_unfinished_block2(
|
|
1290
1312
|
fnp.NewUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1291
1313
|
)
|
|
1292
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
|
+
)
|
|
1293
1322
|
|
|
1294
|
-
|
|
1295
|
-
async def test_new_unfinished_block2_forward_limit(self, wallet_nodes, self_hostname: str):
|
|
1296
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1297
|
-
blocks = bt.get_consecutive_blocks(3, guarantee_transaction_block=True)
|
|
1298
|
-
for block in blocks:
|
|
1299
|
-
await full_node_1.full_node.add_block(block)
|
|
1300
|
-
coin = blocks[-1].get_included_reward_coins()[0]
|
|
1301
|
-
puzzle_hash = wallet_receiver.get_new_puzzlehash()
|
|
1302
|
-
|
|
1303
|
-
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1304
|
-
|
|
1305
|
-
# notify the node of unfinished blocks for this reward block hash
|
|
1306
|
-
# we forward 3 different blocks with the same reward block hash, but no
|
|
1307
|
-
# more (it's configurable)
|
|
1308
|
-
# also, we don't forward unfinished blocks that are "worse" than the
|
|
1309
|
-
# best block we've already seen, so we may need to send more than 3
|
|
1310
|
-
# blocks to the node for it to forward 3
|
|
1311
|
-
|
|
1312
|
-
unf_blocks: List[UnfinishedBlock] = []
|
|
1313
|
-
|
|
1314
|
-
last_reward_hash: Optional[bytes32] = None
|
|
1315
|
-
for idx in range(0, 6):
|
|
1316
|
-
# we include a different transaction in each block. This makes the
|
|
1317
|
-
# foliage different in each of them, but the reward block (plot) the same
|
|
1318
|
-
tx = wallet_a.generate_signed_transaction(100 * (idx + 1), puzzle_hash, coin)
|
|
1319
|
-
|
|
1320
|
-
# note that we use the same chain to build the new block on top of every time
|
|
1321
|
-
block = bt.get_consecutive_blocks(
|
|
1322
|
-
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
1323
|
-
)[-1]
|
|
1324
|
-
unf = make_unfinished_block(block, bt.constants)
|
|
1325
|
-
unf_blocks.append(unf)
|
|
1326
|
-
|
|
1327
|
-
if last_reward_hash is None:
|
|
1328
|
-
last_reward_hash = unf.partial_hash
|
|
1329
|
-
else:
|
|
1330
|
-
assert last_reward_hash == unf.partial_hash
|
|
1323
|
+
await full_node_1.full_node.add_unfinished_block(unf, peer)
|
|
1331
1324
|
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
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
|
|
1336
1330
|
|
|
1337
|
-
unf_blocks.sort(reverse=True, key=sort_key)
|
|
1338
1331
|
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
fnp.RequestUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1348
|
-
)
|
|
1349
|
-
else:
|
|
1350
|
-
# too many UnfinishedBlocks with the same reward hash
|
|
1351
|
-
assert res is None
|
|
1352
|
-
await full_node_1.full_node.add_unfinished_block(unf, peer)
|
|
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()
|
|
1353
1340
|
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
if committment > 0:
|
|
1381
|
-
tr = block.transactions_info
|
|
1382
|
-
transactions_info = TransactionsInfo(
|
|
1383
|
-
std_hash(bytes(replaced_generator)),
|
|
1384
|
-
tr.generator_refs_root,
|
|
1385
|
-
tr.aggregated_signature,
|
|
1386
|
-
tr.fees,
|
|
1387
|
-
tr.cost,
|
|
1388
|
-
tr.reward_claims_incorporated,
|
|
1389
|
-
)
|
|
1390
|
-
else:
|
|
1391
|
-
transactions_info = block.transactions_info
|
|
1392
|
-
|
|
1393
|
-
if committment > 1:
|
|
1394
|
-
tb = block.foliage_transaction_block
|
|
1395
|
-
transaction_block = FoliageTransactionBlock(
|
|
1396
|
-
tb.prev_transaction_block_hash,
|
|
1397
|
-
tb.timestamp,
|
|
1398
|
-
tb.filter_hash,
|
|
1399
|
-
tb.additions_root,
|
|
1400
|
-
tb.removals_root,
|
|
1401
|
-
transactions_info.get_hash(),
|
|
1402
|
-
)
|
|
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
|
|
1403
1367
|
else:
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
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)
|
|
1415
1386
|
)
|
|
1416
1387
|
else:
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
fl = block.foliage
|
|
1421
|
-
|
|
1422
|
-
secret_key: PrivateKey = AugSchemeMPL.key_gen(bytes([2] * 32))
|
|
1423
|
-
public_key = secret_key.get_g1()
|
|
1424
|
-
signature = AugSchemeMPL.sign(secret_key, transaction_block.get_hash())
|
|
1425
|
-
|
|
1426
|
-
foliage = Foliage(
|
|
1427
|
-
fl.prev_block_hash,
|
|
1428
|
-
fl.reward_block_hash,
|
|
1429
|
-
fl.foliage_block_data,
|
|
1430
|
-
fl.foliage_block_data_signature,
|
|
1431
|
-
transaction_block.get_hash(),
|
|
1432
|
-
signature,
|
|
1433
|
-
)
|
|
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)
|
|
1434
1391
|
|
|
1435
|
-
if committment > 4:
|
|
1436
|
-
pos = block.reward_chain_block.proof_of_space
|
|
1437
1392
|
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
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
|
|
1444
1476
|
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
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
|
|
1451
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
|
|
1452
1487
|
else:
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
proof_of_space = ProofOfSpace(
|
|
1456
|
-
challenge,
|
|
1457
|
-
pos.pool_public_key,
|
|
1458
|
-
pos.pool_contract_puzzle_hash,
|
|
1459
|
-
public_key,
|
|
1460
|
-
pos.size,
|
|
1461
|
-
pos.proof,
|
|
1462
|
-
)
|
|
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)
|
|
1463
1490
|
|
|
1464
|
-
rcb = block.reward_chain_block.get_unfinished()
|
|
1465
|
-
reward_chain_block = RewardChainBlockUnfinished(
|
|
1466
|
-
rcb.total_iters,
|
|
1467
|
-
rcb.signage_point_index,
|
|
1468
|
-
rcb.pos_ss_cc_challenge_hash,
|
|
1469
|
-
proof_of_space,
|
|
1470
|
-
rcb.challenge_chain_sp_vdf,
|
|
1471
|
-
rcb.challenge_chain_sp_signature,
|
|
1472
|
-
rcb.reward_chain_sp_vdf,
|
|
1473
|
-
rcb.reward_chain_sp_signature,
|
|
1474
|
-
)
|
|
1475
1491
|
else:
|
|
1476
|
-
|
|
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
|
+
)
|
|
1477
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
|
+
)
|
|
1478
1514
|
else:
|
|
1479
1515
|
reward_chain_block = block.reward_chain_block.get_unfinished()
|
|
1480
1516
|
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
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
|
+
)
|
|
1496
1535
|
|
|
1497
|
-
|
|
1498
|
-
|
|
1536
|
+
_, header_error = await full_node_1.full_node.blockchain.validate_unfinished_block_header(unf)
|
|
1537
|
+
assert header_error == expected
|
|
1499
1538
|
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
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)
|
|
1505
1544
|
|
|
1506
|
-
@pytest.mark.anyio
|
|
1507
|
-
async def test_double_blocks_same_pospace(self, wallet_nodes, self_hostname):
|
|
1508
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1509
1545
|
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
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
|
|
1513
1549
|
|
|
1514
|
-
|
|
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)
|
|
1515
1553
|
|
|
1516
|
-
|
|
1517
|
-
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
1518
|
-
blocks: List[FullBlock] = await full_node_1.get_all_full_blocks()
|
|
1554
|
+
ph = wallet_a.get_new_puzzlehash()
|
|
1519
1555
|
|
|
1520
|
-
|
|
1521
|
-
|
|
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()
|
|
1522
1559
|
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
)
|
|
1560
|
+
coin = blocks[-1].get_included_reward_coins()[0]
|
|
1561
|
+
tx = wallet_a.generate_signed_transaction(10000, wallet_receiver.get_new_puzzlehash(), coin)
|
|
1526
1562
|
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
assert full_node_1.full_node.full_node_store.get_unfinished_block(unf.partial_hash)
|
|
1563
|
+
blocks = bt.get_consecutive_blocks(
|
|
1564
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
1565
|
+
)
|
|
1531
1566
|
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
new_fbh_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
|
|
1537
|
-
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fbh_sig)
|
|
1538
|
-
block_2 = recursive_replace(block_2, "transactions_generator", None)
|
|
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)
|
|
1539
1571
|
|
|
1540
|
-
|
|
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)
|
|
1541
1579
|
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
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]
|
|
1554
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
|
|
1555
1641
|
|
|
1556
1642
|
# Don't have
|
|
1557
|
-
res = await full_node_1.
|
|
1643
|
+
res = await full_node_1.request_unfinished_block2(
|
|
1644
|
+
fnp.RequestUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1645
|
+
)
|
|
1558
1646
|
assert res is None
|
|
1647
|
+
|
|
1559
1648
|
await full_node_1.full_node.add_unfinished_block(unf, peer)
|
|
1560
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
|
+
|
|
1561
1655
|
res = await full_node_1.request_unfinished_block(fnp.RequestUnfinishedBlock(unf.partial_hash))
|
|
1562
|
-
assert res
|
|
1656
|
+
assert res.data == bytes(fnp.RespondUnfinishedBlock(best_unf))
|
|
1563
1657
|
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
full_node_1, full_node_2, server_1, server_2, wallet_a, wallet_receiver, bt = wallet_nodes
|
|
1567
|
-
blocks = await full_node_1.get_all_full_blocks()
|
|
1568
|
-
blocks = bt.get_consecutive_blocks(3, guarantee_transaction_block=True)
|
|
1569
|
-
for block in blocks:
|
|
1570
|
-
await full_node_1.full_node.add_block(block)
|
|
1571
|
-
coin = blocks[-1].get_included_reward_coins()[0]
|
|
1572
|
-
puzzle_hash = wallet_receiver.get_new_puzzlehash()
|
|
1573
|
-
|
|
1574
|
-
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1575
|
-
|
|
1576
|
-
# the "best" unfinished block according to the metric we use to pick one
|
|
1577
|
-
# deterministically
|
|
1578
|
-
best_unf: Optional[UnfinishedBlock] = None
|
|
1579
|
-
|
|
1580
|
-
for idx in range(0, 6):
|
|
1581
|
-
# we include a different transaction in each block. This makes the
|
|
1582
|
-
# foliage different in each of them, but the reward block (plot) the same
|
|
1583
|
-
tx = wallet_a.generate_signed_transaction(100 * (idx + 1), puzzle_hash, coin)
|
|
1584
|
-
|
|
1585
|
-
# note that we use the same chain to build the new block on top of every time
|
|
1586
|
-
block = bt.get_consecutive_blocks(
|
|
1587
|
-
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
1588
|
-
)[-1]
|
|
1589
|
-
unf = make_unfinished_block(block, bt.constants)
|
|
1590
|
-
assert unf.foliage.foliage_transaction_block_hash is not None
|
|
1591
|
-
|
|
1592
|
-
if best_unf is None:
|
|
1593
|
-
best_unf = unf
|
|
1594
|
-
elif (
|
|
1595
|
-
unf.foliage.foliage_transaction_block_hash is not None
|
|
1596
|
-
and unf.foliage.foliage_transaction_block_hash < best_unf.foliage.foliage_transaction_block_hash
|
|
1597
|
-
):
|
|
1598
|
-
best_unf = unf
|
|
1658
|
+
res = await full_node_1.request_unfinished_block2(fnp.RequestUnfinishedBlock2(unf.partial_hash, None))
|
|
1659
|
+
assert res.data == bytes(fnp.RespondUnfinishedBlock(best_unf))
|
|
1599
1660
|
|
|
1600
|
-
# Don't have
|
|
1601
|
-
res = await full_node_1.request_unfinished_block2(
|
|
1602
|
-
fnp.RequestUnfinishedBlock2(unf.partial_hash, unf.foliage.foliage_transaction_block_hash)
|
|
1603
|
-
)
|
|
1604
|
-
assert res is None
|
|
1605
1661
|
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
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
|
+
)
|
|
1612
1684
|
|
|
1613
|
-
|
|
1614
|
-
|
|
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)
|
|
1615
1691
|
|
|
1616
|
-
|
|
1617
|
-
|
|
1692
|
+
for block in blocks:
|
|
1693
|
+
await full_node_2.full_node.add_block(block)
|
|
1618
1694
|
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
blocks = await full_node_1.get_all_full_blocks()
|
|
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
|
|
1623
1698
|
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
await full_node_1.full_node.add_block(blocks[-2])
|
|
1627
|
-
await full_node_1.full_node.add_block(blocks[-1])
|
|
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
|
|
1628
1701
|
|
|
1629
|
-
|
|
1630
|
-
|
|
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
|
|
1631
1705
|
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
peak,
|
|
1636
|
-
peak.ip_sub_slot_total_iters(bt.constants),
|
|
1637
|
-
uint8(11),
|
|
1638
|
-
[],
|
|
1639
|
-
peak.sub_slot_iters,
|
|
1640
|
-
)
|
|
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)
|
|
1641
1709
|
|
|
1642
|
-
|
|
1643
|
-
res = await full_node_1.new_signage_point_or_end_of_sub_slot(
|
|
1644
|
-
fnp.NewSignagePointOrEndOfSubSlot(None, sp.cc_vdf.challenge, uint8(11), sp.rc_vdf.challenge), peer
|
|
1645
|
-
)
|
|
1646
|
-
assert res.type == ProtocolMessageTypes.request_signage_point_or_end_of_sub_slot.value
|
|
1647
|
-
assert fnp.RequestSignagePointOrEndOfSubSlot.from_bytes(res.data).index_from_challenge == uint8(11)
|
|
1710
|
+
assert len(full_node_1.full_node.full_node_store.finished_sub_slots) >= num_slots
|
|
1648
1711
|
|
|
1649
|
-
|
|
1650
|
-
|
|
1712
|
+
def caught_up_slots():
|
|
1713
|
+
return len(full_node_2.full_node.full_node_store.finished_sub_slots) >= num_slots
|
|
1651
1714
|
|
|
1652
|
-
|
|
1653
|
-
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=num_slots)
|
|
1654
|
-
slots = blocks[-1].finished_sub_slots
|
|
1715
|
+
await time_out_assert(20, caught_up_slots)
|
|
1655
1716
|
|
|
1656
|
-
assert len(full_node_2.full_node.full_node_store.finished_sub_slots) <= 2
|
|
1657
|
-
assert len(full_node_2.full_node.full_node_store.finished_sub_slots) <= 2
|
|
1658
1717
|
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
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
|
|
1662
1767
|
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slots[-1]), dummy_peer)
|
|
1768
|
+
# Add block
|
|
1769
|
+
await full_node_1.full_node.add_block(blocks[-1], peer)
|
|
1666
1770
|
|
|
1667
|
-
|
|
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
|
|
1668
1774
|
|
|
1669
|
-
def caught_up_slots():
|
|
1670
|
-
return len(full_node_2.full_node.full_node_store.finished_sub_slots) >= num_slots
|
|
1671
1775
|
|
|
1672
|
-
|
|
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]
|
|
1673
1783
|
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
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
|
|
1678
1788
|
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
await full_node_1.full_node.add_block(blocks[-3])
|
|
1682
|
-
await full_node_1.full_node.add_block(blocks[-2])
|
|
1683
|
-
await full_node_1.full_node.add_block(blocks[-1])
|
|
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
|
|
1684
1791
|
|
|
1685
|
-
|
|
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
|
|
1686
1795
|
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
)
|
|
1696
|
-
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot2), peer)
|
|
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
|
|
1697
1804
|
|
|
1698
|
-
|
|
1699
|
-
for block in blocks:
|
|
1700
|
-
await _validate_and_add_block(second_blockchain, block)
|
|
1805
|
+
await time_out_assert(20, caught_up_slots)
|
|
1701
1806
|
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
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(
|
|
1705
1821
|
bt.constants,
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
[],
|
|
1711
|
-
peak_2.sub_slot_iters,
|
|
1712
|
-
)
|
|
1713
|
-
# Submits the signage point, cannot add because don't have block
|
|
1714
|
-
await full_node_1.respond_signage_point(
|
|
1715
|
-
fnp.RespondSignagePoint(4, sp.cc_vdf, sp.cc_proof, sp.rc_vdf, sp.rc_proof), peer
|
|
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,
|
|
1716
1826
|
)
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
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
|
+
)
|
|
1720
1836
|
)
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
assert sp is not None
|
|
1730
|
-
|
|
1731
|
-
@pytest.mark.anyio
|
|
1732
|
-
async def test_slot_catch_up_genesis(self, setup_two_nodes_fixture, self_hostname):
|
|
1733
|
-
nodes, _, bt = setup_two_nodes_fixture
|
|
1734
|
-
server_1 = nodes[0].full_node.server
|
|
1735
|
-
server_2 = nodes[1].full_node.server
|
|
1736
|
-
full_node_1 = nodes[0]
|
|
1737
|
-
full_node_2 = nodes[1]
|
|
1738
|
-
|
|
1739
|
-
peer = await connect_and_get_peer(server_1, server_2, self_hostname)
|
|
1740
|
-
num_slots = 20
|
|
1741
|
-
blocks = bt.get_consecutive_blocks(1, skip_slots=num_slots)
|
|
1742
|
-
slots = blocks[-1].finished_sub_slots
|
|
1743
|
-
|
|
1744
|
-
assert len(full_node_2.full_node.full_node_store.finished_sub_slots) <= 2
|
|
1745
|
-
assert len(full_node_2.full_node.full_node_store.finished_sub_slots) <= 2
|
|
1746
|
-
|
|
1747
|
-
for slot in slots[:-1]:
|
|
1748
|
-
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot), peer)
|
|
1749
|
-
assert len(full_node_1.full_node.full_node_store.finished_sub_slots) >= num_slots - 1
|
|
1750
|
-
|
|
1751
|
-
incoming_queue, dummy_node_id = await add_dummy_connection(server_1, self_hostname, 12315)
|
|
1752
|
-
dummy_peer = server_1.all_connections[dummy_node_id]
|
|
1753
|
-
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slots[-1]), dummy_peer)
|
|
1754
|
-
|
|
1755
|
-
assert len(full_node_1.full_node.full_node_store.finished_sub_slots) >= num_slots
|
|
1756
|
-
|
|
1757
|
-
def caught_up_slots():
|
|
1758
|
-
return len(full_node_2.full_node.full_node_store.finished_sub_slots) >= num_slots
|
|
1759
|
-
|
|
1760
|
-
await time_out_assert(20, caught_up_slots)
|
|
1761
|
-
|
|
1762
|
-
@pytest.mark.anyio
|
|
1763
|
-
async def test_compact_protocol(self, setup_two_nodes_fixture):
|
|
1764
|
-
nodes, _, bt = setup_two_nodes_fixture
|
|
1765
|
-
full_node_1 = nodes[0]
|
|
1766
|
-
full_node_2 = nodes[1]
|
|
1767
|
-
blocks = bt.get_consecutive_blocks(num_blocks=10, skip_slots=3)
|
|
1768
|
-
block = blocks[0]
|
|
1769
|
-
for b in blocks:
|
|
1770
|
-
await full_node_1.full_node.add_block(b)
|
|
1771
|
-
timelord_protocol_finished = []
|
|
1772
|
-
cc_eos_count = 0
|
|
1773
|
-
for sub_slot in block.finished_sub_slots:
|
|
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
|
|
1774
1845
|
vdf_info, vdf_proof = get_vdf_info_and_proof(
|
|
1775
1846
|
bt.constants,
|
|
1776
1847
|
ClassgroupElement.get_default_element(),
|
|
1777
|
-
sub_slot.
|
|
1778
|
-
sub_slot.
|
|
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,
|
|
1779
1850
|
True,
|
|
1780
1851
|
)
|
|
1781
|
-
cc_eos_count += 1
|
|
1782
1852
|
timelord_protocol_finished.append(
|
|
1783
1853
|
timelord_protocol.RespondCompactProofOfTime(
|
|
1784
1854
|
vdf_info,
|
|
1785
1855
|
vdf_proof,
|
|
1786
1856
|
block.header_hash,
|
|
1787
1857
|
block.height,
|
|
1788
|
-
CompressibleVDFField.
|
|
1789
|
-
)
|
|
1790
|
-
)
|
|
1791
|
-
blocks_2 = bt.get_consecutive_blocks(num_blocks=10, block_list_input=blocks, skip_slots=3)
|
|
1792
|
-
block = blocks_2[-10]
|
|
1793
|
-
for b in blocks_2[-11:]:
|
|
1794
|
-
await full_node_1.full_node.add_block(b)
|
|
1795
|
-
icc_eos_count = 0
|
|
1796
|
-
for sub_slot in block.finished_sub_slots:
|
|
1797
|
-
if sub_slot.infused_challenge_chain is not None:
|
|
1798
|
-
icc_eos_count += 1
|
|
1799
|
-
vdf_info, vdf_proof = get_vdf_info_and_proof(
|
|
1800
|
-
bt.constants,
|
|
1801
|
-
ClassgroupElement.get_default_element(),
|
|
1802
|
-
sub_slot.infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.challenge,
|
|
1803
|
-
sub_slot.infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.number_of_iterations,
|
|
1804
|
-
True,
|
|
1805
|
-
)
|
|
1806
|
-
timelord_protocol_finished.append(
|
|
1807
|
-
timelord_protocol.RespondCompactProofOfTime(
|
|
1808
|
-
vdf_info,
|
|
1809
|
-
vdf_proof,
|
|
1810
|
-
block.header_hash,
|
|
1811
|
-
block.height,
|
|
1812
|
-
CompressibleVDFField.ICC_EOS_VDF,
|
|
1813
|
-
)
|
|
1858
|
+
CompressibleVDFField.ICC_EOS_VDF,
|
|
1814
1859
|
)
|
|
1815
|
-
assert block.reward_chain_block.challenge_chain_sp_vdf is not None
|
|
1816
|
-
vdf_info, vdf_proof = get_vdf_info_and_proof(
|
|
1817
|
-
bt.constants,
|
|
1818
|
-
ClassgroupElement.get_default_element(),
|
|
1819
|
-
block.reward_chain_block.challenge_chain_sp_vdf.challenge,
|
|
1820
|
-
block.reward_chain_block.challenge_chain_sp_vdf.number_of_iterations,
|
|
1821
|
-
True,
|
|
1822
|
-
)
|
|
1823
|
-
timelord_protocol_finished.append(
|
|
1824
|
-
timelord_protocol.RespondCompactProofOfTime(
|
|
1825
|
-
vdf_info,
|
|
1826
|
-
vdf_proof,
|
|
1827
|
-
block.header_hash,
|
|
1828
|
-
block.height,
|
|
1829
|
-
CompressibleVDFField.CC_SP_VDF,
|
|
1830
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,
|
|
1831
1876
|
)
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
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,
|
|
1838
1892
|
)
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
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
|
+
)
|
|
1846
1966
|
)
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
has_compact_cc_ip_vdf = False
|
|
1858
|
-
for block in stored_blocks:
|
|
1859
|
-
for sub_slot in block.finished_sub_slots:
|
|
1860
|
-
if sub_slot.proofs.challenge_chain_slot_proof.normalized_to_identity:
|
|
1861
|
-
cc_eos_compact_count += 1
|
|
1862
|
-
if (
|
|
1863
|
-
sub_slot.proofs.infused_challenge_chain_slot_proof is not None
|
|
1864
|
-
and sub_slot.proofs.infused_challenge_chain_slot_proof.normalized_to_identity
|
|
1865
|
-
):
|
|
1866
|
-
icc_eos_compact_count += 1
|
|
1867
|
-
if block.challenge_chain_sp_proof is not None and block.challenge_chain_sp_proof.normalized_to_identity:
|
|
1868
|
-
has_compact_cc_sp_vdf = True
|
|
1869
|
-
if block.challenge_chain_ip_proof.normalized_to_identity:
|
|
1870
|
-
has_compact_cc_ip_vdf = True
|
|
1871
|
-
# Note: the below numbers depend on the block cache, so might need to be updated
|
|
1872
|
-
assert cc_eos_compact_count == 3
|
|
1873
|
-
assert icc_eos_compact_count == 3
|
|
1874
|
-
assert has_compact_cc_sp_vdf
|
|
1875
|
-
assert has_compact_cc_ip_vdf
|
|
1876
|
-
for height, block in enumerate(stored_blocks):
|
|
1877
|
-
await full_node_2.full_node.add_block(block)
|
|
1878
|
-
assert full_node_2.full_node.blockchain.get_peak().height == height
|
|
1879
|
-
|
|
1880
|
-
@pytest.mark.anyio
|
|
1881
|
-
async def test_compact_protocol_invalid_messages(self, setup_two_nodes_fixture, self_hostname):
|
|
1882
|
-
nodes, _, bt = setup_two_nodes_fixture
|
|
1883
|
-
full_node_1 = nodes[0]
|
|
1884
|
-
full_node_2 = nodes[1]
|
|
1885
|
-
blocks = bt.get_consecutive_blocks(num_blocks=1, skip_slots=3)
|
|
1886
|
-
blocks_2 = bt.get_consecutive_blocks(num_blocks=3, block_list_input=blocks, skip_slots=3)
|
|
1887
|
-
for block in blocks_2[:2]:
|
|
1888
|
-
await full_node_1.full_node.add_block(block)
|
|
1889
|
-
assert full_node_1.full_node.blockchain.get_peak().height == 1
|
|
1890
|
-
# (wrong_vdf_info, wrong_vdf_proof) pair verifies, but it's not present in the blockchain at all.
|
|
1891
|
-
block = blocks_2[2]
|
|
1892
|
-
wrong_vdf_info, wrong_vdf_proof = get_vdf_info_and_proof(
|
|
1893
|
-
bt.constants,
|
|
1894
|
-
ClassgroupElement.get_default_element(),
|
|
1895
|
-
block.reward_chain_block.challenge_chain_ip_vdf.challenge,
|
|
1896
|
-
block.reward_chain_block.challenge_chain_ip_vdf.number_of_iterations,
|
|
1897
|
-
True,
|
|
1898
|
-
)
|
|
1899
|
-
timelord_protocol_invalid_messages = []
|
|
1900
|
-
full_node_protocol_invalid_messaages = []
|
|
1901
|
-
for block in blocks_2[:2]:
|
|
1902
|
-
for sub_slot in block.finished_sub_slots:
|
|
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:
|
|
1903
1977
|
vdf_info, correct_vdf_proof = get_vdf_info_and_proof(
|
|
1904
1978
|
bt.constants,
|
|
1905
1979
|
ClassgroupElement.get_default_element(),
|
|
1906
|
-
sub_slot.
|
|
1907
|
-
sub_slot.
|
|
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,
|
|
1908
1982
|
True,
|
|
1909
1983
|
)
|
|
1910
1984
|
assert wrong_vdf_proof != correct_vdf_proof
|
|
@@ -1914,288 +1988,262 @@ class TestFullNodeProtocol:
|
|
|
1914
1988
|
wrong_vdf_proof,
|
|
1915
1989
|
block.header_hash,
|
|
1916
1990
|
block.height,
|
|
1917
|
-
CompressibleVDFField.
|
|
1991
|
+
CompressibleVDFField.ICC_EOS_VDF,
|
|
1918
1992
|
)
|
|
1919
1993
|
)
|
|
1920
1994
|
full_node_protocol_invalid_messaages.append(
|
|
1921
1995
|
fnp.RespondCompactVDF(
|
|
1922
1996
|
block.height,
|
|
1923
1997
|
block.header_hash,
|
|
1924
|
-
CompressibleVDFField.
|
|
1998
|
+
CompressibleVDFField.ICC_EOS_VDF,
|
|
1925
1999
|
vdf_info,
|
|
1926
2000
|
wrong_vdf_proof,
|
|
1927
2001
|
)
|
|
1928
2002
|
)
|
|
1929
|
-
if sub_slot.infused_challenge_chain is not None:
|
|
1930
|
-
vdf_info, correct_vdf_proof = get_vdf_info_and_proof(
|
|
1931
|
-
bt.constants,
|
|
1932
|
-
ClassgroupElement.get_default_element(),
|
|
1933
|
-
sub_slot.infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.challenge,
|
|
1934
|
-
sub_slot.infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.number_of_iterations,
|
|
1935
|
-
True,
|
|
1936
|
-
)
|
|
1937
|
-
assert wrong_vdf_proof != correct_vdf_proof
|
|
1938
|
-
timelord_protocol_invalid_messages.append(
|
|
1939
|
-
timelord_protocol.RespondCompactProofOfTime(
|
|
1940
|
-
vdf_info,
|
|
1941
|
-
wrong_vdf_proof,
|
|
1942
|
-
block.header_hash,
|
|
1943
|
-
block.height,
|
|
1944
|
-
CompressibleVDFField.ICC_EOS_VDF,
|
|
1945
|
-
)
|
|
1946
|
-
)
|
|
1947
|
-
full_node_protocol_invalid_messaages.append(
|
|
1948
|
-
fnp.RespondCompactVDF(
|
|
1949
|
-
block.height,
|
|
1950
|
-
block.header_hash,
|
|
1951
|
-
CompressibleVDFField.ICC_EOS_VDF,
|
|
1952
|
-
vdf_info,
|
|
1953
|
-
wrong_vdf_proof,
|
|
1954
|
-
)
|
|
1955
|
-
)
|
|
1956
|
-
|
|
1957
|
-
if block.reward_chain_block.challenge_chain_sp_vdf is not None:
|
|
1958
|
-
vdf_info, correct_vdf_proof = get_vdf_info_and_proof(
|
|
1959
|
-
bt.constants,
|
|
1960
|
-
ClassgroupElement.get_default_element(),
|
|
1961
|
-
block.reward_chain_block.challenge_chain_sp_vdf.challenge,
|
|
1962
|
-
block.reward_chain_block.challenge_chain_sp_vdf.number_of_iterations,
|
|
1963
|
-
True,
|
|
1964
|
-
)
|
|
1965
|
-
sp_vdf_proof = wrong_vdf_proof
|
|
1966
|
-
if wrong_vdf_proof == correct_vdf_proof:
|
|
1967
|
-
# This can actually happen...
|
|
1968
|
-
sp_vdf_proof = VDFProof(uint8(0), b"1239819023890", True)
|
|
1969
|
-
timelord_protocol_invalid_messages.append(
|
|
1970
|
-
timelord_protocol.RespondCompactProofOfTime(
|
|
1971
|
-
vdf_info,
|
|
1972
|
-
sp_vdf_proof,
|
|
1973
|
-
block.header_hash,
|
|
1974
|
-
block.height,
|
|
1975
|
-
CompressibleVDFField.CC_SP_VDF,
|
|
1976
|
-
)
|
|
1977
|
-
)
|
|
1978
|
-
full_node_protocol_invalid_messaages.append(
|
|
1979
|
-
fnp.RespondCompactVDF(
|
|
1980
|
-
block.height,
|
|
1981
|
-
block.header_hash,
|
|
1982
|
-
CompressibleVDFField.CC_SP_VDF,
|
|
1983
|
-
vdf_info,
|
|
1984
|
-
sp_vdf_proof,
|
|
1985
|
-
)
|
|
1986
|
-
)
|
|
1987
2003
|
|
|
2004
|
+
if block.reward_chain_block.challenge_chain_sp_vdf is not None:
|
|
1988
2005
|
vdf_info, correct_vdf_proof = get_vdf_info_and_proof(
|
|
1989
2006
|
bt.constants,
|
|
1990
2007
|
ClassgroupElement.get_default_element(),
|
|
1991
|
-
block.reward_chain_block.
|
|
1992
|
-
block.reward_chain_block.
|
|
2008
|
+
block.reward_chain_block.challenge_chain_sp_vdf.challenge,
|
|
2009
|
+
block.reward_chain_block.challenge_chain_sp_vdf.number_of_iterations,
|
|
1993
2010
|
True,
|
|
1994
2011
|
)
|
|
1995
|
-
|
|
2012
|
+
sp_vdf_proof = wrong_vdf_proof
|
|
1996
2013
|
if wrong_vdf_proof == correct_vdf_proof:
|
|
1997
2014
|
# This can actually happen...
|
|
1998
|
-
|
|
2015
|
+
sp_vdf_proof = VDFProof(uint8(0), b"1239819023890", True)
|
|
1999
2016
|
timelord_protocol_invalid_messages.append(
|
|
2000
2017
|
timelord_protocol.RespondCompactProofOfTime(
|
|
2001
2018
|
vdf_info,
|
|
2002
|
-
|
|
2019
|
+
sp_vdf_proof,
|
|
2003
2020
|
block.header_hash,
|
|
2004
2021
|
block.height,
|
|
2005
|
-
CompressibleVDFField.
|
|
2022
|
+
CompressibleVDFField.CC_SP_VDF,
|
|
2006
2023
|
)
|
|
2007
2024
|
)
|
|
2008
2025
|
full_node_protocol_invalid_messaages.append(
|
|
2009
2026
|
fnp.RespondCompactVDF(
|
|
2010
2027
|
block.height,
|
|
2011
2028
|
block.header_hash,
|
|
2012
|
-
CompressibleVDFField.
|
|
2029
|
+
CompressibleVDFField.CC_SP_VDF,
|
|
2013
2030
|
vdf_info,
|
|
2014
|
-
|
|
2031
|
+
sp_vdf_proof,
|
|
2015
2032
|
)
|
|
2016
2033
|
)
|
|
2017
2034
|
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
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,
|
|
2026
2053
|
)
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
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,
|
|
2035
2062
|
)
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
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,
|
|
2044
2072
|
)
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
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,
|
|
2053
2081
|
)
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
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,
|
|
2062
2090
|
)
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
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,
|
|
2071
2099
|
)
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
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,
|
|
2080
2108
|
)
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
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,
|
|
2089
2117
|
)
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
for block in stored_blocks:
|
|
2099
|
-
for sub_slot in block.finished_sub_slots:
|
|
2100
|
-
assert not sub_slot.proofs.challenge_chain_slot_proof.normalized_to_identity
|
|
2101
|
-
if sub_slot.proofs.infused_challenge_chain_slot_proof is not None:
|
|
2102
|
-
assert not sub_slot.proofs.infused_challenge_chain_slot_proof.normalized_to_identity
|
|
2103
|
-
if block.challenge_chain_sp_proof is not None:
|
|
2104
|
-
assert not block.challenge_chain_sp_proof.normalized_to_identity
|
|
2105
|
-
assert not block.challenge_chain_ip_proof.normalized_to_identity
|
|
2106
|
-
|
|
2107
|
-
@pytest.mark.anyio
|
|
2108
|
-
async def test_respond_compact_proof_message_limit(self, setup_two_nodes_fixture):
|
|
2109
|
-
nodes, _, bt = setup_two_nodes_fixture
|
|
2110
|
-
full_node_1 = nodes[0]
|
|
2111
|
-
full_node_2 = nodes[1]
|
|
2112
|
-
NUM_BLOCKS = 20
|
|
2113
|
-
# We don't compactify the last 5 blocks.
|
|
2114
|
-
EXPECTED_COMPACTIFIED = NUM_BLOCKS - 5
|
|
2115
|
-
blocks = bt.get_consecutive_blocks(num_blocks=NUM_BLOCKS)
|
|
2116
|
-
finished_compact_proofs = []
|
|
2117
|
-
for block in blocks:
|
|
2118
|
-
await full_node_1.full_node.add_block(block)
|
|
2119
|
-
await full_node_2.full_node.add_block(block)
|
|
2120
|
-
vdf_info, vdf_proof = get_vdf_info_and_proof(
|
|
2121
|
-
bt.constants,
|
|
2122
|
-
ClassgroupElement.get_default_element(),
|
|
2123
|
-
block.reward_chain_block.challenge_chain_ip_vdf.challenge,
|
|
2124
|
-
block.reward_chain_block.challenge_chain_ip_vdf.number_of_iterations,
|
|
2125
|
-
True,
|
|
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
2126
|
)
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
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
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
|
|
2136
2153
|
|
|
2137
|
-
async def coro(full_node, compact_proof):
|
|
2138
|
-
await full_node.respond_compact_proof_of_time(compact_proof)
|
|
2139
2154
|
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
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,
|
|
2143
2174
|
)
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
assert compactified == EXPECTED_COMPACTIFIED
|
|
2161
|
-
|
|
2162
|
-
@pytest.mark.parametrize(
|
|
2163
|
-
argnames=["custom_capabilities", "expect_success"],
|
|
2164
|
-
argvalues=[
|
|
2165
|
-
# standard
|
|
2166
|
-
[default_capabilities[NodeType.FULL_NODE], True],
|
|
2167
|
-
# an additional enabled but unknown capability
|
|
2168
|
-
[[*default_capabilities[NodeType.FULL_NODE], (uint16(max(Capability) + 1), "1")], True],
|
|
2169
|
-
# no capability, not even Chia mainnet
|
|
2170
|
-
# TODO: shouldn't we fail without Capability.BASE?
|
|
2171
|
-
[[], True],
|
|
2172
|
-
# only an unknown capability
|
|
2173
|
-
# TODO: shouldn't we fail without Capability.BASE?
|
|
2174
|
-
[[(uint16(max(Capability) + 1), "1")], True],
|
|
2175
|
-
],
|
|
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]
|
|
2176
2191
|
)
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
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?
|
|
2186
2234
|
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2235
|
+
[
|
|
2236
|
+
_initiating_full_node_api,
|
|
2237
|
+
_listening_full_node_api,
|
|
2238
|
+
initiating_server,
|
|
2239
|
+
listening_server,
|
|
2240
|
+
_bt,
|
|
2241
|
+
] = two_nodes
|
|
2194
2242
|
|
|
2195
|
-
|
|
2243
|
+
initiating_server._local_capabilities_for_handshake = custom_capabilities
|
|
2196
2244
|
|
|
2197
|
-
|
|
2198
|
-
|
|
2245
|
+
connected = await initiating_server.start_client(PeerInfo(self_hostname, listening_server.get_port()), None)
|
|
2246
|
+
assert connected == expect_success, custom_capabilities
|
|
2199
2247
|
|
|
2200
2248
|
|
|
2201
2249
|
@pytest.mark.anyio
|
|
@@ -2254,17 +2302,81 @@ async def test_wallet_sync_task_failure(
|
|
|
2254
2302
|
assert not full_node.wallet_sync_task.done()
|
|
2255
2303
|
|
|
2256
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
|
+
|
|
2257
2369
|
@pytest.mark.anyio
|
|
2258
2370
|
@pytest.mark.parametrize("light_blocks", [True, False])
|
|
2259
2371
|
async def test_long_reorg(
|
|
2260
2372
|
light_blocks: bool,
|
|
2261
2373
|
one_node_one_block,
|
|
2262
|
-
default_10000_blocks:
|
|
2263
|
-
test_long_reorg_1500_blocks:
|
|
2264
|
-
test_long_reorg_1500_blocks_light:
|
|
2374
|
+
default_10000_blocks: list[FullBlock],
|
|
2375
|
+
test_long_reorg_1500_blocks: list[FullBlock],
|
|
2376
|
+
test_long_reorg_1500_blocks_light: list[FullBlock],
|
|
2265
2377
|
seeded_random: random.Random,
|
|
2266
2378
|
):
|
|
2267
|
-
node,
|
|
2379
|
+
node, _server, _bt = one_node_one_block
|
|
2268
2380
|
|
|
2269
2381
|
fork_point = 1499
|
|
2270
2382
|
blocks = default_10000_blocks[:3000]
|
|
@@ -2285,20 +2397,13 @@ async def test_long_reorg(
|
|
|
2285
2397
|
assert reorg_blocks[fork_point] == default_10000_blocks[fork_point]
|
|
2286
2398
|
assert reorg_blocks[fork_point + 1] != default_10000_blocks[fork_point + 1]
|
|
2287
2399
|
|
|
2400
|
+
await validate_coin_set(node.full_node._coin_store, blocks)
|
|
2401
|
+
|
|
2288
2402
|
# one aspect of this test is to make sure we can reorg blocks that are
|
|
2289
2403
|
# not in the cache. We need to explicitly prune the cache to get that
|
|
2290
2404
|
# effect.
|
|
2291
2405
|
node.full_node.blockchain.clean_block_records()
|
|
2292
|
-
|
|
2293
|
-
fork_info: Optional[ForkInfo] = None
|
|
2294
|
-
for b in reorg_blocks:
|
|
2295
|
-
if (b.height % 128) == 0:
|
|
2296
|
-
peak = node.full_node.blockchain.get_peak()
|
|
2297
|
-
print(f"reorg chain: {b.height:4} " f"weight: {b.weight:7} " f"peak: {str(peak.header_hash)[:6]}")
|
|
2298
|
-
if b.height > fork_point and fork_info is None:
|
|
2299
|
-
fork_info = ForkInfo(fork_point, fork_point, reorg_blocks[fork_point].header_hash)
|
|
2300
|
-
await node.full_node.add_block(b, fork_info=fork_info)
|
|
2301
|
-
|
|
2406
|
+
await add_blocks_in_batches(reorg_blocks, node.full_node)
|
|
2302
2407
|
# if these asserts fires, there was no reorg
|
|
2303
2408
|
peak = node.full_node.blockchain.get_peak()
|
|
2304
2409
|
assert peak.header_hash != chain_1_peak
|
|
@@ -2306,6 +2411,8 @@ async def test_long_reorg(
|
|
|
2306
2411
|
chain_2_weight = peak.weight
|
|
2307
2412
|
chain_2_peak = peak.header_hash
|
|
2308
2413
|
|
|
2414
|
+
await validate_coin_set(node.full_node._coin_store, reorg_blocks)
|
|
2415
|
+
|
|
2309
2416
|
# if the reorg chain has lighter blocks, once we've re-orged onto it, we
|
|
2310
2417
|
# have a greater block height. If the reorg chain has heavier blocks, we
|
|
2311
2418
|
# end up with a lower height than the original chain (but greater weight)
|
|
@@ -2313,7 +2420,6 @@ async def test_long_reorg(
|
|
|
2313
2420
|
assert peak.height > chain_1_height
|
|
2314
2421
|
else:
|
|
2315
2422
|
assert peak.height < chain_1_height
|
|
2316
|
-
|
|
2317
2423
|
# now reorg back to the original chain
|
|
2318
2424
|
# this exercises the case where we have some of the blocks in the DB already
|
|
2319
2425
|
node.full_node.blockchain.clean_block_records()
|
|
@@ -2323,20 +2429,14 @@ async def test_long_reorg(
|
|
|
2323
2429
|
blocks = default_10000_blocks[fork_point - 100 : 3200]
|
|
2324
2430
|
else:
|
|
2325
2431
|
blocks = default_10000_blocks[fork_point - 100 : 5500]
|
|
2326
|
-
|
|
2327
|
-
fork_block = blocks[0]
|
|
2328
|
-
fork_info = ForkInfo(fork_block.height - 1, fork_block.height - 1, fork_block.prev_header_hash)
|
|
2329
|
-
for b in blocks:
|
|
2330
|
-
if (b.height % 128) == 0:
|
|
2331
|
-
peak = node.full_node.blockchain.get_peak()
|
|
2332
|
-
print(f"original chain: {b.height:4} " f"weight: {b.weight:7} " f"peak: {str(peak.header_hash)[:6]}")
|
|
2333
|
-
await node.full_node.add_block(b, fork_info=fork_info)
|
|
2334
|
-
|
|
2432
|
+
await add_blocks_in_batches(blocks, node.full_node)
|
|
2335
2433
|
# if these asserts fires, there was no reorg back to the original chain
|
|
2336
2434
|
peak = node.full_node.blockchain.get_peak()
|
|
2337
2435
|
assert peak.header_hash != chain_2_peak
|
|
2338
2436
|
assert peak.weight > chain_2_weight
|
|
2339
2437
|
|
|
2438
|
+
await validate_coin_set(node.full_node._coin_store, blocks)
|
|
2439
|
+
|
|
2340
2440
|
|
|
2341
2441
|
@pytest.mark.anyio
|
|
2342
2442
|
@pytest.mark.parametrize("light_blocks", [True, False])
|
|
@@ -2348,11 +2448,11 @@ async def test_long_reorg_nodes(
|
|
|
2348
2448
|
chain_length: int,
|
|
2349
2449
|
fork_point: int,
|
|
2350
2450
|
three_nodes,
|
|
2351
|
-
default_10000_blocks:
|
|
2352
|
-
test_long_reorg_blocks:
|
|
2353
|
-
test_long_reorg_blocks_light:
|
|
2354
|
-
test_long_reorg_1500_blocks:
|
|
2355
|
-
test_long_reorg_1500_blocks_light:
|
|
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],
|
|
2356
2456
|
self_hostname: str,
|
|
2357
2457
|
seeded_random: random.Random,
|
|
2358
2458
|
):
|
|
@@ -2409,6 +2509,9 @@ async def test_long_reorg_nodes(
|
|
|
2409
2509
|
assert p1.header_hash == reorg_blocks[-1].header_hash
|
|
2410
2510
|
assert p2.header_hash == reorg_blocks[-1].header_hash
|
|
2411
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
|
+
|
|
2412
2515
|
blocks = default_10000_blocks[:reorg_height]
|
|
2413
2516
|
|
|
2414
2517
|
# this is a pre-requisite for a reorg to happen
|
|
@@ -2443,3 +2546,155 @@ async def test_long_reorg_nodes(
|
|
|
2443
2546
|
|
|
2444
2547
|
print(f"reorg1 timing: {reorg1_timing:0.2f}s")
|
|
2445
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
|