chia-blockchain 2.5.1rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chia/__init__.py +10 -0
- chia/__main__.py +5 -0
- chia/_tests/README.md +53 -0
- chia/_tests/__init__.py +0 -0
- chia/_tests/blockchain/__init__.py +0 -0
- chia/_tests/blockchain/blockchain_test_utils.py +195 -0
- chia/_tests/blockchain/config.py +4 -0
- chia/_tests/blockchain/test_augmented_chain.py +145 -0
- chia/_tests/blockchain/test_blockchain.py +4202 -0
- chia/_tests/blockchain/test_blockchain_transactions.py +1031 -0
- chia/_tests/blockchain/test_build_chains.py +59 -0
- chia/_tests/blockchain/test_get_block_generator.py +72 -0
- chia/_tests/blockchain/test_lookup_fork_chain.py +194 -0
- chia/_tests/build-init-files.py +92 -0
- chia/_tests/build-job-matrix.py +204 -0
- chia/_tests/check_pytest_monitor_output.py +34 -0
- chia/_tests/check_sql_statements.py +72 -0
- chia/_tests/chia-start-sim +42 -0
- chia/_tests/clvm/__init__.py +0 -0
- chia/_tests/clvm/benchmark_costs.py +23 -0
- chia/_tests/clvm/coin_store.py +149 -0
- chia/_tests/clvm/test_chialisp_deserialization.py +101 -0
- chia/_tests/clvm/test_clvm_step.py +37 -0
- chia/_tests/clvm/test_condition_codes.py +13 -0
- chia/_tests/clvm/test_curry_and_treehash.py +55 -0
- chia/_tests/clvm/test_message_conditions.py +184 -0
- chia/_tests/clvm/test_program.py +150 -0
- chia/_tests/clvm/test_puzzle_compression.py +143 -0
- chia/_tests/clvm/test_puzzle_drivers.py +45 -0
- chia/_tests/clvm/test_puzzles.py +242 -0
- chia/_tests/clvm/test_singletons.py +540 -0
- chia/_tests/clvm/test_spend_sim.py +181 -0
- chia/_tests/cmds/__init__.py +0 -0
- chia/_tests/cmds/cmd_test_utils.py +469 -0
- chia/_tests/cmds/config.py +3 -0
- chia/_tests/cmds/conftest.py +23 -0
- chia/_tests/cmds/test_click_types.py +200 -0
- chia/_tests/cmds/test_cmd_framework.py +620 -0
- chia/_tests/cmds/test_cmds_util.py +97 -0
- chia/_tests/cmds/test_daemon.py +92 -0
- chia/_tests/cmds/test_dev_gh.py +131 -0
- chia/_tests/cmds/test_farm_cmd.py +66 -0
- chia/_tests/cmds/test_show.py +116 -0
- chia/_tests/cmds/test_sim.py +207 -0
- chia/_tests/cmds/test_timelock_args.py +75 -0
- chia/_tests/cmds/test_tx_config_args.py +154 -0
- chia/_tests/cmds/testing_classes.py +59 -0
- chia/_tests/cmds/wallet/__init__.py +0 -0
- chia/_tests/cmds/wallet/test_consts.py +47 -0
- chia/_tests/cmds/wallet/test_dao.py +565 -0
- chia/_tests/cmds/wallet/test_did.py +403 -0
- chia/_tests/cmds/wallet/test_nft.py +471 -0
- chia/_tests/cmds/wallet/test_notifications.py +124 -0
- chia/_tests/cmds/wallet/test_offer.toffer +1 -0
- chia/_tests/cmds/wallet/test_tx_decorators.py +27 -0
- chia/_tests/cmds/wallet/test_vcs.py +400 -0
- chia/_tests/cmds/wallet/test_wallet.py +1125 -0
- chia/_tests/cmds/wallet/test_wallet_check.py +109 -0
- chia/_tests/conftest.py +1419 -0
- chia/_tests/connection_utils.py +125 -0
- chia/_tests/core/__init__.py +0 -0
- chia/_tests/core/cmds/__init__.py +0 -0
- chia/_tests/core/cmds/test_beta.py +382 -0
- chia/_tests/core/cmds/test_keys.py +1734 -0
- chia/_tests/core/cmds/test_wallet.py +126 -0
- chia/_tests/core/config.py +3 -0
- chia/_tests/core/consensus/__init__.py +0 -0
- chia/_tests/core/consensus/test_block_creation.py +54 -0
- chia/_tests/core/consensus/test_pot_iterations.py +117 -0
- chia/_tests/core/custom_types/__init__.py +0 -0
- chia/_tests/core/custom_types/test_coin.py +107 -0
- chia/_tests/core/custom_types/test_proof_of_space.py +144 -0
- chia/_tests/core/custom_types/test_spend_bundle.py +70 -0
- chia/_tests/core/daemon/__init__.py +0 -0
- chia/_tests/core/daemon/config.py +4 -0
- chia/_tests/core/daemon/test_daemon.py +2128 -0
- chia/_tests/core/daemon/test_daemon_register.py +109 -0
- chia/_tests/core/daemon/test_keychain_proxy.py +101 -0
- chia/_tests/core/data_layer/__init__.py +0 -0
- chia/_tests/core/data_layer/config.py +5 -0
- chia/_tests/core/data_layer/conftest.py +106 -0
- chia/_tests/core/data_layer/test_data_cli.py +56 -0
- chia/_tests/core/data_layer/test_data_layer.py +83 -0
- chia/_tests/core/data_layer/test_data_layer_util.py +218 -0
- chia/_tests/core/data_layer/test_data_rpc.py +3847 -0
- chia/_tests/core/data_layer/test_data_store.py +2424 -0
- chia/_tests/core/data_layer/test_data_store_schema.py +381 -0
- chia/_tests/core/data_layer/test_plugin.py +91 -0
- chia/_tests/core/data_layer/util.py +233 -0
- chia/_tests/core/farmer/__init__.py +0 -0
- chia/_tests/core/farmer/config.py +3 -0
- chia/_tests/core/farmer/test_farmer_api.py +103 -0
- chia/_tests/core/full_node/__init__.py +0 -0
- chia/_tests/core/full_node/config.py +4 -0
- chia/_tests/core/full_node/dos/__init__.py +0 -0
- chia/_tests/core/full_node/dos/config.py +3 -0
- chia/_tests/core/full_node/full_sync/__init__.py +0 -0
- chia/_tests/core/full_node/full_sync/config.py +4 -0
- chia/_tests/core/full_node/full_sync/test_full_sync.py +443 -0
- chia/_tests/core/full_node/ram_db.py +27 -0
- chia/_tests/core/full_node/stores/__init__.py +0 -0
- chia/_tests/core/full_node/stores/config.py +4 -0
- chia/_tests/core/full_node/stores/test_block_store.py +590 -0
- chia/_tests/core/full_node/stores/test_coin_store.py +897 -0
- chia/_tests/core/full_node/stores/test_full_node_store.py +1219 -0
- chia/_tests/core/full_node/stores/test_hint_store.py +229 -0
- chia/_tests/core/full_node/stores/test_sync_store.py +135 -0
- chia/_tests/core/full_node/test_address_manager.py +588 -0
- chia/_tests/core/full_node/test_block_height_map.py +556 -0
- chia/_tests/core/full_node/test_conditions.py +556 -0
- chia/_tests/core/full_node/test_full_node.py +2700 -0
- chia/_tests/core/full_node/test_generator_tools.py +82 -0
- chia/_tests/core/full_node/test_hint_management.py +104 -0
- chia/_tests/core/full_node/test_node_load.py +34 -0
- chia/_tests/core/full_node/test_performance.py +179 -0
- chia/_tests/core/full_node/test_subscriptions.py +492 -0
- chia/_tests/core/full_node/test_transactions.py +203 -0
- chia/_tests/core/full_node/test_tx_processing_queue.py +155 -0
- chia/_tests/core/large_block.py +2388 -0
- chia/_tests/core/make_block_generator.py +70 -0
- chia/_tests/core/mempool/__init__.py +0 -0
- chia/_tests/core/mempool/config.py +4 -0
- chia/_tests/core/mempool/test_mempool.py +3255 -0
- chia/_tests/core/mempool/test_mempool_fee_estimator.py +104 -0
- chia/_tests/core/mempool/test_mempool_fee_protocol.py +55 -0
- chia/_tests/core/mempool/test_mempool_item_queries.py +190 -0
- chia/_tests/core/mempool/test_mempool_manager.py +2084 -0
- chia/_tests/core/mempool/test_mempool_performance.py +64 -0
- chia/_tests/core/mempool/test_singleton_fast_forward.py +567 -0
- chia/_tests/core/node_height.py +28 -0
- chia/_tests/core/server/__init__.py +0 -0
- chia/_tests/core/server/config.py +3 -0
- chia/_tests/core/server/flood.py +84 -0
- chia/_tests/core/server/serve.py +135 -0
- chia/_tests/core/server/test_api_protocol.py +21 -0
- chia/_tests/core/server/test_capabilities.py +66 -0
- chia/_tests/core/server/test_dos.py +319 -0
- chia/_tests/core/server/test_event_loop.py +109 -0
- chia/_tests/core/server/test_loop.py +294 -0
- chia/_tests/core/server/test_node_discovery.py +73 -0
- chia/_tests/core/server/test_rate_limits.py +482 -0
- chia/_tests/core/server/test_server.py +226 -0
- chia/_tests/core/server/test_upnp.py +8 -0
- chia/_tests/core/services/__init__.py +0 -0
- chia/_tests/core/services/config.py +3 -0
- chia/_tests/core/services/test_services.py +188 -0
- chia/_tests/core/ssl/__init__.py +0 -0
- chia/_tests/core/ssl/config.py +3 -0
- chia/_tests/core/ssl/test_ssl.py +202 -0
- chia/_tests/core/test_coins.py +33 -0
- chia/_tests/core/test_cost_calculation.py +313 -0
- chia/_tests/core/test_crawler.py +175 -0
- chia/_tests/core/test_crawler_rpc.py +53 -0
- chia/_tests/core/test_daemon_rpc.py +24 -0
- chia/_tests/core/test_db_conversion.py +130 -0
- chia/_tests/core/test_db_validation.py +162 -0
- chia/_tests/core/test_farmer_harvester_rpc.py +505 -0
- chia/_tests/core/test_filter.py +35 -0
- chia/_tests/core/test_full_node_rpc.py +768 -0
- chia/_tests/core/test_merkle_set.py +343 -0
- chia/_tests/core/test_program.py +47 -0
- chia/_tests/core/test_rpc_util.py +86 -0
- chia/_tests/core/test_seeder.py +420 -0
- chia/_tests/core/test_setproctitle.py +13 -0
- chia/_tests/core/util/__init__.py +0 -0
- chia/_tests/core/util/config.py +4 -0
- chia/_tests/core/util/test_block_cache.py +44 -0
- chia/_tests/core/util/test_cached_bls.py +57 -0
- chia/_tests/core/util/test_config.py +337 -0
- chia/_tests/core/util/test_file_keyring_synchronization.py +105 -0
- chia/_tests/core/util/test_files.py +391 -0
- chia/_tests/core/util/test_jsonify.py +146 -0
- chia/_tests/core/util/test_keychain.py +522 -0
- chia/_tests/core/util/test_keyring_wrapper.py +491 -0
- chia/_tests/core/util/test_lockfile.py +380 -0
- chia/_tests/core/util/test_log_exceptions.py +187 -0
- chia/_tests/core/util/test_lru_cache.py +56 -0
- chia/_tests/core/util/test_significant_bits.py +40 -0
- chia/_tests/core/util/test_streamable.py +883 -0
- chia/_tests/db/__init__.py +0 -0
- chia/_tests/db/test_db_wrapper.py +566 -0
- chia/_tests/environments/__init__.py +0 -0
- chia/_tests/environments/common.py +35 -0
- chia/_tests/environments/full_node.py +47 -0
- chia/_tests/environments/wallet.py +429 -0
- chia/_tests/ether.py +19 -0
- chia/_tests/farmer_harvester/__init__.py +0 -0
- chia/_tests/farmer_harvester/config.py +3 -0
- chia/_tests/farmer_harvester/test_farmer.py +1264 -0
- chia/_tests/farmer_harvester/test_farmer_harvester.py +292 -0
- chia/_tests/farmer_harvester/test_filter_prefix_bits.py +131 -0
- chia/_tests/farmer_harvester/test_third_party_harvesters.py +528 -0
- chia/_tests/farmer_harvester/test_third_party_harvesters_data.json +29 -0
- chia/_tests/fee_estimation/__init__.py +0 -0
- chia/_tests/fee_estimation/config.py +3 -0
- chia/_tests/fee_estimation/test_fee_estimation_integration.py +262 -0
- chia/_tests/fee_estimation/test_fee_estimation_rpc.py +287 -0
- chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +144 -0
- chia/_tests/fee_estimation/test_mempoolitem_height_added.py +146 -0
- chia/_tests/generator/__init__.py +0 -0
- chia/_tests/generator/puzzles/__init__.py +0 -0
- chia/_tests/generator/puzzles/test_generator_deserialize.clsp +3 -0
- chia/_tests/generator/puzzles/test_generator_deserialize.clsp.hex +1 -0
- chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp +19 -0
- chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp.hex +1 -0
- chia/_tests/generator/test_compression.py +201 -0
- chia/_tests/generator/test_generator_types.py +44 -0
- chia/_tests/generator/test_rom.py +180 -0
- chia/_tests/plot_sync/__init__.py +0 -0
- chia/_tests/plot_sync/config.py +3 -0
- chia/_tests/plot_sync/test_delta.py +101 -0
- chia/_tests/plot_sync/test_plot_sync.py +618 -0
- chia/_tests/plot_sync/test_receiver.py +451 -0
- chia/_tests/plot_sync/test_sender.py +116 -0
- chia/_tests/plot_sync/test_sync_simulated.py +451 -0
- chia/_tests/plot_sync/util.py +68 -0
- chia/_tests/plotting/__init__.py +0 -0
- chia/_tests/plotting/config.py +3 -0
- chia/_tests/plotting/test_plot_manager.py +781 -0
- chia/_tests/plotting/util.py +12 -0
- chia/_tests/pools/__init__.py +0 -0
- chia/_tests/pools/config.py +5 -0
- chia/_tests/pools/test_pool_cli_parsing.py +128 -0
- chia/_tests/pools/test_pool_cmdline.py +1001 -0
- chia/_tests/pools/test_pool_config.py +42 -0
- chia/_tests/pools/test_pool_puzzles_lifecycle.py +397 -0
- chia/_tests/pools/test_pool_rpc.py +1123 -0
- chia/_tests/pools/test_pool_wallet.py +205 -0
- chia/_tests/pools/test_wallet_pool_store.py +161 -0
- chia/_tests/process_junit.py +348 -0
- chia/_tests/rpc/__init__.py +0 -0
- chia/_tests/rpc/test_rpc_client.py +138 -0
- chia/_tests/rpc/test_rpc_server.py +183 -0
- chia/_tests/simulation/__init__.py +0 -0
- chia/_tests/simulation/config.py +6 -0
- chia/_tests/simulation/test_simulation.py +501 -0
- chia/_tests/simulation/test_simulator.py +232 -0
- chia/_tests/simulation/test_start_simulator.py +107 -0
- chia/_tests/testconfig.py +13 -0
- chia/_tests/timelord/__init__.py +0 -0
- chia/_tests/timelord/config.py +3 -0
- chia/_tests/timelord/test_new_peak.py +437 -0
- chia/_tests/timelord/test_timelord.py +11 -0
- chia/_tests/tools/1315537.json +170 -0
- chia/_tests/tools/1315544.json +160 -0
- chia/_tests/tools/1315630.json +150 -0
- chia/_tests/tools/300000.json +105 -0
- chia/_tests/tools/442734.json +140 -0
- chia/_tests/tools/466212.json +130 -0
- chia/_tests/tools/__init__.py +0 -0
- chia/_tests/tools/config.py +5 -0
- chia/_tests/tools/test-blockchain-db.sqlite +0 -0
- chia/_tests/tools/test_full_sync.py +30 -0
- chia/_tests/tools/test_legacy_keyring.py +82 -0
- chia/_tests/tools/test_run_block.py +128 -0
- chia/_tests/tools/test_virtual_project.py +591 -0
- chia/_tests/util/__init__.py +0 -0
- chia/_tests/util/benchmark_cost.py +170 -0
- chia/_tests/util/benchmarks.py +153 -0
- chia/_tests/util/bip39_test_vectors.json +148 -0
- chia/_tests/util/blockchain.py +134 -0
- chia/_tests/util/blockchain_mock.py +132 -0
- chia/_tests/util/build_network_protocol_files.py +302 -0
- chia/_tests/util/clvm_generator.bin +0 -0
- chia/_tests/util/config.py +3 -0
- chia/_tests/util/constants.py +20 -0
- chia/_tests/util/db_connection.py +37 -0
- chia/_tests/util/full_sync.py +253 -0
- chia/_tests/util/gen_ssl_certs.py +114 -0
- chia/_tests/util/generator_tools_testing.py +45 -0
- chia/_tests/util/get_name_puzzle_conditions.py +52 -0
- chia/_tests/util/key_tool.py +36 -0
- chia/_tests/util/misc.py +675 -0
- chia/_tests/util/network_protocol_data.py +1072 -0
- chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
- chia/_tests/util/protocol_messages_json.py +2701 -0
- chia/_tests/util/rpc.py +26 -0
- chia/_tests/util/run_block.py +163 -0
- chia/_tests/util/setup_nodes.py +481 -0
- chia/_tests/util/spend_sim.py +492 -0
- chia/_tests/util/split_managers.py +102 -0
- chia/_tests/util/temp_file.py +14 -0
- chia/_tests/util/test_action_scope.py +144 -0
- chia/_tests/util/test_async_pool.py +366 -0
- chia/_tests/util/test_build_job_matrix.py +42 -0
- chia/_tests/util/test_build_network_protocol_files.py +7 -0
- chia/_tests/util/test_chia_version.py +50 -0
- chia/_tests/util/test_collection.py +11 -0
- chia/_tests/util/test_condition_tools.py +229 -0
- chia/_tests/util/test_config.py +426 -0
- chia/_tests/util/test_dump_keyring.py +60 -0
- chia/_tests/util/test_errors.py +10 -0
- chia/_tests/util/test_full_block_utils.py +279 -0
- chia/_tests/util/test_installed.py +20 -0
- chia/_tests/util/test_limited_semaphore.py +53 -0
- chia/_tests/util/test_logging_filter.py +42 -0
- chia/_tests/util/test_misc.py +445 -0
- chia/_tests/util/test_network.py +73 -0
- chia/_tests/util/test_network_protocol_files.py +578 -0
- chia/_tests/util/test_network_protocol_json.py +267 -0
- chia/_tests/util/test_network_protocol_test.py +256 -0
- chia/_tests/util/test_paginator.py +71 -0
- chia/_tests/util/test_pprint.py +17 -0
- chia/_tests/util/test_priority_mutex.py +488 -0
- chia/_tests/util/test_recursive_replace.py +116 -0
- chia/_tests/util/test_replace_str_to_bytes.py +137 -0
- chia/_tests/util/test_service_groups.py +15 -0
- chia/_tests/util/test_ssl_check.py +31 -0
- chia/_tests/util/test_testnet_overrides.py +19 -0
- chia/_tests/util/test_tests_misc.py +38 -0
- chia/_tests/util/test_timing.py +37 -0
- chia/_tests/util/test_trusted_peer.py +51 -0
- chia/_tests/util/time_out_assert.py +191 -0
- chia/_tests/wallet/__init__.py +0 -0
- chia/_tests/wallet/cat_wallet/__init__.py +0 -0
- chia/_tests/wallet/cat_wallet/config.py +4 -0
- chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +468 -0
- chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +69 -0
- chia/_tests/wallet/cat_wallet/test_cat_wallet.py +1826 -0
- chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +291 -0
- chia/_tests/wallet/cat_wallet/test_trades.py +2600 -0
- chia/_tests/wallet/clawback/__init__.py +0 -0
- chia/_tests/wallet/clawback/config.py +3 -0
- chia/_tests/wallet/clawback/test_clawback_decorator.py +78 -0
- chia/_tests/wallet/clawback/test_clawback_lifecycle.py +292 -0
- chia/_tests/wallet/clawback/test_clawback_metadata.py +50 -0
- chia/_tests/wallet/config.py +4 -0
- chia/_tests/wallet/conftest.py +278 -0
- chia/_tests/wallet/dao_wallet/__init__.py +0 -0
- chia/_tests/wallet/dao_wallet/config.py +3 -0
- chia/_tests/wallet/dao_wallet/test_dao_clvm.py +1330 -0
- chia/_tests/wallet/dao_wallet/test_dao_wallets.py +3488 -0
- chia/_tests/wallet/db_wallet/__init__.py +0 -0
- chia/_tests/wallet/db_wallet/config.py +3 -0
- chia/_tests/wallet/db_wallet/test_db_graftroot.py +141 -0
- chia/_tests/wallet/db_wallet/test_dl_offers.py +491 -0
- chia/_tests/wallet/db_wallet/test_dl_wallet.py +823 -0
- chia/_tests/wallet/did_wallet/__init__.py +0 -0
- chia/_tests/wallet/did_wallet/config.py +4 -0
- chia/_tests/wallet/did_wallet/test_did.py +2284 -0
- chia/_tests/wallet/nft_wallet/__init__.py +0 -0
- chia/_tests/wallet/nft_wallet/config.py +4 -0
- chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +1493 -0
- chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +1024 -0
- chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +375 -0
- chia/_tests/wallet/nft_wallet/test_nft_offers.py +1209 -0
- chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +172 -0
- chia/_tests/wallet/nft_wallet/test_nft_wallet.py +2584 -0
- chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +70 -0
- chia/_tests/wallet/rpc/__init__.py +0 -0
- chia/_tests/wallet/rpc/config.py +4 -0
- chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +285 -0
- chia/_tests/wallet/rpc/test_wallet_rpc.py +3153 -0
- chia/_tests/wallet/simple_sync/__init__.py +0 -0
- chia/_tests/wallet/simple_sync/config.py +3 -0
- chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +718 -0
- chia/_tests/wallet/sync/__init__.py +0 -0
- chia/_tests/wallet/sync/config.py +4 -0
- chia/_tests/wallet/sync/test_wallet_sync.py +1692 -0
- chia/_tests/wallet/test_address_type.py +189 -0
- chia/_tests/wallet/test_bech32m.py +45 -0
- chia/_tests/wallet/test_clvm_streamable.py +244 -0
- chia/_tests/wallet/test_coin_management.py +354 -0
- chia/_tests/wallet/test_coin_selection.py +588 -0
- chia/_tests/wallet/test_conditions.py +400 -0
- chia/_tests/wallet/test_debug_spend_bundle.py +218 -0
- chia/_tests/wallet/test_new_wallet_protocol.py +1174 -0
- chia/_tests/wallet/test_nft_store.py +192 -0
- chia/_tests/wallet/test_notifications.py +196 -0
- chia/_tests/wallet/test_offer_parsing_performance.py +48 -0
- chia/_tests/wallet/test_puzzle_store.py +132 -0
- chia/_tests/wallet/test_sign_coin_spends.py +159 -0
- chia/_tests/wallet/test_signer_protocol.py +947 -0
- chia/_tests/wallet/test_singleton.py +122 -0
- chia/_tests/wallet/test_singleton_lifecycle_fast.py +772 -0
- chia/_tests/wallet/test_singleton_store.py +152 -0
- chia/_tests/wallet/test_taproot.py +19 -0
- chia/_tests/wallet/test_transaction_store.py +945 -0
- chia/_tests/wallet/test_util.py +185 -0
- chia/_tests/wallet/test_wallet.py +2139 -0
- chia/_tests/wallet/test_wallet_action_scope.py +85 -0
- chia/_tests/wallet/test_wallet_blockchain.py +111 -0
- chia/_tests/wallet/test_wallet_coin_store.py +1002 -0
- chia/_tests/wallet/test_wallet_interested_store.py +43 -0
- chia/_tests/wallet/test_wallet_key_val_store.py +40 -0
- chia/_tests/wallet/test_wallet_node.py +780 -0
- chia/_tests/wallet/test_wallet_retry.py +95 -0
- chia/_tests/wallet/test_wallet_state_manager.py +259 -0
- chia/_tests/wallet/test_wallet_test_framework.py +275 -0
- chia/_tests/wallet/test_wallet_trade_store.py +218 -0
- chia/_tests/wallet/test_wallet_user_store.py +34 -0
- chia/_tests/wallet/test_wallet_utils.py +156 -0
- chia/_tests/wallet/vc_wallet/__init__.py +0 -0
- chia/_tests/wallet/vc_wallet/config.py +3 -0
- chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +70 -0
- chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +883 -0
- chia/_tests/wallet/vc_wallet/test_vc_wallet.py +830 -0
- chia/_tests/wallet/wallet_block_tools.py +327 -0
- chia/_tests/weight_proof/__init__.py +0 -0
- chia/_tests/weight_proof/config.py +3 -0
- chia/_tests/weight_proof/test_weight_proof.py +528 -0
- chia/apis.py +19 -0
- chia/clvm/__init__.py +0 -0
- chia/cmds/__init__.py +0 -0
- chia/cmds/beta.py +184 -0
- chia/cmds/beta_funcs.py +137 -0
- chia/cmds/check_wallet_db.py +420 -0
- chia/cmds/chia.py +151 -0
- chia/cmds/cmd_classes.py +323 -0
- chia/cmds/cmd_helpers.py +242 -0
- chia/cmds/cmds_util.py +488 -0
- chia/cmds/coin_funcs.py +275 -0
- chia/cmds/coins.py +182 -0
- chia/cmds/completion.py +49 -0
- chia/cmds/configure.py +332 -0
- chia/cmds/dao.py +1064 -0
- chia/cmds/dao_funcs.py +598 -0
- chia/cmds/data.py +708 -0
- chia/cmds/data_funcs.py +385 -0
- chia/cmds/db.py +87 -0
- chia/cmds/db_backup_func.py +77 -0
- chia/cmds/db_upgrade_func.py +452 -0
- chia/cmds/db_validate_func.py +184 -0
- chia/cmds/dev.py +18 -0
- chia/cmds/farm.py +100 -0
- chia/cmds/farm_funcs.py +200 -0
- chia/cmds/gh.py +275 -0
- chia/cmds/init.py +63 -0
- chia/cmds/init_funcs.py +367 -0
- chia/cmds/installers.py +131 -0
- chia/cmds/keys.py +527 -0
- chia/cmds/keys_funcs.py +863 -0
- chia/cmds/netspace.py +50 -0
- chia/cmds/netspace_funcs.py +54 -0
- chia/cmds/options.py +32 -0
- chia/cmds/param_types.py +238 -0
- chia/cmds/passphrase.py +131 -0
- chia/cmds/passphrase_funcs.py +292 -0
- chia/cmds/peer.py +51 -0
- chia/cmds/peer_funcs.py +129 -0
- chia/cmds/plotnft.py +260 -0
- chia/cmds/plotnft_funcs.py +405 -0
- chia/cmds/plots.py +230 -0
- chia/cmds/plotters.py +18 -0
- chia/cmds/rpc.py +208 -0
- chia/cmds/show.py +72 -0
- chia/cmds/show_funcs.py +215 -0
- chia/cmds/signer.py +296 -0
- chia/cmds/sim.py +225 -0
- chia/cmds/sim_funcs.py +509 -0
- chia/cmds/start.py +24 -0
- chia/cmds/start_funcs.py +109 -0
- chia/cmds/stop.py +62 -0
- chia/cmds/units.py +9 -0
- chia/cmds/wallet.py +1901 -0
- chia/cmds/wallet_funcs.py +1874 -0
- chia/consensus/__init__.py +0 -0
- chia/consensus/block_body_validation.py +562 -0
- chia/consensus/block_creation.py +546 -0
- chia/consensus/block_header_validation.py +1059 -0
- chia/consensus/block_record.py +31 -0
- chia/consensus/block_rewards.py +53 -0
- chia/consensus/blockchain.py +1087 -0
- chia/consensus/blockchain_interface.py +56 -0
- chia/consensus/coinbase.py +30 -0
- chia/consensus/condition_costs.py +9 -0
- chia/consensus/constants.py +49 -0
- chia/consensus/cost_calculator.py +15 -0
- chia/consensus/default_constants.py +89 -0
- chia/consensus/deficit.py +55 -0
- chia/consensus/difficulty_adjustment.py +412 -0
- chia/consensus/find_fork_point.py +111 -0
- chia/consensus/full_block_to_block_record.py +167 -0
- chia/consensus/get_block_challenge.py +106 -0
- chia/consensus/get_block_generator.py +27 -0
- chia/consensus/make_sub_epoch_summary.py +210 -0
- chia/consensus/multiprocess_validation.py +268 -0
- chia/consensus/pos_quality.py +19 -0
- chia/consensus/pot_iterations.py +67 -0
- chia/consensus/puzzles/__init__.py +0 -0
- chia/consensus/puzzles/chialisp_deserialisation.clsp +69 -0
- chia/consensus/puzzles/chialisp_deserialisation.clsp.hex +1 -0
- chia/consensus/puzzles/rom_bootstrap_generator.clsp +37 -0
- chia/consensus/puzzles/rom_bootstrap_generator.clsp.hex +1 -0
- chia/consensus/vdf_info_computation.py +156 -0
- chia/daemon/__init__.py +0 -0
- chia/daemon/client.py +252 -0
- chia/daemon/keychain_proxy.py +502 -0
- chia/daemon/keychain_server.py +365 -0
- chia/daemon/server.py +1606 -0
- chia/daemon/windows_signal.py +56 -0
- chia/data_layer/__init__.py +0 -0
- chia/data_layer/data_layer.py +1291 -0
- chia/data_layer/data_layer_api.py +33 -0
- chia/data_layer/data_layer_errors.py +50 -0
- chia/data_layer/data_layer_server.py +170 -0
- chia/data_layer/data_layer_util.py +985 -0
- chia/data_layer/data_layer_wallet.py +1311 -0
- chia/data_layer/data_store.py +2267 -0
- chia/data_layer/dl_wallet_store.py +407 -0
- chia/data_layer/download_data.py +389 -0
- chia/data_layer/puzzles/__init__.py +0 -0
- chia/data_layer/puzzles/graftroot_dl_offers.clsp +100 -0
- chia/data_layer/puzzles/graftroot_dl_offers.clsp.hex +1 -0
- chia/data_layer/s3_plugin_config.yml +33 -0
- chia/data_layer/s3_plugin_service.py +468 -0
- chia/data_layer/util/__init__.py +0 -0
- chia/data_layer/util/benchmark.py +107 -0
- chia/data_layer/util/plugin.py +40 -0
- chia/farmer/__init__.py +0 -0
- chia/farmer/farmer.py +923 -0
- chia/farmer/farmer_api.py +820 -0
- chia/full_node/__init__.py +0 -0
- chia/full_node/bitcoin_fee_estimator.py +85 -0
- chia/full_node/block_height_map.py +271 -0
- chia/full_node/block_store.py +576 -0
- chia/full_node/bundle_tools.py +19 -0
- chia/full_node/coin_store.py +647 -0
- chia/full_node/fee_estimate.py +54 -0
- chia/full_node/fee_estimate_store.py +24 -0
- chia/full_node/fee_estimation.py +92 -0
- chia/full_node/fee_estimator.py +90 -0
- chia/full_node/fee_estimator_constants.py +38 -0
- chia/full_node/fee_estimator_interface.py +42 -0
- chia/full_node/fee_history.py +25 -0
- chia/full_node/fee_tracker.py +564 -0
- chia/full_node/full_node.py +3327 -0
- chia/full_node/full_node_api.py +2025 -0
- chia/full_node/full_node_store.py +1033 -0
- chia/full_node/hint_management.py +56 -0
- chia/full_node/hint_store.py +93 -0
- chia/full_node/mempool.py +589 -0
- chia/full_node/mempool_check_conditions.py +146 -0
- chia/full_node/mempool_manager.py +853 -0
- chia/full_node/pending_tx_cache.py +112 -0
- chia/full_node/puzzles/__init__.py +0 -0
- chia/full_node/puzzles/block_program_zero.clsp +14 -0
- chia/full_node/puzzles/block_program_zero.clsp.hex +1 -0
- chia/full_node/puzzles/decompress_coin_spend_entry.clsp +5 -0
- chia/full_node/puzzles/decompress_coin_spend_entry.clsp.hex +1 -0
- chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp +7 -0
- chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp.hex +1 -0
- chia/full_node/puzzles/decompress_puzzle.clsp +6 -0
- chia/full_node/puzzles/decompress_puzzle.clsp.hex +1 -0
- chia/full_node/signage_point.py +16 -0
- chia/full_node/subscriptions.py +247 -0
- chia/full_node/sync_store.py +146 -0
- chia/full_node/tx_processing_queue.py +78 -0
- chia/full_node/util/__init__.py +0 -0
- chia/full_node/weight_proof.py +1720 -0
- chia/harvester/__init__.py +0 -0
- chia/harvester/harvester.py +272 -0
- chia/harvester/harvester_api.py +380 -0
- chia/introducer/__init__.py +0 -0
- chia/introducer/introducer.py +122 -0
- chia/introducer/introducer_api.py +70 -0
- chia/legacy/__init__.py +0 -0
- chia/legacy/keyring.py +155 -0
- chia/plot_sync/__init__.py +0 -0
- chia/plot_sync/delta.py +61 -0
- chia/plot_sync/exceptions.py +56 -0
- chia/plot_sync/receiver.py +386 -0
- chia/plot_sync/sender.py +340 -0
- chia/plot_sync/util.py +43 -0
- chia/plotters/__init__.py +0 -0
- chia/plotters/bladebit.py +388 -0
- chia/plotters/chiapos.py +63 -0
- chia/plotters/madmax.py +224 -0
- chia/plotters/plotters.py +577 -0
- chia/plotters/plotters_util.py +133 -0
- chia/plotting/__init__.py +0 -0
- chia/plotting/cache.py +213 -0
- chia/plotting/check_plots.py +283 -0
- chia/plotting/create_plots.py +278 -0
- chia/plotting/manager.py +436 -0
- chia/plotting/util.py +336 -0
- chia/pools/__init__.py +0 -0
- chia/pools/pool_config.py +110 -0
- chia/pools/pool_puzzles.py +459 -0
- chia/pools/pool_wallet.py +933 -0
- chia/pools/pool_wallet_info.py +118 -0
- chia/pools/puzzles/__init__.py +0 -0
- chia/pools/puzzles/pool_member_innerpuz.clsp +70 -0
- chia/pools/puzzles/pool_member_innerpuz.clsp.hex +1 -0
- chia/pools/puzzles/pool_waitingroom_innerpuz.clsp +69 -0
- chia/pools/puzzles/pool_waitingroom_innerpuz.clsp.hex +1 -0
- chia/protocols/__init__.py +0 -0
- chia/protocols/farmer_protocol.py +102 -0
- chia/protocols/full_node_protocol.py +219 -0
- chia/protocols/harvester_protocol.py +216 -0
- chia/protocols/introducer_protocol.py +25 -0
- chia/protocols/pool_protocol.py +177 -0
- chia/protocols/protocol_message_types.py +139 -0
- chia/protocols/protocol_state_machine.py +87 -0
- chia/protocols/protocol_timing.py +8 -0
- chia/protocols/shared_protocol.py +86 -0
- chia/protocols/timelord_protocol.py +93 -0
- chia/protocols/wallet_protocol.py +401 -0
- chia/py.typed +0 -0
- chia/rpc/__init__.py +0 -0
- chia/rpc/crawler_rpc_api.py +80 -0
- chia/rpc/data_layer_rpc_api.py +644 -0
- chia/rpc/data_layer_rpc_client.py +188 -0
- chia/rpc/data_layer_rpc_util.py +58 -0
- chia/rpc/farmer_rpc_api.py +365 -0
- chia/rpc/farmer_rpc_client.py +86 -0
- chia/rpc/full_node_rpc_api.py +959 -0
- chia/rpc/full_node_rpc_client.py +292 -0
- chia/rpc/harvester_rpc_api.py +141 -0
- chia/rpc/harvester_rpc_client.py +54 -0
- chia/rpc/rpc_client.py +164 -0
- chia/rpc/rpc_server.py +521 -0
- chia/rpc/timelord_rpc_api.py +32 -0
- chia/rpc/util.py +93 -0
- chia/rpc/wallet_request_types.py +904 -0
- chia/rpc/wallet_rpc_api.py +4943 -0
- chia/rpc/wallet_rpc_client.py +1814 -0
- chia/seeder/__init__.py +0 -0
- chia/seeder/crawl_store.py +425 -0
- chia/seeder/crawler.py +410 -0
- chia/seeder/crawler_api.py +135 -0
- chia/seeder/dns_server.py +593 -0
- chia/seeder/peer_record.py +146 -0
- chia/seeder/start_crawler.py +92 -0
- chia/server/__init__.py +0 -0
- chia/server/address_manager.py +658 -0
- chia/server/address_manager_store.py +237 -0
- chia/server/api_protocol.py +116 -0
- chia/server/capabilities.py +24 -0
- chia/server/chia_policy.py +346 -0
- chia/server/introducer_peers.py +76 -0
- chia/server/node_discovery.py +714 -0
- chia/server/outbound_message.py +33 -0
- chia/server/rate_limit_numbers.py +214 -0
- chia/server/rate_limits.py +153 -0
- chia/server/server.py +741 -0
- chia/server/signal_handlers.py +120 -0
- chia/server/ssl_context.py +32 -0
- chia/server/start_data_layer.py +151 -0
- chia/server/start_farmer.py +98 -0
- chia/server/start_full_node.py +112 -0
- chia/server/start_harvester.py +93 -0
- chia/server/start_introducer.py +81 -0
- chia/server/start_service.py +316 -0
- chia/server/start_timelord.py +89 -0
- chia/server/start_wallet.py +113 -0
- chia/server/upnp.py +118 -0
- chia/server/ws_connection.py +766 -0
- chia/simulator/__init__.py +0 -0
- chia/simulator/add_blocks_in_batches.py +54 -0
- chia/simulator/block_tools.py +2054 -0
- chia/simulator/full_node_simulator.py +794 -0
- chia/simulator/keyring.py +128 -0
- chia/simulator/setup_services.py +506 -0
- chia/simulator/simulator_constants.py +13 -0
- chia/simulator/simulator_full_node_rpc_api.py +99 -0
- chia/simulator/simulator_full_node_rpc_client.py +60 -0
- chia/simulator/simulator_protocol.py +29 -0
- chia/simulator/simulator_test_tools.py +164 -0
- chia/simulator/socket.py +24 -0
- chia/simulator/ssl_certs.py +114 -0
- chia/simulator/ssl_certs_1.py +697 -0
- chia/simulator/ssl_certs_10.py +697 -0
- chia/simulator/ssl_certs_2.py +697 -0
- chia/simulator/ssl_certs_3.py +697 -0
- chia/simulator/ssl_certs_4.py +697 -0
- chia/simulator/ssl_certs_5.py +697 -0
- chia/simulator/ssl_certs_6.py +697 -0
- chia/simulator/ssl_certs_7.py +697 -0
- chia/simulator/ssl_certs_8.py +697 -0
- chia/simulator/ssl_certs_9.py +697 -0
- chia/simulator/start_simulator.py +143 -0
- chia/simulator/wallet_tools.py +246 -0
- chia/ssl/__init__.py +0 -0
- chia/ssl/chia_ca.crt +19 -0
- chia/ssl/chia_ca.key +28 -0
- chia/ssl/create_ssl.py +249 -0
- chia/ssl/dst_root_ca.pem +20 -0
- chia/timelord/__init__.py +0 -0
- chia/timelord/iters_from_block.py +50 -0
- chia/timelord/timelord.py +1226 -0
- chia/timelord/timelord_api.py +138 -0
- chia/timelord/timelord_launcher.py +190 -0
- chia/timelord/timelord_state.py +244 -0
- chia/timelord/types.py +22 -0
- chia/types/__init__.py +0 -0
- chia/types/aliases.py +35 -0
- chia/types/block_protocol.py +20 -0
- chia/types/blockchain_format/__init__.py +0 -0
- chia/types/blockchain_format/classgroup.py +5 -0
- chia/types/blockchain_format/coin.py +28 -0
- chia/types/blockchain_format/foliage.py +8 -0
- chia/types/blockchain_format/pool_target.py +5 -0
- chia/types/blockchain_format/program.py +269 -0
- chia/types/blockchain_format/proof_of_space.py +135 -0
- chia/types/blockchain_format/reward_chain_block.py +6 -0
- chia/types/blockchain_format/serialized_program.py +5 -0
- chia/types/blockchain_format/sized_bytes.py +11 -0
- chia/types/blockchain_format/slots.py +9 -0
- chia/types/blockchain_format/sub_epoch_summary.py +5 -0
- chia/types/blockchain_format/tree_hash.py +72 -0
- chia/types/blockchain_format/vdf.py +86 -0
- chia/types/clvm_cost.py +13 -0
- chia/types/coin_record.py +43 -0
- chia/types/coin_spend.py +115 -0
- chia/types/condition_opcodes.py +73 -0
- chia/types/condition_with_args.py +16 -0
- chia/types/eligible_coin_spends.py +365 -0
- chia/types/end_of_slot_bundle.py +5 -0
- chia/types/fee_rate.py +38 -0
- chia/types/full_block.py +5 -0
- chia/types/generator_types.py +13 -0
- chia/types/header_block.py +5 -0
- chia/types/internal_mempool_item.py +18 -0
- chia/types/mempool_inclusion_status.py +9 -0
- chia/types/mempool_item.py +85 -0
- chia/types/mempool_submission_status.py +30 -0
- chia/types/mojos.py +7 -0
- chia/types/peer_info.py +64 -0
- chia/types/signing_mode.py +29 -0
- chia/types/spend_bundle.py +30 -0
- chia/types/spend_bundle_conditions.py +7 -0
- chia/types/transaction_queue_entry.py +55 -0
- chia/types/unfinished_block.py +5 -0
- chia/types/unfinished_header_block.py +37 -0
- chia/types/validation_state.py +14 -0
- chia/types/weight_proof.py +49 -0
- chia/util/__init__.py +0 -0
- chia/util/action_scope.py +168 -0
- chia/util/async_pool.py +226 -0
- chia/util/augmented_chain.py +134 -0
- chia/util/batches.py +42 -0
- chia/util/bech32m.py +126 -0
- chia/util/beta_metrics.py +119 -0
- chia/util/block_cache.py +56 -0
- chia/util/byte_types.py +12 -0
- chia/util/check_fork_next_block.py +33 -0
- chia/util/chia_logging.py +144 -0
- chia/util/chia_version.py +33 -0
- chia/util/collection.py +17 -0
- chia/util/condition_tools.py +201 -0
- chia/util/config.py +367 -0
- chia/util/cpu.py +22 -0
- chia/util/db_synchronous.py +23 -0
- chia/util/db_version.py +32 -0
- chia/util/db_wrapper.py +430 -0
- chia/util/default_root.py +27 -0
- chia/util/dump_keyring.py +93 -0
- chia/util/english.txt +2048 -0
- chia/util/errors.py +353 -0
- chia/util/file_keyring.py +469 -0
- chia/util/files.py +97 -0
- chia/util/full_block_utils.py +345 -0
- chia/util/generator_tools.py +72 -0
- chia/util/hash.py +31 -0
- chia/util/initial-config.yaml +694 -0
- chia/util/inline_executor.py +26 -0
- chia/util/ints.py +19 -0
- chia/util/ip_address.py +39 -0
- chia/util/json_util.py +37 -0
- chia/util/keychain.py +676 -0
- chia/util/keyring_wrapper.py +327 -0
- chia/util/limited_semaphore.py +41 -0
- chia/util/lock.py +49 -0
- chia/util/log_exceptions.py +32 -0
- chia/util/logging.py +36 -0
- chia/util/lru_cache.py +31 -0
- chia/util/math.py +20 -0
- chia/util/network.py +182 -0
- chia/util/paginator.py +48 -0
- chia/util/path.py +31 -0
- chia/util/permissions.py +20 -0
- chia/util/prev_transaction_block.py +21 -0
- chia/util/priority_mutex.py +95 -0
- chia/util/profiler.py +197 -0
- chia/util/recursive_replace.py +24 -0
- chia/util/safe_cancel_task.py +16 -0
- chia/util/service_groups.py +47 -0
- chia/util/setproctitle.py +22 -0
- chia/util/significant_bits.py +32 -0
- chia/util/ssl_check.py +213 -0
- chia/util/streamable.py +642 -0
- chia/util/task_referencer.py +59 -0
- chia/util/task_timing.py +382 -0
- chia/util/timing.py +67 -0
- chia/util/vdf_prover.py +30 -0
- chia/util/virtual_project_analysis.py +540 -0
- chia/util/ws_message.py +66 -0
- chia/wallet/__init__.py +0 -0
- chia/wallet/cat_wallet/__init__.py +0 -0
- chia/wallet/cat_wallet/cat_constants.py +75 -0
- chia/wallet/cat_wallet/cat_info.py +47 -0
- chia/wallet/cat_wallet/cat_outer_puzzle.py +120 -0
- chia/wallet/cat_wallet/cat_utils.py +164 -0
- chia/wallet/cat_wallet/cat_wallet.py +855 -0
- chia/wallet/cat_wallet/dao_cat_info.py +28 -0
- chia/wallet/cat_wallet/dao_cat_wallet.py +669 -0
- chia/wallet/cat_wallet/lineage_store.py +74 -0
- chia/wallet/cat_wallet/puzzles/__init__.py +0 -0
- chia/wallet/cat_wallet/puzzles/cat_truths.clib +31 -0
- chia/wallet/cat_wallet/puzzles/cat_v2.clsp +397 -0
- chia/wallet/cat_wallet/puzzles/cat_v2.clsp.hex +1 -0
- chia/wallet/cat_wallet/puzzles/delegated_tail.clsp +25 -0
- chia/wallet/cat_wallet/puzzles/delegated_tail.clsp.hex +1 -0
- chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp +15 -0
- chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp.hex +1 -0
- chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp +26 -0
- chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp.hex +1 -0
- chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp +42 -0
- chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp.hex +1 -0
- chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp +24 -0
- chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp.hex +1 -0
- chia/wallet/coin_selection.py +188 -0
- chia/wallet/conditions.py +1512 -0
- chia/wallet/dao_wallet/__init__.py +0 -0
- chia/wallet/dao_wallet/dao_info.py +61 -0
- chia/wallet/dao_wallet/dao_utils.py +811 -0
- chia/wallet/dao_wallet/dao_wallet.py +2119 -0
- chia/wallet/db_wallet/__init__.py +0 -0
- chia/wallet/db_wallet/db_wallet_puzzles.py +111 -0
- chia/wallet/derivation_record.py +30 -0
- chia/wallet/derive_keys.py +146 -0
- chia/wallet/did_wallet/__init__.py +0 -0
- chia/wallet/did_wallet/did_info.py +39 -0
- chia/wallet/did_wallet/did_wallet.py +1494 -0
- chia/wallet/did_wallet/did_wallet_puzzles.py +221 -0
- chia/wallet/did_wallet/puzzles/__init__.py +0 -0
- chia/wallet/did_wallet/puzzles/did_innerpuz.clsp +135 -0
- chia/wallet/did_wallet/puzzles/did_innerpuz.clsp.hex +1 -0
- chia/wallet/driver_protocol.py +26 -0
- chia/wallet/key_val_store.py +55 -0
- chia/wallet/lineage_proof.py +58 -0
- chia/wallet/nft_wallet/__init__.py +0 -0
- chia/wallet/nft_wallet/metadata_outer_puzzle.py +92 -0
- chia/wallet/nft_wallet/nft_info.py +120 -0
- chia/wallet/nft_wallet/nft_puzzles.py +305 -0
- chia/wallet/nft_wallet/nft_wallet.py +1687 -0
- chia/wallet/nft_wallet/ownership_outer_puzzle.py +101 -0
- chia/wallet/nft_wallet/puzzles/__init__.py +0 -0
- chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp +6 -0
- chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp.hex +1 -0
- chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp +6 -0
- chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp.hex +1 -0
- chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp +30 -0
- chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp.hex +1 -0
- chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp +28 -0
- chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp.hex +1 -0
- chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp +100 -0
- chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp.hex +1 -0
- chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp +78 -0
- chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp.hex +1 -0
- chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp +74 -0
- chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp.hex +1 -0
- chia/wallet/nft_wallet/singleton_outer_puzzle.py +101 -0
- chia/wallet/nft_wallet/transfer_program_puzzle.py +82 -0
- chia/wallet/nft_wallet/uncurry_nft.py +217 -0
- chia/wallet/notification_manager.py +117 -0
- chia/wallet/notification_store.py +178 -0
- chia/wallet/outer_puzzles.py +84 -0
- chia/wallet/payment.py +33 -0
- chia/wallet/puzzle_drivers.py +118 -0
- chia/wallet/puzzles/__init__.py +0 -0
- chia/wallet/puzzles/augmented_condition.clsp +13 -0
- chia/wallet/puzzles/augmented_condition.clsp.hex +1 -0
- chia/wallet/puzzles/clawback/__init__.py +0 -0
- chia/wallet/puzzles/clawback/drivers.py +188 -0
- chia/wallet/puzzles/clawback/metadata.py +38 -0
- chia/wallet/puzzles/clawback/puzzle_decorator.py +67 -0
- chia/wallet/puzzles/condition_codes.clib +77 -0
- chia/wallet/puzzles/curry-and-treehash.clib +102 -0
- chia/wallet/puzzles/curry.clib +135 -0
- chia/wallet/puzzles/curry_by_index.clib +16 -0
- chia/wallet/puzzles/dao_cat_eve.clsp +17 -0
- chia/wallet/puzzles/dao_cat_eve.clsp.hex +1 -0
- chia/wallet/puzzles/dao_cat_launcher.clsp +36 -0
- chia/wallet/puzzles/dao_cat_launcher.clsp.hex +1 -0
- chia/wallet/puzzles/dao_finished_state.clsp +35 -0
- chia/wallet/puzzles/dao_finished_state.clsp.hex +1 -0
- chia/wallet/puzzles/dao_finished_state.clsp.hex.sha256tree +1 -0
- chia/wallet/puzzles/dao_lockup.clsp +288 -0
- chia/wallet/puzzles/dao_lockup.clsp.hex +1 -0
- chia/wallet/puzzles/dao_lockup.clsp.hex.sha256tree +1 -0
- chia/wallet/puzzles/dao_proposal.clsp +377 -0
- chia/wallet/puzzles/dao_proposal.clsp.hex +1 -0
- chia/wallet/puzzles/dao_proposal.clsp.hex.sha256tree +1 -0
- chia/wallet/puzzles/dao_proposal_timer.clsp +78 -0
- chia/wallet/puzzles/dao_proposal_timer.clsp.hex +1 -0
- chia/wallet/puzzles/dao_proposal_timer.clsp.hex.sha256tree +1 -0
- chia/wallet/puzzles/dao_proposal_validator.clsp +87 -0
- chia/wallet/puzzles/dao_proposal_validator.clsp.hex +1 -0
- chia/wallet/puzzles/dao_proposal_validator.clsp.hex.sha256tree +1 -0
- chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp +240 -0
- chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex +1 -0
- chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex.sha256tree +1 -0
- chia/wallet/puzzles/dao_treasury.clsp +115 -0
- chia/wallet/puzzles/dao_treasury.clsp.hex +1 -0
- chia/wallet/puzzles/dao_update_proposal.clsp +44 -0
- chia/wallet/puzzles/dao_update_proposal.clsp.hex +1 -0
- chia/wallet/puzzles/deployed_puzzle_hashes.json +67 -0
- chia/wallet/puzzles/json.clib +25 -0
- chia/wallet/puzzles/load_clvm.py +161 -0
- chia/wallet/puzzles/merkle_utils.clib +18 -0
- chia/wallet/puzzles/notification.clsp +7 -0
- chia/wallet/puzzles/notification.clsp.hex +1 -0
- chia/wallet/puzzles/p2_1_of_n.clsp +22 -0
- chia/wallet/puzzles/p2_1_of_n.clsp.hex +1 -0
- chia/wallet/puzzles/p2_conditions.clsp +3 -0
- chia/wallet/puzzles/p2_conditions.clsp.hex +1 -0
- chia/wallet/puzzles/p2_conditions.py +26 -0
- chia/wallet/puzzles/p2_delegated_conditions.clsp +18 -0
- chia/wallet/puzzles/p2_delegated_conditions.clsp.hex +1 -0
- chia/wallet/puzzles/p2_delegated_conditions.py +21 -0
- chia/wallet/puzzles/p2_delegated_puzzle.clsp +19 -0
- chia/wallet/puzzles/p2_delegated_puzzle.clsp.hex +1 -0
- chia/wallet/puzzles/p2_delegated_puzzle.py +34 -0
- chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp +91 -0
- chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp.hex +1 -0
- chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +160 -0
- chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp +108 -0
- chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp.hex +1 -0
- chia/wallet/puzzles/p2_m_of_n_delegate_direct.py +21 -0
- chia/wallet/puzzles/p2_parent.clsp +19 -0
- chia/wallet/puzzles/p2_parent.clsp.hex +1 -0
- chia/wallet/puzzles/p2_puzzle_hash.clsp +18 -0
- chia/wallet/puzzles/p2_puzzle_hash.clsp.hex +1 -0
- chia/wallet/puzzles/p2_puzzle_hash.py +27 -0
- chia/wallet/puzzles/p2_singleton.clsp +30 -0
- chia/wallet/puzzles/p2_singleton.clsp.hex +1 -0
- chia/wallet/puzzles/p2_singleton_aggregator.clsp +81 -0
- chia/wallet/puzzles/p2_singleton_aggregator.clsp.hex +1 -0
- chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp +50 -0
- chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp.hex +1 -0
- chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp +47 -0
- chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp.hex +1 -0
- chia/wallet/puzzles/puzzle_utils.py +34 -0
- chia/wallet/puzzles/settlement_payments.clsp +49 -0
- chia/wallet/puzzles/settlement_payments.clsp.hex +1 -0
- chia/wallet/puzzles/sha256tree.clib +11 -0
- chia/wallet/puzzles/singleton_launcher.clsp +16 -0
- chia/wallet/puzzles/singleton_launcher.clsp.hex +1 -0
- chia/wallet/puzzles/singleton_top_layer.clsp +177 -0
- chia/wallet/puzzles/singleton_top_layer.clsp.hex +1 -0
- chia/wallet/puzzles/singleton_top_layer.py +296 -0
- chia/wallet/puzzles/singleton_top_layer_v1_1.clsp +107 -0
- chia/wallet/puzzles/singleton_top_layer_v1_1.clsp.hex +1 -0
- chia/wallet/puzzles/singleton_top_layer_v1_1.py +345 -0
- chia/wallet/puzzles/singleton_truths.clib +21 -0
- chia/wallet/puzzles/tails.py +348 -0
- chia/wallet/puzzles/utility_macros.clib +48 -0
- chia/wallet/signer_protocol.py +125 -0
- chia/wallet/singleton.py +106 -0
- chia/wallet/singleton_record.py +30 -0
- chia/wallet/trade_manager.py +1102 -0
- chia/wallet/trade_record.py +67 -0
- chia/wallet/trading/__init__.py +0 -0
- chia/wallet/trading/offer.py +702 -0
- chia/wallet/trading/trade_status.py +13 -0
- chia/wallet/trading/trade_store.py +526 -0
- chia/wallet/transaction_record.py +158 -0
- chia/wallet/transaction_sorting.py +14 -0
- chia/wallet/uncurried_puzzle.py +17 -0
- chia/wallet/util/__init__.py +0 -0
- chia/wallet/util/address_type.py +55 -0
- chia/wallet/util/blind_signer_tl.py +164 -0
- chia/wallet/util/clvm_streamable.py +203 -0
- chia/wallet/util/compute_hints.py +66 -0
- chia/wallet/util/compute_memos.py +43 -0
- chia/wallet/util/curry_and_treehash.py +91 -0
- chia/wallet/util/debug_spend_bundle.py +232 -0
- chia/wallet/util/merkle_tree.py +100 -0
- chia/wallet/util/merkle_utils.py +102 -0
- chia/wallet/util/new_peak_queue.py +82 -0
- chia/wallet/util/notifications.py +12 -0
- chia/wallet/util/peer_request_cache.py +174 -0
- chia/wallet/util/pprint.py +39 -0
- chia/wallet/util/puzzle_compression.py +95 -0
- chia/wallet/util/puzzle_decorator.py +100 -0
- chia/wallet/util/puzzle_decorator_type.py +7 -0
- chia/wallet/util/query_filter.py +59 -0
- chia/wallet/util/transaction_type.py +23 -0
- chia/wallet/util/tx_config.py +158 -0
- chia/wallet/util/wallet_sync_utils.py +351 -0
- chia/wallet/util/wallet_types.py +72 -0
- chia/wallet/vc_wallet/__init__.py +0 -0
- chia/wallet/vc_wallet/cr_cat_drivers.py +664 -0
- chia/wallet/vc_wallet/cr_cat_wallet.py +877 -0
- chia/wallet/vc_wallet/cr_outer_puzzle.py +102 -0
- chia/wallet/vc_wallet/cr_puzzles/__init__.py +0 -0
- chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp +3 -0
- chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp.hex +1 -0
- chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp +304 -0
- chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp.hex +1 -0
- chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp +45 -0
- chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_drivers.py +838 -0
- chia/wallet/vc_wallet/vc_puzzles/__init__.py +0 -0
- chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp +30 -0
- chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp +75 -0
- chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp +32 -0
- chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp +80 -0
- chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp +163 -0
- chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp +16 -0
- chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp +74 -0
- chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp +23 -0
- chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp +64 -0
- chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp.hex +1 -0
- chia/wallet/vc_wallet/vc_store.py +263 -0
- chia/wallet/vc_wallet/vc_wallet.py +638 -0
- chia/wallet/wallet.py +698 -0
- chia/wallet/wallet_action_scope.py +96 -0
- chia/wallet/wallet_blockchain.py +244 -0
- chia/wallet/wallet_coin_record.py +72 -0
- chia/wallet/wallet_coin_store.py +351 -0
- chia/wallet/wallet_info.py +35 -0
- chia/wallet/wallet_interested_store.py +188 -0
- chia/wallet/wallet_nft_store.py +279 -0
- chia/wallet/wallet_node.py +1765 -0
- chia/wallet/wallet_node_api.py +207 -0
- chia/wallet/wallet_pool_store.py +119 -0
- chia/wallet/wallet_protocol.py +90 -0
- chia/wallet/wallet_puzzle_store.py +396 -0
- chia/wallet/wallet_retry_store.py +70 -0
- chia/wallet/wallet_singleton_store.py +259 -0
- chia/wallet/wallet_spend_bundle.py +25 -0
- chia/wallet/wallet_state_manager.py +2819 -0
- chia/wallet/wallet_transaction_store.py +496 -0
- chia/wallet/wallet_user_store.py +110 -0
- chia/wallet/wallet_weight_proof_handler.py +126 -0
- chia_blockchain-2.5.1rc1.dist-info/LICENSE +201 -0
- chia_blockchain-2.5.1rc1.dist-info/METADATA +156 -0
- chia_blockchain-2.5.1rc1.dist-info/RECORD +1042 -0
- chia_blockchain-2.5.1rc1.dist-info/WHEEL +4 -0
- chia_blockchain-2.5.1rc1.dist-info/entry_points.txt +17 -0
- mozilla-ca/cacert.pem +3611 -0
|
@@ -0,0 +1,4202 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
import random
|
|
6
|
+
import time
|
|
7
|
+
from collections.abc import AsyncIterator, Awaitable
|
|
8
|
+
from contextlib import asynccontextmanager
|
|
9
|
+
from dataclasses import replace
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
from chia_rs import AugSchemeMPL, G2Element, MerkleSet
|
|
14
|
+
from clvm.casts import int_to_bytes
|
|
15
|
+
|
|
16
|
+
from chia._tests.blockchain.blockchain_test_utils import (
|
|
17
|
+
_validate_and_add_block,
|
|
18
|
+
_validate_and_add_block_multi_error,
|
|
19
|
+
_validate_and_add_block_multi_result,
|
|
20
|
+
_validate_and_add_block_no_error,
|
|
21
|
+
check_block_store_invariant,
|
|
22
|
+
)
|
|
23
|
+
from chia._tests.conftest import ConsensusMode
|
|
24
|
+
from chia._tests.util.blockchain import create_blockchain
|
|
25
|
+
from chia._tests.util.get_name_puzzle_conditions import get_name_puzzle_conditions
|
|
26
|
+
from chia.consensus.block_body_validation import ForkInfo
|
|
27
|
+
from chia.consensus.block_header_validation import validate_finished_header_block
|
|
28
|
+
from chia.consensus.block_record import BlockRecord
|
|
29
|
+
from chia.consensus.block_rewards import calculate_base_farmer_reward
|
|
30
|
+
from chia.consensus.blockchain import AddBlockResult, Blockchain
|
|
31
|
+
from chia.consensus.coinbase import create_farmer_coin
|
|
32
|
+
from chia.consensus.constants import ConsensusConstants
|
|
33
|
+
from chia.consensus.find_fork_point import lookup_fork_chain
|
|
34
|
+
from chia.consensus.full_block_to_block_record import block_to_block_record
|
|
35
|
+
from chia.consensus.get_block_generator import get_block_generator
|
|
36
|
+
from chia.consensus.multiprocess_validation import PreValidationResult, pre_validate_block
|
|
37
|
+
from chia.consensus.pot_iterations import is_overflow_block
|
|
38
|
+
from chia.simulator.block_tools import BlockTools, create_block_tools_async
|
|
39
|
+
from chia.simulator.keyring import TempKeyring
|
|
40
|
+
from chia.simulator.wallet_tools import WalletTool
|
|
41
|
+
from chia.types.blockchain_format.classgroup import ClassgroupElement
|
|
42
|
+
from chia.types.blockchain_format.coin import Coin
|
|
43
|
+
from chia.types.blockchain_format.foliage import TransactionsInfo
|
|
44
|
+
from chia.types.blockchain_format.serialized_program import SerializedProgram
|
|
45
|
+
from chia.types.blockchain_format.sized_bytes import bytes32
|
|
46
|
+
from chia.types.blockchain_format.slots import InfusedChallengeChainSubSlot
|
|
47
|
+
from chia.types.blockchain_format.vdf import VDFInfo, VDFProof, validate_vdf
|
|
48
|
+
from chia.types.condition_opcodes import ConditionOpcode
|
|
49
|
+
from chia.types.condition_with_args import ConditionWithArgs
|
|
50
|
+
from chia.types.end_of_slot_bundle import EndOfSubSlotBundle
|
|
51
|
+
from chia.types.full_block import FullBlock
|
|
52
|
+
from chia.types.generator_types import BlockGenerator
|
|
53
|
+
from chia.types.spend_bundle import SpendBundle
|
|
54
|
+
from chia.types.unfinished_block import UnfinishedBlock
|
|
55
|
+
from chia.types.validation_state import ValidationState
|
|
56
|
+
from chia.util.augmented_chain import AugmentedBlockchain
|
|
57
|
+
from chia.util.errors import Err
|
|
58
|
+
from chia.util.generator_tools import get_block_header
|
|
59
|
+
from chia.util.hash import std_hash
|
|
60
|
+
from chia.util.ints import uint8, uint32, uint64
|
|
61
|
+
from chia.util.keychain import Keychain
|
|
62
|
+
from chia.util.recursive_replace import recursive_replace
|
|
63
|
+
from chia.util.vdf_prover import get_vdf_info_and_proof
|
|
64
|
+
from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import (
|
|
65
|
+
DEFAULT_HIDDEN_PUZZLE_HASH,
|
|
66
|
+
calculate_synthetic_secret_key,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
log = logging.getLogger(__name__)
|
|
70
|
+
bad_element = ClassgroupElement.create(b"\x00")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@asynccontextmanager
|
|
74
|
+
async def make_empty_blockchain(constants: ConsensusConstants) -> AsyncIterator[Blockchain]:
|
|
75
|
+
"""
|
|
76
|
+
Provides a list of 10 valid blocks, as well as a blockchain with 9 blocks added to it.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
async with create_blockchain(constants, 2) as (bc, _):
|
|
80
|
+
yield bc
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class TestGenesisBlock:
|
|
84
|
+
@pytest.mark.anyio
|
|
85
|
+
async def test_block_tools_proofs_400(
|
|
86
|
+
self, default_400_blocks: list[FullBlock], blockchain_constants: ConsensusConstants
|
|
87
|
+
) -> None:
|
|
88
|
+
vdf, proof = get_vdf_info_and_proof(
|
|
89
|
+
blockchain_constants,
|
|
90
|
+
ClassgroupElement.get_default_element(),
|
|
91
|
+
blockchain_constants.GENESIS_CHALLENGE,
|
|
92
|
+
uint64(231),
|
|
93
|
+
)
|
|
94
|
+
if validate_vdf(proof, blockchain_constants, ClassgroupElement.get_default_element(), vdf) is False:
|
|
95
|
+
raise Exception("invalid proof")
|
|
96
|
+
|
|
97
|
+
@pytest.mark.anyio
|
|
98
|
+
async def test_block_tools_proofs_1000(
|
|
99
|
+
self, default_1000_blocks: list[FullBlock], blockchain_constants: ConsensusConstants
|
|
100
|
+
) -> None:
|
|
101
|
+
vdf, proof = get_vdf_info_and_proof(
|
|
102
|
+
blockchain_constants,
|
|
103
|
+
ClassgroupElement.get_default_element(),
|
|
104
|
+
blockchain_constants.GENESIS_CHALLENGE,
|
|
105
|
+
uint64(231),
|
|
106
|
+
)
|
|
107
|
+
if validate_vdf(proof, blockchain_constants, ClassgroupElement.get_default_element(), vdf) is False:
|
|
108
|
+
raise Exception("invalid proof")
|
|
109
|
+
|
|
110
|
+
@pytest.mark.anyio
|
|
111
|
+
async def test_block_tools_proofs(self, blockchain_constants: ConsensusConstants) -> None:
|
|
112
|
+
vdf, proof = get_vdf_info_and_proof(
|
|
113
|
+
blockchain_constants,
|
|
114
|
+
ClassgroupElement.get_default_element(),
|
|
115
|
+
blockchain_constants.GENESIS_CHALLENGE,
|
|
116
|
+
uint64(231),
|
|
117
|
+
)
|
|
118
|
+
if validate_vdf(proof, blockchain_constants, ClassgroupElement.get_default_element(), vdf) is False:
|
|
119
|
+
raise Exception("invalid proof")
|
|
120
|
+
|
|
121
|
+
@pytest.mark.anyio
|
|
122
|
+
async def test_non_overflow_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
123
|
+
assert empty_blockchain.get_peak() is None
|
|
124
|
+
genesis = bt.get_consecutive_blocks(1, force_overflow=False)[0]
|
|
125
|
+
await _validate_and_add_block(empty_blockchain, genesis)
|
|
126
|
+
peak = empty_blockchain.get_peak()
|
|
127
|
+
assert peak is not None
|
|
128
|
+
assert peak.height == 0
|
|
129
|
+
|
|
130
|
+
@pytest.mark.anyio
|
|
131
|
+
async def test_overflow_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
132
|
+
genesis = bt.get_consecutive_blocks(1, force_overflow=True)[0]
|
|
133
|
+
await _validate_and_add_block(empty_blockchain, genesis)
|
|
134
|
+
|
|
135
|
+
@pytest.mark.anyio
|
|
136
|
+
async def test_genesis_empty_slots(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
137
|
+
genesis = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=30)[0]
|
|
138
|
+
await _validate_and_add_block(empty_blockchain, genesis)
|
|
139
|
+
|
|
140
|
+
@pytest.mark.anyio
|
|
141
|
+
async def test_overflow_genesis_empty_slots(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
142
|
+
genesis = bt.get_consecutive_blocks(1, force_overflow=True, skip_slots=3)[0]
|
|
143
|
+
await _validate_and_add_block(empty_blockchain, genesis)
|
|
144
|
+
|
|
145
|
+
@pytest.mark.anyio
|
|
146
|
+
async def test_genesis_validate_1(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
147
|
+
genesis = bt.get_consecutive_blocks(1, force_overflow=False)[0]
|
|
148
|
+
bad_prev = bytes([1] * 32)
|
|
149
|
+
genesis = recursive_replace(genesis, "foliage.prev_block_hash", bad_prev)
|
|
150
|
+
await _validate_and_add_block(empty_blockchain, genesis, expected_error=Err.INVALID_PREV_BLOCK_HASH)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class TestBlockHeaderValidation:
|
|
154
|
+
@pytest.mark.limit_consensus_modes(reason="save time")
|
|
155
|
+
@pytest.mark.anyio
|
|
156
|
+
async def test_long_chain(self, empty_blockchain: Blockchain, default_1000_blocks: list[FullBlock]) -> None:
|
|
157
|
+
blocks = default_1000_blocks
|
|
158
|
+
fork_info = ForkInfo(blocks[0].height - 1, blocks[0].height - 1, blocks[0].prev_header_hash)
|
|
159
|
+
for block in blocks:
|
|
160
|
+
if (
|
|
161
|
+
len(block.finished_sub_slots) > 0
|
|
162
|
+
and block.finished_sub_slots[0].challenge_chain.subepoch_summary_hash is not None
|
|
163
|
+
):
|
|
164
|
+
# Sub/Epoch. Try using a bad ssi and difficulty to test 2m and 2n
|
|
165
|
+
new_finished_ss = recursive_replace(
|
|
166
|
+
block.finished_sub_slots[0],
|
|
167
|
+
"challenge_chain.new_sub_slot_iters",
|
|
168
|
+
uint64(10_000_000),
|
|
169
|
+
)
|
|
170
|
+
block_bad = recursive_replace(
|
|
171
|
+
block, "finished_sub_slots", [new_finished_ss] + block.finished_sub_slots[1:]
|
|
172
|
+
)
|
|
173
|
+
header_block_bad = get_block_header(block_bad)
|
|
174
|
+
# TODO: Inspect these block values as they are currently None
|
|
175
|
+
expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
|
|
176
|
+
expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
|
|
177
|
+
expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None)
|
|
178
|
+
_, error = validate_finished_header_block(
|
|
179
|
+
empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs
|
|
180
|
+
)
|
|
181
|
+
assert error is not None
|
|
182
|
+
assert error.code == Err.INVALID_NEW_SUB_SLOT_ITERS
|
|
183
|
+
|
|
184
|
+
# Also fails calling the outer methods, but potentially with a different error
|
|
185
|
+
await _validate_and_add_block(
|
|
186
|
+
empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
new_finished_ss_2 = recursive_replace(
|
|
190
|
+
block.finished_sub_slots[0],
|
|
191
|
+
"challenge_chain.new_difficulty",
|
|
192
|
+
uint64(10_000_000),
|
|
193
|
+
)
|
|
194
|
+
block_bad_2 = recursive_replace(
|
|
195
|
+
block, "finished_sub_slots", [new_finished_ss_2] + block.finished_sub_slots[1:]
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
header_block_bad_2 = get_block_header(block_bad_2)
|
|
199
|
+
# TODO: Inspect these block values as they are currently None
|
|
200
|
+
expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
|
|
201
|
+
expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
|
|
202
|
+
expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None)
|
|
203
|
+
_, error = validate_finished_header_block(
|
|
204
|
+
empty_blockchain.constants, empty_blockchain, header_block_bad_2, False, expected_vs
|
|
205
|
+
)
|
|
206
|
+
assert error is not None
|
|
207
|
+
assert error.code == Err.INVALID_NEW_DIFFICULTY
|
|
208
|
+
|
|
209
|
+
# Also fails calling the outer methods, but potentially with a different error
|
|
210
|
+
await _validate_and_add_block(
|
|
211
|
+
empty_blockchain, block_bad_2, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# 3c
|
|
215
|
+
new_finished_ss_3: EndOfSubSlotBundle = recursive_replace(
|
|
216
|
+
block.finished_sub_slots[0],
|
|
217
|
+
"challenge_chain.subepoch_summary_hash",
|
|
218
|
+
bytes([0] * 32),
|
|
219
|
+
)
|
|
220
|
+
new_finished_ss_3 = recursive_replace(
|
|
221
|
+
new_finished_ss_3,
|
|
222
|
+
"reward_chain.challenge_chain_sub_slot_hash",
|
|
223
|
+
new_finished_ss_3.challenge_chain.get_hash(),
|
|
224
|
+
)
|
|
225
|
+
log.warning(f"Number of slots: {len(block.finished_sub_slots)}")
|
|
226
|
+
block_bad_3 = recursive_replace(block, "finished_sub_slots", [new_finished_ss_3])
|
|
227
|
+
|
|
228
|
+
header_block_bad_3 = get_block_header(block_bad_3)
|
|
229
|
+
# TODO: Inspect these block values as they are currently None
|
|
230
|
+
expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
|
|
231
|
+
expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
|
|
232
|
+
expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None)
|
|
233
|
+
_, error = validate_finished_header_block(
|
|
234
|
+
empty_blockchain.constants, empty_blockchain, header_block_bad_3, False, expected_vs
|
|
235
|
+
)
|
|
236
|
+
assert error is not None
|
|
237
|
+
assert error.code == Err.INVALID_SUB_EPOCH_SUMMARY
|
|
238
|
+
|
|
239
|
+
# Also fails calling the outer methods, but potentially with a different error
|
|
240
|
+
await _validate_and_add_block(
|
|
241
|
+
empty_blockchain, block_bad_3, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# 3d
|
|
245
|
+
new_finished_ss_4 = recursive_replace(
|
|
246
|
+
block.finished_sub_slots[0],
|
|
247
|
+
"challenge_chain.subepoch_summary_hash",
|
|
248
|
+
std_hash(b"123"),
|
|
249
|
+
)
|
|
250
|
+
new_finished_ss_4 = recursive_replace(
|
|
251
|
+
new_finished_ss_4,
|
|
252
|
+
"reward_chain.challenge_chain_sub_slot_hash",
|
|
253
|
+
new_finished_ss_4.challenge_chain.get_hash(),
|
|
254
|
+
)
|
|
255
|
+
block_bad_4 = recursive_replace(block, "finished_sub_slots", [new_finished_ss_4])
|
|
256
|
+
|
|
257
|
+
header_block_bad_4 = get_block_header(block_bad_4)
|
|
258
|
+
# TODO: Inspect these block values as they are currently None
|
|
259
|
+
expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
|
|
260
|
+
expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
|
|
261
|
+
expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None)
|
|
262
|
+
_, error = validate_finished_header_block(
|
|
263
|
+
empty_blockchain.constants, empty_blockchain, header_block_bad_4, False, expected_vs
|
|
264
|
+
)
|
|
265
|
+
assert error is not None
|
|
266
|
+
assert error.code == Err.INVALID_SUB_EPOCH_SUMMARY
|
|
267
|
+
|
|
268
|
+
# Also fails calling the outer methods, but potentially with a different error
|
|
269
|
+
await _validate_and_add_block(
|
|
270
|
+
empty_blockchain, block_bad_4, expected_result=AddBlockResult.INVALID_BLOCK, fork_info=fork_info
|
|
271
|
+
)
|
|
272
|
+
await _validate_and_add_block(empty_blockchain, block, fork_info=fork_info)
|
|
273
|
+
log.info(
|
|
274
|
+
f"Added block {block.height} total iters {block.total_iters} "
|
|
275
|
+
f"new slot? {len(block.finished_sub_slots)}"
|
|
276
|
+
)
|
|
277
|
+
peak = empty_blockchain.get_peak()
|
|
278
|
+
assert peak is not None
|
|
279
|
+
assert peak.height == len(blocks) - 1
|
|
280
|
+
|
|
281
|
+
@pytest.mark.anyio
|
|
282
|
+
async def test_unfinished_blocks(
|
|
283
|
+
self, empty_blockchain: Blockchain, softfork_height: uint32, bt: BlockTools
|
|
284
|
+
) -> None:
|
|
285
|
+
blockchain = empty_blockchain
|
|
286
|
+
blocks = bt.get_consecutive_blocks(3)
|
|
287
|
+
for block in blocks[:-1]:
|
|
288
|
+
await _validate_and_add_block(empty_blockchain, block)
|
|
289
|
+
block = blocks[-1]
|
|
290
|
+
unf = UnfinishedBlock(
|
|
291
|
+
block.finished_sub_slots,
|
|
292
|
+
block.reward_chain_block.get_unfinished(),
|
|
293
|
+
block.challenge_chain_sp_proof,
|
|
294
|
+
block.reward_chain_sp_proof,
|
|
295
|
+
block.foliage,
|
|
296
|
+
block.foliage_transaction_block,
|
|
297
|
+
block.transactions_info,
|
|
298
|
+
block.transactions_generator,
|
|
299
|
+
[],
|
|
300
|
+
)
|
|
301
|
+
npc_result = None
|
|
302
|
+
# if this assert fires, remove it along with the pragma for the block
|
|
303
|
+
# below
|
|
304
|
+
assert unf.transactions_generator is None
|
|
305
|
+
if unf.transactions_generator is not None: # pragma: no cover
|
|
306
|
+
block_generator = await get_block_generator(blockchain.lookup_block_generators, unf)
|
|
307
|
+
assert block_generator is not None
|
|
308
|
+
block_bytes = bytes(unf)
|
|
309
|
+
npc_result = await blockchain.run_generator(block_bytes, block_generator, height=softfork_height)
|
|
310
|
+
|
|
311
|
+
validate_res = await blockchain.validate_unfinished_block(unf, npc_result, False)
|
|
312
|
+
err = validate_res.error
|
|
313
|
+
assert err is None
|
|
314
|
+
|
|
315
|
+
await _validate_and_add_block(empty_blockchain, block)
|
|
316
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, force_overflow=True)
|
|
317
|
+
block = blocks[-1]
|
|
318
|
+
unf = UnfinishedBlock(
|
|
319
|
+
block.finished_sub_slots,
|
|
320
|
+
block.reward_chain_block.get_unfinished(),
|
|
321
|
+
block.challenge_chain_sp_proof,
|
|
322
|
+
block.reward_chain_sp_proof,
|
|
323
|
+
block.foliage,
|
|
324
|
+
block.foliage_transaction_block,
|
|
325
|
+
block.transactions_info,
|
|
326
|
+
block.transactions_generator,
|
|
327
|
+
[],
|
|
328
|
+
)
|
|
329
|
+
npc_result = None
|
|
330
|
+
# if this assert fires, remove it along with the pragma for the block
|
|
331
|
+
# below
|
|
332
|
+
assert unf.transactions_generator is None
|
|
333
|
+
if unf.transactions_generator is not None: # pragma: no cover
|
|
334
|
+
block_generator = await get_block_generator(blockchain.lookup_block_generators, unf)
|
|
335
|
+
assert block_generator is not None
|
|
336
|
+
block_bytes = bytes(unf)
|
|
337
|
+
npc_result = await blockchain.run_generator(block_bytes, block_generator, height=softfork_height)
|
|
338
|
+
validate_res = await blockchain.validate_unfinished_block(unf, npc_result, False)
|
|
339
|
+
assert validate_res.error is None
|
|
340
|
+
|
|
341
|
+
@pytest.mark.anyio
|
|
342
|
+
async def test_empty_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
343
|
+
for block in bt.get_consecutive_blocks(2, skip_slots=3):
|
|
344
|
+
await _validate_and_add_block(empty_blockchain, block)
|
|
345
|
+
|
|
346
|
+
@pytest.mark.anyio
|
|
347
|
+
async def test_empty_slots_non_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
348
|
+
blockchain = empty_blockchain
|
|
349
|
+
blocks = bt.get_consecutive_blocks(10)
|
|
350
|
+
for block in blocks:
|
|
351
|
+
await _validate_and_add_block(empty_blockchain, block)
|
|
352
|
+
|
|
353
|
+
blocks = bt.get_consecutive_blocks(10, skip_slots=2, block_list_input=blocks)
|
|
354
|
+
for block in blocks[10:]:
|
|
355
|
+
await _validate_and_add_block(empty_blockchain, block)
|
|
356
|
+
peak = blockchain.get_peak()
|
|
357
|
+
assert peak is not None
|
|
358
|
+
assert peak.height == 19
|
|
359
|
+
|
|
360
|
+
@pytest.mark.anyio
|
|
361
|
+
async def test_one_sb_per_slot(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
362
|
+
blockchain = empty_blockchain
|
|
363
|
+
num_blocks = 20
|
|
364
|
+
blocks: list[FullBlock] = []
|
|
365
|
+
for _ in range(num_blocks):
|
|
366
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
|
|
367
|
+
await _validate_and_add_block(empty_blockchain, blocks[-1])
|
|
368
|
+
peak = blockchain.get_peak()
|
|
369
|
+
assert peak is not None
|
|
370
|
+
assert peak.height == num_blocks - 1
|
|
371
|
+
|
|
372
|
+
@pytest.mark.anyio
|
|
373
|
+
async def test_all_overflow(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
374
|
+
blockchain = empty_blockchain
|
|
375
|
+
num_rounds = 5
|
|
376
|
+
blocks: list[FullBlock] = []
|
|
377
|
+
num_blocks = 0
|
|
378
|
+
for i in range(1, num_rounds):
|
|
379
|
+
num_blocks += i
|
|
380
|
+
blocks = bt.get_consecutive_blocks(i, block_list_input=blocks, skip_slots=1, force_overflow=True)
|
|
381
|
+
for block in blocks[-i:]:
|
|
382
|
+
await _validate_and_add_block(empty_blockchain, block)
|
|
383
|
+
peak = blockchain.get_peak()
|
|
384
|
+
assert peak is not None
|
|
385
|
+
assert peak.height == num_blocks - 1
|
|
386
|
+
|
|
387
|
+
@pytest.mark.anyio
|
|
388
|
+
async def test_unf_block_overflow(
|
|
389
|
+
self, empty_blockchain: Blockchain, softfork_height: uint32, bt: BlockTools
|
|
390
|
+
) -> None:
|
|
391
|
+
blockchain = empty_blockchain
|
|
392
|
+
|
|
393
|
+
blocks: list[FullBlock] = []
|
|
394
|
+
while True:
|
|
395
|
+
# This creates an overflow block, then a normal block, and then an overflow in the next sub-slot
|
|
396
|
+
# blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, force_overflow=True)
|
|
397
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
398
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, force_overflow=True)
|
|
399
|
+
|
|
400
|
+
await _validate_and_add_block(blockchain, blocks[-2])
|
|
401
|
+
|
|
402
|
+
sb_1 = blockchain.block_record(blocks[-2].header_hash)
|
|
403
|
+
|
|
404
|
+
sb_2_next_ss = blocks[-1].total_iters - blocks[-2].total_iters < sb_1.sub_slot_iters
|
|
405
|
+
# We might not get a normal block for sb_2, and we might not get them in the right slots
|
|
406
|
+
# So this while loop keeps trying
|
|
407
|
+
if sb_1.overflow and sb_2_next_ss:
|
|
408
|
+
block = blocks[-1]
|
|
409
|
+
unf = UnfinishedBlock(
|
|
410
|
+
[],
|
|
411
|
+
block.reward_chain_block.get_unfinished(),
|
|
412
|
+
block.challenge_chain_sp_proof,
|
|
413
|
+
block.reward_chain_sp_proof,
|
|
414
|
+
block.foliage,
|
|
415
|
+
block.foliage_transaction_block,
|
|
416
|
+
block.transactions_info,
|
|
417
|
+
block.transactions_generator,
|
|
418
|
+
[],
|
|
419
|
+
)
|
|
420
|
+
npc_result = None
|
|
421
|
+
# if this assert fires, remove it along with the pragma for the block
|
|
422
|
+
# below
|
|
423
|
+
assert block.transactions_generator is None
|
|
424
|
+
if block.transactions_generator is not None: # pragma: no cover
|
|
425
|
+
block_generator = await get_block_generator(blockchain.lookup_block_generators, unf)
|
|
426
|
+
assert block_generator is not None
|
|
427
|
+
block_bytes = bytes(unf)
|
|
428
|
+
npc_result = await blockchain.run_generator(block_bytes, block_generator, height=softfork_height)
|
|
429
|
+
validate_res = await blockchain.validate_unfinished_block(
|
|
430
|
+
unf, npc_result, skip_overflow_ss_validation=True
|
|
431
|
+
)
|
|
432
|
+
assert validate_res.error is None
|
|
433
|
+
return None
|
|
434
|
+
|
|
435
|
+
await _validate_and_add_block(blockchain, blocks[-1])
|
|
436
|
+
|
|
437
|
+
@pytest.mark.anyio
|
|
438
|
+
async def test_one_sb_per_two_slots(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
439
|
+
blockchain = empty_blockchain
|
|
440
|
+
num_blocks = 20
|
|
441
|
+
blocks: list[FullBlock] = []
|
|
442
|
+
for _ in range(num_blocks): # Same thing, but 2 sub-slots per block
|
|
443
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=2)
|
|
444
|
+
await _validate_and_add_block(blockchain, blocks[-1])
|
|
445
|
+
peak = blockchain.get_peak()
|
|
446
|
+
assert peak is not None
|
|
447
|
+
assert peak.height == num_blocks - 1
|
|
448
|
+
|
|
449
|
+
@pytest.mark.anyio
|
|
450
|
+
async def test_one_sb_per_five_slots(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
451
|
+
blockchain = empty_blockchain
|
|
452
|
+
num_blocks = 10
|
|
453
|
+
blocks: list[FullBlock] = []
|
|
454
|
+
for _ in range(num_blocks): # Same thing, but 5 sub-slots per block
|
|
455
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=5)
|
|
456
|
+
await _validate_and_add_block(blockchain, blocks[-1])
|
|
457
|
+
peak = blockchain.get_peak()
|
|
458
|
+
assert peak is not None
|
|
459
|
+
assert peak.height == num_blocks - 1
|
|
460
|
+
|
|
461
|
+
@pytest.mark.anyio
|
|
462
|
+
async def test_basic_chain_overflow(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
463
|
+
blocks = bt.get_consecutive_blocks(5, force_overflow=True)
|
|
464
|
+
for block in blocks:
|
|
465
|
+
await _validate_and_add_block(empty_blockchain, block)
|
|
466
|
+
peak = empty_blockchain.get_peak()
|
|
467
|
+
assert peak is not None
|
|
468
|
+
assert peak.height == len(blocks) - 1
|
|
469
|
+
|
|
470
|
+
@pytest.mark.anyio
|
|
471
|
+
async def test_one_sb_per_two_slots_force_overflow(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
472
|
+
blockchain = empty_blockchain
|
|
473
|
+
num_blocks = 10
|
|
474
|
+
blocks: list[FullBlock] = []
|
|
475
|
+
for _ in range(num_blocks):
|
|
476
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=2, force_overflow=True)
|
|
477
|
+
await _validate_and_add_block(blockchain, blocks[-1])
|
|
478
|
+
peak = blockchain.get_peak()
|
|
479
|
+
assert peak is not None
|
|
480
|
+
assert peak.height == num_blocks - 1
|
|
481
|
+
|
|
482
|
+
@pytest.mark.anyio
|
|
483
|
+
async def test_invalid_prev(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
484
|
+
# 1
|
|
485
|
+
blocks = bt.get_consecutive_blocks(2, force_overflow=False)
|
|
486
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
487
|
+
block_1_bad = recursive_replace(blocks[-1], "foliage.prev_block_hash", bytes([0] * 32))
|
|
488
|
+
|
|
489
|
+
await _validate_and_add_block(empty_blockchain, block_1_bad, expected_error=Err.INVALID_PREV_BLOCK_HASH)
|
|
490
|
+
|
|
491
|
+
@pytest.mark.anyio
|
|
492
|
+
async def test_invalid_pospace(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
493
|
+
# 2
|
|
494
|
+
blocks = bt.get_consecutive_blocks(2, force_overflow=False)
|
|
495
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
496
|
+
block_1_bad = recursive_replace(blocks[-1], "reward_chain_block.proof_of_space.proof", bytes([0] * 32))
|
|
497
|
+
|
|
498
|
+
await _validate_and_add_block(empty_blockchain, block_1_bad, expected_error=Err.INVALID_POSPACE)
|
|
499
|
+
|
|
500
|
+
@pytest.mark.anyio
|
|
501
|
+
async def test_invalid_sub_slot_challenge_hash_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
502
|
+
# 2a
|
|
503
|
+
blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1)
|
|
504
|
+
new_finished_ss = recursive_replace(
|
|
505
|
+
blocks[0].finished_sub_slots[0],
|
|
506
|
+
"challenge_chain.challenge_chain_end_of_slot_vdf.challenge",
|
|
507
|
+
bytes([2] * 32),
|
|
508
|
+
)
|
|
509
|
+
block_0_bad = recursive_replace(
|
|
510
|
+
blocks[0], "finished_sub_slots", [new_finished_ss] + blocks[0].finished_sub_slots[1:]
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
header_block_bad = get_block_header(block_0_bad)
|
|
514
|
+
expected_vs = ValidationState(
|
|
515
|
+
empty_blockchain.constants.SUB_SLOT_ITERS_STARTING, empty_blockchain.constants.DIFFICULTY_STARTING, None
|
|
516
|
+
)
|
|
517
|
+
_, error = validate_finished_header_block(
|
|
518
|
+
empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
assert error is not None
|
|
522
|
+
assert error.code == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
|
|
523
|
+
await _validate_and_add_block(empty_blockchain, block_0_bad, expected_result=AddBlockResult.INVALID_BLOCK)
|
|
524
|
+
|
|
525
|
+
@pytest.mark.anyio
|
|
526
|
+
async def test_invalid_sub_slot_challenge_hash_non_genesis(
|
|
527
|
+
self, empty_blockchain: Blockchain, bt: BlockTools
|
|
528
|
+
) -> None:
|
|
529
|
+
# 2b
|
|
530
|
+
blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=0)
|
|
531
|
+
blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1, block_list_input=blocks)
|
|
532
|
+
new_finished_ss = recursive_replace(
|
|
533
|
+
blocks[1].finished_sub_slots[0],
|
|
534
|
+
"challenge_chain.challenge_chain_end_of_slot_vdf.challenge",
|
|
535
|
+
bytes([2] * 32),
|
|
536
|
+
)
|
|
537
|
+
block_1_bad = recursive_replace(
|
|
538
|
+
blocks[1], "finished_sub_slots", [new_finished_ss] + blocks[1].finished_sub_slots[1:]
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
542
|
+
header_block_bad = get_block_header(block_1_bad)
|
|
543
|
+
# TODO: Inspect these block values as they are currently None
|
|
544
|
+
expected_difficulty = blocks[1].finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
|
|
545
|
+
expected_sub_slot_iters = blocks[1].finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
|
|
546
|
+
expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None)
|
|
547
|
+
_, error = validate_finished_header_block(
|
|
548
|
+
empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs
|
|
549
|
+
)
|
|
550
|
+
assert error is not None
|
|
551
|
+
assert error.code == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
|
|
552
|
+
await _validate_and_add_block(empty_blockchain, block_1_bad, expected_result=AddBlockResult.INVALID_BLOCK)
|
|
553
|
+
|
|
554
|
+
@pytest.mark.anyio
|
|
555
|
+
async def test_invalid_sub_slot_challenge_hash_empty_ss(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
556
|
+
# 2c
|
|
557
|
+
blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=0)
|
|
558
|
+
blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=2, block_list_input=blocks)
|
|
559
|
+
new_finished_ss = recursive_replace(
|
|
560
|
+
blocks[1].finished_sub_slots[-1],
|
|
561
|
+
"challenge_chain.challenge_chain_end_of_slot_vdf.challenge",
|
|
562
|
+
bytes([2] * 32),
|
|
563
|
+
)
|
|
564
|
+
block_1_bad = recursive_replace(
|
|
565
|
+
blocks[1], "finished_sub_slots", blocks[1].finished_sub_slots[:-1] + [new_finished_ss]
|
|
566
|
+
)
|
|
567
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
568
|
+
|
|
569
|
+
header_block_bad = get_block_header(block_1_bad)
|
|
570
|
+
# TODO: Inspect these block values as they are currently None
|
|
571
|
+
expected_difficulty = blocks[1].finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
|
|
572
|
+
expected_sub_slot_iters = blocks[1].finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
|
|
573
|
+
expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None)
|
|
574
|
+
_, error = validate_finished_header_block(
|
|
575
|
+
empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs
|
|
576
|
+
)
|
|
577
|
+
assert error is not None
|
|
578
|
+
assert error.code == Err.INVALID_PREV_CHALLENGE_SLOT_HASH
|
|
579
|
+
await _validate_and_add_block(empty_blockchain, block_1_bad, expected_result=AddBlockResult.INVALID_BLOCK)
|
|
580
|
+
|
|
581
|
+
@pytest.mark.anyio
|
|
582
|
+
async def test_genesis_no_icc(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
583
|
+
# 2d
|
|
584
|
+
blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1)
|
|
585
|
+
new_finished_ss = recursive_replace(
|
|
586
|
+
blocks[0].finished_sub_slots[0],
|
|
587
|
+
"infused_challenge_chain",
|
|
588
|
+
InfusedChallengeChainSubSlot(
|
|
589
|
+
VDFInfo(
|
|
590
|
+
bytes32.zeros,
|
|
591
|
+
uint64(1200),
|
|
592
|
+
ClassgroupElement.get_default_element(),
|
|
593
|
+
)
|
|
594
|
+
),
|
|
595
|
+
)
|
|
596
|
+
block_0_bad = recursive_replace(
|
|
597
|
+
blocks[0], "finished_sub_slots", [new_finished_ss] + blocks[0].finished_sub_slots[1:]
|
|
598
|
+
)
|
|
599
|
+
await _validate_and_add_block(empty_blockchain, block_0_bad, expected_error=Err.SHOULD_NOT_HAVE_ICC)
|
|
600
|
+
|
|
601
|
+
async def do_test_invalid_icc_sub_slot_vdf(
|
|
602
|
+
self, keychain: Keychain, db_version: int, constants: ConsensusConstants
|
|
603
|
+
) -> None:
|
|
604
|
+
bt_high_iters = await create_block_tools_async(
|
|
605
|
+
constants=constants.replace(
|
|
606
|
+
SUB_SLOT_ITERS_STARTING=uint64(2**12),
|
|
607
|
+
DIFFICULTY_STARTING=uint64(2**14),
|
|
608
|
+
),
|
|
609
|
+
keychain=keychain,
|
|
610
|
+
)
|
|
611
|
+
async with create_blockchain(bt_high_iters.constants, db_version) as (bc1, _):
|
|
612
|
+
blocks = bt_high_iters.get_consecutive_blocks(10)
|
|
613
|
+
for block in blocks:
|
|
614
|
+
if (
|
|
615
|
+
len(block.finished_sub_slots) > 0
|
|
616
|
+
and block.finished_sub_slots[-1].infused_challenge_chain is not None
|
|
617
|
+
):
|
|
618
|
+
# Bad iters
|
|
619
|
+
new_finished_ss = recursive_replace(
|
|
620
|
+
block.finished_sub_slots[-1],
|
|
621
|
+
"infused_challenge_chain",
|
|
622
|
+
InfusedChallengeChainSubSlot(
|
|
623
|
+
block.finished_sub_slots[
|
|
624
|
+
-1
|
|
625
|
+
].infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.replace(
|
|
626
|
+
number_of_iterations=uint64(10000000),
|
|
627
|
+
)
|
|
628
|
+
),
|
|
629
|
+
)
|
|
630
|
+
block_bad = recursive_replace(
|
|
631
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
|
|
632
|
+
)
|
|
633
|
+
await _validate_and_add_block(bc1, block_bad, expected_error=Err.INVALID_ICC_EOS_VDF)
|
|
634
|
+
|
|
635
|
+
# Bad output
|
|
636
|
+
new_finished_ss_2 = recursive_replace(
|
|
637
|
+
block.finished_sub_slots[-1],
|
|
638
|
+
"infused_challenge_chain",
|
|
639
|
+
InfusedChallengeChainSubSlot(
|
|
640
|
+
block.finished_sub_slots[
|
|
641
|
+
-1
|
|
642
|
+
].infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.replace(
|
|
643
|
+
output=ClassgroupElement.get_default_element(),
|
|
644
|
+
)
|
|
645
|
+
),
|
|
646
|
+
)
|
|
647
|
+
log.warning(f"Proof: {block.finished_sub_slots[-1].proofs}")
|
|
648
|
+
block_bad_2 = recursive_replace(
|
|
649
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_2]
|
|
650
|
+
)
|
|
651
|
+
await _validate_and_add_block(bc1, block_bad_2, expected_error=Err.INVALID_ICC_EOS_VDF)
|
|
652
|
+
|
|
653
|
+
# Bad challenge hash
|
|
654
|
+
new_finished_ss_3 = recursive_replace(
|
|
655
|
+
block.finished_sub_slots[-1],
|
|
656
|
+
"infused_challenge_chain",
|
|
657
|
+
InfusedChallengeChainSubSlot(
|
|
658
|
+
block.finished_sub_slots[
|
|
659
|
+
-1
|
|
660
|
+
].infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf.replace(
|
|
661
|
+
challenge=bytes32.zeros
|
|
662
|
+
)
|
|
663
|
+
),
|
|
664
|
+
)
|
|
665
|
+
block_bad_3 = recursive_replace(
|
|
666
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_3]
|
|
667
|
+
)
|
|
668
|
+
await _validate_and_add_block(bc1, block_bad_3, expected_error=Err.INVALID_ICC_EOS_VDF)
|
|
669
|
+
|
|
670
|
+
# Bad proof
|
|
671
|
+
new_finished_ss_5 = recursive_replace(
|
|
672
|
+
block.finished_sub_slots[-1],
|
|
673
|
+
"proofs.infused_challenge_chain_slot_proof",
|
|
674
|
+
VDFProof(uint8(0), b"1239819023890", False),
|
|
675
|
+
)
|
|
676
|
+
block_bad_5 = recursive_replace(
|
|
677
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_5]
|
|
678
|
+
)
|
|
679
|
+
await _validate_and_add_block(bc1, block_bad_5, expected_error=Err.INVALID_ICC_EOS_VDF)
|
|
680
|
+
|
|
681
|
+
await _validate_and_add_block(bc1, block)
|
|
682
|
+
|
|
683
|
+
@pytest.mark.anyio
|
|
684
|
+
async def test_invalid_icc_sub_slot_vdf(self, db_version: int, blockchain_constants: ConsensusConstants) -> None:
|
|
685
|
+
with TempKeyring() as keychain:
|
|
686
|
+
await self.do_test_invalid_icc_sub_slot_vdf(keychain, db_version, blockchain_constants)
|
|
687
|
+
|
|
688
|
+
@pytest.mark.anyio
|
|
689
|
+
async def test_invalid_icc_into_cc(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
690
|
+
blockchain = empty_blockchain
|
|
691
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
692
|
+
await _validate_and_add_block(blockchain, blocks[0])
|
|
693
|
+
case_1, case_2 = False, False
|
|
694
|
+
while not case_1 or not case_2:
|
|
695
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
|
|
696
|
+
block = blocks[-1]
|
|
697
|
+
if len(block.finished_sub_slots) > 0 and block.finished_sub_slots[-1].infused_challenge_chain is not None:
|
|
698
|
+
if block.finished_sub_slots[-1].reward_chain.deficit == bt.constants.MIN_BLOCKS_PER_CHALLENGE_BLOCK:
|
|
699
|
+
# 2g
|
|
700
|
+
case_1 = True
|
|
701
|
+
new_finished_ss = recursive_replace(
|
|
702
|
+
block.finished_sub_slots[-1],
|
|
703
|
+
"challenge_chain",
|
|
704
|
+
block.finished_sub_slots[-1].challenge_chain.replace(
|
|
705
|
+
infused_challenge_chain_sub_slot_hash=bytes32([1] * 32)
|
|
706
|
+
),
|
|
707
|
+
)
|
|
708
|
+
else:
|
|
709
|
+
# 2h
|
|
710
|
+
case_2 = True
|
|
711
|
+
new_finished_ss = recursive_replace(
|
|
712
|
+
block.finished_sub_slots[-1],
|
|
713
|
+
"challenge_chain",
|
|
714
|
+
block.finished_sub_slots[-1].challenge_chain.replace(
|
|
715
|
+
infused_challenge_chain_sub_slot_hash=block.finished_sub_slots[
|
|
716
|
+
-1
|
|
717
|
+
].infused_challenge_chain.get_hash(),
|
|
718
|
+
),
|
|
719
|
+
)
|
|
720
|
+
block_bad = recursive_replace(
|
|
721
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
|
|
722
|
+
)
|
|
723
|
+
|
|
724
|
+
header_block_bad = get_block_header(block_bad)
|
|
725
|
+
# TODO: Inspect these block values as they are currently None
|
|
726
|
+
expected_difficulty = block.finished_sub_slots[0].challenge_chain.new_difficulty or uint64(0)
|
|
727
|
+
expected_sub_slot_iters = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters or uint64(0)
|
|
728
|
+
expected_vs = ValidationState(expected_sub_slot_iters, expected_difficulty, None)
|
|
729
|
+
_, error = validate_finished_header_block(
|
|
730
|
+
empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs
|
|
731
|
+
)
|
|
732
|
+
assert error is not None
|
|
733
|
+
assert error.code == Err.INVALID_ICC_HASH_CC
|
|
734
|
+
await _validate_and_add_block(blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK)
|
|
735
|
+
|
|
736
|
+
# 2i
|
|
737
|
+
new_finished_ss_bad_rc = recursive_replace(
|
|
738
|
+
block.finished_sub_slots[-1],
|
|
739
|
+
"reward_chain",
|
|
740
|
+
block.finished_sub_slots[-1].reward_chain.replace(infused_challenge_chain_sub_slot_hash=None),
|
|
741
|
+
)
|
|
742
|
+
block_bad = recursive_replace(
|
|
743
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_bad_rc]
|
|
744
|
+
)
|
|
745
|
+
await _validate_and_add_block(blockchain, block_bad, expected_error=Err.INVALID_ICC_HASH_RC)
|
|
746
|
+
elif len(block.finished_sub_slots) > 0 and block.finished_sub_slots[-1].infused_challenge_chain is None:
|
|
747
|
+
# 2j
|
|
748
|
+
# TODO: This code path is currently not exercised
|
|
749
|
+
new_finished_ss_bad_cc = recursive_replace(
|
|
750
|
+
block.finished_sub_slots[-1],
|
|
751
|
+
"challenge_chain",
|
|
752
|
+
block.finished_sub_slots[-1].challenge_chain.replace(
|
|
753
|
+
infused_challenge_chain_sub_slot_hash=bytes32([1] * 32)
|
|
754
|
+
),
|
|
755
|
+
)
|
|
756
|
+
block_bad = recursive_replace(
|
|
757
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_bad_cc]
|
|
758
|
+
)
|
|
759
|
+
await _validate_and_add_block(blockchain, block_bad, expected_error=Err.INVALID_ICC_HASH_CC)
|
|
760
|
+
|
|
761
|
+
# 2k
|
|
762
|
+
# TODO: This code path is currently not exercised
|
|
763
|
+
new_finished_ss_bad_rc = recursive_replace(
|
|
764
|
+
block.finished_sub_slots[-1],
|
|
765
|
+
"reward_chain",
|
|
766
|
+
block.finished_sub_slots[-1].reward_chain.replace(
|
|
767
|
+
infused_challenge_chain_sub_slot_hash=bytes32([1] * 32)
|
|
768
|
+
),
|
|
769
|
+
)
|
|
770
|
+
block_bad = recursive_replace(
|
|
771
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_bad_rc]
|
|
772
|
+
)
|
|
773
|
+
await _validate_and_add_block(blockchain, block_bad, expected_error=Err.INVALID_ICC_HASH_RC)
|
|
774
|
+
|
|
775
|
+
# Finally, add the block properly
|
|
776
|
+
await _validate_and_add_block(blockchain, block)
|
|
777
|
+
|
|
778
|
+
@pytest.mark.anyio
|
|
779
|
+
async def test_empty_slot_no_ses(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
780
|
+
# 2l
|
|
781
|
+
blockchain = empty_blockchain
|
|
782
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
783
|
+
await _validate_and_add_block(blockchain, blocks[0])
|
|
784
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=4)
|
|
785
|
+
|
|
786
|
+
new_finished_ss = recursive_replace(
|
|
787
|
+
blocks[-1].finished_sub_slots[-1],
|
|
788
|
+
"challenge_chain",
|
|
789
|
+
blocks[-1].finished_sub_slots[-1].challenge_chain.replace(subepoch_summary_hash=std_hash(b"0")),
|
|
790
|
+
)
|
|
791
|
+
block_bad = recursive_replace(
|
|
792
|
+
blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
|
|
793
|
+
)
|
|
794
|
+
|
|
795
|
+
header_block_bad = get_block_header(block_bad)
|
|
796
|
+
expected_vs = ValidationState(
|
|
797
|
+
empty_blockchain.constants.SUB_SLOT_ITERS_STARTING, empty_blockchain.constants.DIFFICULTY_STARTING, None
|
|
798
|
+
)
|
|
799
|
+
_, error = validate_finished_header_block(
|
|
800
|
+
empty_blockchain.constants, empty_blockchain, header_block_bad, False, expected_vs
|
|
801
|
+
)
|
|
802
|
+
assert error is not None
|
|
803
|
+
assert error.code == Err.INVALID_SUB_EPOCH_SUMMARY_HASH
|
|
804
|
+
await _validate_and_add_block(blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK)
|
|
805
|
+
|
|
806
|
+
@pytest.mark.anyio
|
|
807
|
+
async def test_empty_sub_slots_epoch(
|
|
808
|
+
self, empty_blockchain: Blockchain, default_400_blocks: list[FullBlock], bt: BlockTools
|
|
809
|
+
) -> None:
|
|
810
|
+
# 2m
|
|
811
|
+
# Tests adding an empty sub slot after the sub-epoch / epoch.
|
|
812
|
+
# Also tests overflow block in epoch
|
|
813
|
+
blocks_base = default_400_blocks[: bt.constants.EPOCH_BLOCKS]
|
|
814
|
+
assert len(blocks_base) == bt.constants.EPOCH_BLOCKS
|
|
815
|
+
blocks_1 = bt.get_consecutive_blocks(1, block_list_input=blocks_base, force_overflow=True)
|
|
816
|
+
blocks_2 = bt.get_consecutive_blocks(1, skip_slots=5, block_list_input=blocks_base, force_overflow=True)
|
|
817
|
+
for block in blocks_base:
|
|
818
|
+
await _validate_and_add_block(empty_blockchain, block, skip_prevalidation=True)
|
|
819
|
+
await _validate_and_add_block(
|
|
820
|
+
empty_blockchain, blocks_1[-1], expected_result=AddBlockResult.NEW_PEAK, skip_prevalidation=True
|
|
821
|
+
)
|
|
822
|
+
assert blocks_1[-1].header_hash != blocks_2[-1].header_hash
|
|
823
|
+
await _validate_and_add_block(
|
|
824
|
+
empty_blockchain, blocks_2[-1], expected_result=AddBlockResult.ADDED_AS_ORPHAN, skip_prevalidation=True
|
|
825
|
+
)
|
|
826
|
+
|
|
827
|
+
@pytest.mark.anyio
|
|
828
|
+
async def test_wrong_cc_hash_rc(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
829
|
+
# 2o
|
|
830
|
+
blockchain = empty_blockchain
|
|
831
|
+
blocks = bt.get_consecutive_blocks(1, skip_slots=1)
|
|
832
|
+
blocks = bt.get_consecutive_blocks(1, skip_slots=1, block_list_input=blocks)
|
|
833
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
834
|
+
|
|
835
|
+
new_finished_ss = recursive_replace(
|
|
836
|
+
blocks[-1].finished_sub_slots[-1],
|
|
837
|
+
"reward_chain",
|
|
838
|
+
blocks[-1].finished_sub_slots[-1].reward_chain.replace(challenge_chain_sub_slot_hash=bytes32([3] * 32)),
|
|
839
|
+
)
|
|
840
|
+
block_1_bad = recursive_replace(
|
|
841
|
+
blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
|
|
842
|
+
)
|
|
843
|
+
|
|
844
|
+
await _validate_and_add_block(blockchain, block_1_bad, expected_error=Err.INVALID_CHALLENGE_SLOT_HASH_RC)
|
|
845
|
+
|
|
846
|
+
@pytest.mark.anyio
|
|
847
|
+
async def test_invalid_cc_sub_slot_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
848
|
+
# 2q
|
|
849
|
+
blocks: list[FullBlock] = []
|
|
850
|
+
found_overflow_slot: bool = False
|
|
851
|
+
|
|
852
|
+
while not found_overflow_slot:
|
|
853
|
+
blocks = bt.get_consecutive_blocks(1, blocks)
|
|
854
|
+
block = blocks[-1]
|
|
855
|
+
if (
|
|
856
|
+
len(block.finished_sub_slots)
|
|
857
|
+
and is_overflow_block(bt.constants, block.reward_chain_block.signage_point_index)
|
|
858
|
+
and block.finished_sub_slots[-1].challenge_chain.challenge_chain_end_of_slot_vdf.output
|
|
859
|
+
!= ClassgroupElement.get_default_element()
|
|
860
|
+
):
|
|
861
|
+
found_overflow_slot = True
|
|
862
|
+
# Bad iters
|
|
863
|
+
new_finished_ss = recursive_replace(
|
|
864
|
+
block.finished_sub_slots[-1],
|
|
865
|
+
"challenge_chain",
|
|
866
|
+
recursive_replace(
|
|
867
|
+
block.finished_sub_slots[-1].challenge_chain,
|
|
868
|
+
"challenge_chain_end_of_slot_vdf.number_of_iterations",
|
|
869
|
+
uint64(10000000),
|
|
870
|
+
),
|
|
871
|
+
)
|
|
872
|
+
new_finished_ss = recursive_replace(
|
|
873
|
+
new_finished_ss,
|
|
874
|
+
"reward_chain.challenge_chain_sub_slot_hash",
|
|
875
|
+
new_finished_ss.challenge_chain.get_hash(),
|
|
876
|
+
)
|
|
877
|
+
log.warning(f"Num slots: {len(block.finished_sub_slots)}")
|
|
878
|
+
block_bad = recursive_replace(
|
|
879
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
|
|
880
|
+
)
|
|
881
|
+
log.warning(f"Signage point index: {block_bad.reward_chain_block.signage_point_index}")
|
|
882
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_EOS_VDF)
|
|
883
|
+
|
|
884
|
+
# Bad output
|
|
885
|
+
new_finished_ss_2 = recursive_replace(
|
|
886
|
+
block.finished_sub_slots[-1],
|
|
887
|
+
"challenge_chain",
|
|
888
|
+
recursive_replace(
|
|
889
|
+
block.finished_sub_slots[-1].challenge_chain,
|
|
890
|
+
"challenge_chain_end_of_slot_vdf.output",
|
|
891
|
+
ClassgroupElement.get_default_element(),
|
|
892
|
+
),
|
|
893
|
+
)
|
|
894
|
+
|
|
895
|
+
new_finished_ss_2 = recursive_replace(
|
|
896
|
+
new_finished_ss_2,
|
|
897
|
+
"reward_chain.challenge_chain_sub_slot_hash",
|
|
898
|
+
new_finished_ss_2.challenge_chain.get_hash(),
|
|
899
|
+
)
|
|
900
|
+
block_bad_2 = recursive_replace(
|
|
901
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_2]
|
|
902
|
+
)
|
|
903
|
+
await _validate_and_add_block(empty_blockchain, block_bad_2, expected_error=Err.INVALID_CC_EOS_VDF)
|
|
904
|
+
|
|
905
|
+
# Bad challenge hash
|
|
906
|
+
new_finished_ss_3 = recursive_replace(
|
|
907
|
+
block.finished_sub_slots[-1],
|
|
908
|
+
"challenge_chain",
|
|
909
|
+
recursive_replace(
|
|
910
|
+
block.finished_sub_slots[-1].challenge_chain,
|
|
911
|
+
"challenge_chain_end_of_slot_vdf.challenge",
|
|
912
|
+
bytes([1] * 32),
|
|
913
|
+
),
|
|
914
|
+
)
|
|
915
|
+
|
|
916
|
+
new_finished_ss_3 = recursive_replace(
|
|
917
|
+
new_finished_ss_3,
|
|
918
|
+
"reward_chain.challenge_chain_sub_slot_hash",
|
|
919
|
+
new_finished_ss_3.challenge_chain.get_hash(),
|
|
920
|
+
)
|
|
921
|
+
block_bad_3 = recursive_replace(
|
|
922
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_3]
|
|
923
|
+
)
|
|
924
|
+
|
|
925
|
+
await _validate_and_add_block_multi_error(
|
|
926
|
+
empty_blockchain,
|
|
927
|
+
block_bad_3,
|
|
928
|
+
[Err.INVALID_CC_EOS_VDF, Err.INVALID_PREV_CHALLENGE_SLOT_HASH, Err.INVALID_POSPACE],
|
|
929
|
+
)
|
|
930
|
+
|
|
931
|
+
# Bad proof
|
|
932
|
+
new_finished_ss_5 = recursive_replace(
|
|
933
|
+
block.finished_sub_slots[-1],
|
|
934
|
+
"proofs.challenge_chain_slot_proof",
|
|
935
|
+
VDFProof(uint8(0), b"1239819023890", False),
|
|
936
|
+
)
|
|
937
|
+
block_bad_5 = recursive_replace(
|
|
938
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_5]
|
|
939
|
+
)
|
|
940
|
+
await _validate_and_add_block(empty_blockchain, block_bad_5, expected_error=Err.INVALID_CC_EOS_VDF)
|
|
941
|
+
|
|
942
|
+
await _validate_and_add_block(empty_blockchain, block)
|
|
943
|
+
|
|
944
|
+
@pytest.mark.anyio
|
|
945
|
+
async def test_invalid_rc_sub_slot_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
946
|
+
# 2p
|
|
947
|
+
blocks: list[FullBlock] = []
|
|
948
|
+
found_block: bool = False
|
|
949
|
+
|
|
950
|
+
while not found_block:
|
|
951
|
+
blocks = bt.get_consecutive_blocks(1, blocks)
|
|
952
|
+
block = blocks[-1]
|
|
953
|
+
if (
|
|
954
|
+
len(block.finished_sub_slots)
|
|
955
|
+
and block.finished_sub_slots[-1].reward_chain.end_of_slot_vdf.output
|
|
956
|
+
!= ClassgroupElement.get_default_element()
|
|
957
|
+
):
|
|
958
|
+
found_block = True
|
|
959
|
+
# Bad iters
|
|
960
|
+
new_finished_ss = recursive_replace(
|
|
961
|
+
block.finished_sub_slots[-1],
|
|
962
|
+
"reward_chain",
|
|
963
|
+
recursive_replace(
|
|
964
|
+
block.finished_sub_slots[-1].reward_chain,
|
|
965
|
+
"end_of_slot_vdf.number_of_iterations",
|
|
966
|
+
uint64(10000000),
|
|
967
|
+
),
|
|
968
|
+
)
|
|
969
|
+
block_bad = recursive_replace(
|
|
970
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss]
|
|
971
|
+
)
|
|
972
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_EOS_VDF)
|
|
973
|
+
|
|
974
|
+
# Bad output
|
|
975
|
+
new_finished_ss_2 = recursive_replace(
|
|
976
|
+
block.finished_sub_slots[-1],
|
|
977
|
+
"reward_chain",
|
|
978
|
+
recursive_replace(
|
|
979
|
+
block.finished_sub_slots[-1].reward_chain,
|
|
980
|
+
"end_of_slot_vdf.output",
|
|
981
|
+
ClassgroupElement.get_default_element(),
|
|
982
|
+
),
|
|
983
|
+
)
|
|
984
|
+
block_bad_2 = recursive_replace(
|
|
985
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_2]
|
|
986
|
+
)
|
|
987
|
+
await _validate_and_add_block(empty_blockchain, block_bad_2, expected_error=Err.INVALID_RC_EOS_VDF)
|
|
988
|
+
|
|
989
|
+
# Bad challenge hash
|
|
990
|
+
new_finished_ss_3 = recursive_replace(
|
|
991
|
+
block.finished_sub_slots[-1],
|
|
992
|
+
"reward_chain",
|
|
993
|
+
recursive_replace(
|
|
994
|
+
block.finished_sub_slots[-1].reward_chain,
|
|
995
|
+
"end_of_slot_vdf.challenge",
|
|
996
|
+
bytes32([1] * 32),
|
|
997
|
+
),
|
|
998
|
+
)
|
|
999
|
+
block_bad_3 = recursive_replace(
|
|
1000
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_3]
|
|
1001
|
+
)
|
|
1002
|
+
await _validate_and_add_block(empty_blockchain, block_bad_3, expected_error=Err.INVALID_RC_EOS_VDF)
|
|
1003
|
+
|
|
1004
|
+
# Bad proof
|
|
1005
|
+
new_finished_ss_5 = recursive_replace(
|
|
1006
|
+
block.finished_sub_slots[-1],
|
|
1007
|
+
"proofs.reward_chain_slot_proof",
|
|
1008
|
+
VDFProof(uint8(0), b"1239819023890", False),
|
|
1009
|
+
)
|
|
1010
|
+
block_bad_5 = recursive_replace(
|
|
1011
|
+
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_5]
|
|
1012
|
+
)
|
|
1013
|
+
await _validate_and_add_block(empty_blockchain, block_bad_5, expected_error=Err.INVALID_RC_EOS_VDF)
|
|
1014
|
+
|
|
1015
|
+
await _validate_and_add_block(empty_blockchain, block)
|
|
1016
|
+
|
|
1017
|
+
@pytest.mark.anyio
|
|
1018
|
+
async def test_genesis_bad_deficit(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1019
|
+
# 2r
|
|
1020
|
+
block = bt.get_consecutive_blocks(1, skip_slots=2)[0]
|
|
1021
|
+
new_finished_ss = recursive_replace(
|
|
1022
|
+
block.finished_sub_slots[-1],
|
|
1023
|
+
"reward_chain",
|
|
1024
|
+
recursive_replace(
|
|
1025
|
+
block.finished_sub_slots[-1].reward_chain,
|
|
1026
|
+
"deficit",
|
|
1027
|
+
bt.constants.MIN_BLOCKS_PER_CHALLENGE_BLOCK - 1,
|
|
1028
|
+
),
|
|
1029
|
+
)
|
|
1030
|
+
block_bad = recursive_replace(block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss])
|
|
1031
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_DEFICIT)
|
|
1032
|
+
|
|
1033
|
+
@pytest.mark.anyio
|
|
1034
|
+
async def test_reset_deficit(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1035
|
+
# 2s, 2t
|
|
1036
|
+
blockchain = empty_blockchain
|
|
1037
|
+
blocks = bt.get_consecutive_blocks(2)
|
|
1038
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1039
|
+
await _validate_and_add_block(empty_blockchain, blocks[1])
|
|
1040
|
+
case_1, case_2 = False, False
|
|
1041
|
+
while not case_1 or not case_2:
|
|
1042
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
|
|
1043
|
+
if len(blocks[-1].finished_sub_slots) > 0:
|
|
1044
|
+
new_finished_ss = recursive_replace(
|
|
1045
|
+
blocks[-1].finished_sub_slots[-1],
|
|
1046
|
+
"reward_chain",
|
|
1047
|
+
recursive_replace(
|
|
1048
|
+
blocks[-1].finished_sub_slots[-1].reward_chain,
|
|
1049
|
+
"deficit",
|
|
1050
|
+
uint8(0),
|
|
1051
|
+
),
|
|
1052
|
+
)
|
|
1053
|
+
if blockchain.block_record(blocks[-2].header_hash).deficit == 0:
|
|
1054
|
+
case_1 = True
|
|
1055
|
+
else:
|
|
1056
|
+
case_2 = True
|
|
1057
|
+
|
|
1058
|
+
block_bad = recursive_replace(
|
|
1059
|
+
blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
|
|
1060
|
+
)
|
|
1061
|
+
await _validate_and_add_block_multi_error(
|
|
1062
|
+
empty_blockchain, block_bad, [Err.INVALID_DEFICIT, Err.INVALID_ICC_HASH_CC]
|
|
1063
|
+
)
|
|
1064
|
+
|
|
1065
|
+
await _validate_and_add_block(empty_blockchain, blocks[-1])
|
|
1066
|
+
|
|
1067
|
+
@pytest.mark.anyio
|
|
1068
|
+
async def test_genesis_has_ses(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1069
|
+
# 3a
|
|
1070
|
+
block = bt.get_consecutive_blocks(1, skip_slots=1)[0]
|
|
1071
|
+
new_finished_ss = recursive_replace(
|
|
1072
|
+
block.finished_sub_slots[0],
|
|
1073
|
+
"challenge_chain",
|
|
1074
|
+
recursive_replace(
|
|
1075
|
+
block.finished_sub_slots[0].challenge_chain,
|
|
1076
|
+
"subepoch_summary_hash",
|
|
1077
|
+
bytes32.zeros,
|
|
1078
|
+
),
|
|
1079
|
+
)
|
|
1080
|
+
|
|
1081
|
+
new_finished_ss = recursive_replace(
|
|
1082
|
+
new_finished_ss,
|
|
1083
|
+
"reward_chain",
|
|
1084
|
+
new_finished_ss.reward_chain.replace(
|
|
1085
|
+
challenge_chain_sub_slot_hash=new_finished_ss.challenge_chain.get_hash()
|
|
1086
|
+
),
|
|
1087
|
+
)
|
|
1088
|
+
block_bad = recursive_replace(block, "finished_sub_slots", [new_finished_ss] + block.finished_sub_slots[1:])
|
|
1089
|
+
with pytest.raises(AssertionError):
|
|
1090
|
+
# Fails pre validation
|
|
1091
|
+
await _validate_and_add_block(
|
|
1092
|
+
empty_blockchain, block_bad, expected_error=Err.INVALID_SUB_EPOCH_SUMMARY_HASH
|
|
1093
|
+
)
|
|
1094
|
+
|
|
1095
|
+
@pytest.mark.anyio
|
|
1096
|
+
async def test_no_ses_if_no_se(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1097
|
+
# 3b
|
|
1098
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1099
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1100
|
+
|
|
1101
|
+
while True:
|
|
1102
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1103
|
+
if len(blocks[-1].finished_sub_slots) > 0 and is_overflow_block(
|
|
1104
|
+
bt.constants, blocks[-1].reward_chain_block.signage_point_index
|
|
1105
|
+
):
|
|
1106
|
+
new_finished_ss: EndOfSubSlotBundle = recursive_replace(
|
|
1107
|
+
blocks[-1].finished_sub_slots[0],
|
|
1108
|
+
"challenge_chain",
|
|
1109
|
+
recursive_replace(
|
|
1110
|
+
blocks[-1].finished_sub_slots[0].challenge_chain,
|
|
1111
|
+
"subepoch_summary_hash",
|
|
1112
|
+
bytes32.zeros,
|
|
1113
|
+
),
|
|
1114
|
+
)
|
|
1115
|
+
|
|
1116
|
+
new_finished_ss = recursive_replace(
|
|
1117
|
+
new_finished_ss,
|
|
1118
|
+
"reward_chain",
|
|
1119
|
+
new_finished_ss.reward_chain.replace(
|
|
1120
|
+
challenge_chain_sub_slot_hash=new_finished_ss.challenge_chain.get_hash(),
|
|
1121
|
+
),
|
|
1122
|
+
)
|
|
1123
|
+
block_bad = recursive_replace(
|
|
1124
|
+
blocks[-1], "finished_sub_slots", [new_finished_ss] + blocks[-1].finished_sub_slots[1:]
|
|
1125
|
+
)
|
|
1126
|
+
await _validate_and_add_block_multi_error(
|
|
1127
|
+
empty_blockchain,
|
|
1128
|
+
block_bad,
|
|
1129
|
+
expected_errors=[
|
|
1130
|
+
Err.INVALID_SUB_EPOCH_SUMMARY_HASH,
|
|
1131
|
+
Err.INVALID_SUB_EPOCH_SUMMARY,
|
|
1132
|
+
],
|
|
1133
|
+
)
|
|
1134
|
+
return None
|
|
1135
|
+
await _validate_and_add_block(empty_blockchain, blocks[-1])
|
|
1136
|
+
|
|
1137
|
+
@pytest.mark.anyio
|
|
1138
|
+
async def test_too_many_blocks(self, empty_blockchain: Blockchain) -> None:
|
|
1139
|
+
# 4: TODO
|
|
1140
|
+
pass
|
|
1141
|
+
|
|
1142
|
+
@pytest.mark.anyio
|
|
1143
|
+
async def test_bad_pos(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1144
|
+
# 5
|
|
1145
|
+
blocks = bt.get_consecutive_blocks(2)
|
|
1146
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1147
|
+
|
|
1148
|
+
block_bad = recursive_replace(blocks[-1], "reward_chain_block.proof_of_space.challenge", std_hash(b""))
|
|
1149
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POSPACE)
|
|
1150
|
+
|
|
1151
|
+
block_bad = recursive_replace(
|
|
1152
|
+
blocks[-1], "reward_chain_block.proof_of_space.pool_contract_puzzle_hash", std_hash(b"")
|
|
1153
|
+
)
|
|
1154
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POSPACE)
|
|
1155
|
+
|
|
1156
|
+
block_bad = recursive_replace(blocks[-1], "reward_chain_block.proof_of_space.size", 62)
|
|
1157
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POSPACE)
|
|
1158
|
+
|
|
1159
|
+
block_bad = recursive_replace(
|
|
1160
|
+
blocks[-1],
|
|
1161
|
+
"reward_chain_block.proof_of_space.plot_public_key",
|
|
1162
|
+
AugSchemeMPL.key_gen(std_hash(b"1231n")).get_g1(),
|
|
1163
|
+
)
|
|
1164
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POSPACE)
|
|
1165
|
+
block_bad = recursive_replace(
|
|
1166
|
+
blocks[-1],
|
|
1167
|
+
"reward_chain_block.proof_of_space.size",
|
|
1168
|
+
32,
|
|
1169
|
+
)
|
|
1170
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POSPACE)
|
|
1171
|
+
block_bad = recursive_replace(
|
|
1172
|
+
blocks[-1],
|
|
1173
|
+
"reward_chain_block.proof_of_space.proof",
|
|
1174
|
+
bytes([1] * int(blocks[-1].reward_chain_block.proof_of_space.size * 64 / 8)),
|
|
1175
|
+
)
|
|
1176
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POSPACE)
|
|
1177
|
+
|
|
1178
|
+
# TODO: test not passing the plot filter
|
|
1179
|
+
|
|
1180
|
+
@pytest.mark.anyio
|
|
1181
|
+
async def test_bad_signage_point_index(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1182
|
+
# 6
|
|
1183
|
+
blocks = bt.get_consecutive_blocks(2)
|
|
1184
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1185
|
+
|
|
1186
|
+
with pytest.raises(ValueError):
|
|
1187
|
+
block_bad = recursive_replace(
|
|
1188
|
+
blocks[-1], "reward_chain_block.signage_point_index", bt.constants.NUM_SPS_SUB_SLOT
|
|
1189
|
+
)
|
|
1190
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_SP_INDEX)
|
|
1191
|
+
with pytest.raises(ValueError):
|
|
1192
|
+
block_bad = recursive_replace(
|
|
1193
|
+
blocks[-1], "reward_chain_block.signage_point_index", bt.constants.NUM_SPS_SUB_SLOT + 1
|
|
1194
|
+
)
|
|
1195
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_SP_INDEX)
|
|
1196
|
+
|
|
1197
|
+
@pytest.mark.anyio
|
|
1198
|
+
async def test_sp_0_no_sp(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1199
|
+
# 7
|
|
1200
|
+
blocks: list[FullBlock] = []
|
|
1201
|
+
case_1, case_2 = False, False
|
|
1202
|
+
while not case_1 or not case_2:
|
|
1203
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1204
|
+
if blocks[-1].reward_chain_block.signage_point_index == 0:
|
|
1205
|
+
case_1 = True
|
|
1206
|
+
block_bad = recursive_replace(blocks[-1], "reward_chain_block.signage_point_index", uint8(1))
|
|
1207
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_SP_INDEX)
|
|
1208
|
+
|
|
1209
|
+
elif not is_overflow_block(bt.constants, blocks[-1].reward_chain_block.signage_point_index):
|
|
1210
|
+
case_2 = True
|
|
1211
|
+
block_bad = recursive_replace(blocks[-1], "reward_chain_block.signage_point_index", uint8(0))
|
|
1212
|
+
await _validate_and_add_block_multi_error(
|
|
1213
|
+
empty_blockchain, block_bad, [Err.INVALID_SP_INDEX, Err.INVALID_POSPACE]
|
|
1214
|
+
)
|
|
1215
|
+
await _validate_and_add_block(empty_blockchain, blocks[-1])
|
|
1216
|
+
|
|
1217
|
+
@pytest.mark.anyio
|
|
1218
|
+
async def test_epoch_overflows(self, empty_blockchain: Blockchain) -> None:
|
|
1219
|
+
# 9. TODO. This is hard to test because it requires modifying the block tools to make these special blocks
|
|
1220
|
+
pass
|
|
1221
|
+
|
|
1222
|
+
@pytest.mark.anyio
|
|
1223
|
+
async def test_bad_total_iters(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1224
|
+
# 10
|
|
1225
|
+
blocks = bt.get_consecutive_blocks(2)
|
|
1226
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1227
|
+
|
|
1228
|
+
block_bad = recursive_replace(
|
|
1229
|
+
blocks[-1], "reward_chain_block.total_iters", blocks[-1].reward_chain_block.total_iters + 1
|
|
1230
|
+
)
|
|
1231
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_TOTAL_ITERS)
|
|
1232
|
+
|
|
1233
|
+
@pytest.mark.anyio
|
|
1234
|
+
async def test_bad_rc_sp_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1235
|
+
# 11
|
|
1236
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1237
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1238
|
+
|
|
1239
|
+
while True:
|
|
1240
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1241
|
+
if blocks[-1].reward_chain_block.signage_point_index != 0:
|
|
1242
|
+
block_bad = recursive_replace(
|
|
1243
|
+
blocks[-1], "reward_chain_block.reward_chain_sp_vdf.challenge", std_hash(b"1")
|
|
1244
|
+
)
|
|
1245
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_SP_VDF)
|
|
1246
|
+
block_bad = recursive_replace(
|
|
1247
|
+
blocks[-1],
|
|
1248
|
+
"reward_chain_block.reward_chain_sp_vdf.output",
|
|
1249
|
+
bad_element,
|
|
1250
|
+
)
|
|
1251
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_SP_VDF)
|
|
1252
|
+
block_bad = recursive_replace(
|
|
1253
|
+
blocks[-1],
|
|
1254
|
+
"reward_chain_block.reward_chain_sp_vdf.number_of_iterations",
|
|
1255
|
+
uint64(1111111111111),
|
|
1256
|
+
)
|
|
1257
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_SP_VDF)
|
|
1258
|
+
block_bad = recursive_replace(
|
|
1259
|
+
blocks[-1],
|
|
1260
|
+
"reward_chain_sp_proof",
|
|
1261
|
+
VDFProof(uint8(0), std_hash(b""), False),
|
|
1262
|
+
)
|
|
1263
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_SP_VDF)
|
|
1264
|
+
return None
|
|
1265
|
+
await _validate_and_add_block(empty_blockchain, blocks[-1])
|
|
1266
|
+
|
|
1267
|
+
@pytest.mark.anyio
|
|
1268
|
+
async def test_bad_rc_sp_sig(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1269
|
+
# 12
|
|
1270
|
+
blocks = bt.get_consecutive_blocks(2)
|
|
1271
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1272
|
+
block_bad = recursive_replace(blocks[-1], "reward_chain_block.reward_chain_sp_signature", G2Element.generator())
|
|
1273
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_SIGNATURE)
|
|
1274
|
+
|
|
1275
|
+
@pytest.mark.anyio
|
|
1276
|
+
async def test_bad_cc_sp_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1277
|
+
# 13. Note: does not validate fully due to proof of space being validated first
|
|
1278
|
+
|
|
1279
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1280
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1281
|
+
|
|
1282
|
+
while True:
|
|
1283
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1284
|
+
if blocks[-1].reward_chain_block.signage_point_index != 0:
|
|
1285
|
+
block_bad = recursive_replace(
|
|
1286
|
+
blocks[-1], "reward_chain_block.challenge_chain_sp_vdf.challenge", std_hash(b"1")
|
|
1287
|
+
)
|
|
1288
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK)
|
|
1289
|
+
block_bad = recursive_replace(
|
|
1290
|
+
blocks[-1],
|
|
1291
|
+
"reward_chain_block.challenge_chain_sp_vdf.output",
|
|
1292
|
+
bad_element,
|
|
1293
|
+
)
|
|
1294
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK)
|
|
1295
|
+
block_bad = recursive_replace(
|
|
1296
|
+
blocks[-1],
|
|
1297
|
+
"reward_chain_block.challenge_chain_sp_vdf.number_of_iterations",
|
|
1298
|
+
uint64(1111111111111),
|
|
1299
|
+
)
|
|
1300
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_result=AddBlockResult.INVALID_BLOCK)
|
|
1301
|
+
block_bad = recursive_replace(
|
|
1302
|
+
blocks[-1],
|
|
1303
|
+
"challenge_chain_sp_proof",
|
|
1304
|
+
VDFProof(uint8(0), std_hash(b""), False),
|
|
1305
|
+
)
|
|
1306
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_SP_VDF)
|
|
1307
|
+
return None
|
|
1308
|
+
await _validate_and_add_block(empty_blockchain, blocks[-1])
|
|
1309
|
+
|
|
1310
|
+
@pytest.mark.anyio
|
|
1311
|
+
async def test_bad_cc_sp_sig(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1312
|
+
# 14
|
|
1313
|
+
blocks = bt.get_consecutive_blocks(2)
|
|
1314
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1315
|
+
block_bad = recursive_replace(
|
|
1316
|
+
blocks[-1], "reward_chain_block.challenge_chain_sp_signature", G2Element.generator()
|
|
1317
|
+
)
|
|
1318
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_SIGNATURE)
|
|
1319
|
+
|
|
1320
|
+
@pytest.mark.anyio
|
|
1321
|
+
async def test_is_transaction_block(self, empty_blockchain: Blockchain) -> None:
|
|
1322
|
+
# 15: TODO
|
|
1323
|
+
pass
|
|
1324
|
+
|
|
1325
|
+
@pytest.mark.anyio
|
|
1326
|
+
async def test_bad_foliage_sb_sig(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1327
|
+
# 16
|
|
1328
|
+
blocks = bt.get_consecutive_blocks(2)
|
|
1329
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1330
|
+
block_bad = recursive_replace(blocks[-1], "foliage.foliage_block_data_signature", G2Element.generator())
|
|
1331
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_PLOT_SIGNATURE)
|
|
1332
|
+
|
|
1333
|
+
@pytest.mark.anyio
|
|
1334
|
+
async def test_bad_foliage_transaction_block_sig(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1335
|
+
# 17
|
|
1336
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1337
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1338
|
+
|
|
1339
|
+
while True:
|
|
1340
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1341
|
+
if blocks[-1].foliage_transaction_block is not None:
|
|
1342
|
+
block_bad = recursive_replace(
|
|
1343
|
+
blocks[-1], "foliage.foliage_transaction_block_signature", G2Element.generator()
|
|
1344
|
+
)
|
|
1345
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_PLOT_SIGNATURE)
|
|
1346
|
+
return None
|
|
1347
|
+
await _validate_and_add_block(empty_blockchain, blocks[-1])
|
|
1348
|
+
|
|
1349
|
+
@pytest.mark.anyio
|
|
1350
|
+
async def test_unfinished_reward_chain_sb_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1351
|
+
# 18
|
|
1352
|
+
blocks = bt.get_consecutive_blocks(2)
|
|
1353
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1354
|
+
block_bad: FullBlock = recursive_replace(
|
|
1355
|
+
blocks[-1], "foliage.foliage_block_data.unfinished_reward_block_hash", std_hash(b"2")
|
|
1356
|
+
)
|
|
1357
|
+
new_m = block_bad.foliage.foliage_block_data.get_hash()
|
|
1358
|
+
assert new_m is not None
|
|
1359
|
+
new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
|
|
1360
|
+
block_bad = recursive_replace(block_bad, "foliage.foliage_block_data_signature", new_fsb_sig)
|
|
1361
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_URSB_HASH)
|
|
1362
|
+
|
|
1363
|
+
@pytest.mark.anyio
|
|
1364
|
+
async def test_pool_target_height(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1365
|
+
# 19
|
|
1366
|
+
blocks = bt.get_consecutive_blocks(3)
|
|
1367
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1368
|
+
await _validate_and_add_block(empty_blockchain, blocks[1])
|
|
1369
|
+
block_bad: FullBlock = recursive_replace(blocks[-1], "foliage.foliage_block_data.pool_target.max_height", 1)
|
|
1370
|
+
new_m = block_bad.foliage.foliage_block_data.get_hash()
|
|
1371
|
+
assert new_m is not None
|
|
1372
|
+
new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
|
|
1373
|
+
block_bad = recursive_replace(block_bad, "foliage.foliage_block_data_signature", new_fsb_sig)
|
|
1374
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.OLD_POOL_TARGET)
|
|
1375
|
+
|
|
1376
|
+
@pytest.mark.anyio
|
|
1377
|
+
async def test_pool_target_pre_farm(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1378
|
+
# 20a
|
|
1379
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1380
|
+
block_bad: FullBlock = recursive_replace(
|
|
1381
|
+
blocks[-1], "foliage.foliage_block_data.pool_target.puzzle_hash", std_hash(b"12")
|
|
1382
|
+
)
|
|
1383
|
+
new_m = block_bad.foliage.foliage_block_data.get_hash()
|
|
1384
|
+
assert new_m is not None
|
|
1385
|
+
new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
|
|
1386
|
+
block_bad = recursive_replace(block_bad, "foliage.foliage_block_data_signature", new_fsb_sig)
|
|
1387
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_PREFARM)
|
|
1388
|
+
|
|
1389
|
+
@pytest.mark.anyio
|
|
1390
|
+
async def test_pool_target_signature(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1391
|
+
# 20b
|
|
1392
|
+
blocks_initial = bt.get_consecutive_blocks(2)
|
|
1393
|
+
await _validate_and_add_block(empty_blockchain, blocks_initial[0])
|
|
1394
|
+
await _validate_and_add_block(empty_blockchain, blocks_initial[1])
|
|
1395
|
+
|
|
1396
|
+
attempts = 0
|
|
1397
|
+
while True:
|
|
1398
|
+
# Go until we get a block that has a pool pk, as opposed to a pool contract
|
|
1399
|
+
blocks = bt.get_consecutive_blocks(
|
|
1400
|
+
1, blocks_initial, seed=std_hash(attempts.to_bytes(4, byteorder="big", signed=False))
|
|
1401
|
+
)
|
|
1402
|
+
if blocks[-1].foliage.foliage_block_data.pool_signature is not None:
|
|
1403
|
+
block_bad: FullBlock = recursive_replace(
|
|
1404
|
+
blocks[-1], "foliage.foliage_block_data.pool_signature", G2Element.generator()
|
|
1405
|
+
)
|
|
1406
|
+
new_m = block_bad.foliage.foliage_block_data.get_hash()
|
|
1407
|
+
assert new_m is not None
|
|
1408
|
+
new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
|
|
1409
|
+
block_bad = recursive_replace(block_bad, "foliage.foliage_block_data_signature", new_fsb_sig)
|
|
1410
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POOL_SIGNATURE)
|
|
1411
|
+
return None
|
|
1412
|
+
attempts += 1
|
|
1413
|
+
|
|
1414
|
+
@pytest.mark.anyio
|
|
1415
|
+
async def test_pool_target_contract(
|
|
1416
|
+
self, empty_blockchain: Blockchain, bt: BlockTools, seeded_random: random.Random
|
|
1417
|
+
) -> None:
|
|
1418
|
+
# 20c invalid pool target with contract
|
|
1419
|
+
blocks_initial = bt.get_consecutive_blocks(2)
|
|
1420
|
+
await _validate_and_add_block(empty_blockchain, blocks_initial[0])
|
|
1421
|
+
await _validate_and_add_block(empty_blockchain, blocks_initial[1])
|
|
1422
|
+
|
|
1423
|
+
attempts = 0
|
|
1424
|
+
while True:
|
|
1425
|
+
# Go until we get a block that has a pool contract opposed to a pool pk
|
|
1426
|
+
blocks = bt.get_consecutive_blocks(
|
|
1427
|
+
1, blocks_initial, seed=std_hash(attempts.to_bytes(4, byteorder="big", signed=False))
|
|
1428
|
+
)
|
|
1429
|
+
if blocks[-1].foliage.foliage_block_data.pool_signature is None:
|
|
1430
|
+
block_bad: FullBlock = recursive_replace(
|
|
1431
|
+
blocks[-1], "foliage.foliage_block_data.pool_target.puzzle_hash", bytes32.random(seeded_random)
|
|
1432
|
+
)
|
|
1433
|
+
new_m = block_bad.foliage.foliage_block_data.get_hash()
|
|
1434
|
+
assert new_m is not None
|
|
1435
|
+
new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
|
|
1436
|
+
block_bad = recursive_replace(block_bad, "foliage.foliage_block_data_signature", new_fsb_sig)
|
|
1437
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_POOL_TARGET)
|
|
1438
|
+
return None
|
|
1439
|
+
attempts += 1
|
|
1440
|
+
|
|
1441
|
+
@pytest.mark.anyio
|
|
1442
|
+
async def test_foliage_data_presence(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1443
|
+
# 22
|
|
1444
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1445
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1446
|
+
case_1, case_2 = False, False
|
|
1447
|
+
while not case_1 or not case_2:
|
|
1448
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1449
|
+
if blocks[-1].foliage_transaction_block is not None:
|
|
1450
|
+
case_1 = True
|
|
1451
|
+
block_bad: FullBlock = recursive_replace(blocks[-1], "foliage.foliage_transaction_block_hash", None)
|
|
1452
|
+
else:
|
|
1453
|
+
case_2 = True
|
|
1454
|
+
block_bad = recursive_replace(blocks[-1], "foliage.foliage_transaction_block_hash", std_hash(b""))
|
|
1455
|
+
await _validate_and_add_block_multi_error(
|
|
1456
|
+
empty_blockchain,
|
|
1457
|
+
block_bad,
|
|
1458
|
+
[
|
|
1459
|
+
Err.INVALID_FOLIAGE_BLOCK_PRESENCE,
|
|
1460
|
+
Err.INVALID_IS_TRANSACTION_BLOCK,
|
|
1461
|
+
Err.INVALID_PREV_BLOCK_HASH,
|
|
1462
|
+
Err.INVALID_PREV_BLOCK_HASH,
|
|
1463
|
+
],
|
|
1464
|
+
)
|
|
1465
|
+
|
|
1466
|
+
@pytest.mark.anyio
|
|
1467
|
+
async def test_foliage_transaction_block_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1468
|
+
# 23
|
|
1469
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1470
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1471
|
+
case_1, case_2 = False, False
|
|
1472
|
+
while not case_1 or not case_2:
|
|
1473
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1474
|
+
if blocks[-1].foliage_transaction_block is not None:
|
|
1475
|
+
block_bad: FullBlock = recursive_replace(
|
|
1476
|
+
blocks[-1], "foliage.foliage_transaction_block_hash", std_hash(b"2")
|
|
1477
|
+
)
|
|
1478
|
+
|
|
1479
|
+
new_m = block_bad.foliage.foliage_transaction_block_hash
|
|
1480
|
+
assert new_m is not None
|
|
1481
|
+
new_fbh_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
|
|
1482
|
+
block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
|
|
1483
|
+
await _validate_and_add_block(
|
|
1484
|
+
empty_blockchain, block_bad, expected_error=Err.INVALID_FOLIAGE_BLOCK_HASH
|
|
1485
|
+
)
|
|
1486
|
+
return None
|
|
1487
|
+
await _validate_and_add_block(empty_blockchain, blocks[-1])
|
|
1488
|
+
|
|
1489
|
+
@pytest.mark.anyio
|
|
1490
|
+
async def test_genesis_bad_prev_block(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1491
|
+
# 24a
|
|
1492
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1493
|
+
block_bad: FullBlock = recursive_replace(
|
|
1494
|
+
blocks[-1], "foliage_transaction_block.prev_transaction_block_hash", std_hash(b"2")
|
|
1495
|
+
)
|
|
1496
|
+
assert block_bad.foliage_transaction_block is not None
|
|
1497
|
+
block_bad = recursive_replace(
|
|
1498
|
+
block_bad, "foliage.foliage_transaction_block_hash", block_bad.foliage_transaction_block.get_hash()
|
|
1499
|
+
)
|
|
1500
|
+
new_m = block_bad.foliage.foliage_transaction_block_hash
|
|
1501
|
+
assert new_m is not None
|
|
1502
|
+
new_fbh_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
|
|
1503
|
+
block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
|
|
1504
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_PREV_BLOCK_HASH)
|
|
1505
|
+
|
|
1506
|
+
@pytest.mark.anyio
|
|
1507
|
+
async def test_bad_prev_block_non_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1508
|
+
# 24b
|
|
1509
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1510
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1511
|
+
while True:
|
|
1512
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1513
|
+
if blocks[-1].foliage_transaction_block is not None:
|
|
1514
|
+
block_bad: FullBlock = recursive_replace(
|
|
1515
|
+
blocks[-1], "foliage_transaction_block.prev_transaction_block_hash", std_hash(b"2")
|
|
1516
|
+
)
|
|
1517
|
+
assert block_bad.foliage_transaction_block is not None
|
|
1518
|
+
block_bad = recursive_replace(
|
|
1519
|
+
block_bad, "foliage.foliage_transaction_block_hash", block_bad.foliage_transaction_block.get_hash()
|
|
1520
|
+
)
|
|
1521
|
+
new_m = block_bad.foliage.foliage_transaction_block_hash
|
|
1522
|
+
assert new_m is not None
|
|
1523
|
+
new_fbh_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
|
|
1524
|
+
block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
|
|
1525
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_PREV_BLOCK_HASH)
|
|
1526
|
+
return None
|
|
1527
|
+
await _validate_and_add_block(empty_blockchain, blocks[-1])
|
|
1528
|
+
|
|
1529
|
+
@pytest.mark.anyio
|
|
1530
|
+
async def test_bad_filter_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1531
|
+
# 25
|
|
1532
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1533
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1534
|
+
while True:
|
|
1535
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1536
|
+
if blocks[-1].foliage_transaction_block is not None:
|
|
1537
|
+
block_bad: FullBlock = recursive_replace(
|
|
1538
|
+
blocks[-1], "foliage_transaction_block.filter_hash", std_hash(b"2")
|
|
1539
|
+
)
|
|
1540
|
+
assert block_bad.foliage_transaction_block is not None
|
|
1541
|
+
block_bad = recursive_replace(
|
|
1542
|
+
block_bad, "foliage.foliage_transaction_block_hash", block_bad.foliage_transaction_block.get_hash()
|
|
1543
|
+
)
|
|
1544
|
+
new_m = block_bad.foliage.foliage_transaction_block_hash
|
|
1545
|
+
assert new_m is not None
|
|
1546
|
+
new_fbh_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
|
|
1547
|
+
block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
|
|
1548
|
+
await _validate_and_add_block(
|
|
1549
|
+
empty_blockchain, block_bad, expected_error=Err.INVALID_TRANSACTIONS_FILTER_HASH
|
|
1550
|
+
)
|
|
1551
|
+
return None
|
|
1552
|
+
await _validate_and_add_block(empty_blockchain, blocks[-1])
|
|
1553
|
+
|
|
1554
|
+
@pytest.mark.anyio
|
|
1555
|
+
async def test_bad_timestamp(self, bt: BlockTools) -> None:
|
|
1556
|
+
# 26
|
|
1557
|
+
# the test constants set MAX_FUTURE_TIME to 10 days, restore it to
|
|
1558
|
+
# default for this test
|
|
1559
|
+
constants = bt.constants.replace(MAX_FUTURE_TIME2=uint32(2 * 60))
|
|
1560
|
+
time_delta = 2 * 60 + 1
|
|
1561
|
+
|
|
1562
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1563
|
+
|
|
1564
|
+
async with make_empty_blockchain(constants) as b:
|
|
1565
|
+
await _validate_and_add_block(b, blocks[0])
|
|
1566
|
+
while True:
|
|
1567
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1568
|
+
if blocks[-1].foliage_transaction_block is not None:
|
|
1569
|
+
assert blocks[0].foliage_transaction_block is not None
|
|
1570
|
+
block_bad: FullBlock = recursive_replace(
|
|
1571
|
+
blocks[-1],
|
|
1572
|
+
"foliage_transaction_block.timestamp",
|
|
1573
|
+
blocks[0].foliage_transaction_block.timestamp - 10,
|
|
1574
|
+
)
|
|
1575
|
+
assert block_bad.foliage_transaction_block is not None
|
|
1576
|
+
block_bad = recursive_replace(
|
|
1577
|
+
block_bad,
|
|
1578
|
+
"foliage.foliage_transaction_block_hash",
|
|
1579
|
+
block_bad.foliage_transaction_block.get_hash(),
|
|
1580
|
+
)
|
|
1581
|
+
new_m = block_bad.foliage.foliage_transaction_block_hash
|
|
1582
|
+
assert new_m is not None
|
|
1583
|
+
new_fbh_sig = bt.get_plot_signature(
|
|
1584
|
+
new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key
|
|
1585
|
+
)
|
|
1586
|
+
block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
|
|
1587
|
+
await _validate_and_add_block(b, block_bad, expected_error=Err.TIMESTAMP_TOO_FAR_IN_PAST)
|
|
1588
|
+
|
|
1589
|
+
assert blocks[0].foliage_transaction_block is not None
|
|
1590
|
+
block_bad = recursive_replace(
|
|
1591
|
+
blocks[-1],
|
|
1592
|
+
"foliage_transaction_block.timestamp",
|
|
1593
|
+
blocks[0].foliage_transaction_block.timestamp,
|
|
1594
|
+
)
|
|
1595
|
+
assert block_bad.foliage_transaction_block is not None
|
|
1596
|
+
block_bad = recursive_replace(
|
|
1597
|
+
block_bad,
|
|
1598
|
+
"foliage.foliage_transaction_block_hash",
|
|
1599
|
+
block_bad.foliage_transaction_block.get_hash(),
|
|
1600
|
+
)
|
|
1601
|
+
new_m = block_bad.foliage.foliage_transaction_block_hash
|
|
1602
|
+
assert new_m is not None
|
|
1603
|
+
new_fbh_sig = bt.get_plot_signature(
|
|
1604
|
+
new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key
|
|
1605
|
+
)
|
|
1606
|
+
block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
|
|
1607
|
+
await _validate_and_add_block(b, block_bad, expected_error=Err.TIMESTAMP_TOO_FAR_IN_PAST)
|
|
1608
|
+
|
|
1609
|
+
# since tests can run slow sometimes, and since we're using
|
|
1610
|
+
# the system clock, add some extra slack
|
|
1611
|
+
slack = 30
|
|
1612
|
+
block_bad = recursive_replace(
|
|
1613
|
+
blocks[-1],
|
|
1614
|
+
"foliage_transaction_block.timestamp",
|
|
1615
|
+
blocks[0].foliage_transaction_block.timestamp + time_delta + slack,
|
|
1616
|
+
)
|
|
1617
|
+
assert block_bad.foliage_transaction_block is not None
|
|
1618
|
+
block_bad = recursive_replace(
|
|
1619
|
+
block_bad,
|
|
1620
|
+
"foliage.foliage_transaction_block_hash",
|
|
1621
|
+
block_bad.foliage_transaction_block.get_hash(),
|
|
1622
|
+
)
|
|
1623
|
+
new_m = block_bad.foliage.foliage_transaction_block_hash
|
|
1624
|
+
assert new_m is not None
|
|
1625
|
+
new_fbh_sig = bt.get_plot_signature(
|
|
1626
|
+
new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key
|
|
1627
|
+
)
|
|
1628
|
+
block_bad = recursive_replace(block_bad, "foliage.foliage_transaction_block_signature", new_fbh_sig)
|
|
1629
|
+
await _validate_and_add_block(b, block_bad, expected_error=Err.TIMESTAMP_TOO_FAR_IN_FUTURE)
|
|
1630
|
+
return None
|
|
1631
|
+
await _validate_and_add_block(b, blocks[-1])
|
|
1632
|
+
|
|
1633
|
+
@pytest.mark.anyio
|
|
1634
|
+
async def test_height(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1635
|
+
# 27
|
|
1636
|
+
blocks = bt.get_consecutive_blocks(2)
|
|
1637
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1638
|
+
block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_block.height", 2)
|
|
1639
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_HEIGHT)
|
|
1640
|
+
|
|
1641
|
+
@pytest.mark.anyio
|
|
1642
|
+
async def test_height_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1643
|
+
# 27
|
|
1644
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1645
|
+
block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_block.height", 1)
|
|
1646
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_PREV_BLOCK_HASH)
|
|
1647
|
+
|
|
1648
|
+
@pytest.mark.anyio
|
|
1649
|
+
async def test_weight(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1650
|
+
# 28
|
|
1651
|
+
blocks = bt.get_consecutive_blocks(2)
|
|
1652
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1653
|
+
block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_block.weight", 22131)
|
|
1654
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_WEIGHT)
|
|
1655
|
+
|
|
1656
|
+
@pytest.mark.anyio
|
|
1657
|
+
async def test_weight_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1658
|
+
# 28
|
|
1659
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1660
|
+
block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_block.weight", 0)
|
|
1661
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_WEIGHT)
|
|
1662
|
+
|
|
1663
|
+
@pytest.mark.anyio
|
|
1664
|
+
async def test_bad_cc_ip_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1665
|
+
# 29
|
|
1666
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1667
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1668
|
+
|
|
1669
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1670
|
+
block_bad = recursive_replace(blocks[-1], "reward_chain_block.challenge_chain_ip_vdf.challenge", std_hash(b"1"))
|
|
1671
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_IP_VDF)
|
|
1672
|
+
block_bad = recursive_replace(
|
|
1673
|
+
blocks[-1],
|
|
1674
|
+
"reward_chain_block.challenge_chain_ip_vdf.output",
|
|
1675
|
+
bad_element,
|
|
1676
|
+
)
|
|
1677
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_IP_VDF)
|
|
1678
|
+
block_bad = recursive_replace(
|
|
1679
|
+
blocks[-1],
|
|
1680
|
+
"reward_chain_block.challenge_chain_ip_vdf.number_of_iterations",
|
|
1681
|
+
uint64(1111111111111),
|
|
1682
|
+
)
|
|
1683
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_IP_VDF)
|
|
1684
|
+
block_bad = recursive_replace(
|
|
1685
|
+
blocks[-1],
|
|
1686
|
+
"challenge_chain_ip_proof",
|
|
1687
|
+
VDFProof(uint8(0), std_hash(b""), False),
|
|
1688
|
+
)
|
|
1689
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_CC_IP_VDF)
|
|
1690
|
+
|
|
1691
|
+
@pytest.mark.anyio
|
|
1692
|
+
async def test_bad_rc_ip_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1693
|
+
# 30
|
|
1694
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1695
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1696
|
+
|
|
1697
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1698
|
+
block_bad = recursive_replace(blocks[-1], "reward_chain_block.reward_chain_ip_vdf.challenge", std_hash(b"1"))
|
|
1699
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_IP_VDF)
|
|
1700
|
+
block_bad = recursive_replace(
|
|
1701
|
+
blocks[-1],
|
|
1702
|
+
"reward_chain_block.reward_chain_ip_vdf.output",
|
|
1703
|
+
bad_element,
|
|
1704
|
+
)
|
|
1705
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_IP_VDF)
|
|
1706
|
+
block_bad = recursive_replace(
|
|
1707
|
+
blocks[-1],
|
|
1708
|
+
"reward_chain_block.reward_chain_ip_vdf.number_of_iterations",
|
|
1709
|
+
uint64(1111111111111),
|
|
1710
|
+
)
|
|
1711
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_IP_VDF)
|
|
1712
|
+
block_bad = recursive_replace(
|
|
1713
|
+
blocks[-1],
|
|
1714
|
+
"reward_chain_ip_proof",
|
|
1715
|
+
VDFProof(uint8(0), std_hash(b""), False),
|
|
1716
|
+
)
|
|
1717
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_RC_IP_VDF)
|
|
1718
|
+
|
|
1719
|
+
@pytest.mark.anyio
|
|
1720
|
+
async def test_bad_icc_ip_vdf(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1721
|
+
# 31
|
|
1722
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1723
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1724
|
+
|
|
1725
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1726
|
+
block_bad = recursive_replace(
|
|
1727
|
+
blocks[-1], "reward_chain_block.infused_challenge_chain_ip_vdf.challenge", std_hash(b"1")
|
|
1728
|
+
)
|
|
1729
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_ICC_VDF)
|
|
1730
|
+
block_bad = recursive_replace(
|
|
1731
|
+
blocks[-1],
|
|
1732
|
+
"reward_chain_block.infused_challenge_chain_ip_vdf.output",
|
|
1733
|
+
bad_element,
|
|
1734
|
+
)
|
|
1735
|
+
|
|
1736
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_ICC_VDF)
|
|
1737
|
+
block_bad = recursive_replace(
|
|
1738
|
+
blocks[-1],
|
|
1739
|
+
"reward_chain_block.infused_challenge_chain_ip_vdf.number_of_iterations",
|
|
1740
|
+
uint64(1111111111111),
|
|
1741
|
+
)
|
|
1742
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_ICC_VDF)
|
|
1743
|
+
block_bad = recursive_replace(
|
|
1744
|
+
blocks[-1],
|
|
1745
|
+
"infused_challenge_chain_ip_proof",
|
|
1746
|
+
VDFProof(uint8(0), std_hash(b""), False),
|
|
1747
|
+
)
|
|
1748
|
+
|
|
1749
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_ICC_VDF)
|
|
1750
|
+
|
|
1751
|
+
@pytest.mark.anyio
|
|
1752
|
+
async def test_reward_block_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1753
|
+
# 32
|
|
1754
|
+
blocks = bt.get_consecutive_blocks(2)
|
|
1755
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1756
|
+
block_bad: FullBlock = recursive_replace(blocks[-1], "foliage.reward_block_hash", std_hash(b""))
|
|
1757
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_REWARD_BLOCK_HASH)
|
|
1758
|
+
|
|
1759
|
+
@pytest.mark.anyio
|
|
1760
|
+
async def test_reward_block_hash_2(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1761
|
+
# 33
|
|
1762
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
1763
|
+
block_bad: FullBlock = recursive_replace(blocks[0], "reward_chain_block.is_transaction_block", False)
|
|
1764
|
+
block_bad = recursive_replace(block_bad, "foliage.reward_block_hash", block_bad.reward_chain_block.get_hash())
|
|
1765
|
+
await _validate_and_add_block(empty_blockchain, block_bad, expected_error=Err.INVALID_FOLIAGE_BLOCK_PRESENCE)
|
|
1766
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1767
|
+
|
|
1768
|
+
# Test one which should not be a tx block
|
|
1769
|
+
while True:
|
|
1770
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
1771
|
+
if not blocks[-1].is_transaction_block():
|
|
1772
|
+
block_bad = recursive_replace(blocks[-1], "reward_chain_block.is_transaction_block", True)
|
|
1773
|
+
block_bad = recursive_replace(
|
|
1774
|
+
block_bad, "foliage.reward_block_hash", block_bad.reward_chain_block.get_hash()
|
|
1775
|
+
)
|
|
1776
|
+
await _validate_and_add_block(
|
|
1777
|
+
empty_blockchain, block_bad, expected_error=Err.INVALID_FOLIAGE_BLOCK_PRESENCE
|
|
1778
|
+
)
|
|
1779
|
+
return None
|
|
1780
|
+
await _validate_and_add_block(empty_blockchain, blocks[-1])
|
|
1781
|
+
|
|
1782
|
+
|
|
1783
|
+
co = ConditionOpcode
|
|
1784
|
+
rbr = AddBlockResult
|
|
1785
|
+
|
|
1786
|
+
|
|
1787
|
+
class TestPreValidation:
|
|
1788
|
+
@pytest.mark.anyio
|
|
1789
|
+
async def test_pre_validation_fails_bad_blocks(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
1790
|
+
blocks = bt.get_consecutive_blocks(2)
|
|
1791
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1792
|
+
ssi = empty_blockchain.constants.SUB_SLOT_ITERS_STARTING
|
|
1793
|
+
difficulty = empty_blockchain.constants.DIFFICULTY_STARTING
|
|
1794
|
+
block_bad = recursive_replace(
|
|
1795
|
+
blocks[-1], "reward_chain_block.total_iters", blocks[-1].reward_chain_block.total_iters + 1
|
|
1796
|
+
)
|
|
1797
|
+
futures = []
|
|
1798
|
+
vs = ValidationState(ssi, difficulty, None)
|
|
1799
|
+
chain = AugmentedBlockchain(empty_blockchain)
|
|
1800
|
+
for block in [blocks[0], block_bad]:
|
|
1801
|
+
futures.append(
|
|
1802
|
+
await pre_validate_block(
|
|
1803
|
+
empty_blockchain.constants,
|
|
1804
|
+
chain,
|
|
1805
|
+
block,
|
|
1806
|
+
empty_blockchain.pool,
|
|
1807
|
+
None,
|
|
1808
|
+
vs,
|
|
1809
|
+
)
|
|
1810
|
+
)
|
|
1811
|
+
res: list[PreValidationResult] = list(await asyncio.gather(*futures))
|
|
1812
|
+
assert res[0].error is None
|
|
1813
|
+
assert res[1].error is not None
|
|
1814
|
+
|
|
1815
|
+
@pytest.mark.anyio
|
|
1816
|
+
async def test_pre_validation(
|
|
1817
|
+
self, empty_blockchain: Blockchain, default_1000_blocks: list[FullBlock], bt: BlockTools
|
|
1818
|
+
) -> None:
|
|
1819
|
+
blocks = default_1000_blocks[:100]
|
|
1820
|
+
start = time.time()
|
|
1821
|
+
ssi = empty_blockchain.constants.SUB_SLOT_ITERS_STARTING
|
|
1822
|
+
difficulty = empty_blockchain.constants.DIFFICULTY_STARTING
|
|
1823
|
+
blockchain = AugmentedBlockchain(empty_blockchain)
|
|
1824
|
+
vs = ValidationState(ssi, difficulty, None)
|
|
1825
|
+
futures: list[Awaitable[PreValidationResult]] = []
|
|
1826
|
+
start = time.monotonic()
|
|
1827
|
+
for block in blocks:
|
|
1828
|
+
futures.append(
|
|
1829
|
+
await pre_validate_block(
|
|
1830
|
+
bt.constants,
|
|
1831
|
+
blockchain,
|
|
1832
|
+
block,
|
|
1833
|
+
empty_blockchain.pool,
|
|
1834
|
+
None,
|
|
1835
|
+
vs,
|
|
1836
|
+
)
|
|
1837
|
+
)
|
|
1838
|
+
|
|
1839
|
+
results = await asyncio.gather(*futures)
|
|
1840
|
+
end = time.monotonic()
|
|
1841
|
+
validation_time = start - end
|
|
1842
|
+
db_start = end
|
|
1843
|
+
|
|
1844
|
+
fork_info = ForkInfo(-1, -1, bt.constants.GENESIS_CHALLENGE)
|
|
1845
|
+
for block, res in zip(blocks, results):
|
|
1846
|
+
assert res.error is None
|
|
1847
|
+
result, err, _ = await empty_blockchain.add_block(block, res, ssi, fork_info=fork_info)
|
|
1848
|
+
assert err is None
|
|
1849
|
+
assert result == AddBlockResult.NEW_PEAK
|
|
1850
|
+
end = time.monotonic()
|
|
1851
|
+
log.info(f"Total time: {end - start} seconds")
|
|
1852
|
+
log.info(f"Average validation: {validation_time / len(blocks)}")
|
|
1853
|
+
log.info(f"Average database: {(end - db_start) / (len(blocks))}")
|
|
1854
|
+
|
|
1855
|
+
|
|
1856
|
+
class TestBodyValidation:
|
|
1857
|
+
# TODO: add test for
|
|
1858
|
+
# ASSERT_COIN_ANNOUNCEMENT,
|
|
1859
|
+
# CREATE_COIN_ANNOUNCEMENT,
|
|
1860
|
+
# CREATE_PUZZLE_ANNOUNCEMENT,
|
|
1861
|
+
# ASSERT_PUZZLE_ANNOUNCEMENT,
|
|
1862
|
+
|
|
1863
|
+
@pytest.mark.anyio
|
|
1864
|
+
@pytest.mark.parametrize(
|
|
1865
|
+
"opcode",
|
|
1866
|
+
[
|
|
1867
|
+
ConditionOpcode.ASSERT_MY_AMOUNT,
|
|
1868
|
+
ConditionOpcode.ASSERT_MY_PUZZLEHASH,
|
|
1869
|
+
ConditionOpcode.ASSERT_MY_COIN_ID,
|
|
1870
|
+
ConditionOpcode.ASSERT_MY_PARENT_ID,
|
|
1871
|
+
],
|
|
1872
|
+
)
|
|
1873
|
+
@pytest.mark.parametrize("with_garbage", [True, False])
|
|
1874
|
+
async def test_conditions(
|
|
1875
|
+
self, empty_blockchain: Blockchain, opcode: ConditionOpcode, with_garbage: bool, bt: BlockTools
|
|
1876
|
+
) -> None:
|
|
1877
|
+
b = empty_blockchain
|
|
1878
|
+
blocks = bt.get_consecutive_blocks(
|
|
1879
|
+
3,
|
|
1880
|
+
guarantee_transaction_block=True,
|
|
1881
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
1882
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
1883
|
+
genesis_timestamp=uint64(10_000),
|
|
1884
|
+
time_per_block=10,
|
|
1885
|
+
)
|
|
1886
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
1887
|
+
await _validate_and_add_block(empty_blockchain, blocks[1])
|
|
1888
|
+
await _validate_and_add_block(empty_blockchain, blocks[2])
|
|
1889
|
+
|
|
1890
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
1891
|
+
|
|
1892
|
+
tx1 = wt.generate_signed_transaction(
|
|
1893
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
1894
|
+
)
|
|
1895
|
+
coin1: Coin = tx1.additions()[0]
|
|
1896
|
+
|
|
1897
|
+
if opcode == ConditionOpcode.ASSERT_MY_AMOUNT:
|
|
1898
|
+
args = [int_to_bytes(coin1.amount)]
|
|
1899
|
+
elif opcode == ConditionOpcode.ASSERT_MY_PUZZLEHASH:
|
|
1900
|
+
args = [coin1.puzzle_hash]
|
|
1901
|
+
elif opcode == ConditionOpcode.ASSERT_MY_COIN_ID:
|
|
1902
|
+
args = [coin1.name()]
|
|
1903
|
+
elif opcode == ConditionOpcode.ASSERT_MY_PARENT_ID:
|
|
1904
|
+
args = [coin1.parent_coin_info]
|
|
1905
|
+
# elif opcode == ConditionOpcode.RESERVE_FEE:
|
|
1906
|
+
# args = [int_to_bytes(5)]
|
|
1907
|
+
# TODO: since we use the production wallet code, we can't (easily)
|
|
1908
|
+
# create a transaction with fee without also including a valid
|
|
1909
|
+
# RESERVE_FEE condition
|
|
1910
|
+
else:
|
|
1911
|
+
assert False
|
|
1912
|
+
|
|
1913
|
+
conditions: dict[ConditionOpcode, list[ConditionWithArgs]] = {
|
|
1914
|
+
opcode: [ConditionWithArgs(opcode, args + ([b"garbage"] if with_garbage else []))]
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
tx2 = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), coin1, condition_dic=conditions)
|
|
1918
|
+
assert coin1 in tx2.removals()
|
|
1919
|
+
|
|
1920
|
+
bundles = SpendBundle.aggregate([tx1, tx2])
|
|
1921
|
+
blocks = bt.get_consecutive_blocks(
|
|
1922
|
+
1,
|
|
1923
|
+
block_list_input=blocks,
|
|
1924
|
+
guarantee_transaction_block=True,
|
|
1925
|
+
transaction_data=bundles,
|
|
1926
|
+
time_per_block=10,
|
|
1927
|
+
)
|
|
1928
|
+
ssi = b.constants.SUB_SLOT_ITERS_STARTING
|
|
1929
|
+
diff = b.constants.DIFFICULTY_STARTING
|
|
1930
|
+
block = blocks[-1]
|
|
1931
|
+
future = await pre_validate_block(
|
|
1932
|
+
b.constants,
|
|
1933
|
+
AugmentedBlockchain(b),
|
|
1934
|
+
block,
|
|
1935
|
+
b.pool,
|
|
1936
|
+
None,
|
|
1937
|
+
ValidationState(ssi, diff, None),
|
|
1938
|
+
)
|
|
1939
|
+
pre_validation_result: PreValidationResult = await future
|
|
1940
|
+
# Ignore errors from pre-validation, we are testing block_body_validation
|
|
1941
|
+
repl_preval_results = replace(pre_validation_result, error=None, required_iters=uint64(1))
|
|
1942
|
+
fork_info = ForkInfo(block.height - 1, block.height - 1, block.prev_header_hash)
|
|
1943
|
+
code, err, state_change = await b.add_block(block, repl_preval_results, sub_slot_iters=ssi, fork_info=fork_info)
|
|
1944
|
+
assert code == AddBlockResult.NEW_PEAK
|
|
1945
|
+
assert err is None
|
|
1946
|
+
assert state_change is not None
|
|
1947
|
+
assert state_change.fork_height == 2
|
|
1948
|
+
|
|
1949
|
+
@pytest.mark.anyio
|
|
1950
|
+
@pytest.mark.parametrize(
|
|
1951
|
+
"opcode,lock_value,expected",
|
|
1952
|
+
[
|
|
1953
|
+
# the 3 blocks, starting at timestamp 10000 (and height 0).
|
|
1954
|
+
# each block is 10 seconds apart.
|
|
1955
|
+
# the 4th block (height 3, time 10030) spends a coin with the condition specified
|
|
1956
|
+
# by the test case. The coin was born in height 2 at time 10020
|
|
1957
|
+
# MY BIRHT HEIGHT
|
|
1958
|
+
(co.ASSERT_MY_BIRTH_HEIGHT, -1, rbr.INVALID_BLOCK),
|
|
1959
|
+
(co.ASSERT_MY_BIRTH_HEIGHT, 0x100000000, rbr.INVALID_BLOCK),
|
|
1960
|
+
(co.ASSERT_MY_BIRTH_HEIGHT, 2, rbr.NEW_PEAK), # <- coin birth height
|
|
1961
|
+
(co.ASSERT_MY_BIRTH_HEIGHT, 3, rbr.INVALID_BLOCK),
|
|
1962
|
+
# MY BIRHT SECONDS
|
|
1963
|
+
(co.ASSERT_MY_BIRTH_SECONDS, -1, rbr.INVALID_BLOCK),
|
|
1964
|
+
(co.ASSERT_MY_BIRTH_SECONDS, 0x10000000000000000, rbr.INVALID_BLOCK),
|
|
1965
|
+
(co.ASSERT_MY_BIRTH_SECONDS, 10019, rbr.INVALID_BLOCK),
|
|
1966
|
+
(co.ASSERT_MY_BIRTH_SECONDS, 10020, rbr.NEW_PEAK), # <- coin birth time
|
|
1967
|
+
(co.ASSERT_MY_BIRTH_SECONDS, 10021, rbr.INVALID_BLOCK),
|
|
1968
|
+
# SECONDS RELATIVE
|
|
1969
|
+
(co.ASSERT_SECONDS_RELATIVE, -2, rbr.NEW_PEAK),
|
|
1970
|
+
(co.ASSERT_SECONDS_RELATIVE, -1, rbr.NEW_PEAK),
|
|
1971
|
+
(co.ASSERT_SECONDS_RELATIVE, 0, rbr.NEW_PEAK), # <- birth time
|
|
1972
|
+
(co.ASSERT_SECONDS_RELATIVE, 1, rbr.INVALID_BLOCK),
|
|
1973
|
+
(co.ASSERT_SECONDS_RELATIVE, 9, rbr.INVALID_BLOCK),
|
|
1974
|
+
(co.ASSERT_SECONDS_RELATIVE, 10, rbr.INVALID_BLOCK), # <- current block time
|
|
1975
|
+
(co.ASSERT_SECONDS_RELATIVE, 11, rbr.INVALID_BLOCK),
|
|
1976
|
+
# BEFORE SECONDS RELATIVE
|
|
1977
|
+
(co.ASSERT_BEFORE_SECONDS_RELATIVE, -2, rbr.INVALID_BLOCK),
|
|
1978
|
+
(co.ASSERT_BEFORE_SECONDS_RELATIVE, -1, rbr.INVALID_BLOCK),
|
|
1979
|
+
(co.ASSERT_BEFORE_SECONDS_RELATIVE, 0, rbr.INVALID_BLOCK), # <- birth time
|
|
1980
|
+
(co.ASSERT_BEFORE_SECONDS_RELATIVE, 1, rbr.NEW_PEAK),
|
|
1981
|
+
(co.ASSERT_BEFORE_SECONDS_RELATIVE, 9, rbr.NEW_PEAK),
|
|
1982
|
+
(co.ASSERT_BEFORE_SECONDS_RELATIVE, 10, rbr.NEW_PEAK), # <- current block time
|
|
1983
|
+
(co.ASSERT_BEFORE_SECONDS_RELATIVE, 11, rbr.NEW_PEAK),
|
|
1984
|
+
# HEIGHT RELATIVE
|
|
1985
|
+
(co.ASSERT_HEIGHT_RELATIVE, -2, rbr.NEW_PEAK),
|
|
1986
|
+
(co.ASSERT_HEIGHT_RELATIVE, -1, rbr.NEW_PEAK),
|
|
1987
|
+
(co.ASSERT_HEIGHT_RELATIVE, 0, rbr.NEW_PEAK),
|
|
1988
|
+
(co.ASSERT_HEIGHT_RELATIVE, 1, rbr.INVALID_BLOCK),
|
|
1989
|
+
# BEFORE HEIGHT RELATIVE
|
|
1990
|
+
(co.ASSERT_BEFORE_HEIGHT_RELATIVE, -2, rbr.INVALID_BLOCK),
|
|
1991
|
+
(co.ASSERT_BEFORE_HEIGHT_RELATIVE, -1, rbr.INVALID_BLOCK),
|
|
1992
|
+
(co.ASSERT_BEFORE_HEIGHT_RELATIVE, 0, rbr.INVALID_BLOCK),
|
|
1993
|
+
(co.ASSERT_BEFORE_HEIGHT_RELATIVE, 1, rbr.NEW_PEAK),
|
|
1994
|
+
# HEIGHT ABSOLUTE
|
|
1995
|
+
(co.ASSERT_HEIGHT_ABSOLUTE, 1, rbr.NEW_PEAK),
|
|
1996
|
+
(co.ASSERT_HEIGHT_ABSOLUTE, 2, rbr.NEW_PEAK),
|
|
1997
|
+
(co.ASSERT_HEIGHT_ABSOLUTE, 3, rbr.INVALID_BLOCK),
|
|
1998
|
+
(co.ASSERT_HEIGHT_ABSOLUTE, 4, rbr.INVALID_BLOCK),
|
|
1999
|
+
# BEFORE HEIGHT ABSOLUTE
|
|
2000
|
+
(co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 1, rbr.INVALID_BLOCK),
|
|
2001
|
+
(co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 2, rbr.INVALID_BLOCK),
|
|
2002
|
+
(co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 3, rbr.NEW_PEAK),
|
|
2003
|
+
(co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 4, rbr.NEW_PEAK),
|
|
2004
|
+
# SECONDS ABSOLUTE
|
|
2005
|
+
# genesis timestamp is 10000 and each block is 10 seconds
|
|
2006
|
+
(co.ASSERT_SECONDS_ABSOLUTE, 10019, rbr.NEW_PEAK),
|
|
2007
|
+
(co.ASSERT_SECONDS_ABSOLUTE, 10020, rbr.NEW_PEAK), # <- previous tx-block
|
|
2008
|
+
(co.ASSERT_SECONDS_ABSOLUTE, 10021, rbr.INVALID_BLOCK),
|
|
2009
|
+
(co.ASSERT_SECONDS_ABSOLUTE, 10029, rbr.INVALID_BLOCK),
|
|
2010
|
+
(co.ASSERT_SECONDS_ABSOLUTE, 10030, rbr.INVALID_BLOCK), # <- current block
|
|
2011
|
+
(co.ASSERT_SECONDS_ABSOLUTE, 10031, rbr.INVALID_BLOCK),
|
|
2012
|
+
(co.ASSERT_SECONDS_ABSOLUTE, 10032, rbr.INVALID_BLOCK),
|
|
2013
|
+
# BEFORE SECONDS ABSOLUTE
|
|
2014
|
+
(co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10019, rbr.INVALID_BLOCK),
|
|
2015
|
+
(co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10020, rbr.INVALID_BLOCK), # <- previous tx-block
|
|
2016
|
+
(co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10021, rbr.NEW_PEAK),
|
|
2017
|
+
(co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10029, rbr.NEW_PEAK),
|
|
2018
|
+
(co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10030, rbr.NEW_PEAK), # <- current block
|
|
2019
|
+
(co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10031, rbr.NEW_PEAK),
|
|
2020
|
+
(co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10032, rbr.NEW_PEAK),
|
|
2021
|
+
],
|
|
2022
|
+
)
|
|
2023
|
+
async def test_timelock_conditions(
|
|
2024
|
+
self, opcode: ConditionOpcode, lock_value: int, expected: AddBlockResult, bt: BlockTools
|
|
2025
|
+
) -> None:
|
|
2026
|
+
async with make_empty_blockchain(bt.constants) as b:
|
|
2027
|
+
blocks = bt.get_consecutive_blocks(
|
|
2028
|
+
3,
|
|
2029
|
+
guarantee_transaction_block=True,
|
|
2030
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
2031
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
2032
|
+
genesis_timestamp=uint64(10_000),
|
|
2033
|
+
time_per_block=10,
|
|
2034
|
+
)
|
|
2035
|
+
for bl in blocks:
|
|
2036
|
+
await _validate_and_add_block(b, bl)
|
|
2037
|
+
|
|
2038
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
2039
|
+
|
|
2040
|
+
conditions = {opcode: [ConditionWithArgs(opcode, [int_to_bytes(lock_value)])]}
|
|
2041
|
+
|
|
2042
|
+
coin = blocks[-1].get_included_reward_coins()[0]
|
|
2043
|
+
tx = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), coin, condition_dic=conditions)
|
|
2044
|
+
|
|
2045
|
+
blocks = bt.get_consecutive_blocks(
|
|
2046
|
+
1,
|
|
2047
|
+
block_list_input=blocks,
|
|
2048
|
+
guarantee_transaction_block=True,
|
|
2049
|
+
transaction_data=tx,
|
|
2050
|
+
time_per_block=10,
|
|
2051
|
+
)
|
|
2052
|
+
ssi = b.constants.SUB_SLOT_ITERS_STARTING
|
|
2053
|
+
diff = b.constants.DIFFICULTY_STARTING
|
|
2054
|
+
block = blocks[-1]
|
|
2055
|
+
future = await pre_validate_block(
|
|
2056
|
+
b.constants,
|
|
2057
|
+
AugmentedBlockchain(b),
|
|
2058
|
+
block,
|
|
2059
|
+
b.pool,
|
|
2060
|
+
None,
|
|
2061
|
+
ValidationState(ssi, diff, None),
|
|
2062
|
+
)
|
|
2063
|
+
pre_validation_result: PreValidationResult = await future
|
|
2064
|
+
fork_info = ForkInfo(block.height - 1, block.height - 1, block.prev_header_hash)
|
|
2065
|
+
assert (await b.add_block(block, pre_validation_result, sub_slot_iters=ssi, fork_info=fork_info))[
|
|
2066
|
+
0
|
|
2067
|
+
] == expected
|
|
2068
|
+
|
|
2069
|
+
if expected == AddBlockResult.NEW_PEAK:
|
|
2070
|
+
# ensure coin was in fact spent
|
|
2071
|
+
c = await b.coin_store.get_coin_record(coin.name())
|
|
2072
|
+
assert c is not None and c.spent
|
|
2073
|
+
|
|
2074
|
+
@pytest.mark.anyio
|
|
2075
|
+
@pytest.mark.parametrize(
|
|
2076
|
+
"opcode",
|
|
2077
|
+
[
|
|
2078
|
+
ConditionOpcode.AGG_SIG_ME,
|
|
2079
|
+
ConditionOpcode.AGG_SIG_UNSAFE,
|
|
2080
|
+
ConditionOpcode.AGG_SIG_PARENT,
|
|
2081
|
+
ConditionOpcode.AGG_SIG_PUZZLE,
|
|
2082
|
+
ConditionOpcode.AGG_SIG_AMOUNT,
|
|
2083
|
+
ConditionOpcode.AGG_SIG_PUZZLE_AMOUNT,
|
|
2084
|
+
ConditionOpcode.AGG_SIG_PARENT_AMOUNT,
|
|
2085
|
+
ConditionOpcode.AGG_SIG_PARENT_PUZZLE,
|
|
2086
|
+
],
|
|
2087
|
+
)
|
|
2088
|
+
@pytest.mark.parametrize("with_garbage", [True, False])
|
|
2089
|
+
async def test_aggsig_garbage(
|
|
2090
|
+
self,
|
|
2091
|
+
empty_blockchain: Blockchain,
|
|
2092
|
+
opcode: ConditionOpcode,
|
|
2093
|
+
with_garbage: bool,
|
|
2094
|
+
bt: BlockTools,
|
|
2095
|
+
consensus_mode: ConsensusMode,
|
|
2096
|
+
) -> None:
|
|
2097
|
+
b = empty_blockchain
|
|
2098
|
+
blocks = bt.get_consecutive_blocks(
|
|
2099
|
+
3,
|
|
2100
|
+
guarantee_transaction_block=True,
|
|
2101
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
2102
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
2103
|
+
genesis_timestamp=uint64(10_000),
|
|
2104
|
+
time_per_block=10,
|
|
2105
|
+
)
|
|
2106
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
2107
|
+
await _validate_and_add_block(empty_blockchain, blocks[1])
|
|
2108
|
+
await _validate_and_add_block(empty_blockchain, blocks[2])
|
|
2109
|
+
|
|
2110
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
2111
|
+
|
|
2112
|
+
tx1 = wt.generate_signed_transaction(
|
|
2113
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
2114
|
+
)
|
|
2115
|
+
coin1: Coin = tx1.additions()[0]
|
|
2116
|
+
secret_key = wt.get_private_key_for_puzzle_hash(coin1.puzzle_hash)
|
|
2117
|
+
synthetic_secret_key = calculate_synthetic_secret_key(secret_key, DEFAULT_HIDDEN_PUZZLE_HASH)
|
|
2118
|
+
public_key = synthetic_secret_key.get_g1()
|
|
2119
|
+
|
|
2120
|
+
args = [bytes(public_key), b"msg"] + ([b"garbage"] if with_garbage else [])
|
|
2121
|
+
conditions = {opcode: [ConditionWithArgs(opcode, args)]}
|
|
2122
|
+
|
|
2123
|
+
tx2 = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), coin1, condition_dic=conditions)
|
|
2124
|
+
assert coin1 in tx2.removals()
|
|
2125
|
+
|
|
2126
|
+
bundles = SpendBundle.aggregate([tx1, tx2])
|
|
2127
|
+
blocks = bt.get_consecutive_blocks(
|
|
2128
|
+
1,
|
|
2129
|
+
block_list_input=blocks,
|
|
2130
|
+
guarantee_transaction_block=True,
|
|
2131
|
+
transaction_data=bundles,
|
|
2132
|
+
time_per_block=10,
|
|
2133
|
+
)
|
|
2134
|
+
ssi = b.constants.SUB_SLOT_ITERS_STARTING
|
|
2135
|
+
diff = b.constants.DIFFICULTY_STARTING
|
|
2136
|
+
block = blocks[-1]
|
|
2137
|
+
future = await pre_validate_block(
|
|
2138
|
+
b.constants,
|
|
2139
|
+
AugmentedBlockchain(b),
|
|
2140
|
+
block,
|
|
2141
|
+
b.pool,
|
|
2142
|
+
None,
|
|
2143
|
+
ValidationState(ssi, diff, None),
|
|
2144
|
+
)
|
|
2145
|
+
pre_validation_result: PreValidationResult = await future
|
|
2146
|
+
# Ignore errors from pre-validation, we are testing block_body_validation
|
|
2147
|
+
repl_preval_results = replace(pre_validation_result, error=None, required_iters=uint64(1))
|
|
2148
|
+
fork_info = ForkInfo(block.height - 1, block.height - 1, block.prev_header_hash)
|
|
2149
|
+
res, error, state_change = await b.add_block(
|
|
2150
|
+
block, repl_preval_results, sub_slot_iters=ssi, fork_info=fork_info
|
|
2151
|
+
)
|
|
2152
|
+
assert res == AddBlockResult.NEW_PEAK
|
|
2153
|
+
assert error is None
|
|
2154
|
+
assert state_change is not None and state_change.fork_height == uint32(2)
|
|
2155
|
+
|
|
2156
|
+
@pytest.mark.anyio
|
|
2157
|
+
@pytest.mark.parametrize("with_garbage", [True, False])
|
|
2158
|
+
@pytest.mark.parametrize(
|
|
2159
|
+
"opcode,lock_value,expected",
|
|
2160
|
+
[
|
|
2161
|
+
# we don't allow any birth assertions, not
|
|
2162
|
+
# relative time locks on ephemeral coins. This test is only for
|
|
2163
|
+
# ephemeral coins, so these cases should always fail
|
|
2164
|
+
# MY BIRHT HEIGHT
|
|
2165
|
+
(co.ASSERT_MY_BIRTH_HEIGHT, -1, rbr.INVALID_BLOCK),
|
|
2166
|
+
(co.ASSERT_MY_BIRTH_HEIGHT, 0x100000000, rbr.INVALID_BLOCK),
|
|
2167
|
+
(co.ASSERT_MY_BIRTH_HEIGHT, 2, rbr.INVALID_BLOCK),
|
|
2168
|
+
(co.ASSERT_MY_BIRTH_HEIGHT, 3, rbr.INVALID_BLOCK),
|
|
2169
|
+
# MY BIRHT SECONDS
|
|
2170
|
+
(co.ASSERT_MY_BIRTH_SECONDS, -1, rbr.INVALID_BLOCK),
|
|
2171
|
+
(co.ASSERT_MY_BIRTH_SECONDS, 0x10000000000000000, rbr.INVALID_BLOCK),
|
|
2172
|
+
(co.ASSERT_MY_BIRTH_SECONDS, 10029, rbr.INVALID_BLOCK),
|
|
2173
|
+
(co.ASSERT_MY_BIRTH_SECONDS, 10030, rbr.INVALID_BLOCK),
|
|
2174
|
+
(co.ASSERT_MY_BIRTH_SECONDS, 10031, rbr.INVALID_BLOCK),
|
|
2175
|
+
# SECONDS RELATIVE
|
|
2176
|
+
# genesis timestamp is 10000 and each block is 10 seconds
|
|
2177
|
+
(co.ASSERT_SECONDS_RELATIVE, -2, rbr.INVALID_BLOCK),
|
|
2178
|
+
(co.ASSERT_SECONDS_RELATIVE, -1, rbr.INVALID_BLOCK),
|
|
2179
|
+
(co.ASSERT_SECONDS_RELATIVE, 0, rbr.INVALID_BLOCK),
|
|
2180
|
+
(co.ASSERT_SECONDS_RELATIVE, 1, rbr.INVALID_BLOCK),
|
|
2181
|
+
# BEFORE SECONDS RELATIVE
|
|
2182
|
+
# relative conditions are not allowed on ephemeral spends
|
|
2183
|
+
(co.ASSERT_BEFORE_SECONDS_RELATIVE, -2, rbr.INVALID_BLOCK),
|
|
2184
|
+
(co.ASSERT_BEFORE_SECONDS_RELATIVE, -1, rbr.INVALID_BLOCK),
|
|
2185
|
+
(co.ASSERT_BEFORE_SECONDS_RELATIVE, 0, rbr.INVALID_BLOCK),
|
|
2186
|
+
(co.ASSERT_BEFORE_SECONDS_RELATIVE, 10, rbr.INVALID_BLOCK),
|
|
2187
|
+
(co.ASSERT_BEFORE_SECONDS_RELATIVE, 0x10000000000000000, rbr.INVALID_BLOCK),
|
|
2188
|
+
# HEIGHT RELATIVE
|
|
2189
|
+
(co.ASSERT_HEIGHT_RELATIVE, -2, rbr.INVALID_BLOCK),
|
|
2190
|
+
(co.ASSERT_HEIGHT_RELATIVE, -1, rbr.INVALID_BLOCK),
|
|
2191
|
+
(co.ASSERT_HEIGHT_RELATIVE, 0, rbr.INVALID_BLOCK),
|
|
2192
|
+
(co.ASSERT_HEIGHT_RELATIVE, 1, rbr.INVALID_BLOCK),
|
|
2193
|
+
# BEFORE HEIGHT RELATIVE
|
|
2194
|
+
# relative conditions are not allowed on ephemeral spends
|
|
2195
|
+
(co.ASSERT_BEFORE_HEIGHT_RELATIVE, -2, rbr.INVALID_BLOCK),
|
|
2196
|
+
(co.ASSERT_BEFORE_HEIGHT_RELATIVE, -1, rbr.INVALID_BLOCK),
|
|
2197
|
+
(co.ASSERT_BEFORE_HEIGHT_RELATIVE, 0, rbr.INVALID_BLOCK),
|
|
2198
|
+
(co.ASSERT_BEFORE_HEIGHT_RELATIVE, 1, rbr.INVALID_BLOCK),
|
|
2199
|
+
(co.ASSERT_BEFORE_HEIGHT_RELATIVE, 0x100000000, rbr.INVALID_BLOCK),
|
|
2200
|
+
# HEIGHT ABSOLUTE
|
|
2201
|
+
(co.ASSERT_HEIGHT_ABSOLUTE, 2, rbr.NEW_PEAK),
|
|
2202
|
+
(co.ASSERT_HEIGHT_ABSOLUTE, 3, rbr.INVALID_BLOCK),
|
|
2203
|
+
(co.ASSERT_HEIGHT_ABSOLUTE, 4, rbr.INVALID_BLOCK),
|
|
2204
|
+
# BEFORE HEIGHT ABSOLUTE
|
|
2205
|
+
(co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 2, rbr.INVALID_BLOCK),
|
|
2206
|
+
(co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 3, rbr.NEW_PEAK),
|
|
2207
|
+
(co.ASSERT_BEFORE_HEIGHT_ABSOLUTE, 4, rbr.NEW_PEAK),
|
|
2208
|
+
# SECONDS ABSOLUTE
|
|
2209
|
+
# genesis timestamp is 10000 and each block is 10 seconds
|
|
2210
|
+
(co.ASSERT_SECONDS_ABSOLUTE, 10020, rbr.NEW_PEAK), # <- previous tx-block
|
|
2211
|
+
(co.ASSERT_SECONDS_ABSOLUTE, 10021, rbr.INVALID_BLOCK),
|
|
2212
|
+
(co.ASSERT_SECONDS_ABSOLUTE, 10029, rbr.INVALID_BLOCK),
|
|
2213
|
+
(co.ASSERT_SECONDS_ABSOLUTE, 10030, rbr.INVALID_BLOCK), # <- current tx-block
|
|
2214
|
+
(co.ASSERT_SECONDS_ABSOLUTE, 10031, rbr.INVALID_BLOCK),
|
|
2215
|
+
(co.ASSERT_SECONDS_ABSOLUTE, 10032, rbr.INVALID_BLOCK),
|
|
2216
|
+
# BEFORE SECONDS ABSOLUTE
|
|
2217
|
+
(co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10020, rbr.INVALID_BLOCK),
|
|
2218
|
+
(co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10021, rbr.NEW_PEAK),
|
|
2219
|
+
(co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10030, rbr.NEW_PEAK),
|
|
2220
|
+
(co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10031, rbr.NEW_PEAK),
|
|
2221
|
+
(co.ASSERT_BEFORE_SECONDS_ABSOLUTE, 10032, rbr.NEW_PEAK),
|
|
2222
|
+
],
|
|
2223
|
+
)
|
|
2224
|
+
async def test_ephemeral_timelock(
|
|
2225
|
+
self, opcode: ConditionOpcode, lock_value: int, expected: AddBlockResult, with_garbage: bool, bt: BlockTools
|
|
2226
|
+
) -> None:
|
|
2227
|
+
async with make_empty_blockchain(bt.constants) as b:
|
|
2228
|
+
blocks = bt.get_consecutive_blocks(
|
|
2229
|
+
3,
|
|
2230
|
+
guarantee_transaction_block=True,
|
|
2231
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
2232
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
2233
|
+
genesis_timestamp=uint64(10_000),
|
|
2234
|
+
time_per_block=10,
|
|
2235
|
+
)
|
|
2236
|
+
await _validate_and_add_block(b, blocks[0])
|
|
2237
|
+
await _validate_and_add_block(b, blocks[1])
|
|
2238
|
+
await _validate_and_add_block(b, blocks[2])
|
|
2239
|
+
|
|
2240
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
2241
|
+
|
|
2242
|
+
conditions = {
|
|
2243
|
+
opcode: [ConditionWithArgs(opcode, [int_to_bytes(lock_value)] + ([b"garbage"] if with_garbage else []))]
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
tx1 = wt.generate_signed_transaction(
|
|
2247
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
2248
|
+
)
|
|
2249
|
+
coin1: Coin = tx1.additions()[0]
|
|
2250
|
+
tx2 = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), coin1, condition_dic=conditions)
|
|
2251
|
+
assert coin1 in tx2.removals()
|
|
2252
|
+
coin2: Coin = tx2.additions()[0]
|
|
2253
|
+
|
|
2254
|
+
bundles = SpendBundle.aggregate([tx1, tx2])
|
|
2255
|
+
blocks = bt.get_consecutive_blocks(
|
|
2256
|
+
1,
|
|
2257
|
+
block_list_input=blocks,
|
|
2258
|
+
guarantee_transaction_block=True,
|
|
2259
|
+
transaction_data=bundles,
|
|
2260
|
+
time_per_block=10,
|
|
2261
|
+
)
|
|
2262
|
+
ssi = b.constants.SUB_SLOT_ITERS_STARTING
|
|
2263
|
+
diff = b.constants.DIFFICULTY_STARTING
|
|
2264
|
+
block = blocks[-1]
|
|
2265
|
+
future = await pre_validate_block(
|
|
2266
|
+
b.constants,
|
|
2267
|
+
AugmentedBlockchain(b),
|
|
2268
|
+
block,
|
|
2269
|
+
b.pool,
|
|
2270
|
+
None,
|
|
2271
|
+
ValidationState(ssi, diff, None),
|
|
2272
|
+
)
|
|
2273
|
+
pre_validation_result: PreValidationResult = await future
|
|
2274
|
+
fork_info = ForkInfo(block.height - 1, block.height - 1, block.prev_header_hash)
|
|
2275
|
+
assert (await b.add_block(block, pre_validation_result, sub_slot_iters=ssi, fork_info=fork_info))[
|
|
2276
|
+
0
|
|
2277
|
+
] == expected
|
|
2278
|
+
|
|
2279
|
+
if expected == AddBlockResult.NEW_PEAK:
|
|
2280
|
+
# ensure coin1 was in fact spent
|
|
2281
|
+
c = await b.coin_store.get_coin_record(coin1.name())
|
|
2282
|
+
assert c is not None and c.spent
|
|
2283
|
+
# ensure coin2 was NOT spent
|
|
2284
|
+
c = await b.coin_store.get_coin_record(coin2.name())
|
|
2285
|
+
assert c is not None and not c.spent
|
|
2286
|
+
|
|
2287
|
+
@pytest.mark.anyio
|
|
2288
|
+
async def test_not_tx_block_but_has_data(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
2289
|
+
# 1
|
|
2290
|
+
blocks = bt.get_consecutive_blocks(1)
|
|
2291
|
+
while blocks[-1].foliage_transaction_block is not None:
|
|
2292
|
+
await _validate_and_add_block(empty_blockchain, blocks[-1])
|
|
2293
|
+
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
|
2294
|
+
original_block: FullBlock = blocks[-1]
|
|
2295
|
+
|
|
2296
|
+
block = recursive_replace(original_block, "transactions_generator", SerializedProgram.to(None))
|
|
2297
|
+
await _validate_and_add_block(
|
|
2298
|
+
empty_blockchain, block, expected_error=Err.NOT_BLOCK_BUT_HAS_DATA, skip_prevalidation=True
|
|
2299
|
+
)
|
|
2300
|
+
h = std_hash(b"")
|
|
2301
|
+
i = uint64(1)
|
|
2302
|
+
block = recursive_replace(
|
|
2303
|
+
original_block,
|
|
2304
|
+
"transactions_info",
|
|
2305
|
+
TransactionsInfo(h, h, G2Element(), uint64(1), uint64(1), []),
|
|
2306
|
+
)
|
|
2307
|
+
await _validate_and_add_block(
|
|
2308
|
+
empty_blockchain, block, expected_error=Err.NOT_BLOCK_BUT_HAS_DATA, skip_prevalidation=True
|
|
2309
|
+
)
|
|
2310
|
+
|
|
2311
|
+
block = recursive_replace(original_block, "transactions_generator_ref_list", [i])
|
|
2312
|
+
await _validate_and_add_block(
|
|
2313
|
+
empty_blockchain, block, expected_error=Err.NOT_BLOCK_BUT_HAS_DATA, skip_prevalidation=True
|
|
2314
|
+
)
|
|
2315
|
+
|
|
2316
|
+
@pytest.mark.anyio
|
|
2317
|
+
async def test_tx_block_missing_data(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
2318
|
+
# 2
|
|
2319
|
+
b = empty_blockchain
|
|
2320
|
+
blocks = bt.get_consecutive_blocks(2, guarantee_transaction_block=True)
|
|
2321
|
+
await _validate_and_add_block(b, blocks[0])
|
|
2322
|
+
block = recursive_replace(
|
|
2323
|
+
blocks[-1],
|
|
2324
|
+
"foliage_transaction_block",
|
|
2325
|
+
None,
|
|
2326
|
+
)
|
|
2327
|
+
await _validate_and_add_block_multi_error(
|
|
2328
|
+
b, block, [Err.IS_TRANSACTION_BLOCK_BUT_NO_DATA, Err.INVALID_FOLIAGE_BLOCK_PRESENCE]
|
|
2329
|
+
)
|
|
2330
|
+
|
|
2331
|
+
block = recursive_replace(
|
|
2332
|
+
blocks[-1],
|
|
2333
|
+
"transactions_info",
|
|
2334
|
+
None,
|
|
2335
|
+
)
|
|
2336
|
+
with pytest.raises(AssertionError):
|
|
2337
|
+
await _validate_and_add_block_multi_error(
|
|
2338
|
+
b, block, [Err.IS_TRANSACTION_BLOCK_BUT_NO_DATA, Err.INVALID_FOLIAGE_BLOCK_PRESENCE]
|
|
2339
|
+
)
|
|
2340
|
+
|
|
2341
|
+
@pytest.mark.anyio
|
|
2342
|
+
async def test_invalid_transactions_info_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
2343
|
+
# 3
|
|
2344
|
+
b = empty_blockchain
|
|
2345
|
+
blocks = bt.get_consecutive_blocks(2, guarantee_transaction_block=True)
|
|
2346
|
+
await _validate_and_add_block(b, blocks[0])
|
|
2347
|
+
h = std_hash(b"")
|
|
2348
|
+
block = recursive_replace(
|
|
2349
|
+
blocks[-1],
|
|
2350
|
+
"foliage_transaction_block.transactions_info_hash",
|
|
2351
|
+
h,
|
|
2352
|
+
)
|
|
2353
|
+
block = recursive_replace(
|
|
2354
|
+
block, "foliage.foliage_transaction_block_hash", std_hash(block.foliage_transaction_block)
|
|
2355
|
+
)
|
|
2356
|
+
new_m = block.foliage.foliage_transaction_block_hash
|
|
2357
|
+
assert new_m is not None
|
|
2358
|
+
new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
|
|
2359
|
+
block = recursive_replace(block, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2360
|
+
|
|
2361
|
+
await _validate_and_add_block(b, block, expected_error=Err.INVALID_TRANSACTIONS_INFO_HASH)
|
|
2362
|
+
|
|
2363
|
+
@pytest.mark.anyio
|
|
2364
|
+
async def test_invalid_transactions_block_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
2365
|
+
# 4
|
|
2366
|
+
b = empty_blockchain
|
|
2367
|
+
blocks = bt.get_consecutive_blocks(2, guarantee_transaction_block=True)
|
|
2368
|
+
await _validate_and_add_block(b, blocks[0])
|
|
2369
|
+
h = std_hash(b"")
|
|
2370
|
+
block = recursive_replace(blocks[-1], "foliage.foliage_transaction_block_hash", h)
|
|
2371
|
+
new_m = block.foliage.foliage_transaction_block_hash
|
|
2372
|
+
assert new_m is not None
|
|
2373
|
+
new_fsb_sig = bt.get_plot_signature(new_m, blocks[-1].reward_chain_block.proof_of_space.plot_public_key)
|
|
2374
|
+
block = recursive_replace(block, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2375
|
+
|
|
2376
|
+
await _validate_and_add_block(b, block, expected_error=Err.INVALID_FOLIAGE_BLOCK_HASH)
|
|
2377
|
+
|
|
2378
|
+
@pytest.mark.anyio
|
|
2379
|
+
async def test_invalid_reward_claims(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
2380
|
+
# 5
|
|
2381
|
+
b = empty_blockchain
|
|
2382
|
+
blocks = bt.get_consecutive_blocks(2, guarantee_transaction_block=True)
|
|
2383
|
+
await _validate_and_add_block(b, blocks[0])
|
|
2384
|
+
block: FullBlock = blocks[-1]
|
|
2385
|
+
|
|
2386
|
+
# Too few
|
|
2387
|
+
assert block.transactions_info is not None
|
|
2388
|
+
too_few_reward_claims = block.transactions_info.reward_claims_incorporated[:-1]
|
|
2389
|
+
block_2: FullBlock = recursive_replace(
|
|
2390
|
+
block, "transactions_info.reward_claims_incorporated", too_few_reward_claims
|
|
2391
|
+
)
|
|
2392
|
+
assert block_2.transactions_info is not None
|
|
2393
|
+
block_2 = recursive_replace(
|
|
2394
|
+
block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
|
|
2395
|
+
)
|
|
2396
|
+
|
|
2397
|
+
assert block_2.foliage_transaction_block is not None
|
|
2398
|
+
block_2 = recursive_replace(
|
|
2399
|
+
block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
|
|
2400
|
+
)
|
|
2401
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
2402
|
+
assert new_m is not None
|
|
2403
|
+
new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
|
|
2404
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2405
|
+
|
|
2406
|
+
await _validate_and_add_block(b, block_2, expected_error=Err.INVALID_REWARD_COINS, skip_prevalidation=True)
|
|
2407
|
+
|
|
2408
|
+
# Too many
|
|
2409
|
+
h = std_hash(b"")
|
|
2410
|
+
too_many_reward_claims = [
|
|
2411
|
+
*block.transactions_info.reward_claims_incorporated,
|
|
2412
|
+
Coin(h, h, too_few_reward_claims[0].amount),
|
|
2413
|
+
]
|
|
2414
|
+
block_2 = recursive_replace(block, "transactions_info.reward_claims_incorporated", too_many_reward_claims)
|
|
2415
|
+
assert block_2.transactions_info is not None
|
|
2416
|
+
block_2 = recursive_replace(
|
|
2417
|
+
block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
|
|
2418
|
+
)
|
|
2419
|
+
assert block_2.foliage_transaction_block is not None
|
|
2420
|
+
block_2 = recursive_replace(
|
|
2421
|
+
block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
|
|
2422
|
+
)
|
|
2423
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
2424
|
+
assert new_m is not None
|
|
2425
|
+
new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
|
|
2426
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2427
|
+
|
|
2428
|
+
await _validate_and_add_block(b, block_2, expected_error=Err.INVALID_REWARD_COINS, skip_prevalidation=True)
|
|
2429
|
+
|
|
2430
|
+
# Duplicates
|
|
2431
|
+
duplicate_reward_claims = [
|
|
2432
|
+
*block.transactions_info.reward_claims_incorporated,
|
|
2433
|
+
block.transactions_info.reward_claims_incorporated[-1],
|
|
2434
|
+
]
|
|
2435
|
+
block_2 = recursive_replace(block, "transactions_info.reward_claims_incorporated", duplicate_reward_claims)
|
|
2436
|
+
assert block_2.transactions_info is not None
|
|
2437
|
+
block_2 = recursive_replace(
|
|
2438
|
+
block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
|
|
2439
|
+
)
|
|
2440
|
+
assert block_2.foliage_transaction_block is not None
|
|
2441
|
+
block_2 = recursive_replace(
|
|
2442
|
+
block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
|
|
2443
|
+
)
|
|
2444
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
2445
|
+
assert new_m is not None
|
|
2446
|
+
new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
|
|
2447
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2448
|
+
|
|
2449
|
+
await _validate_and_add_block(b, block_2, expected_error=Err.INVALID_REWARD_COINS, skip_prevalidation=True)
|
|
2450
|
+
|
|
2451
|
+
@pytest.mark.anyio
|
|
2452
|
+
async def test_invalid_transactions_generator_hash(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
2453
|
+
# 7
|
|
2454
|
+
b = empty_blockchain
|
|
2455
|
+
blocks = bt.get_consecutive_blocks(2, guarantee_transaction_block=True)
|
|
2456
|
+
await _validate_and_add_block(b, blocks[0])
|
|
2457
|
+
|
|
2458
|
+
# No tx should have all zeroes
|
|
2459
|
+
block: FullBlock = blocks[-1]
|
|
2460
|
+
block_2 = recursive_replace(block, "transactions_info.generator_root", bytes([1] * 32))
|
|
2461
|
+
block_2 = recursive_replace(
|
|
2462
|
+
block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
|
|
2463
|
+
)
|
|
2464
|
+
block_2 = recursive_replace(
|
|
2465
|
+
block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
|
|
2466
|
+
)
|
|
2467
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
2468
|
+
assert new_m is not None
|
|
2469
|
+
new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
|
|
2470
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2471
|
+
|
|
2472
|
+
await _validate_and_add_block(
|
|
2473
|
+
b, block_2, expected_error=Err.INVALID_TRANSACTIONS_GENERATOR_HASH, skip_prevalidation=True
|
|
2474
|
+
)
|
|
2475
|
+
|
|
2476
|
+
await _validate_and_add_block(b, blocks[1])
|
|
2477
|
+
blocks = bt.get_consecutive_blocks(
|
|
2478
|
+
2,
|
|
2479
|
+
block_list_input=blocks,
|
|
2480
|
+
guarantee_transaction_block=True,
|
|
2481
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
2482
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
2483
|
+
)
|
|
2484
|
+
await _validate_and_add_block(b, blocks[2])
|
|
2485
|
+
await _validate_and_add_block(b, blocks[3])
|
|
2486
|
+
|
|
2487
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
2488
|
+
tx = wt.generate_signed_transaction(
|
|
2489
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
2490
|
+
)
|
|
2491
|
+
blocks = bt.get_consecutive_blocks(
|
|
2492
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
2493
|
+
)
|
|
2494
|
+
|
|
2495
|
+
# Non empty generator hash must be correct
|
|
2496
|
+
block = blocks[-1]
|
|
2497
|
+
block_2 = recursive_replace(block, "transactions_info.generator_root", bytes([0] * 32))
|
|
2498
|
+
block_2 = recursive_replace(
|
|
2499
|
+
block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
|
|
2500
|
+
)
|
|
2501
|
+
block_2 = recursive_replace(
|
|
2502
|
+
block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
|
|
2503
|
+
)
|
|
2504
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
2505
|
+
assert new_m is not None
|
|
2506
|
+
new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
|
|
2507
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2508
|
+
await _validate_and_add_block(b, block_2, expected_error=Err.INVALID_TRANSACTIONS_GENERATOR_HASH)
|
|
2509
|
+
|
|
2510
|
+
@pytest.mark.anyio
|
|
2511
|
+
async def test_invalid_transactions_ref_list(
|
|
2512
|
+
self, empty_blockchain: Blockchain, bt: BlockTools, consensus_mode: ConsensusMode
|
|
2513
|
+
) -> None:
|
|
2514
|
+
# No generator should have [1]s for the root
|
|
2515
|
+
b = empty_blockchain
|
|
2516
|
+
blocks = bt.get_consecutive_blocks(
|
|
2517
|
+
3,
|
|
2518
|
+
guarantee_transaction_block=True,
|
|
2519
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
2520
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
2521
|
+
)
|
|
2522
|
+
await _validate_and_add_block(b, blocks[0])
|
|
2523
|
+
await _validate_and_add_block(b, blocks[1])
|
|
2524
|
+
|
|
2525
|
+
block: FullBlock = blocks[-1]
|
|
2526
|
+
block_2 = recursive_replace(block, "transactions_info.generator_refs_root", bytes([0] * 32))
|
|
2527
|
+
block_2 = recursive_replace(
|
|
2528
|
+
block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
|
|
2529
|
+
)
|
|
2530
|
+
block_2 = recursive_replace(
|
|
2531
|
+
block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
|
|
2532
|
+
)
|
|
2533
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
2534
|
+
assert new_m is not None
|
|
2535
|
+
new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
|
|
2536
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2537
|
+
|
|
2538
|
+
await _validate_and_add_block(
|
|
2539
|
+
b, block_2, expected_error=Err.INVALID_TRANSACTIONS_GENERATOR_REFS_ROOT, skip_prevalidation=True
|
|
2540
|
+
)
|
|
2541
|
+
|
|
2542
|
+
# No generator should have no refs list
|
|
2543
|
+
block_2 = recursive_replace(block, "transactions_generator_ref_list", [uint32(0)])
|
|
2544
|
+
|
|
2545
|
+
await _validate_and_add_block(
|
|
2546
|
+
b, block_2, expected_error=Err.INVALID_TRANSACTIONS_GENERATOR_REFS_ROOT, skip_prevalidation=True
|
|
2547
|
+
)
|
|
2548
|
+
|
|
2549
|
+
# Hash should be correct when there is a ref list
|
|
2550
|
+
await _validate_and_add_block(b, blocks[-1])
|
|
2551
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
2552
|
+
tx = wt.generate_signed_transaction(
|
|
2553
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
2554
|
+
)
|
|
2555
|
+
blocks = bt.get_consecutive_blocks(5, block_list_input=blocks, guarantee_transaction_block=False)
|
|
2556
|
+
for block in blocks[-5:]:
|
|
2557
|
+
await _validate_and_add_block(b, block)
|
|
2558
|
+
|
|
2559
|
+
blocks = bt.get_consecutive_blocks(
|
|
2560
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
2561
|
+
)
|
|
2562
|
+
await _validate_and_add_block(b, blocks[-1])
|
|
2563
|
+
assert blocks[-1].transactions_generator is not None
|
|
2564
|
+
|
|
2565
|
+
blocks = bt.get_consecutive_blocks(
|
|
2566
|
+
1,
|
|
2567
|
+
block_list_input=blocks,
|
|
2568
|
+
guarantee_transaction_block=True,
|
|
2569
|
+
transaction_data=tx,
|
|
2570
|
+
block_refs=[blocks[-1].height],
|
|
2571
|
+
)
|
|
2572
|
+
block = blocks[-1]
|
|
2573
|
+
# once the hard fork activated, we no longer use this form of block
|
|
2574
|
+
# compression anymore
|
|
2575
|
+
assert len(block.transactions_generator_ref_list) == 0
|
|
2576
|
+
|
|
2577
|
+
@pytest.mark.anyio
|
|
2578
|
+
async def test_cost_exceeds_max(
|
|
2579
|
+
self, empty_blockchain: Blockchain, softfork_height: uint32, bt: BlockTools
|
|
2580
|
+
) -> None:
|
|
2581
|
+
# 7
|
|
2582
|
+
b = empty_blockchain
|
|
2583
|
+
blocks = bt.get_consecutive_blocks(
|
|
2584
|
+
3,
|
|
2585
|
+
guarantee_transaction_block=True,
|
|
2586
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
2587
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
2588
|
+
)
|
|
2589
|
+
await _validate_and_add_block(b, blocks[0])
|
|
2590
|
+
await _validate_and_add_block(b, blocks[1])
|
|
2591
|
+
await _validate_and_add_block(b, blocks[2])
|
|
2592
|
+
|
|
2593
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
2594
|
+
|
|
2595
|
+
condition_dict: dict[ConditionOpcode, list[ConditionWithArgs]] = {ConditionOpcode.CREATE_COIN: []}
|
|
2596
|
+
for i in range(7_000):
|
|
2597
|
+
output = ConditionWithArgs(ConditionOpcode.CREATE_COIN, [bt.pool_ph, int_to_bytes(i)])
|
|
2598
|
+
condition_dict[ConditionOpcode.CREATE_COIN].append(output)
|
|
2599
|
+
|
|
2600
|
+
tx = wt.generate_signed_transaction(
|
|
2601
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0], condition_dic=condition_dict
|
|
2602
|
+
)
|
|
2603
|
+
|
|
2604
|
+
blocks = bt.get_consecutive_blocks(
|
|
2605
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
2606
|
+
)
|
|
2607
|
+
|
|
2608
|
+
assert blocks[-1].transactions_generator is not None
|
|
2609
|
+
assert blocks[-1].transactions_info is not None
|
|
2610
|
+
block_generator = BlockGenerator(blocks[-1].transactions_generator, [])
|
|
2611
|
+
npc_result = get_name_puzzle_conditions(
|
|
2612
|
+
block_generator,
|
|
2613
|
+
b.constants.MAX_BLOCK_COST_CLVM * 1000,
|
|
2614
|
+
mempool_mode=False,
|
|
2615
|
+
height=softfork_height,
|
|
2616
|
+
constants=bt.constants,
|
|
2617
|
+
)
|
|
2618
|
+
assert npc_result.conds is not None
|
|
2619
|
+
ssi = b.constants.SUB_SLOT_ITERS_STARTING
|
|
2620
|
+
diff = b.constants.DIFFICULTY_STARTING
|
|
2621
|
+
block = blocks[-1]
|
|
2622
|
+
fork_info = ForkInfo(block.height - 1, block.height - 1, block.prev_header_hash)
|
|
2623
|
+
err = (
|
|
2624
|
+
await b.add_block(
|
|
2625
|
+
blocks[-1],
|
|
2626
|
+
PreValidationResult(None, uint64(1), npc_result.conds.replace(validated_signature=True), uint32(0)),
|
|
2627
|
+
sub_slot_iters=ssi,
|
|
2628
|
+
fork_info=fork_info,
|
|
2629
|
+
)
|
|
2630
|
+
)[1]
|
|
2631
|
+
assert err == Err.BLOCK_COST_EXCEEDS_MAX
|
|
2632
|
+
future = await pre_validate_block(
|
|
2633
|
+
b.constants,
|
|
2634
|
+
AugmentedBlockchain(b),
|
|
2635
|
+
blocks[-1],
|
|
2636
|
+
b.pool,
|
|
2637
|
+
None,
|
|
2638
|
+
ValidationState(ssi, diff, None),
|
|
2639
|
+
)
|
|
2640
|
+
result: PreValidationResult = await future
|
|
2641
|
+
assert Err(result.error) == Err.BLOCK_COST_EXCEEDS_MAX
|
|
2642
|
+
|
|
2643
|
+
@pytest.mark.anyio
|
|
2644
|
+
async def test_clvm_must_not_fail(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
2645
|
+
# 8
|
|
2646
|
+
pass
|
|
2647
|
+
|
|
2648
|
+
@pytest.mark.anyio
|
|
2649
|
+
async def test_invalid_cost_in_block(
|
|
2650
|
+
self, empty_blockchain: Blockchain, softfork_height: uint32, bt: BlockTools
|
|
2651
|
+
) -> None:
|
|
2652
|
+
# 9
|
|
2653
|
+
b = empty_blockchain
|
|
2654
|
+
blocks = bt.get_consecutive_blocks(
|
|
2655
|
+
3,
|
|
2656
|
+
guarantee_transaction_block=True,
|
|
2657
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
2658
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
2659
|
+
)
|
|
2660
|
+
await _validate_and_add_block(b, blocks[0])
|
|
2661
|
+
await _validate_and_add_block(b, blocks[1])
|
|
2662
|
+
await _validate_and_add_block(b, blocks[2])
|
|
2663
|
+
|
|
2664
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
2665
|
+
|
|
2666
|
+
tx = wt.generate_signed_transaction(
|
|
2667
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
2668
|
+
)
|
|
2669
|
+
|
|
2670
|
+
blocks = bt.get_consecutive_blocks(
|
|
2671
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
2672
|
+
)
|
|
2673
|
+
block: FullBlock = blocks[-1]
|
|
2674
|
+
|
|
2675
|
+
# zero
|
|
2676
|
+
block_2: FullBlock = recursive_replace(block, "transactions_info.cost", uint64(0))
|
|
2677
|
+
assert block_2.transactions_info is not None
|
|
2678
|
+
block_2 = recursive_replace(
|
|
2679
|
+
block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
|
|
2680
|
+
)
|
|
2681
|
+
assert block_2.foliage_transaction_block is not None
|
|
2682
|
+
block_2 = recursive_replace(
|
|
2683
|
+
block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
|
|
2684
|
+
)
|
|
2685
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
2686
|
+
assert new_m is not None
|
|
2687
|
+
new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
|
|
2688
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2689
|
+
assert block_2.transactions_generator is not None
|
|
2690
|
+
block_generator = BlockGenerator(block_2.transactions_generator, [])
|
|
2691
|
+
assert block.transactions_info is not None
|
|
2692
|
+
npc_result = get_name_puzzle_conditions(
|
|
2693
|
+
block_generator,
|
|
2694
|
+
min(b.constants.MAX_BLOCK_COST_CLVM * 1000, block.transactions_info.cost),
|
|
2695
|
+
mempool_mode=False,
|
|
2696
|
+
height=softfork_height,
|
|
2697
|
+
constants=bt.constants,
|
|
2698
|
+
)
|
|
2699
|
+
assert npc_result.conds is not None
|
|
2700
|
+
ssi = b.constants.SUB_SLOT_ITERS_STARTING
|
|
2701
|
+
fork_info = ForkInfo(block_2.height - 1, block_2.height - 1, block_2.prev_header_hash)
|
|
2702
|
+
_, err, _ = await b.add_block(
|
|
2703
|
+
block_2,
|
|
2704
|
+
PreValidationResult(None, uint64(1), npc_result.conds.replace(validated_signature=True), uint32(0)),
|
|
2705
|
+
sub_slot_iters=ssi,
|
|
2706
|
+
fork_info=fork_info,
|
|
2707
|
+
)
|
|
2708
|
+
assert err == Err.INVALID_BLOCK_COST
|
|
2709
|
+
|
|
2710
|
+
# too low
|
|
2711
|
+
block_2 = recursive_replace(block, "transactions_info.cost", uint64(1))
|
|
2712
|
+
assert block_2.transactions_info is not None
|
|
2713
|
+
block_2 = recursive_replace(
|
|
2714
|
+
block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
|
|
2715
|
+
)
|
|
2716
|
+
assert block_2.foliage_transaction_block is not None
|
|
2717
|
+
block_2 = recursive_replace(
|
|
2718
|
+
block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
|
|
2719
|
+
)
|
|
2720
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
2721
|
+
assert new_m is not None
|
|
2722
|
+
new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
|
|
2723
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2724
|
+
assert block_2.transactions_generator is not None
|
|
2725
|
+
block_generator = BlockGenerator(block_2.transactions_generator, [])
|
|
2726
|
+
assert block.transactions_info is not None
|
|
2727
|
+
npc_result = get_name_puzzle_conditions(
|
|
2728
|
+
block_generator,
|
|
2729
|
+
min(b.constants.MAX_BLOCK_COST_CLVM * 1000, block.transactions_info.cost),
|
|
2730
|
+
mempool_mode=False,
|
|
2731
|
+
height=softfork_height,
|
|
2732
|
+
constants=bt.constants,
|
|
2733
|
+
)
|
|
2734
|
+
assert npc_result.conds is not None
|
|
2735
|
+
fork_info = ForkInfo(block_2.height - 1, block_2.height - 1, block_2.prev_header_hash)
|
|
2736
|
+
_, err, _ = await b.add_block(
|
|
2737
|
+
block_2,
|
|
2738
|
+
PreValidationResult(None, uint64(1), npc_result.conds.replace(validated_signature=True), uint32(0)),
|
|
2739
|
+
sub_slot_iters=ssi,
|
|
2740
|
+
fork_info=fork_info,
|
|
2741
|
+
)
|
|
2742
|
+
assert err == Err.INVALID_BLOCK_COST
|
|
2743
|
+
|
|
2744
|
+
# too high
|
|
2745
|
+
block_2 = recursive_replace(block, "transactions_info.cost", uint64(1000000))
|
|
2746
|
+
assert block_2.transactions_info is not None
|
|
2747
|
+
block_2 = recursive_replace(
|
|
2748
|
+
block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
|
|
2749
|
+
)
|
|
2750
|
+
assert block_2.foliage_transaction_block is not None
|
|
2751
|
+
block_2 = recursive_replace(
|
|
2752
|
+
block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
|
|
2753
|
+
)
|
|
2754
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
2755
|
+
assert new_m is not None
|
|
2756
|
+
new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
|
|
2757
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2758
|
+
|
|
2759
|
+
assert block_2.transactions_generator is not None
|
|
2760
|
+
block_generator = BlockGenerator(block_2.transactions_generator, [])
|
|
2761
|
+
max_cost = (
|
|
2762
|
+
min(b.constants.MAX_BLOCK_COST_CLVM * 1000, block.transactions_info.cost)
|
|
2763
|
+
if block.transactions_info is not None
|
|
2764
|
+
else b.constants.MAX_BLOCK_COST_CLVM * 1000
|
|
2765
|
+
)
|
|
2766
|
+
npc_result = get_name_puzzle_conditions(
|
|
2767
|
+
block_generator,
|
|
2768
|
+
max_cost,
|
|
2769
|
+
mempool_mode=False,
|
|
2770
|
+
height=softfork_height,
|
|
2771
|
+
constants=bt.constants,
|
|
2772
|
+
)
|
|
2773
|
+
assert npc_result.conds is not None
|
|
2774
|
+
fork_info = ForkInfo(block_2.height - 1, block_2.height - 1, block_2.prev_header_hash)
|
|
2775
|
+
_result, err, _ = await b.add_block(
|
|
2776
|
+
block_2,
|
|
2777
|
+
PreValidationResult(None, uint64(1), npc_result.conds.replace(validated_signature=True), uint32(0)),
|
|
2778
|
+
sub_slot_iters=ssi,
|
|
2779
|
+
fork_info=fork_info,
|
|
2780
|
+
)
|
|
2781
|
+
assert err == Err.INVALID_BLOCK_COST
|
|
2782
|
+
|
|
2783
|
+
# when the CLVM program exceeds cost during execution, it will fail with
|
|
2784
|
+
# a general runtime error. The previous test tests this.
|
|
2785
|
+
|
|
2786
|
+
@pytest.mark.anyio
|
|
2787
|
+
async def test_max_coin_amount(self, db_version: int, bt: BlockTools) -> None:
|
|
2788
|
+
# 10
|
|
2789
|
+
# TODO: fix, this is not reaching validation. Because we can't create a block with such amounts due to uint64
|
|
2790
|
+
# limit in Coin
|
|
2791
|
+
pass
|
|
2792
|
+
#
|
|
2793
|
+
# with TempKeyring() as keychain:
|
|
2794
|
+
# new_test_constants = bt.constants.replace(
|
|
2795
|
+
# GENESIS_PRE_FARM_POOL_PUZZLE_HASH=bt.pool_ph,
|
|
2796
|
+
# GENESIS_PRE_FARM_FARMER_PUZZLE_HASH=bt.pool_ph,
|
|
2797
|
+
# )
|
|
2798
|
+
# b, db_wrapper = await create_blockchain(new_test_constants, db_version)
|
|
2799
|
+
# bt_2 = await create_block_tools_async(constants=new_test_constants, keychain=keychain)
|
|
2800
|
+
# bt_2.constants = bt_2.constants.replace(
|
|
2801
|
+
# GENESIS_PRE_FARM_POOL_PUZZLE_HASH=bt.pool_ph,
|
|
2802
|
+
# GENESIS_PRE_FARM_FARMER_PUZZLE_HASH=bt.pool_ph,
|
|
2803
|
+
# )
|
|
2804
|
+
# blocks = bt_2.get_consecutive_blocks(
|
|
2805
|
+
# 3,
|
|
2806
|
+
# guarantee_transaction_block=True,
|
|
2807
|
+
# farmer_reward_puzzle_hash=bt.pool_ph,
|
|
2808
|
+
# pool_reward_puzzle_hash=bt.pool_ph,
|
|
2809
|
+
# )
|
|
2810
|
+
# assert (await b.add_block(blocks[0]))[0] == AddBlockResult.NEW_PEAK
|
|
2811
|
+
# assert (await b.add_block(blocks[1]))[0] == AddBlockResult.NEW_PEAK
|
|
2812
|
+
# assert (await b.add_block(blocks[2]))[0] == AddBlockResult.NEW_PEAK
|
|
2813
|
+
|
|
2814
|
+
# wt: WalletTool = bt_2.get_pool_wallet_tool()
|
|
2815
|
+
|
|
2816
|
+
# condition_dict: dict[ConditionOpcode, list[ConditionWithArgs]] = {ConditionOpcode.CREATE_COIN: []}
|
|
2817
|
+
# output = ConditionWithArgs(ConditionOpcode.CREATE_COIN, [bt_2.pool_ph, int_to_bytes(2 ** 64)])
|
|
2818
|
+
# condition_dict[ConditionOpcode.CREATE_COIN].append(output)
|
|
2819
|
+
|
|
2820
|
+
# tx = wt.generate_signed_transaction_multiple_coins(
|
|
2821
|
+
# uint64(10),
|
|
2822
|
+
# wt.get_new_puzzlehash(),
|
|
2823
|
+
# blocks[1].get_included_reward_coins(),
|
|
2824
|
+
# condition_dic=condition_dict,
|
|
2825
|
+
# )
|
|
2826
|
+
# with pytest.raises(Exception):
|
|
2827
|
+
# blocks = bt_2.get_consecutive_blocks(
|
|
2828
|
+
# 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
2829
|
+
# )
|
|
2830
|
+
# await db_wrapper.close()
|
|
2831
|
+
# b.shut_down()
|
|
2832
|
+
|
|
2833
|
+
@pytest.mark.anyio
|
|
2834
|
+
async def test_invalid_merkle_roots(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
2835
|
+
# 11
|
|
2836
|
+
blocks = bt.get_consecutive_blocks(
|
|
2837
|
+
3,
|
|
2838
|
+
guarantee_transaction_block=True,
|
|
2839
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
2840
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
2841
|
+
)
|
|
2842
|
+
await _validate_and_add_block(empty_blockchain, blocks[0])
|
|
2843
|
+
await _validate_and_add_block(empty_blockchain, blocks[1])
|
|
2844
|
+
await _validate_and_add_block(empty_blockchain, blocks[2])
|
|
2845
|
+
|
|
2846
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
2847
|
+
|
|
2848
|
+
tx = wt.generate_signed_transaction(
|
|
2849
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
2850
|
+
)
|
|
2851
|
+
|
|
2852
|
+
blocks = bt.get_consecutive_blocks(
|
|
2853
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
2854
|
+
)
|
|
2855
|
+
block: FullBlock = blocks[-1]
|
|
2856
|
+
|
|
2857
|
+
merkle_set = MerkleSet([])
|
|
2858
|
+
# additions
|
|
2859
|
+
block_2 = recursive_replace(block, "foliage_transaction_block.additions_root", merkle_set.get_root())
|
|
2860
|
+
block_2 = recursive_replace(
|
|
2861
|
+
block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
|
|
2862
|
+
)
|
|
2863
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
2864
|
+
assert new_m is not None
|
|
2865
|
+
new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
|
|
2866
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2867
|
+
|
|
2868
|
+
await _validate_and_add_block(empty_blockchain, block_2, expected_error=Err.BAD_ADDITION_ROOT)
|
|
2869
|
+
|
|
2870
|
+
# removals
|
|
2871
|
+
merkle_set = MerkleSet([std_hash(b"1")])
|
|
2872
|
+
block_2 = recursive_replace(block, "foliage_transaction_block.removals_root", merkle_set.get_root())
|
|
2873
|
+
block_2 = recursive_replace(
|
|
2874
|
+
block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
|
|
2875
|
+
)
|
|
2876
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
2877
|
+
assert new_m is not None
|
|
2878
|
+
new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
|
|
2879
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2880
|
+
|
|
2881
|
+
await _validate_and_add_block(empty_blockchain, block_2, expected_error=Err.BAD_REMOVAL_ROOT)
|
|
2882
|
+
|
|
2883
|
+
@pytest.mark.anyio
|
|
2884
|
+
async def test_invalid_filter(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
2885
|
+
# 12
|
|
2886
|
+
b = empty_blockchain
|
|
2887
|
+
blocks = bt.get_consecutive_blocks(
|
|
2888
|
+
3,
|
|
2889
|
+
guarantee_transaction_block=True,
|
|
2890
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
2891
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
2892
|
+
)
|
|
2893
|
+
await _validate_and_add_block(b, blocks[0])
|
|
2894
|
+
await _validate_and_add_block(b, blocks[1])
|
|
2895
|
+
await _validate_and_add_block(b, blocks[2])
|
|
2896
|
+
|
|
2897
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
2898
|
+
|
|
2899
|
+
tx = wt.generate_signed_transaction(
|
|
2900
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
2901
|
+
)
|
|
2902
|
+
|
|
2903
|
+
blocks = bt.get_consecutive_blocks(
|
|
2904
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
2905
|
+
)
|
|
2906
|
+
block: FullBlock = blocks[-1]
|
|
2907
|
+
block_2 = recursive_replace(block, "foliage_transaction_block.filter_hash", std_hash(b"3"))
|
|
2908
|
+
block_2 = recursive_replace(
|
|
2909
|
+
block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
|
|
2910
|
+
)
|
|
2911
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
2912
|
+
assert new_m is not None
|
|
2913
|
+
new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
|
|
2914
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
2915
|
+
|
|
2916
|
+
await _validate_and_add_block(b, block_2, expected_error=Err.INVALID_TRANSACTIONS_FILTER_HASH)
|
|
2917
|
+
|
|
2918
|
+
@pytest.mark.anyio
|
|
2919
|
+
async def test_duplicate_outputs(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
2920
|
+
# 13
|
|
2921
|
+
b = empty_blockchain
|
|
2922
|
+
blocks = bt.get_consecutive_blocks(
|
|
2923
|
+
3,
|
|
2924
|
+
guarantee_transaction_block=True,
|
|
2925
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
2926
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
2927
|
+
)
|
|
2928
|
+
await _validate_and_add_block(b, blocks[0])
|
|
2929
|
+
await _validate_and_add_block(b, blocks[1])
|
|
2930
|
+
await _validate_and_add_block(b, blocks[2])
|
|
2931
|
+
|
|
2932
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
2933
|
+
|
|
2934
|
+
condition_dict: dict[ConditionOpcode, list[ConditionWithArgs]] = {ConditionOpcode.CREATE_COIN: []}
|
|
2935
|
+
for _ in range(2):
|
|
2936
|
+
output = ConditionWithArgs(ConditionOpcode.CREATE_COIN, [bt.pool_ph, int_to_bytes(1)])
|
|
2937
|
+
condition_dict[ConditionOpcode.CREATE_COIN].append(output)
|
|
2938
|
+
|
|
2939
|
+
tx = wt.generate_signed_transaction(
|
|
2940
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0], condition_dic=condition_dict
|
|
2941
|
+
)
|
|
2942
|
+
|
|
2943
|
+
blocks = bt.get_consecutive_blocks(
|
|
2944
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
2945
|
+
)
|
|
2946
|
+
await _validate_and_add_block(b, blocks[-1], expected_error=Err.DUPLICATE_OUTPUT)
|
|
2947
|
+
|
|
2948
|
+
@pytest.mark.anyio
|
|
2949
|
+
async def test_duplicate_removals(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
2950
|
+
# 14
|
|
2951
|
+
b = empty_blockchain
|
|
2952
|
+
blocks = bt.get_consecutive_blocks(
|
|
2953
|
+
3,
|
|
2954
|
+
guarantee_transaction_block=True,
|
|
2955
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
2956
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
2957
|
+
)
|
|
2958
|
+
await _validate_and_add_block(b, blocks[0])
|
|
2959
|
+
await _validate_and_add_block(b, blocks[1])
|
|
2960
|
+
await _validate_and_add_block(b, blocks[2])
|
|
2961
|
+
|
|
2962
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
2963
|
+
|
|
2964
|
+
tx = wt.generate_signed_transaction(
|
|
2965
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
2966
|
+
)
|
|
2967
|
+
tx_2 = wt.generate_signed_transaction(
|
|
2968
|
+
uint64(11), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
2969
|
+
)
|
|
2970
|
+
agg = SpendBundle.aggregate([tx, tx_2])
|
|
2971
|
+
|
|
2972
|
+
blocks = bt.get_consecutive_blocks(
|
|
2973
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=agg
|
|
2974
|
+
)
|
|
2975
|
+
await _validate_and_add_block(b, blocks[-1], expected_error=Err.DOUBLE_SPEND)
|
|
2976
|
+
|
|
2977
|
+
@pytest.mark.anyio
|
|
2978
|
+
async def test_double_spent_in_coin_store(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
2979
|
+
# 15
|
|
2980
|
+
b = empty_blockchain
|
|
2981
|
+
blocks = bt.get_consecutive_blocks(
|
|
2982
|
+
3,
|
|
2983
|
+
guarantee_transaction_block=True,
|
|
2984
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
2985
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
2986
|
+
)
|
|
2987
|
+
await _validate_and_add_block(b, blocks[0])
|
|
2988
|
+
await _validate_and_add_block(b, blocks[1])
|
|
2989
|
+
await _validate_and_add_block(b, blocks[2])
|
|
2990
|
+
|
|
2991
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
2992
|
+
|
|
2993
|
+
tx = wt.generate_signed_transaction(
|
|
2994
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
2995
|
+
)
|
|
2996
|
+
|
|
2997
|
+
blocks = bt.get_consecutive_blocks(
|
|
2998
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
2999
|
+
)
|
|
3000
|
+
await _validate_and_add_block(b, blocks[-1])
|
|
3001
|
+
|
|
3002
|
+
tx_2 = wt.generate_signed_transaction(
|
|
3003
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-2].get_included_reward_coins()[0]
|
|
3004
|
+
)
|
|
3005
|
+
blocks = bt.get_consecutive_blocks(
|
|
3006
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx_2
|
|
3007
|
+
)
|
|
3008
|
+
|
|
3009
|
+
await _validate_and_add_block(b, blocks[-1], expected_error=Err.DOUBLE_SPEND)
|
|
3010
|
+
|
|
3011
|
+
@pytest.mark.anyio
|
|
3012
|
+
async def test_double_spent_in_reorg(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
3013
|
+
# 15
|
|
3014
|
+
b = empty_blockchain
|
|
3015
|
+
blocks = bt.get_consecutive_blocks(
|
|
3016
|
+
3,
|
|
3017
|
+
guarantee_transaction_block=True,
|
|
3018
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
3019
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
3020
|
+
)
|
|
3021
|
+
await _validate_and_add_block(b, blocks[0])
|
|
3022
|
+
await _validate_and_add_block(b, blocks[1])
|
|
3023
|
+
await _validate_and_add_block(b, blocks[2])
|
|
3024
|
+
|
|
3025
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
3026
|
+
|
|
3027
|
+
tx = wt.generate_signed_transaction(
|
|
3028
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
3029
|
+
)
|
|
3030
|
+
blocks = bt.get_consecutive_blocks(
|
|
3031
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
3032
|
+
)
|
|
3033
|
+
await _validate_and_add_block(b, blocks[-1])
|
|
3034
|
+
|
|
3035
|
+
new_coin: Coin = tx.additions()[0]
|
|
3036
|
+
tx_2 = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), new_coin)
|
|
3037
|
+
# This is fine because coin exists
|
|
3038
|
+
blocks = bt.get_consecutive_blocks(
|
|
3039
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx_2
|
|
3040
|
+
)
|
|
3041
|
+
await _validate_and_add_block(b, blocks[-1])
|
|
3042
|
+
blocks = bt.get_consecutive_blocks(5, block_list_input=blocks, guarantee_transaction_block=True)
|
|
3043
|
+
for block in blocks[-5:]:
|
|
3044
|
+
await _validate_and_add_block(b, block)
|
|
3045
|
+
|
|
3046
|
+
blocks_reorg = bt.get_consecutive_blocks(2, block_list_input=blocks[:-7], guarantee_transaction_block=True)
|
|
3047
|
+
fork_info = ForkInfo(blocks[-8].height, blocks[-8].height, blocks[-8].header_hash)
|
|
3048
|
+
await _validate_and_add_block(
|
|
3049
|
+
b, blocks_reorg[-2], expected_result=AddBlockResult.ADDED_AS_ORPHAN, fork_info=fork_info
|
|
3050
|
+
)
|
|
3051
|
+
await _validate_and_add_block(
|
|
3052
|
+
b, blocks_reorg[-1], expected_result=AddBlockResult.ADDED_AS_ORPHAN, fork_info=fork_info
|
|
3053
|
+
)
|
|
3054
|
+
|
|
3055
|
+
# Coin does not exist in reorg
|
|
3056
|
+
blocks_reorg = bt.get_consecutive_blocks(
|
|
3057
|
+
1, block_list_input=blocks_reorg, guarantee_transaction_block=True, transaction_data=tx_2
|
|
3058
|
+
)
|
|
3059
|
+
peak = b.get_peak()
|
|
3060
|
+
assert peak is not None
|
|
3061
|
+
await _validate_and_add_block(b, blocks_reorg[-1], expected_error=Err.UNKNOWN_UNSPENT, fork_info=fork_info)
|
|
3062
|
+
|
|
3063
|
+
# Finally add the block to the fork (spending both in same bundle, this is ephemeral)
|
|
3064
|
+
agg = SpendBundle.aggregate([tx, tx_2])
|
|
3065
|
+
blocks_reorg = bt.get_consecutive_blocks(
|
|
3066
|
+
1, block_list_input=blocks_reorg[:-1], guarantee_transaction_block=True, transaction_data=agg
|
|
3067
|
+
)
|
|
3068
|
+
|
|
3069
|
+
peak = b.get_peak()
|
|
3070
|
+
assert peak is not None
|
|
3071
|
+
await _validate_and_add_block(
|
|
3072
|
+
b, blocks_reorg[-1], expected_result=AddBlockResult.ADDED_AS_ORPHAN, fork_info=fork_info
|
|
3073
|
+
)
|
|
3074
|
+
|
|
3075
|
+
blocks_reorg = bt.get_consecutive_blocks(
|
|
3076
|
+
1, block_list_input=blocks_reorg, guarantee_transaction_block=True, transaction_data=tx_2
|
|
3077
|
+
)
|
|
3078
|
+
peak = b.get_peak()
|
|
3079
|
+
assert peak is not None
|
|
3080
|
+
await _validate_and_add_block(b, blocks_reorg[-1], expected_error=Err.DOUBLE_SPEND_IN_FORK, fork_info=fork_info)
|
|
3081
|
+
|
|
3082
|
+
rewards_ph = wt.get_new_puzzlehash()
|
|
3083
|
+
blocks_reorg = bt.get_consecutive_blocks(
|
|
3084
|
+
10,
|
|
3085
|
+
block_list_input=blocks_reorg[:-1],
|
|
3086
|
+
guarantee_transaction_block=True,
|
|
3087
|
+
farmer_reward_puzzle_hash=rewards_ph,
|
|
3088
|
+
)
|
|
3089
|
+
|
|
3090
|
+
peak = b.get_peak()
|
|
3091
|
+
assert peak is not None
|
|
3092
|
+
for block in blocks_reorg[-10:]:
|
|
3093
|
+
await _validate_and_add_block_multi_result(
|
|
3094
|
+
b, block, expected_result=[AddBlockResult.ADDED_AS_ORPHAN, AddBlockResult.NEW_PEAK], fork_info=fork_info
|
|
3095
|
+
)
|
|
3096
|
+
|
|
3097
|
+
# ephemeral coin is spent
|
|
3098
|
+
first_coin = await b.coin_store.get_coin_record(new_coin.name())
|
|
3099
|
+
assert first_coin is not None and first_coin.spent
|
|
3100
|
+
second_coin = await b.coin_store.get_coin_record(tx_2.additions()[0].name())
|
|
3101
|
+
assert second_coin is not None and not second_coin.spent
|
|
3102
|
+
|
|
3103
|
+
farmer_coin = create_farmer_coin(
|
|
3104
|
+
blocks_reorg[-1].height,
|
|
3105
|
+
rewards_ph,
|
|
3106
|
+
calculate_base_farmer_reward(blocks_reorg[-1].height),
|
|
3107
|
+
bt.constants.GENESIS_CHALLENGE,
|
|
3108
|
+
)
|
|
3109
|
+
tx_3 = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), farmer_coin)
|
|
3110
|
+
|
|
3111
|
+
blocks_reorg = bt.get_consecutive_blocks(
|
|
3112
|
+
1, block_list_input=blocks_reorg, guarantee_transaction_block=True, transaction_data=tx_3
|
|
3113
|
+
)
|
|
3114
|
+
await _validate_and_add_block(b, blocks_reorg[-1])
|
|
3115
|
+
|
|
3116
|
+
farmer_coin_record = await b.coin_store.get_coin_record(farmer_coin.name())
|
|
3117
|
+
assert farmer_coin_record is not None and farmer_coin_record.spent
|
|
3118
|
+
|
|
3119
|
+
@pytest.mark.anyio
|
|
3120
|
+
async def test_minting_coin(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
3121
|
+
# 16 Minting coin check
|
|
3122
|
+
b = empty_blockchain
|
|
3123
|
+
blocks = bt.get_consecutive_blocks(
|
|
3124
|
+
3,
|
|
3125
|
+
guarantee_transaction_block=True,
|
|
3126
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
3127
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
3128
|
+
)
|
|
3129
|
+
await _validate_and_add_block(b, blocks[0])
|
|
3130
|
+
await _validate_and_add_block(b, blocks[1])
|
|
3131
|
+
await _validate_and_add_block(b, blocks[2])
|
|
3132
|
+
|
|
3133
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
3134
|
+
|
|
3135
|
+
spend = blocks[-1].get_included_reward_coins()[0]
|
|
3136
|
+
print("spend=", spend)
|
|
3137
|
+
# this create coin will spend all of the coin, so the 10 mojos below
|
|
3138
|
+
# will be "minted".
|
|
3139
|
+
output = ConditionWithArgs(ConditionOpcode.CREATE_COIN, [bt.pool_ph, int_to_bytes(spend.amount)])
|
|
3140
|
+
condition_dict = {ConditionOpcode.CREATE_COIN: [output]}
|
|
3141
|
+
|
|
3142
|
+
tx = wt.generate_signed_transaction(uint64(10), wt.get_new_puzzlehash(), spend, condition_dic=condition_dict)
|
|
3143
|
+
|
|
3144
|
+
blocks = bt.get_consecutive_blocks(
|
|
3145
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
3146
|
+
)
|
|
3147
|
+
await _validate_and_add_block(b, blocks[-1], expected_error=Err.MINTING_COIN)
|
|
3148
|
+
# 17 is tested in mempool tests
|
|
3149
|
+
|
|
3150
|
+
@pytest.mark.anyio
|
|
3151
|
+
async def test_max_coin_amount_fee(self) -> None:
|
|
3152
|
+
# 18 TODO: we can't create a block with such amounts due to uint64
|
|
3153
|
+
pass
|
|
3154
|
+
|
|
3155
|
+
@pytest.mark.anyio
|
|
3156
|
+
async def test_invalid_fees_in_block(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
3157
|
+
# 19
|
|
3158
|
+
b = empty_blockchain
|
|
3159
|
+
blocks = bt.get_consecutive_blocks(
|
|
3160
|
+
3,
|
|
3161
|
+
guarantee_transaction_block=True,
|
|
3162
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
3163
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
3164
|
+
)
|
|
3165
|
+
await _validate_and_add_block(b, blocks[0])
|
|
3166
|
+
await _validate_and_add_block(b, blocks[1])
|
|
3167
|
+
await _validate_and_add_block(b, blocks[2])
|
|
3168
|
+
|
|
3169
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
3170
|
+
|
|
3171
|
+
tx = wt.generate_signed_transaction(
|
|
3172
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
3173
|
+
)
|
|
3174
|
+
|
|
3175
|
+
blocks = bt.get_consecutive_blocks(
|
|
3176
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
3177
|
+
)
|
|
3178
|
+
block: FullBlock = blocks[-1]
|
|
3179
|
+
|
|
3180
|
+
# wrong feees
|
|
3181
|
+
block_2: FullBlock = recursive_replace(block, "transactions_info.fees", uint64(1239))
|
|
3182
|
+
assert block_2.transactions_info is not None
|
|
3183
|
+
block_2 = recursive_replace(
|
|
3184
|
+
block_2, "foliage_transaction_block.transactions_info_hash", block_2.transactions_info.get_hash()
|
|
3185
|
+
)
|
|
3186
|
+
assert block_2.foliage_transaction_block is not None
|
|
3187
|
+
block_2 = recursive_replace(
|
|
3188
|
+
block_2, "foliage.foliage_transaction_block_hash", block_2.foliage_transaction_block.get_hash()
|
|
3189
|
+
)
|
|
3190
|
+
new_m = block_2.foliage.foliage_transaction_block_hash
|
|
3191
|
+
assert new_m is not None
|
|
3192
|
+
new_fsb_sig = bt.get_plot_signature(new_m, block.reward_chain_block.proof_of_space.plot_public_key)
|
|
3193
|
+
block_2 = recursive_replace(block_2, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
3194
|
+
|
|
3195
|
+
await _validate_and_add_block(b, block_2, expected_error=Err.INVALID_BLOCK_FEE_AMOUNT)
|
|
3196
|
+
|
|
3197
|
+
@pytest.mark.anyio
|
|
3198
|
+
async def test_invalid_agg_sig(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
3199
|
+
# 22
|
|
3200
|
+
b = empty_blockchain
|
|
3201
|
+
blocks = bt.get_consecutive_blocks(
|
|
3202
|
+
3,
|
|
3203
|
+
guarantee_transaction_block=True,
|
|
3204
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
3205
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
3206
|
+
)
|
|
3207
|
+
await _validate_and_add_block(b, blocks[0])
|
|
3208
|
+
await _validate_and_add_block(b, blocks[1])
|
|
3209
|
+
await _validate_and_add_block(b, blocks[2])
|
|
3210
|
+
|
|
3211
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
3212
|
+
|
|
3213
|
+
tx = wt.generate_signed_transaction(
|
|
3214
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[-1].get_included_reward_coins()[0]
|
|
3215
|
+
)
|
|
3216
|
+
blocks = bt.get_consecutive_blocks(
|
|
3217
|
+
1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=tx
|
|
3218
|
+
)
|
|
3219
|
+
|
|
3220
|
+
last_block = recursive_replace(blocks[-1], "transactions_info.aggregated_signature", G2Element.generator())
|
|
3221
|
+
assert last_block.transactions_info is not None
|
|
3222
|
+
last_block = recursive_replace(
|
|
3223
|
+
last_block, "foliage_transaction_block.transactions_info_hash", last_block.transactions_info.get_hash()
|
|
3224
|
+
)
|
|
3225
|
+
assert last_block.foliage_transaction_block is not None
|
|
3226
|
+
last_block = recursive_replace(
|
|
3227
|
+
last_block, "foliage.foliage_transaction_block_hash", last_block.foliage_transaction_block.get_hash()
|
|
3228
|
+
)
|
|
3229
|
+
new_m = last_block.foliage.foliage_transaction_block_hash
|
|
3230
|
+
assert new_m is not None
|
|
3231
|
+
new_fsb_sig = bt.get_plot_signature(new_m, last_block.reward_chain_block.proof_of_space.plot_public_key)
|
|
3232
|
+
last_block = recursive_replace(last_block, "foliage.foliage_transaction_block_signature", new_fsb_sig)
|
|
3233
|
+
|
|
3234
|
+
# Bad signature fails during add_block
|
|
3235
|
+
await _validate_and_add_block(b, last_block, expected_error=Err.BAD_AGGREGATE_SIGNATURE)
|
|
3236
|
+
|
|
3237
|
+
# Bad signature also fails in prevalidation
|
|
3238
|
+
ssi = b.constants.SUB_SLOT_ITERS_STARTING
|
|
3239
|
+
diff = b.constants.DIFFICULTY_STARTING
|
|
3240
|
+
future = await pre_validate_block(
|
|
3241
|
+
b.constants,
|
|
3242
|
+
AugmentedBlockchain(b),
|
|
3243
|
+
last_block,
|
|
3244
|
+
b.pool,
|
|
3245
|
+
None,
|
|
3246
|
+
ValidationState(ssi, diff, None),
|
|
3247
|
+
)
|
|
3248
|
+
preval_result: PreValidationResult = await future
|
|
3249
|
+
assert preval_result.error == Err.BAD_AGGREGATE_SIGNATURE.value
|
|
3250
|
+
|
|
3251
|
+
|
|
3252
|
+
def maybe_header_hash(block: Optional[BlockRecord]) -> Optional[bytes32]:
|
|
3253
|
+
if block is None:
|
|
3254
|
+
return None
|
|
3255
|
+
return block.header_hash
|
|
3256
|
+
|
|
3257
|
+
|
|
3258
|
+
class TestReorgs:
|
|
3259
|
+
@pytest.mark.anyio
|
|
3260
|
+
async def test_basic_reorg(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
3261
|
+
b = empty_blockchain
|
|
3262
|
+
blocks = bt.get_consecutive_blocks(15)
|
|
3263
|
+
|
|
3264
|
+
for block in blocks:
|
|
3265
|
+
await _validate_and_add_block(b, block)
|
|
3266
|
+
peak = b.get_peak()
|
|
3267
|
+
assert peak is not None
|
|
3268
|
+
assert peak.height == 14
|
|
3269
|
+
|
|
3270
|
+
blocks_reorg_chain = bt.get_consecutive_blocks(7, blocks[:10], seed=b"2")
|
|
3271
|
+
fork_info = ForkInfo(-1, -1, bt.constants.GENESIS_CHALLENGE)
|
|
3272
|
+
for reorg_block in blocks_reorg_chain:
|
|
3273
|
+
if reorg_block.height < 10:
|
|
3274
|
+
await _validate_and_add_block(
|
|
3275
|
+
b, reorg_block, expected_result=AddBlockResult.ALREADY_HAVE_BLOCK, fork_info=fork_info
|
|
3276
|
+
)
|
|
3277
|
+
elif reorg_block.height < 15:
|
|
3278
|
+
await _validate_and_add_block(
|
|
3279
|
+
b, reorg_block, expected_result=AddBlockResult.ADDED_AS_ORPHAN, fork_info=fork_info
|
|
3280
|
+
)
|
|
3281
|
+
elif reorg_block.height >= 15:
|
|
3282
|
+
await _validate_and_add_block(b, reorg_block, fork_info=fork_info)
|
|
3283
|
+
peak = b.get_peak()
|
|
3284
|
+
assert peak is not None
|
|
3285
|
+
assert peak.height == 16
|
|
3286
|
+
|
|
3287
|
+
@pytest.mark.anyio
|
|
3288
|
+
async def test_get_tx_peak_reorg(
|
|
3289
|
+
self, empty_blockchain: Blockchain, bt: BlockTools, consensus_mode: ConsensusMode
|
|
3290
|
+
) -> None:
|
|
3291
|
+
b = empty_blockchain
|
|
3292
|
+
|
|
3293
|
+
if consensus_mode < ConsensusMode.HARD_FORK_2_0:
|
|
3294
|
+
reorg_point = 13
|
|
3295
|
+
else:
|
|
3296
|
+
reorg_point = 12
|
|
3297
|
+
blocks = bt.get_consecutive_blocks(reorg_point)
|
|
3298
|
+
|
|
3299
|
+
last_tx_block: Optional[bytes32] = None
|
|
3300
|
+
for block in blocks:
|
|
3301
|
+
assert maybe_header_hash(b.get_tx_peak()) == last_tx_block
|
|
3302
|
+
await _validate_and_add_block(b, block)
|
|
3303
|
+
if block.is_transaction_block():
|
|
3304
|
+
last_tx_block = block.header_hash
|
|
3305
|
+
peak = b.get_peak()
|
|
3306
|
+
assert peak is not None
|
|
3307
|
+
assert peak.height == reorg_point - 1
|
|
3308
|
+
assert maybe_header_hash(b.get_tx_peak()) == last_tx_block
|
|
3309
|
+
|
|
3310
|
+
reorg_last_tx_block: Optional[bytes32] = None
|
|
3311
|
+
fork_block = blocks[9]
|
|
3312
|
+
fork_info = ForkInfo(fork_block.height, fork_block.height, fork_block.header_hash)
|
|
3313
|
+
blocks_reorg_chain = bt.get_consecutive_blocks(7, blocks[:10], seed=b"2")
|
|
3314
|
+
assert blocks_reorg_chain[reorg_point].is_transaction_block() is False
|
|
3315
|
+
for reorg_block in blocks_reorg_chain:
|
|
3316
|
+
if reorg_block.height < 10:
|
|
3317
|
+
await _validate_and_add_block(b, reorg_block, expected_result=AddBlockResult.ALREADY_HAVE_BLOCK)
|
|
3318
|
+
elif reorg_block.height < reorg_point:
|
|
3319
|
+
await _validate_and_add_block(
|
|
3320
|
+
b, reorg_block, expected_result=AddBlockResult.ADDED_AS_ORPHAN, fork_info=fork_info
|
|
3321
|
+
)
|
|
3322
|
+
elif reorg_block.height >= reorg_point:
|
|
3323
|
+
await _validate_and_add_block(b, reorg_block, fork_info=fork_info)
|
|
3324
|
+
|
|
3325
|
+
if reorg_block.is_transaction_block():
|
|
3326
|
+
reorg_last_tx_block = reorg_block.header_hash
|
|
3327
|
+
if reorg_block.height >= reorg_point:
|
|
3328
|
+
last_tx_block = reorg_last_tx_block
|
|
3329
|
+
|
|
3330
|
+
assert maybe_header_hash(b.get_tx_peak()) == last_tx_block
|
|
3331
|
+
|
|
3332
|
+
peak = b.get_peak()
|
|
3333
|
+
assert peak is not None
|
|
3334
|
+
assert peak.height == 16
|
|
3335
|
+
|
|
3336
|
+
@pytest.mark.anyio
|
|
3337
|
+
@pytest.mark.parametrize("light_blocks", [True, False])
|
|
3338
|
+
async def test_long_reorg(
|
|
3339
|
+
self,
|
|
3340
|
+
light_blocks: bool,
|
|
3341
|
+
empty_blockchain: Blockchain,
|
|
3342
|
+
default_10000_blocks: list[FullBlock],
|
|
3343
|
+
test_long_reorg_blocks: list[FullBlock],
|
|
3344
|
+
test_long_reorg_blocks_light: list[FullBlock],
|
|
3345
|
+
) -> None:
|
|
3346
|
+
if light_blocks:
|
|
3347
|
+
reorg_blocks = test_long_reorg_blocks_light[:1650]
|
|
3348
|
+
else:
|
|
3349
|
+
reorg_blocks = test_long_reorg_blocks[:1200]
|
|
3350
|
+
|
|
3351
|
+
# Reorg longer than a difficulty adjustment
|
|
3352
|
+
# Also tests higher weight chain but lower height
|
|
3353
|
+
b = empty_blockchain
|
|
3354
|
+
num_blocks_chain_1 = 1600
|
|
3355
|
+
num_blocks_chain_2_start = 500
|
|
3356
|
+
|
|
3357
|
+
assert num_blocks_chain_1 < 10000
|
|
3358
|
+
blocks = default_10000_blocks[:num_blocks_chain_1]
|
|
3359
|
+
|
|
3360
|
+
print(f"pre-validating {len(blocks)} blocks")
|
|
3361
|
+
ssi = b.constants.SUB_SLOT_ITERS_STARTING
|
|
3362
|
+
diff = b.constants.DIFFICULTY_STARTING
|
|
3363
|
+
chain = AugmentedBlockchain(b)
|
|
3364
|
+
vs = ValidationState(ssi, diff, None)
|
|
3365
|
+
futures = []
|
|
3366
|
+
for block in blocks:
|
|
3367
|
+
futures.append(
|
|
3368
|
+
await pre_validate_block(
|
|
3369
|
+
b.constants,
|
|
3370
|
+
chain,
|
|
3371
|
+
block,
|
|
3372
|
+
b.pool,
|
|
3373
|
+
None,
|
|
3374
|
+
vs,
|
|
3375
|
+
)
|
|
3376
|
+
)
|
|
3377
|
+
pre_validation_results: list[PreValidationResult] = list(await asyncio.gather(*futures))
|
|
3378
|
+
for i, block in enumerate(blocks):
|
|
3379
|
+
if block.height != 0 and len(block.finished_sub_slots) > 0:
|
|
3380
|
+
if block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters is not None:
|
|
3381
|
+
ssi = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters
|
|
3382
|
+
assert pre_validation_results[i].error is None
|
|
3383
|
+
if (block.height % 100) == 0:
|
|
3384
|
+
print(f"main chain: {block.height:4} weight: {block.weight}")
|
|
3385
|
+
|
|
3386
|
+
fork_info: ForkInfo = ForkInfo(block.height - 1, block.height - 1, block.prev_header_hash)
|
|
3387
|
+
assert fork_info is not None
|
|
3388
|
+
(result, err, _) = await b.add_block(
|
|
3389
|
+
block, pre_validation_results[i], sub_slot_iters=ssi, fork_info=fork_info
|
|
3390
|
+
)
|
|
3391
|
+
await check_block_store_invariant(b)
|
|
3392
|
+
assert err is None
|
|
3393
|
+
assert result == AddBlockResult.NEW_PEAK
|
|
3394
|
+
|
|
3395
|
+
peak = b.get_peak()
|
|
3396
|
+
assert peak is not None
|
|
3397
|
+
chain_1_height = peak.height
|
|
3398
|
+
chain_1_weight = peak.weight
|
|
3399
|
+
assert chain_1_height == (num_blocks_chain_1 - 1)
|
|
3400
|
+
|
|
3401
|
+
# The reorg blocks will have less time between them (timestamp) and therefore will make difficulty go up
|
|
3402
|
+
# This means that the weight will grow faster, and we can get a heavier chain with lower height
|
|
3403
|
+
|
|
3404
|
+
# If these assert fail, you probably need to change the fixture in reorg_blocks to create the
|
|
3405
|
+
# right amount of blocks at the right time
|
|
3406
|
+
assert reorg_blocks[num_blocks_chain_2_start - 1] == default_10000_blocks[num_blocks_chain_2_start - 1]
|
|
3407
|
+
assert reorg_blocks[num_blocks_chain_2_start] != default_10000_blocks[num_blocks_chain_2_start]
|
|
3408
|
+
|
|
3409
|
+
# one aspect of this test is to make sure we can reorg blocks that are
|
|
3410
|
+
# not in the cache. We need to explicitly prune the cache to get that
|
|
3411
|
+
# effect.
|
|
3412
|
+
b.clean_block_records()
|
|
3413
|
+
|
|
3414
|
+
first_peak = b.get_peak()
|
|
3415
|
+
fork_info2 = None
|
|
3416
|
+
for reorg_block in reorg_blocks:
|
|
3417
|
+
if (reorg_block.height % 100) == 0:
|
|
3418
|
+
peak = b.get_peak()
|
|
3419
|
+
assert peak is not None
|
|
3420
|
+
print(
|
|
3421
|
+
f"reorg chain: {reorg_block.height:4} "
|
|
3422
|
+
f"weight: {reorg_block.weight:7} "
|
|
3423
|
+
f"peak: {str(peak.header_hash)[:6]}"
|
|
3424
|
+
)
|
|
3425
|
+
|
|
3426
|
+
if reorg_block.height < num_blocks_chain_2_start:
|
|
3427
|
+
await _validate_and_add_block(b, reorg_block, expected_result=AddBlockResult.ALREADY_HAVE_BLOCK)
|
|
3428
|
+
elif reorg_block.weight <= chain_1_weight:
|
|
3429
|
+
if fork_info2 is None:
|
|
3430
|
+
fork_info2 = ForkInfo(reorg_block.height - 1, reorg_block.height - 1, reorg_block.prev_header_hash)
|
|
3431
|
+
await _validate_and_add_block(
|
|
3432
|
+
b, reorg_block, expected_result=AddBlockResult.ADDED_AS_ORPHAN, fork_info=fork_info2
|
|
3433
|
+
)
|
|
3434
|
+
elif reorg_block.weight > chain_1_weight:
|
|
3435
|
+
await _validate_and_add_block(
|
|
3436
|
+
b, reorg_block, expected_result=AddBlockResult.NEW_PEAK, fork_info=fork_info2
|
|
3437
|
+
)
|
|
3438
|
+
|
|
3439
|
+
# if these asserts fires, there was no reorg
|
|
3440
|
+
peak = b.get_peak()
|
|
3441
|
+
assert peak is not None
|
|
3442
|
+
assert first_peak != peak
|
|
3443
|
+
assert peak is not None
|
|
3444
|
+
assert peak.weight > chain_1_weight
|
|
3445
|
+
second_peak = peak
|
|
3446
|
+
|
|
3447
|
+
if light_blocks:
|
|
3448
|
+
assert peak.height > chain_1_height
|
|
3449
|
+
else:
|
|
3450
|
+
assert peak.height < chain_1_height
|
|
3451
|
+
|
|
3452
|
+
chain_2_weight = peak.weight
|
|
3453
|
+
|
|
3454
|
+
# now reorg back to the original chain
|
|
3455
|
+
# this exercises the case where we have some of the blocks in the DB already
|
|
3456
|
+
b.clean_block_records()
|
|
3457
|
+
|
|
3458
|
+
if light_blocks:
|
|
3459
|
+
blocks = default_10000_blocks[num_blocks_chain_2_start - 100 : 1800]
|
|
3460
|
+
else:
|
|
3461
|
+
blocks = default_10000_blocks[num_blocks_chain_2_start - 100 : 2600]
|
|
3462
|
+
|
|
3463
|
+
# the block validation requires previous block records to be in the
|
|
3464
|
+
# cache
|
|
3465
|
+
br = await b.get_block_record_from_db(blocks[0].prev_header_hash)
|
|
3466
|
+
for i in range(200):
|
|
3467
|
+
assert br is not None
|
|
3468
|
+
b.add_block_record(br)
|
|
3469
|
+
br = await b.get_block_record_from_db(br.prev_hash)
|
|
3470
|
+
assert br is not None
|
|
3471
|
+
b.add_block_record(br)
|
|
3472
|
+
|
|
3473
|
+
# start the fork point a few blocks back, to test that the blockchain
|
|
3474
|
+
# can catch up
|
|
3475
|
+
fork_block = default_10000_blocks[num_blocks_chain_2_start - 101]
|
|
3476
|
+
fork_info = ForkInfo(fork_block.height, fork_block.height, fork_block.header_hash)
|
|
3477
|
+
await b.warmup(fork_block.height)
|
|
3478
|
+
for block in blocks:
|
|
3479
|
+
if (block.height % 128) == 0:
|
|
3480
|
+
peak = b.get_peak()
|
|
3481
|
+
assert peak is not None
|
|
3482
|
+
print(
|
|
3483
|
+
f"original chain: {block.height:4} "
|
|
3484
|
+
f"weight: {block.weight:7} "
|
|
3485
|
+
f"peak: {str(peak.header_hash)[:6]}"
|
|
3486
|
+
)
|
|
3487
|
+
if block.height <= chain_1_height:
|
|
3488
|
+
expect = AddBlockResult.ALREADY_HAVE_BLOCK
|
|
3489
|
+
elif block.weight < chain_2_weight:
|
|
3490
|
+
expect = AddBlockResult.ADDED_AS_ORPHAN
|
|
3491
|
+
else:
|
|
3492
|
+
expect = AddBlockResult.NEW_PEAK
|
|
3493
|
+
await _validate_and_add_block(b, block, fork_info=fork_info, expected_result=expect)
|
|
3494
|
+
|
|
3495
|
+
# if these asserts fires, there was no reorg back to the original chain
|
|
3496
|
+
peak = b.get_peak()
|
|
3497
|
+
assert peak is not None
|
|
3498
|
+
assert peak.header_hash != second_peak.header_hash
|
|
3499
|
+
assert peak.weight > chain_2_weight
|
|
3500
|
+
|
|
3501
|
+
@pytest.mark.anyio
|
|
3502
|
+
async def test_long_compact_blockchain(
|
|
3503
|
+
self, empty_blockchain: Blockchain, default_2000_blocks_compact: list[FullBlock]
|
|
3504
|
+
) -> None:
|
|
3505
|
+
b = empty_blockchain
|
|
3506
|
+
for block in default_2000_blocks_compact:
|
|
3507
|
+
await _validate_and_add_block(b, block, skip_prevalidation=True)
|
|
3508
|
+
peak = b.get_peak()
|
|
3509
|
+
assert peak is not None
|
|
3510
|
+
assert peak.height == len(default_2000_blocks_compact) - 1
|
|
3511
|
+
|
|
3512
|
+
@pytest.mark.anyio
|
|
3513
|
+
async def test_reorg_from_genesis(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
3514
|
+
b = empty_blockchain
|
|
3515
|
+
|
|
3516
|
+
blocks = bt.get_consecutive_blocks(15)
|
|
3517
|
+
|
|
3518
|
+
for block in blocks:
|
|
3519
|
+
await _validate_and_add_block(b, block)
|
|
3520
|
+
peak = b.get_peak()
|
|
3521
|
+
assert peak is not None
|
|
3522
|
+
assert peak.height == 14
|
|
3523
|
+
|
|
3524
|
+
# Reorg to alternate chain that is 1 height longer
|
|
3525
|
+
blocks_reorg_chain = bt.get_consecutive_blocks(16, [], seed=b"2")
|
|
3526
|
+
fork_info = ForkInfo(-1, -1, bt.constants.GENESIS_CHALLENGE)
|
|
3527
|
+
for reorg_block in blocks_reorg_chain:
|
|
3528
|
+
if reorg_block.height < 15:
|
|
3529
|
+
await _validate_and_add_block_multi_result(
|
|
3530
|
+
b,
|
|
3531
|
+
reorg_block,
|
|
3532
|
+
expected_result=[AddBlockResult.ADDED_AS_ORPHAN, AddBlockResult.ALREADY_HAVE_BLOCK],
|
|
3533
|
+
fork_info=fork_info,
|
|
3534
|
+
)
|
|
3535
|
+
elif reorg_block.height >= 15:
|
|
3536
|
+
await _validate_and_add_block(b, reorg_block, fork_info=fork_info)
|
|
3537
|
+
|
|
3538
|
+
# Back to original chain
|
|
3539
|
+
blocks_reorg_chain_2 = bt.get_consecutive_blocks(3, blocks, seed=b"3")
|
|
3540
|
+
|
|
3541
|
+
# we start from the beginning to make sure fork_info is built correctly
|
|
3542
|
+
fork_info = ForkInfo(-1, -1, bt.constants.GENESIS_CHALLENGE)
|
|
3543
|
+
for reorg_block in blocks_reorg_chain_2:
|
|
3544
|
+
if reorg_block.height < 15:
|
|
3545
|
+
await _validate_and_add_block(
|
|
3546
|
+
b, reorg_block, expected_result=AddBlockResult.ALREADY_HAVE_BLOCK, fork_info=fork_info
|
|
3547
|
+
)
|
|
3548
|
+
elif reorg_block.height < 16:
|
|
3549
|
+
await _validate_and_add_block(
|
|
3550
|
+
b, reorg_block, expected_result=AddBlockResult.ADDED_AS_ORPHAN, fork_info=fork_info
|
|
3551
|
+
)
|
|
3552
|
+
else:
|
|
3553
|
+
await _validate_and_add_block(b, reorg_block, fork_info=fork_info)
|
|
3554
|
+
|
|
3555
|
+
peak = b.get_peak()
|
|
3556
|
+
assert peak is not None
|
|
3557
|
+
assert peak.height == 17
|
|
3558
|
+
|
|
3559
|
+
@pytest.mark.anyio
|
|
3560
|
+
async def test_reorg_transaction(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
3561
|
+
b = empty_blockchain
|
|
3562
|
+
wallet_a = WalletTool(b.constants)
|
|
3563
|
+
WALLET_A_PUZZLE_HASHES = [wallet_a.get_new_puzzlehash() for _ in range(5)]
|
|
3564
|
+
coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
|
|
3565
|
+
receiver_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
|
|
3566
|
+
|
|
3567
|
+
blocks = bt.get_consecutive_blocks(10, farmer_reward_puzzle_hash=coinbase_puzzlehash)
|
|
3568
|
+
blocks = bt.get_consecutive_blocks(
|
|
3569
|
+
2, blocks, farmer_reward_puzzle_hash=coinbase_puzzlehash, guarantee_transaction_block=True
|
|
3570
|
+
)
|
|
3571
|
+
|
|
3572
|
+
spend_block = blocks[10]
|
|
3573
|
+
spend_coin = None
|
|
3574
|
+
for coin in spend_block.get_included_reward_coins():
|
|
3575
|
+
if coin.puzzle_hash == coinbase_puzzlehash:
|
|
3576
|
+
spend_coin = coin
|
|
3577
|
+
assert spend_coin is not None
|
|
3578
|
+
spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, spend_coin)
|
|
3579
|
+
|
|
3580
|
+
blocks = bt.get_consecutive_blocks(
|
|
3581
|
+
2,
|
|
3582
|
+
blocks,
|
|
3583
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3584
|
+
transaction_data=spend_bundle,
|
|
3585
|
+
guarantee_transaction_block=True,
|
|
3586
|
+
)
|
|
3587
|
+
|
|
3588
|
+
blocks_fork = bt.get_consecutive_blocks(
|
|
3589
|
+
1, blocks[:12], farmer_reward_puzzle_hash=coinbase_puzzlehash, seed=b"123", guarantee_transaction_block=True
|
|
3590
|
+
)
|
|
3591
|
+
blocks_fork = bt.get_consecutive_blocks(
|
|
3592
|
+
2,
|
|
3593
|
+
blocks_fork,
|
|
3594
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3595
|
+
transaction_data=spend_bundle,
|
|
3596
|
+
guarantee_transaction_block=True,
|
|
3597
|
+
seed=b"1245",
|
|
3598
|
+
)
|
|
3599
|
+
for block in blocks:
|
|
3600
|
+
await _validate_and_add_block(b, block)
|
|
3601
|
+
fork_block = blocks[11]
|
|
3602
|
+
fork_info = ForkInfo(fork_block.height, fork_block.height, fork_block.header_hash)
|
|
3603
|
+
for block in blocks_fork[12:]:
|
|
3604
|
+
await _validate_and_add_block_no_error(b, block, fork_info=fork_info)
|
|
3605
|
+
|
|
3606
|
+
@pytest.mark.anyio
|
|
3607
|
+
async def test_get_header_blocks_in_range_tx_filter(self, empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
3608
|
+
b = empty_blockchain
|
|
3609
|
+
blocks = bt.get_consecutive_blocks(
|
|
3610
|
+
3,
|
|
3611
|
+
guarantee_transaction_block=True,
|
|
3612
|
+
pool_reward_puzzle_hash=bt.pool_ph,
|
|
3613
|
+
farmer_reward_puzzle_hash=bt.pool_ph,
|
|
3614
|
+
)
|
|
3615
|
+
await _validate_and_add_block(b, blocks[0])
|
|
3616
|
+
await _validate_and_add_block(b, blocks[1])
|
|
3617
|
+
await _validate_and_add_block(b, blocks[2])
|
|
3618
|
+
wt: WalletTool = bt.get_pool_wallet_tool()
|
|
3619
|
+
tx = wt.generate_signed_transaction(
|
|
3620
|
+
uint64(10), wt.get_new_puzzlehash(), blocks[2].get_included_reward_coins()[0]
|
|
3621
|
+
)
|
|
3622
|
+
blocks = bt.get_consecutive_blocks(
|
|
3623
|
+
1,
|
|
3624
|
+
block_list_input=blocks,
|
|
3625
|
+
guarantee_transaction_block=True,
|
|
3626
|
+
transaction_data=tx,
|
|
3627
|
+
)
|
|
3628
|
+
await _validate_and_add_block(b, blocks[-1])
|
|
3629
|
+
|
|
3630
|
+
blocks_with_filter = await b.get_header_blocks_in_range(0, 10, tx_filter=True)
|
|
3631
|
+
blocks_without_filter = await b.get_header_blocks_in_range(0, 10, tx_filter=False)
|
|
3632
|
+
header_hash = blocks[-1].header_hash
|
|
3633
|
+
assert (
|
|
3634
|
+
blocks_with_filter[header_hash].transactions_filter
|
|
3635
|
+
!= blocks_without_filter[header_hash].transactions_filter
|
|
3636
|
+
)
|
|
3637
|
+
assert blocks_with_filter[header_hash].header_hash == blocks_without_filter[header_hash].header_hash
|
|
3638
|
+
|
|
3639
|
+
@pytest.mark.anyio
|
|
3640
|
+
async def test_get_blocks_at(self, empty_blockchain: Blockchain, default_1000_blocks: list[FullBlock]) -> None:
|
|
3641
|
+
b = empty_blockchain
|
|
3642
|
+
heights = []
|
|
3643
|
+
for block in default_1000_blocks[:200]:
|
|
3644
|
+
heights.append(block.height)
|
|
3645
|
+
await _validate_and_add_block(b, block)
|
|
3646
|
+
|
|
3647
|
+
blocks = await b.get_block_records_at(heights, batch_size=2)
|
|
3648
|
+
assert blocks
|
|
3649
|
+
assert len(blocks) == 200
|
|
3650
|
+
assert blocks[-1].height == 199
|
|
3651
|
+
|
|
3652
|
+
|
|
3653
|
+
@pytest.mark.anyio
|
|
3654
|
+
async def test_reorg_new_ref(empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
3655
|
+
b = empty_blockchain
|
|
3656
|
+
wallet_a = WalletTool(b.constants)
|
|
3657
|
+
WALLET_A_PUZZLE_HASHES = [wallet_a.get_new_puzzlehash() for _ in range(5)]
|
|
3658
|
+
coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
|
|
3659
|
+
receiver_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
|
|
3660
|
+
|
|
3661
|
+
blocks = bt.get_consecutive_blocks(
|
|
3662
|
+
5,
|
|
3663
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3664
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3665
|
+
guarantee_transaction_block=True,
|
|
3666
|
+
)
|
|
3667
|
+
|
|
3668
|
+
all_coins = []
|
|
3669
|
+
for spend_block in blocks[:5]:
|
|
3670
|
+
for coin in spend_block.get_included_reward_coins():
|
|
3671
|
+
if coin.puzzle_hash == coinbase_puzzlehash:
|
|
3672
|
+
all_coins.append(coin)
|
|
3673
|
+
spend_bundle_0 = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
|
|
3674
|
+
blocks = bt.get_consecutive_blocks(
|
|
3675
|
+
15,
|
|
3676
|
+
block_list_input=blocks,
|
|
3677
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3678
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3679
|
+
transaction_data=spend_bundle_0,
|
|
3680
|
+
guarantee_transaction_block=True,
|
|
3681
|
+
)
|
|
3682
|
+
|
|
3683
|
+
for block in blocks:
|
|
3684
|
+
await _validate_and_add_block(b, block)
|
|
3685
|
+
peak = b.get_peak()
|
|
3686
|
+
assert peak is not None
|
|
3687
|
+
assert peak.height == 19
|
|
3688
|
+
|
|
3689
|
+
print("first chain done")
|
|
3690
|
+
|
|
3691
|
+
# Make sure a ref back into the reorg chain itself works as expected
|
|
3692
|
+
|
|
3693
|
+
blocks_reorg_chain = bt.get_consecutive_blocks(
|
|
3694
|
+
1,
|
|
3695
|
+
blocks[:10],
|
|
3696
|
+
seed=b"2",
|
|
3697
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3698
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3699
|
+
)
|
|
3700
|
+
spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
|
|
3701
|
+
|
|
3702
|
+
blocks_reorg_chain = bt.get_consecutive_blocks(
|
|
3703
|
+
2,
|
|
3704
|
+
blocks_reorg_chain,
|
|
3705
|
+
seed=b"2",
|
|
3706
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3707
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3708
|
+
transaction_data=spend_bundle,
|
|
3709
|
+
guarantee_transaction_block=True,
|
|
3710
|
+
)
|
|
3711
|
+
|
|
3712
|
+
spend_bundle2 = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
|
|
3713
|
+
blocks_reorg_chain = bt.get_consecutive_blocks(
|
|
3714
|
+
4, blocks_reorg_chain, seed=b"2", block_refs=[uint32(5), uint32(11)], transaction_data=spend_bundle2
|
|
3715
|
+
)
|
|
3716
|
+
blocks_reorg_chain = bt.get_consecutive_blocks(4, blocks_reorg_chain, seed=b"2")
|
|
3717
|
+
|
|
3718
|
+
fork_info = ForkInfo(-1, -1, b.constants.GENESIS_CHALLENGE)
|
|
3719
|
+
for i, block in enumerate(blocks_reorg_chain):
|
|
3720
|
+
if i < 10:
|
|
3721
|
+
expected = AddBlockResult.ALREADY_HAVE_BLOCK
|
|
3722
|
+
elif i < 19:
|
|
3723
|
+
expected = AddBlockResult.ADDED_AS_ORPHAN
|
|
3724
|
+
elif i == 19:
|
|
3725
|
+
# same height as peak decide by iterations
|
|
3726
|
+
peak = b.get_peak()
|
|
3727
|
+
assert peak is not None
|
|
3728
|
+
# same height as peak should be ADDED_AS_ORPHAN if block.total_iters >= peak.total_iters
|
|
3729
|
+
assert block.total_iters < peak.total_iters
|
|
3730
|
+
expected = AddBlockResult.NEW_PEAK
|
|
3731
|
+
else:
|
|
3732
|
+
expected = AddBlockResult.NEW_PEAK
|
|
3733
|
+
await _validate_and_add_block(b, block, expected_result=expected, fork_info=fork_info)
|
|
3734
|
+
peak = b.get_peak()
|
|
3735
|
+
assert peak is not None
|
|
3736
|
+
assert peak.height == 20
|
|
3737
|
+
|
|
3738
|
+
|
|
3739
|
+
# this test doesn't reorg, but _reconsider_peak() is passed a stale
|
|
3740
|
+
# "fork_height" to make it look like it's in a reorg, but all the same blocks
|
|
3741
|
+
# are just added back.
|
|
3742
|
+
@pytest.mark.anyio
|
|
3743
|
+
async def test_reorg_stale_fork_height(empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
3744
|
+
b = empty_blockchain
|
|
3745
|
+
wallet_a = WalletTool(b.constants)
|
|
3746
|
+
WALLET_A_PUZZLE_HASHES = [wallet_a.get_new_puzzlehash() for _ in range(5)]
|
|
3747
|
+
coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
|
|
3748
|
+
receiver_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
|
|
3749
|
+
|
|
3750
|
+
blocks = bt.get_consecutive_blocks(
|
|
3751
|
+
5,
|
|
3752
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3753
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3754
|
+
guarantee_transaction_block=True,
|
|
3755
|
+
)
|
|
3756
|
+
|
|
3757
|
+
all_coins = []
|
|
3758
|
+
for spend_block in blocks:
|
|
3759
|
+
for coin in spend_block.get_included_reward_coins():
|
|
3760
|
+
if coin.puzzle_hash == coinbase_puzzlehash:
|
|
3761
|
+
all_coins.append(coin)
|
|
3762
|
+
|
|
3763
|
+
# Make sure a ref back into the reorg chain itself works as expected
|
|
3764
|
+
spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
|
|
3765
|
+
|
|
3766
|
+
# make sure we have a transaction block, with at least one transaction in it
|
|
3767
|
+
blocks = bt.get_consecutive_blocks(
|
|
3768
|
+
5,
|
|
3769
|
+
blocks,
|
|
3770
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3771
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3772
|
+
transaction_data=spend_bundle,
|
|
3773
|
+
guarantee_transaction_block=True,
|
|
3774
|
+
)
|
|
3775
|
+
|
|
3776
|
+
# this block (height 10) refers back to the generator in block 5
|
|
3777
|
+
spend_bundle2 = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
|
|
3778
|
+
blocks = bt.get_consecutive_blocks(4, blocks, block_refs=[uint32(5)], transaction_data=spend_bundle2)
|
|
3779
|
+
|
|
3780
|
+
for block in blocks[:5]:
|
|
3781
|
+
await _validate_and_add_block(b, block, expected_result=AddBlockResult.NEW_PEAK)
|
|
3782
|
+
|
|
3783
|
+
# fake the fork_info to make every new block look like a reorg
|
|
3784
|
+
fork_info = ForkInfo(blocks[4].height, blocks[4].height, blocks[4].header_hash)
|
|
3785
|
+
for block in blocks[5:]:
|
|
3786
|
+
await _validate_and_add_block(b, block, expected_result=AddBlockResult.NEW_PEAK, fork_info=fork_info)
|
|
3787
|
+
peak = b.get_peak()
|
|
3788
|
+
assert peak is not None
|
|
3789
|
+
assert peak.height == 13
|
|
3790
|
+
|
|
3791
|
+
|
|
3792
|
+
@pytest.mark.anyio
|
|
3793
|
+
async def test_chain_failed_rollback(empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
3794
|
+
b = empty_blockchain
|
|
3795
|
+
wallet_a = WalletTool(b.constants)
|
|
3796
|
+
WALLET_A_PUZZLE_HASHES = [wallet_a.get_new_puzzlehash() for _ in range(5)]
|
|
3797
|
+
coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
|
|
3798
|
+
receiver_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
|
|
3799
|
+
|
|
3800
|
+
blocks = bt.get_consecutive_blocks(
|
|
3801
|
+
20,
|
|
3802
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3803
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3804
|
+
)
|
|
3805
|
+
|
|
3806
|
+
for block in blocks:
|
|
3807
|
+
await _validate_and_add_block(b, block)
|
|
3808
|
+
peak = b.get_peak()
|
|
3809
|
+
assert peak is not None
|
|
3810
|
+
assert peak.height == 19
|
|
3811
|
+
|
|
3812
|
+
print("first chain done")
|
|
3813
|
+
|
|
3814
|
+
# Make sure a ref back into the reorg chain itself works as expected
|
|
3815
|
+
|
|
3816
|
+
all_coins = []
|
|
3817
|
+
for spend_block in blocks[:10]:
|
|
3818
|
+
for coin in spend_block.get_included_reward_coins():
|
|
3819
|
+
if coin.puzzle_hash == coinbase_puzzlehash:
|
|
3820
|
+
all_coins.append(coin)
|
|
3821
|
+
|
|
3822
|
+
spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
|
|
3823
|
+
|
|
3824
|
+
blocks_reorg_chain = bt.get_consecutive_blocks(
|
|
3825
|
+
11,
|
|
3826
|
+
blocks[:10],
|
|
3827
|
+
seed=b"2",
|
|
3828
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3829
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3830
|
+
transaction_data=spend_bundle,
|
|
3831
|
+
guarantee_transaction_block=True,
|
|
3832
|
+
)
|
|
3833
|
+
|
|
3834
|
+
fork_block = blocks_reorg_chain[9]
|
|
3835
|
+
fork_info = ForkInfo(fork_block.height, fork_block.height, fork_block.header_hash)
|
|
3836
|
+
for block in blocks_reorg_chain[10:-1]:
|
|
3837
|
+
await _validate_and_add_block(b, block, expected_result=AddBlockResult.ADDED_AS_ORPHAN, fork_info=fork_info)
|
|
3838
|
+
|
|
3839
|
+
# Incorrectly set the height as spent in DB to trigger an error
|
|
3840
|
+
print(f"{await b.coin_store.get_coin_record(spend_bundle.coin_spends[0].coin.name())}")
|
|
3841
|
+
print(spend_bundle.coin_spends[0].coin.name())
|
|
3842
|
+
# await b.coin_store._set_spent([spend_bundle.coin_spends[0].coin.name()], 8)
|
|
3843
|
+
await b.coin_store.rollback_to_block(2)
|
|
3844
|
+
print(f"{await b.coin_store.get_coin_record(spend_bundle.coin_spends[0].coin.name())}")
|
|
3845
|
+
|
|
3846
|
+
fork_block = blocks_reorg_chain[10 - 1]
|
|
3847
|
+
# fork_info = ForkInfo(fork_block.height, fork_block.height, fork_block.header_hash)
|
|
3848
|
+
with pytest.raises(ValueError, match="Invalid operation to set spent"):
|
|
3849
|
+
await _validate_and_add_block(b, blocks_reorg_chain[-1], fork_info=fork_info)
|
|
3850
|
+
|
|
3851
|
+
peak = b.get_peak()
|
|
3852
|
+
assert peak is not None
|
|
3853
|
+
assert peak.height == 19
|
|
3854
|
+
|
|
3855
|
+
|
|
3856
|
+
@pytest.mark.anyio
|
|
3857
|
+
async def test_reorg_flip_flop(empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
3858
|
+
b = empty_blockchain
|
|
3859
|
+
wallet_a = WalletTool(b.constants)
|
|
3860
|
+
WALLET_A_PUZZLE_HASHES = [wallet_a.get_new_puzzlehash() for _ in range(5)]
|
|
3861
|
+
coinbase_puzzlehash = WALLET_A_PUZZLE_HASHES[0]
|
|
3862
|
+
receiver_puzzlehash = WALLET_A_PUZZLE_HASHES[1]
|
|
3863
|
+
|
|
3864
|
+
chain_a = bt.get_consecutive_blocks(
|
|
3865
|
+
10,
|
|
3866
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3867
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3868
|
+
guarantee_transaction_block=True,
|
|
3869
|
+
)
|
|
3870
|
+
|
|
3871
|
+
all_coins = []
|
|
3872
|
+
for spend_block in chain_a:
|
|
3873
|
+
for coin in spend_block.get_included_reward_coins():
|
|
3874
|
+
if coin.puzzle_hash == coinbase_puzzlehash:
|
|
3875
|
+
all_coins.append(coin)
|
|
3876
|
+
|
|
3877
|
+
# this is a transaction block at height 10
|
|
3878
|
+
spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
|
|
3879
|
+
chain_a = bt.get_consecutive_blocks(
|
|
3880
|
+
5,
|
|
3881
|
+
chain_a,
|
|
3882
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3883
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3884
|
+
transaction_data=spend_bundle,
|
|
3885
|
+
guarantee_transaction_block=True,
|
|
3886
|
+
)
|
|
3887
|
+
|
|
3888
|
+
spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
|
|
3889
|
+
chain_a = bt.get_consecutive_blocks(
|
|
3890
|
+
5,
|
|
3891
|
+
chain_a,
|
|
3892
|
+
block_refs=[uint32(10)],
|
|
3893
|
+
transaction_data=spend_bundle,
|
|
3894
|
+
guarantee_transaction_block=True,
|
|
3895
|
+
)
|
|
3896
|
+
|
|
3897
|
+
spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
|
|
3898
|
+
chain_a = bt.get_consecutive_blocks(
|
|
3899
|
+
20,
|
|
3900
|
+
chain_a,
|
|
3901
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3902
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3903
|
+
transaction_data=spend_bundle,
|
|
3904
|
+
guarantee_transaction_block=True,
|
|
3905
|
+
)
|
|
3906
|
+
|
|
3907
|
+
# chain A is 40 blocks deep
|
|
3908
|
+
# chain B share the first 20 blocks with chain A
|
|
3909
|
+
|
|
3910
|
+
# add 5 blocks on top of the first 20, to form chain B
|
|
3911
|
+
chain_b = bt.get_consecutive_blocks(
|
|
3912
|
+
5,
|
|
3913
|
+
chain_a[:20],
|
|
3914
|
+
seed=b"2",
|
|
3915
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3916
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3917
|
+
)
|
|
3918
|
+
spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
|
|
3919
|
+
|
|
3920
|
+
# this is a transaction block at height 15 (in Chain B)
|
|
3921
|
+
chain_b = bt.get_consecutive_blocks(
|
|
3922
|
+
5,
|
|
3923
|
+
chain_b,
|
|
3924
|
+
seed=b"2",
|
|
3925
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3926
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3927
|
+
transaction_data=spend_bundle,
|
|
3928
|
+
guarantee_transaction_block=True,
|
|
3929
|
+
)
|
|
3930
|
+
|
|
3931
|
+
spend_bundle = wallet_a.generate_signed_transaction(uint64(1_000), receiver_puzzlehash, all_coins.pop())
|
|
3932
|
+
chain_b = bt.get_consecutive_blocks(10, chain_b, seed=b"2", block_refs=[uint32(15)], transaction_data=spend_bundle)
|
|
3933
|
+
|
|
3934
|
+
assert len(chain_a) == len(chain_b)
|
|
3935
|
+
|
|
3936
|
+
counter = 0
|
|
3937
|
+
ssi = b.constants.SUB_SLOT_ITERS_STARTING
|
|
3938
|
+
diff = b.constants.DIFFICULTY_STARTING
|
|
3939
|
+
for b1, b2 in zip(chain_a, chain_b):
|
|
3940
|
+
# alternate the order we add blocks from the two chains, to ensure one
|
|
3941
|
+
# chain overtakes the other one in weight every other time
|
|
3942
|
+
if counter % 2 == 0:
|
|
3943
|
+
block1, block2 = b2, b1
|
|
3944
|
+
else:
|
|
3945
|
+
block1, block2 = b1, b2
|
|
3946
|
+
counter += 1
|
|
3947
|
+
|
|
3948
|
+
preval = await (
|
|
3949
|
+
await pre_validate_block(
|
|
3950
|
+
b.constants,
|
|
3951
|
+
AugmentedBlockchain(b),
|
|
3952
|
+
block1,
|
|
3953
|
+
b.pool,
|
|
3954
|
+
None,
|
|
3955
|
+
ValidationState(ssi, diff, None),
|
|
3956
|
+
)
|
|
3957
|
+
)
|
|
3958
|
+
peak = b.get_peak()
|
|
3959
|
+
if peak is None:
|
|
3960
|
+
fork_info = ForkInfo(-1, -1, bt.constants.GENESIS_CHALLENGE)
|
|
3961
|
+
else:
|
|
3962
|
+
fork_info = await get_fork_info(b, block1, peak)
|
|
3963
|
+
_, err, _ = await b.add_block(block1, preval, sub_slot_iters=ssi, fork_info=fork_info)
|
|
3964
|
+
assert err is None
|
|
3965
|
+
preval = await (
|
|
3966
|
+
await pre_validate_block(
|
|
3967
|
+
b.constants,
|
|
3968
|
+
AugmentedBlockchain(b),
|
|
3969
|
+
block2,
|
|
3970
|
+
b.pool,
|
|
3971
|
+
None,
|
|
3972
|
+
ValidationState(ssi, diff, None),
|
|
3973
|
+
)
|
|
3974
|
+
)
|
|
3975
|
+
peak = b.get_peak()
|
|
3976
|
+
assert peak is not None
|
|
3977
|
+
fork_info = await get_fork_info(b, block2, peak)
|
|
3978
|
+
_, err, _ = await b.add_block(block2, preval, sub_slot_iters=ssi, fork_info=fork_info)
|
|
3979
|
+
assert err is None
|
|
3980
|
+
|
|
3981
|
+
peak = b.get_peak()
|
|
3982
|
+
assert peak is not None
|
|
3983
|
+
assert peak.height == 39
|
|
3984
|
+
|
|
3985
|
+
chain_b = bt.get_consecutive_blocks(
|
|
3986
|
+
10,
|
|
3987
|
+
chain_b,
|
|
3988
|
+
seed=b"2",
|
|
3989
|
+
farmer_reward_puzzle_hash=coinbase_puzzlehash,
|
|
3990
|
+
pool_reward_puzzle_hash=receiver_puzzlehash,
|
|
3991
|
+
)
|
|
3992
|
+
|
|
3993
|
+
for block in chain_b[40:]:
|
|
3994
|
+
await _validate_and_add_block(b, block)
|
|
3995
|
+
|
|
3996
|
+
|
|
3997
|
+
async def test_get_tx_peak(default_400_blocks: list[FullBlock], empty_blockchain: Blockchain) -> None:
|
|
3998
|
+
bc = empty_blockchain
|
|
3999
|
+
test_blocks = default_400_blocks[:100]
|
|
4000
|
+
ssi = bc.constants.SUB_SLOT_ITERS_STARTING
|
|
4001
|
+
diff = bc.constants.DIFFICULTY_STARTING
|
|
4002
|
+
futures: list[Awaitable[PreValidationResult]] = []
|
|
4003
|
+
chain = AugmentedBlockchain(bc)
|
|
4004
|
+
vs = ValidationState(ssi, diff, None)
|
|
4005
|
+
for block in test_blocks:
|
|
4006
|
+
futures.append(
|
|
4007
|
+
await pre_validate_block(
|
|
4008
|
+
bc.constants,
|
|
4009
|
+
chain,
|
|
4010
|
+
block,
|
|
4011
|
+
bc.pool,
|
|
4012
|
+
None,
|
|
4013
|
+
vs,
|
|
4014
|
+
)
|
|
4015
|
+
)
|
|
4016
|
+
|
|
4017
|
+
res: list[PreValidationResult] = list(await asyncio.gather(*futures))
|
|
4018
|
+
|
|
4019
|
+
last_tx_block_record = None
|
|
4020
|
+
for b, prevalidation_res in zip(test_blocks, res):
|
|
4021
|
+
assert bc.get_tx_peak() == last_tx_block_record
|
|
4022
|
+
fork_info = ForkInfo(b.height - 1, b.height - 1, b.prev_header_hash)
|
|
4023
|
+
_, err, _ = await bc.add_block(b, prevalidation_res, sub_slot_iters=ssi, fork_info=fork_info)
|
|
4024
|
+
assert err is None
|
|
4025
|
+
|
|
4026
|
+
if b.is_transaction_block():
|
|
4027
|
+
assert prevalidation_res.required_iters is not None
|
|
4028
|
+
block_record = block_to_block_record(
|
|
4029
|
+
bc.constants,
|
|
4030
|
+
bc,
|
|
4031
|
+
prevalidation_res.required_iters,
|
|
4032
|
+
b,
|
|
4033
|
+
empty_blockchain.constants.SUB_SLOT_ITERS_STARTING,
|
|
4034
|
+
)
|
|
4035
|
+
last_tx_block_record = block_record
|
|
4036
|
+
|
|
4037
|
+
assert bc.get_tx_peak() == last_tx_block_record
|
|
4038
|
+
|
|
4039
|
+
|
|
4040
|
+
def to_bytes(gen: Optional[SerializedProgram]) -> bytes:
|
|
4041
|
+
assert gen is not None
|
|
4042
|
+
return bytes(gen)
|
|
4043
|
+
|
|
4044
|
+
|
|
4045
|
+
@pytest.mark.anyio
|
|
4046
|
+
@pytest.mark.limit_consensus_modes(reason="block heights for generators differ between test chains in different modes")
|
|
4047
|
+
@pytest.mark.parametrize("clear_cache", [True, False])
|
|
4048
|
+
async def test_lookup_block_generators(
|
|
4049
|
+
default_10000_blocks: list[FullBlock],
|
|
4050
|
+
test_long_reorg_blocks_light: list[FullBlock],
|
|
4051
|
+
bt: BlockTools,
|
|
4052
|
+
empty_blockchain: Blockchain,
|
|
4053
|
+
clear_cache: bool,
|
|
4054
|
+
) -> None:
|
|
4055
|
+
b = empty_blockchain
|
|
4056
|
+
blocks_1 = default_10000_blocks
|
|
4057
|
+
blocks_2 = test_long_reorg_blocks_light
|
|
4058
|
+
|
|
4059
|
+
# this test blockchain is expected to have block generators at these
|
|
4060
|
+
# heights:
|
|
4061
|
+
# 2, 3, 4, 5, 6, 7, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
|
4062
|
+
# 24, 25, 26, 28
|
|
4063
|
+
|
|
4064
|
+
# default_10000_blocks and test_long_reorg_blocks_light diverge at height
|
|
4065
|
+
# 500. Add blocks from both past the fork to be able to test both
|
|
4066
|
+
|
|
4067
|
+
# fork 1 is expected to have generators at these heights:
|
|
4068
|
+
# 503, 507, 511, 517, 524, 529, 532, 533, 534, 539, 542, 543, 546, 547
|
|
4069
|
+
|
|
4070
|
+
# fork 2 is expected to have generators at these heights:
|
|
4071
|
+
# 507, 516, 527, 535, 539, 543, 547
|
|
4072
|
+
|
|
4073
|
+
# start with adding some blocks to test lookups from the mainchain
|
|
4074
|
+
fork_info = ForkInfo(-1, -1, bt.constants.GENESIS_CHALLENGE)
|
|
4075
|
+
for block in blocks_2[:550]:
|
|
4076
|
+
await _validate_and_add_block(b, block, expected_result=AddBlockResult.NEW_PEAK, fork_info=fork_info)
|
|
4077
|
+
|
|
4078
|
+
fork_info = ForkInfo(blocks_1[500].height - 1, blocks_1[500].height - 1, blocks_1[500].prev_header_hash)
|
|
4079
|
+
for block in blocks_1[500:550]:
|
|
4080
|
+
await _validate_and_add_block(b, block, expected_result=AddBlockResult.ADDED_AS_ORPHAN, fork_info=fork_info)
|
|
4081
|
+
|
|
4082
|
+
# now we have a blockchain with two forks, the peak is at blocks_2[550] and
|
|
4083
|
+
# the leight weight peak is at blocks_1[550]
|
|
4084
|
+
# make sure we can lookup block generators from each fork
|
|
4085
|
+
|
|
4086
|
+
peak_1 = blocks_1[550]
|
|
4087
|
+
peak_2 = blocks_2[550]
|
|
4088
|
+
|
|
4089
|
+
# single generators, from the shared part of the chain
|
|
4090
|
+
for peak in [peak_1, peak_2]:
|
|
4091
|
+
if clear_cache:
|
|
4092
|
+
b.clean_block_records()
|
|
4093
|
+
generators = await b.lookup_block_generators(peak.prev_header_hash, {uint32(2)})
|
|
4094
|
+
assert generators == {
|
|
4095
|
+
uint32(2): to_bytes(blocks_1[2].transactions_generator),
|
|
4096
|
+
}
|
|
4097
|
+
|
|
4098
|
+
# multiple generators from the shared part of the chain
|
|
4099
|
+
for peak in [peak_1, peak_2]:
|
|
4100
|
+
if clear_cache:
|
|
4101
|
+
b.clean_block_records()
|
|
4102
|
+
generators = await b.lookup_block_generators(peak.prev_header_hash, {uint32(2), uint32(10), uint32(26)})
|
|
4103
|
+
assert generators == {
|
|
4104
|
+
uint32(2): to_bytes(blocks_1[2].transactions_generator),
|
|
4105
|
+
uint32(10): to_bytes(blocks_1[10].transactions_generator),
|
|
4106
|
+
uint32(26): to_bytes(blocks_1[26].transactions_generator),
|
|
4107
|
+
}
|
|
4108
|
+
|
|
4109
|
+
# lookups from the past the fork
|
|
4110
|
+
if clear_cache:
|
|
4111
|
+
b.clean_block_records()
|
|
4112
|
+
generators = await b.lookup_block_generators(peak_1.prev_header_hash, {uint32(503)})
|
|
4113
|
+
assert generators == {uint32(503): to_bytes(blocks_1[503].transactions_generator)}
|
|
4114
|
+
|
|
4115
|
+
if clear_cache:
|
|
4116
|
+
b.clean_block_records()
|
|
4117
|
+
generators = await b.lookup_block_generators(peak_2.prev_header_hash, {uint32(516)})
|
|
4118
|
+
assert generators == {uint32(516): to_bytes(blocks_2[516].transactions_generator)}
|
|
4119
|
+
|
|
4120
|
+
# make sure we don't cross the forks
|
|
4121
|
+
if clear_cache:
|
|
4122
|
+
b.clean_block_records()
|
|
4123
|
+
with pytest.raises(ValueError, match="Err.GENERATOR_REF_HAS_NO_GENERATOR"):
|
|
4124
|
+
await b.lookup_block_generators(peak_1.prev_header_hash, {uint32(516)})
|
|
4125
|
+
|
|
4126
|
+
if clear_cache:
|
|
4127
|
+
b.clean_block_records()
|
|
4128
|
+
with pytest.raises(ValueError, match="Err.GENERATOR_REF_HAS_NO_GENERATOR"):
|
|
4129
|
+
await b.lookup_block_generators(peak_2.prev_header_hash, {uint32(503)})
|
|
4130
|
+
|
|
4131
|
+
# make sure we fail when looking up a non-transaction block from the main
|
|
4132
|
+
# chain, regardless of which chain we start at
|
|
4133
|
+
if clear_cache:
|
|
4134
|
+
b.clean_block_records()
|
|
4135
|
+
with pytest.raises(ValueError, match="Err.GENERATOR_REF_HAS_NO_GENERATOR"):
|
|
4136
|
+
await b.lookup_block_generators(peak_1.prev_header_hash, {uint32(8)})
|
|
4137
|
+
|
|
4138
|
+
if clear_cache:
|
|
4139
|
+
b.clean_block_records()
|
|
4140
|
+
with pytest.raises(ValueError, match="Err.GENERATOR_REF_HAS_NO_GENERATOR"):
|
|
4141
|
+
await b.lookup_block_generators(peak_2.prev_header_hash, {uint32(8)})
|
|
4142
|
+
|
|
4143
|
+
# if we try to look up generators starting from a disconnected block, we
|
|
4144
|
+
# fail
|
|
4145
|
+
if clear_cache:
|
|
4146
|
+
b.clean_block_records()
|
|
4147
|
+
with pytest.raises(AssertionError):
|
|
4148
|
+
await b.lookup_block_generators(blocks_2[600].prev_header_hash, {uint32(3)})
|
|
4149
|
+
|
|
4150
|
+
if clear_cache:
|
|
4151
|
+
b.clean_block_records()
|
|
4152
|
+
with pytest.raises(AssertionError):
|
|
4153
|
+
await b.lookup_block_generators(blocks_1[600].prev_header_hash, {uint32(3)})
|
|
4154
|
+
|
|
4155
|
+
|
|
4156
|
+
async def get_fork_info(blockchain: Blockchain, block: FullBlock, peak: BlockRecord) -> ForkInfo:
|
|
4157
|
+
fork_chain, fork_hash = await lookup_fork_chain(
|
|
4158
|
+
blockchain,
|
|
4159
|
+
(peak.height, peak.header_hash),
|
|
4160
|
+
(block.height - 1, block.prev_header_hash),
|
|
4161
|
+
blockchain.constants,
|
|
4162
|
+
)
|
|
4163
|
+
# now we know how long the fork is, and can compute the fork
|
|
4164
|
+
# height.
|
|
4165
|
+
fork_height = block.height - len(fork_chain) - 1
|
|
4166
|
+
fork_info = ForkInfo(fork_height, fork_height, fork_hash)
|
|
4167
|
+
|
|
4168
|
+
# now run all the blocks of the fork to compute the additions
|
|
4169
|
+
# and removals. They are recorded in the fork_info object
|
|
4170
|
+
counter = 0
|
|
4171
|
+
start = time.monotonic()
|
|
4172
|
+
for height in range(fork_info.fork_height + 1, block.height):
|
|
4173
|
+
fork_block: Optional[FullBlock] = await blockchain.block_store.get_full_block(fork_chain[uint32(height)])
|
|
4174
|
+
assert fork_block is not None
|
|
4175
|
+
assert fork_block.height - 1 == fork_info.peak_height
|
|
4176
|
+
assert fork_block.height == 0 or fork_block.prev_header_hash == fork_info.peak_hash
|
|
4177
|
+
await blockchain.run_single_block(fork_block, fork_info)
|
|
4178
|
+
counter += 1
|
|
4179
|
+
end = time.monotonic()
|
|
4180
|
+
log.info(
|
|
4181
|
+
f"executed {counter} block generators in {end - start:2f} s. "
|
|
4182
|
+
f"{len(fork_info.additions_since_fork)} additions, "
|
|
4183
|
+
f"{len(fork_info.removals_since_fork)} removals"
|
|
4184
|
+
)
|
|
4185
|
+
|
|
4186
|
+
return fork_info
|
|
4187
|
+
|
|
4188
|
+
|
|
4189
|
+
@pytest.mark.anyio
|
|
4190
|
+
async def test_get_header_blocks_in_range_tx_filter_non_tx_block(empty_blockchain: Blockchain, bt: BlockTools) -> None:
|
|
4191
|
+
"""
|
|
4192
|
+
Covers the case of calling `get_header_blocks_in_range`, requesting
|
|
4193
|
+
transactions filter, on a non transaction block.
|
|
4194
|
+
"""
|
|
4195
|
+
b = empty_blockchain
|
|
4196
|
+
blocks = bt.get_consecutive_blocks(2)
|
|
4197
|
+
for block in blocks:
|
|
4198
|
+
await _validate_and_add_block(b, block)
|
|
4199
|
+
non_tx_block = next(block for block in blocks if not block.is_transaction_block())
|
|
4200
|
+
blocks_with_filter = await b.get_header_blocks_in_range(0, 42, tx_filter=True)
|
|
4201
|
+
empty_tx_filter = b"\x00"
|
|
4202
|
+
assert blocks_with_filter[non_tx_block.header_hash].transactions_filter == empty_tx_filter
|