├── .flake8 ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── config.yml ├── dependabot.yml ├── linters │ ├── .flake8 │ ├── .isort.cfg │ ├── .markdown-lint.yml │ ├── .python-black │ └── .python-lint └── workflows │ ├── build-linux-arm64-installer.yml │ ├── build-linux-installer-deb.yml │ ├── build-linux-installer-rpm.yml │ ├── build-macos-installer.yml │ ├── build-macos-m1-installer.yml │ ├── build-test-macos-blockchain.yml │ ├── build-test-macos-clvm.yml │ ├── build-test-macos-core-consensus.yml │ ├── build-test-macos-core-daemon.yml │ ├── build-test-macos-core-full_node-full_sync.yml │ ├── build-test-macos-core-full_node.yml │ ├── build-test-macos-core-server.yml │ ├── build-test-macos-core-ssl.yml │ ├── build-test-macos-core-types.yml │ ├── build-test-macos-core-util.yml │ ├── build-test-macos-core.yml │ ├── build-test-macos-generator.yml │ ├── build-test-macos-pools.yml │ ├── build-test-macos-simulation.yml │ ├── build-test-macos-wallet-cc_wallet.yml │ ├── build-test-macos-wallet-rl_wallet.yml │ ├── build-test-macos-wallet-rpc.yml │ ├── build-test-macos-wallet-sync.yml │ ├── build-test-macos-wallet.yml │ ├── build-test-ubuntu-blockchain.yml │ ├── build-test-ubuntu-clvm.yml │ ├── build-test-ubuntu-core-consensus.yml │ ├── build-test-ubuntu-core-daemon.yml │ ├── build-test-ubuntu-core-full_node-full_sync.yml │ ├── build-test-ubuntu-core-full_node.yml │ ├── build-test-ubuntu-core-server.yml │ ├── build-test-ubuntu-core-ssl.yml │ ├── build-test-ubuntu-core-types.yml │ ├── build-test-ubuntu-core-util.yml │ ├── build-test-ubuntu-core.yml │ ├── build-test-ubuntu-generator.yml │ ├── build-test-ubuntu-pools.yml │ ├── build-test-ubuntu-simulation.yml │ ├── build-test-ubuntu-wallet-cc_wallet.yml │ ├── build-test-ubuntu-wallet-rl_wallet.yml │ ├── build-test-ubuntu-wallet-rpc.yml │ ├── build-test-ubuntu-wallet-sync.yml │ ├── build-test-ubuntu-wallet.yml │ ├── build-windows-installer.yml │ ├── codeql-analysis.yml │ ├── start-release.yml │ ├── super-linter.yml │ └── upload-pypi-source.yml ├── .gitignore ├── .gitmodules ├── .isort.cfg ├── .vs ├── ProjectSettings.json ├── VSWorkspaceState.json ├── avocado-blockchain │ └── v16 │ │ └── .suo └── slnx.sqlite ├── BUILD_TIMELORD.md ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── INSTALL.md ├── LICENSE ├── README.md ├── avocado ├── __init__.py ├── clvm │ └── singleton.py ├── cmds │ ├── __init__.py │ ├── avocado.py │ ├── configure.py │ ├── farm.py │ ├── farm_funcs.py │ ├── init.py │ ├── init_funcs.py │ ├── keys.py │ ├── keys_funcs.py │ ├── netspace.py │ ├── netspace_funcs.py │ ├── plotnft.py │ ├── plotnft_funcs.py │ ├── plots.py │ ├── show.py │ ├── start.py │ ├── start_funcs.py │ ├── stop.py │ ├── units.py │ ├── wallet.py │ └── wallet_funcs.py ├── consensus │ ├── __init__.py │ ├── block_body_validation.py │ ├── block_creation.py │ ├── block_header_validation.py │ ├── block_record.py │ ├── block_rewards.py │ ├── block_root_validation.py │ ├── blockchain.py │ ├── blockchain_interface.py │ ├── coinbase.py │ ├── condition_costs.py │ ├── constants.py │ ├── cost_calculator.py │ ├── default_constants.py │ ├── deficit.py │ ├── difficulty_adjustment.py │ ├── find_fork_point.py │ ├── full_block_to_block_record.py │ ├── get_block_challenge.py │ ├── make_sub_epoch_summary.py │ ├── multiprocess_validation.py │ ├── network_type.py │ ├── pos_quality.py │ ├── pot_iterations.py │ └── vdf_info_computation.py ├── daemon │ ├── __init__.py │ ├── client.py │ ├── server.py │ └── windows_signal.py ├── farmer │ ├── __init__.py │ ├── farmer.py │ └── farmer_api.py ├── full_node │ ├── __init__.py │ ├── block_store.py │ ├── bundle_tools.py │ ├── coin_store.py │ ├── full_node.py │ ├── full_node_api.py │ ├── full_node_store.py │ ├── generator.py │ ├── mempool.py │ ├── mempool_check_conditions.py │ ├── mempool_manager.py │ ├── signage_point.py │ ├── sync_store.py │ └── weight_proof.py ├── harvester │ ├── __init__.py │ ├── harvester.py │ └── harvester_api.py ├── introducer │ ├── __init__.py │ ├── introducer.py │ └── introducer_api.py ├── plotting │ ├── check_plots.py │ ├── create_plots.py │ └── plot_tools.py ├── pools │ ├── __init__.py │ ├── pool_config.py │ ├── pool_puzzles.py │ ├── pool_wallet.py │ └── pool_wallet_info.py ├── protocols │ ├── __init__.py │ ├── farmer_protocol.py │ ├── full_node_protocol.py │ ├── harvester_protocol.py │ ├── introducer_protocol.py │ ├── pool_protocol.py │ ├── protocol_message_types.py │ ├── shared_protocol.py │ ├── timelord_protocol.py │ └── wallet_protocol.py ├── pyinstaller.spec ├── rpc │ ├── __init__.py │ ├── farmer_rpc_api.py │ ├── farmer_rpc_client.py │ ├── full_node_rpc_api.py │ ├── full_node_rpc_client.py │ ├── harvester_rpc_api.py │ ├── harvester_rpc_client.py │ ├── rpc_client.py │ ├── rpc_server.py │ ├── wallet_rpc_api.py │ └── wallet_rpc_client.py ├── server │ ├── __init__.py │ ├── address_manager.py │ ├── address_manager_store.py │ ├── connection_utils.py │ ├── introducer_peers.py │ ├── node_discovery.py │ ├── outbound_message.py │ ├── rate_limits.py │ ├── reconnect_task.py │ ├── server.py │ ├── ssl_context.py │ ├── start_farmer.py │ ├── start_full_node.py │ ├── start_harvester.py │ ├── start_introducer.py │ ├── start_service.py │ ├── start_timelord.py │ ├── start_wallet.py │ ├── upnp.py │ └── ws_connection.py ├── simulator │ ├── __init__.py │ ├── full_node_simulator.py │ ├── simulator_constants.py │ ├── simulator_protocol.py │ └── start_simulator.py ├── ssl │ ├── avocado_ca.crt │ ├── avocado_ca.key │ ├── create_ssl.py │ └── dst_root_ca.pem ├── timelord │ ├── __init__.py │ ├── iters_from_block.py │ ├── timelord.py │ ├── timelord_api.py │ ├── timelord_launcher.py │ ├── timelord_state.py │ └── types.py ├── types │ ├── __init__.py │ ├── announcement.py │ ├── blockchain_format │ │ ├── __init__.py │ │ ├── classgroup.py │ │ ├── coin.py │ │ ├── foliage.py │ │ ├── pool_target.py │ │ ├── program.py │ │ ├── proof_of_space.py │ │ ├── reward_chain_block.py │ │ ├── sized_bytes.py │ │ ├── slots.py │ │ ├── sub_epoch_summary.py │ │ ├── tree_hash.py │ │ └── vdf.py │ ├── coin_record.py │ ├── coin_solution.py │ ├── condition_opcodes.py │ ├── condition_with_args.py │ ├── end_of_slot_bundle.py │ ├── full_block.py │ ├── generator_types.py │ ├── header_block.py │ ├── mempool_inclusion_status.py │ ├── mempool_item.py │ ├── name_puzzle_condition.py │ ├── peer_info.py │ ├── spend_bundle.py │ ├── unfinished_block.py │ ├── unfinished_header_block.py │ └── weight_proof.py ├── util │ ├── __init__.py │ ├── api_decorators.py │ ├── avocado_logging.py │ ├── bech32m.py │ ├── block_cache.py │ ├── byte_types.py │ ├── chain_utils.py │ ├── clvm.py │ ├── condition_tools.py │ ├── config.py │ ├── create_alert_file.py │ ├── db_wrapper.py │ ├── default_root.py │ ├── english.txt │ ├── errors.py │ ├── generator_tools.py │ ├── hash.py │ ├── initial-config.yaml │ ├── ints.py │ ├── json_util.py │ ├── keychain.py │ ├── lru_cache.py │ ├── make_test_constants.py │ ├── merkle_set.py │ ├── misc.py │ ├── network.py │ ├── partial_func.py │ ├── path.py │ ├── pip_import.py │ ├── prev_transaction_block.py │ ├── profiler.py │ ├── recursive_replace.py │ ├── safe_cancel_task.py │ ├── service_groups.py │ ├── setproctitle.py │ ├── significant_bits.py │ ├── streamable.py │ ├── struct_stream.py │ ├── type_checking.py │ ├── validate_alert.py │ ├── vdf_prover.py │ └── ws_message.py └── wallet │ ├── __init__.py │ ├── block_record.py │ ├── cc_wallet │ ├── __init__.py │ ├── cc_info.py │ ├── cc_utils.py │ └── cc_wallet.py │ ├── chialisp.py │ ├── derivation_record.py │ ├── derive_keys.py │ ├── did_wallet │ ├── __init__.py │ ├── did_info.py │ ├── did_wallet.py │ └── did_wallet_puzzles.py │ ├── key_val_store.py │ ├── lineage_proof.py │ ├── puzzles │ ├── __init__.py │ ├── block_program_zero.clvm │ ├── block_program_zero.clvm.hex │ ├── block_program_zero.clvm.hex.sha256tree │ ├── calculate_synthetic_public_key.clvm │ ├── calculate_synthetic_public_key.clvm.hex │ ├── calculate_synthetic_public_key.clvm.hex.sha256tree │ ├── cc.clvm │ ├── cc.clvm.hex │ ├── cc.clvm.hex.sha256tree │ ├── cc_loader.py │ ├── chialisp_deserialisation.clvm │ ├── chialisp_deserialisation.clvm.hex │ ├── chialisp_deserialisation.clvm.hex.sha256tree │ ├── condition_codes.clvm │ ├── create-lock-puzzlehash.clvm │ ├── create-lock-puzzlehash.clvm.hex.sha256tree │ ├── curry-and-treehash.clinc │ ├── decompress_coin_solution_entry.clvm │ ├── decompress_coin_solution_entry.clvm.hex │ ├── decompress_coin_solution_entry.clvm.hex.sha256tree │ ├── decompress_coin_solution_entry_with_prefix.clvm │ ├── decompress_coin_solution_entry_with_prefix.clvm.hex │ ├── decompress_coin_solution_entry_with_prefix.clvm.hex.sha256tree │ ├── decompress_puzzle.clvm │ ├── decompress_puzzle.clvm.hex │ ├── decompress_puzzle.clvm.hex.sha256tree │ ├── did_innerpuz.clvm │ ├── did_innerpuz.clvm.hex │ ├── did_innerpuz.clvm.hex.sha256tree │ ├── generator_for_single_coin.clvm │ ├── generator_for_single_coin.clvm.hex │ ├── generator_for_single_coin.clvm.hex.sha256tree │ ├── generator_loader.py │ ├── genesis-by-coin-id-with-0.clvm │ ├── genesis-by-coin-id-with-0.clvm.hex │ ├── genesis-by-coin-id-with-0.clvm.hex.sha256tree │ ├── genesis-by-puzzle-hash-with-0.clvm │ ├── genesis-by-puzzle-hash-with-0.clvm.hex │ ├── genesis-by-puzzle-hash-with-0.clvm.hex.sha256tree │ ├── genesis_by_coin_id_with_0.py │ ├── genesis_by_puzzle_hash_with_0.py │ ├── load_clvm.py │ ├── lock.inner.puzzle.clvm │ ├── lock.inner.puzzle.clvm.hex │ ├── lock.inner.puzzle.clvm.hex.sha256tree │ ├── p2_conditions.clvm │ ├── p2_conditions.clvm.hex │ ├── p2_conditions.clvm.hex.sha256tree │ ├── p2_conditions.py │ ├── p2_delegated_conditions.clvm │ ├── p2_delegated_conditions.clvm.hex │ ├── p2_delegated_conditions.clvm.hex.sha256tree │ ├── p2_delegated_conditions.py │ ├── p2_delegated_puzzle.clvm │ ├── p2_delegated_puzzle.clvm.hex │ ├── p2_delegated_puzzle.clvm.hex.sha256tree │ ├── p2_delegated_puzzle.py │ ├── p2_delegated_puzzle_or_hidden_puzzle.clvm │ ├── p2_delegated_puzzle_or_hidden_puzzle.clvm.hex │ ├── p2_delegated_puzzle_or_hidden_puzzle.clvm.hex.sha256tree │ ├── p2_delegated_puzzle_or_hidden_puzzle.py │ ├── p2_m_of_n_delegate_direct.clvm │ ├── p2_m_of_n_delegate_direct.clvm.hex │ ├── p2_m_of_n_delegate_direct.clvm.hex.sha256tree │ ├── p2_m_of_n_delegate_direct.py │ ├── p2_puzzle_hash.clvm │ ├── p2_puzzle_hash.clvm.hex │ ├── p2_puzzle_hash.clvm.hex.sha256tree │ ├── p2_puzzle_hash.py │ ├── p2_singleton.clvm │ ├── p2_singleton.clvm.hex │ ├── p2_singleton.clvm.hex.sha256tree │ ├── p2_singleton_or_delayed_puzhash.clvm │ ├── p2_singleton_or_delayed_puzhash.clvm.hex │ ├── p2_singleton_or_delayed_puzhash.clvm.hex.sha256tree │ ├── pool_member_innerpuz.clvm │ ├── pool_member_innerpuz.clvm.hex │ ├── pool_member_innerpuz.clvm.hex.sha256tree │ ├── pool_waitingroom_innerpuz.clvm │ ├── pool_waitingroom_innerpuz.clvm.hex │ ├── pool_waitingroom_innerpuz.clvm.hex.sha256tree │ ├── prefarm │ │ ├── make_prefarm_ph.py │ │ └── spend_prefarm.py │ ├── puzzle_utils.py │ ├── recompile-all.sh │ ├── rl.clvm │ ├── rl.clvm.hex │ ├── rl.clvm.hex.sha256tree │ ├── rl_aggregation.clvm │ ├── rl_aggregation.clvm.hex │ ├── rl_aggregation.clvm.hex.sha256tree │ ├── rom_bootstrap_generator.clvm │ ├── rom_bootstrap_generator.clvm.hex │ ├── rom_bootstrap_generator.clvm.hex.sha256tree │ ├── rom_bootstrap_generator.py │ ├── sha256tree_module.clvm │ ├── sha256tree_module.clvm.hex │ ├── sha256tree_module.clvm.hex.sha256tree │ ├── singleton_launcher.clvm │ ├── singleton_launcher.clvm.hex │ ├── singleton_launcher.clvm.hex.sha256tree │ ├── singleton_top_layer.clvm │ ├── singleton_top_layer.clvm.hex │ ├── singleton_top_layer.clvm.hex.sha256tree │ ├── singleton_top_layer.py │ ├── singleton_truths.clib │ ├── test_cc.py │ ├── test_generator_deserialize.clvm │ ├── test_generator_deserialize.clvm.hex │ ├── test_generator_deserialize.clvm.hex.sha256tree │ ├── test_multiple_generator_input_arguments.clvm │ ├── test_multiple_generator_input_arguments.clvm.hex │ └── test_multiple_generator_input_arguments.clvm.hex.sha256tree │ ├── rl_wallet │ ├── __init__.py │ ├── rl_wallet.py │ └── rl_wallet_puzzles.py │ ├── secret_key_store.py │ ├── settings │ ├── default_settings.py │ ├── settings_objects.py │ └── user_settings.py │ ├── sign_coin_solutions.py │ ├── trade_manager.py │ ├── trade_record.py │ ├── trading │ ├── __init__.py │ ├── trade_status.py │ └── trade_store.py │ ├── transaction_record.py │ ├── util │ ├── __init__.py │ ├── backup_utils.py │ ├── debug_spend_bundle.py │ ├── trade_utils.py │ ├── transaction_type.py │ └── wallet_types.py │ ├── wallet.py │ ├── wallet_action.py │ ├── wallet_action_store.py │ ├── wallet_block_store.py │ ├── wallet_blockchain.py │ ├── wallet_coin_record.py │ ├── wallet_coin_store.py │ ├── wallet_info.py │ ├── wallet_interested_store.py │ ├── wallet_node.py │ ├── wallet_node_api.py │ ├── wallet_pool_store.py │ ├── wallet_puzzle_store.py │ ├── wallet_state_manager.py │ ├── wallet_sync_store.py │ ├── wallet_transaction_store.py │ └── wallet_user_store.py ├── azure-pipelines.yml ├── build_scripts ├── build_linux_deb.sh ├── build_linux_rpm.sh ├── build_macos.sh ├── build_macos_m1.sh ├── build_windows.ps1 └── installer-version.py ├── install-gui.sh ├── install-timelord.sh ├── install.sh ├── mypy.ini ├── pyproject.toml ├── run-py-tests.sh ├── setup.py └── tests ├── README.md ├── __init__.py ├── avocado-start-sim ├── block_tools.py ├── blockchain ├── __init__.py ├── config.py ├── test_blockchain.py └── test_blockchain_transactions.py ├── build-workflows.py ├── check_pytest_monitor_output.py ├── chia-start-sim ├── clvm ├── __init__.py ├── coin_store.py ├── config.py ├── test_chialisp_deserialization.py ├── test_clvm_compilation.py ├── test_puzzles.py ├── test_serialized_program.py └── test_singletons.py ├── connection_utils.py ├── core ├── __init__.py ├── consensus │ ├── __init__.py │ └── test_pot_iterations.py ├── daemon │ └── test_daemon.py ├── fixtures.py ├── full_node │ ├── __init__.py │ ├── config.py │ ├── dos │ │ ├── __init__.py │ │ └── config.py │ ├── full_sync │ │ ├── __init__.py │ │ ├── config.py │ │ └── test_full_sync.py │ ├── ram_db.py │ ├── test_address_manager.py │ ├── test_block_store.py │ ├── test_coin_store.py │ ├── test_conditions.py │ ├── test_full_node.py │ ├── test_full_node_store.py │ ├── test_initial_freeze.py │ ├── test_mempool.py │ ├── test_mempool_performance.py │ ├── test_node_load.py │ ├── test_performance.py │ ├── test_sync_store.py │ └── test_transactions.py ├── make_block_generator.py ├── node_height.py ├── server │ ├── test_dos.py │ └── test_rate_limits.py ├── ssl │ └── test_ssl.py ├── test_cost_calculation.py ├── test_farmer_harvester_rpc.py ├── test_filter.py ├── test_full_node_rpc.py ├── test_merkle_set.py ├── test_setproctitle.py ├── types │ ├── __init__.py │ ├── test_coin.py │ └── test_proof_of_space.py └── util │ ├── __init__.py │ ├── test_keychain.py │ ├── test_lru_cache.py │ ├── test_significant_bits.py │ ├── test_streamable.py │ └── test_type_checking.py ├── generator ├── test_compression.py ├── test_generator_types.py ├── test_rom.py └── test_scan.py ├── pools ├── __init__.py ├── test_pool_config.py ├── test_pool_puzzles_lifecycle.py ├── test_pool_rpc.py ├── test_pool_wallet.py └── test_wallet_pool_store.py ├── pytest.ini ├── runner-templates ├── build-test-macos ├── build-test-ubuntu ├── checkout-test-plots.include.yml └── install-timelord.include.yml ├── setup_nodes.py ├── simulation ├── __init__.py ├── config.py └── test_simulation.py ├── testconfig.py ├── time_out_assert.py ├── util ├── __init__.py ├── alert_server.py ├── benchmark_cost.py ├── bip39_test_vectors.json ├── config.py ├── generator_tools_testing.py ├── key_tool.py ├── misc.py └── test_struct_stream.py ├── wallet ├── __init__.py ├── cc_wallet │ ├── __init__.py │ ├── test_cc_wallet.py │ └── test_trades.py ├── did_wallet │ └── test_did.py ├── rl_wallet │ ├── __init__.py │ ├── test_rl_rpc.py │ └── test_rl_wallet.py ├── rpc │ ├── __init__.py │ └── test_wallet_rpc.py ├── sync │ ├── __init__.py │ ├── config.py │ └── test_wallet_sync.py ├── test_backup.py ├── test_bech32m.py ├── test_chialisp.py ├── test_puzzle_store.py ├── test_singleton.py ├── test_singleton_lifecycle.py ├── test_singleton_lifecycle_fast.py ├── test_taproot.py ├── test_wallet.py ├── test_wallet_interested_store.py └── test_wallet_store.py ├── wallet_tools.py └── weight_proof └── test_weight_proof.py /.flake8: -------------------------------------------------------------------------------- 1 | .github/linters/.flake8 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. (If what you are experiencing is NOT a bug but instead a support issue, please open a Discussion instead!) 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 16 | 1. Go to '...' 17 | 2. Click on '....' 18 | 3. Scroll down to '....' 19 | 4. See error 20 | 21 | **Expected behavior** 22 | A clear and concise description of what you expected to happen. 23 | 24 | **Screenshots** 25 | If applicable, add screenshots to help explain your problem. 26 | 27 | **Desktop (please complete the following information):** 28 | 29 | - OS: [e.g. Linux] 30 | - OS Version/Flavor: [e.g. CentOS 7.2] 31 | - CPU: [e.g. Intel Xeon 8175M] 32 | 33 | **Additional context** 34 | Add any other context about the problem here. 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | contact_links: 2 | - about: Ask a question or request support here 3 | name: Ask for Support 4 | url: >- 5 | https://github.com/Chia-Network/chia-blockchain/discussions/new?category=support 6 | - about: Request a new feature or idea here 7 | name: Make a Request 8 | url: >- 9 | https://github.com/Chia-Network/chia-blockchain/discussions/new?category=ideas 10 | - about: Get support on the Chia Keybase chat channels. 11 | name: Join the Keybase.io support chat 12 | url: 'https://keybase.io/team/chia_network.public' 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Basic dependabot.yml file with 2 | # minimum configuration for two package managers 3 | 4 | version: 2 5 | updates: 6 | # Enable version updates for Python 7 | - package-ecosystem: "pip" 8 | # Look for a `Dockerfile` in the `root` directory 9 | directory: "/" 10 | # Check for updates once a week 11 | schedule: 12 | interval: "weekly" 13 | day: "tuesday" 14 | target-branch: "main" 15 | pull-request-branch-name: 16 | # Separate sections of the branch name with a hyphen 17 | # for example, `dependabot-npm_and_yarn-next_js-acorn-6.4.1` 18 | separator: "-" 19 | 20 | # Maintain dependencies for GitHub Actions 21 | - package-ecosystem: "github-actions" 22 | directory: "/" 23 | # Check for updates once a week 24 | schedule: 25 | interval: "weekly" 26 | day: "tuesday" 27 | target-branch: "main" 28 | pull-request-branch-name: 29 | # Separate sections of the branch name with a hyphen 30 | # for example, `dependabot-npm_and_yarn-next_js-acorn-6.4.1` 31 | separator: "-" 32 | -------------------------------------------------------------------------------- /.github/linters/.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 120 3 | exclude = ./typings/**/* 4 | ignore = E203,W503 5 | -------------------------------------------------------------------------------- /.github/linters/.isort.cfg: -------------------------------------------------------------------------------- 1 | [settings] 2 | profile= 3 | 4 | ; vertical hanging indent mode also used in black configuration 5 | multi_line_output = 3 6 | 7 | ; necessary because black expect the trailing comma 8 | include_trailing_comma = true 9 | 10 | ; black compatibility 11 | force_grid_wrap = 0 12 | 13 | ; black compatibility 14 | use_parentheses = True 15 | 16 | ; black compatibility 17 | ensure_newline_before_comments = True 18 | 19 | ; we chose 120 as line length 20 | line_length = 120 21 | -------------------------------------------------------------------------------- /.github/linters/.markdown-lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ########################### 3 | ########################### 4 | ## Markdown Linter rules ## 5 | ########################### 6 | ########################### 7 | 8 | # Linter rules doc: 9 | # - https://github.com/DavidAnson/markdownlint 10 | # 11 | # Note: 12 | # To comment out a single error: 13 | # 14 | # any violations you want 15 | # 16 | # 17 | 18 | ############### 19 | # Rules by id # 20 | ############### 21 | MD004: false # Unordered list style 22 | MD007: 23 | indent: 2 # Unordered list indentation 24 | MD013: 25 | line_length: 808 # Line length 26 | MD024: 27 | allow_different_nesting: true 28 | MD026: 29 | punctuation: ".,;:!。,;:" # List of not allowed 30 | MD029: false # Ordered list item prefix 31 | MD033: false # Allow inline HTML 32 | MD036: false # Emphasis used instead of a heading 33 | MD041: false # Allow file to start without h1 34 | 35 | ################# 36 | # Rules by tags # 37 | ################# 38 | blank_lines: false # Error on blank lines 39 | -------------------------------------------------------------------------------- /.github/linters/.python-black: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line_length = 120 3 | -------------------------------------------------------------------------------- /.github/workflows/start-release.yml: -------------------------------------------------------------------------------- 1 | # Starts a release for the given ref on the Glue API 2 | name: Start Release 3 | on: 4 | workflow_dispatch: 5 | push: 6 | tags: 7 | - '**' 8 | 9 | jobs: 10 | start_release: 11 | name: Starts release process in Glue API 12 | runs-on: [ARM64] 13 | steps: 14 | - name: Get tag name 15 | if: startsWith(github.ref, 'refs/tags/') 16 | id: tag-name 17 | run: | 18 | echo "::set-output name=TAG_NAME::$(echo ${{ github.ref }} | cut -d'/' -f 3)" 19 | echo "::set-output name=REPO_NAME::$(echo ${{ github.repository }} | cut -d'/' -f 2)" 20 | - name: Start release 21 | if: startsWith(github.ref, 'refs/tags/') 22 | run: | 23 | curl -s -XPOST -H "Authorization: Bearer ${{ secrets.GLUE_ACCESS_TOKEN }}" --data '{"chia_ref": "${{ steps.tag-name.outputs.TAG_NAME }}"}' ${{ secrets.GLUE_API_URL }}/api/v1/${{ steps.tag-name.outputs.REPO_NAME }}/${{ steps.tag-name.outputs.TAG_NAME }}/start 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | **/*.o 9 | **/*.DS_Store 10 | 11 | # Database 12 | nohup.out 13 | mongod.log* 14 | fndb_test* 15 | blockchain_test* 16 | *.db 17 | *.db-journal 18 | 19 | # Logs 20 | *.log 21 | *.out 22 | 23 | # Keys and plot files 24 | config/keys.yaml 25 | config/plots.yaml 26 | 27 | # Bundled code 28 | chia-blockchain.tar.gz.tar.gz 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | #*.spec 35 | build_scripts/*.dmg 36 | build_scripts/build 37 | 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | **/*.egg-info 43 | 44 | # Unit test / coverage reports 45 | .cache 46 | .pytest_cache/ 47 | 48 | # PoSpace plots 49 | **/*.dat 50 | **/*.dat.tmp 51 | *.mo 52 | *.pot 53 | 54 | # pyenv 55 | .python-version 56 | .eggs 57 | .venv 58 | venv 59 | activate 60 | 61 | # mypy 62 | .mypy_cache/ 63 | 64 | # Editors 65 | .vscode 66 | .idea 67 | 68 | # Packaging 69 | chia-blockchain.tar.gz 70 | 71 | # Timelord utilities 72 | vdf_bench 73 | 74 | # Node modules 75 | **/node_modules 76 | 77 | # Offer Files 78 | *.offer 79 | 80 | # Backup Files 81 | *.backup 82 | 83 | # Attest Files 84 | *.attest 85 | 86 | # Compiled CLVM 87 | main.sym 88 | *.recompiled 89 | 90 | # Dev config react 91 | # chia-blockchain-gui/src/dev_config.js 92 | # React built app 93 | chia-blockchain-gui/.eslintcache 94 | chia-blockchain-gui/build 95 | build_scripts/dist 96 | build_scripts/*.Dmg 97 | chia-blockchain-gui/src/locales/_build 98 | build_scripts\win_build 99 | build_scripts/win_build 100 | win_code_sign_cert.p12 101 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "avocado-blockchain-gui"] 2 | path = avocado-blockchain-gui 3 | url = https://github.com/Avocado-Network/avocado-blockchain-gui.git 4 | branch = main 5 | [submodule "mozilla-ca"] 6 | path = mozilla-ca 7 | url = https://github.com/Chia-Network/mozilla-ca.git 8 | branch = main 9 | -------------------------------------------------------------------------------- /.isort.cfg: -------------------------------------------------------------------------------- 1 | .github/linters/.isort.cfg -------------------------------------------------------------------------------- /.vs/ProjectSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "CurrentProjectSetting": null 3 | } -------------------------------------------------------------------------------- /.vs/VSWorkspaceState.json: -------------------------------------------------------------------------------- 1 | { 2 | "ExpandedNodes": [ 3 | "" 4 | ], 5 | "PreviewInSolutionExplorer": false 6 | } -------------------------------------------------------------------------------- /.vs/avocado-blockchain/v16/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/.vs/avocado-blockchain/v16/.suo -------------------------------------------------------------------------------- /.vs/slnx.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/.vs/slnx.sqlite -------------------------------------------------------------------------------- /BUILD_TIMELORD.md: -------------------------------------------------------------------------------- 1 | # Building timelords 2 | 3 | The Linux and MacOS chiavdf binary wheels currently exclude an executable 4 | required to run a [Timelord](https://github.com/Chia-Network/chia-blockchain/wiki/Timelords). 5 | If you want to run a Timelord on Linux or MacOS, you must install the wheel 6 | from source (which may require some additional development packages) while in 7 | the virtual environment. 8 | 9 | ```bash 10 | . ./activate 11 | 12 | chmod +x ./install-timelord.sh 13 | sh install-timelord.sh 14 | ``` 15 | 16 | If the compile fails, it's likely due to a missing dependency. The script 17 | [install-timelord.sh](https://github.com/Chia-Network/chia-blockchain/blob/main/install-timelord.sh) 18 | attempts to install required build dependencies for Linux and MacOS before 19 | invoking pip to build from the source python distribution of chiavdf. 20 | 21 | The `install-timelord.sh` install script leverages two environmental variables 22 | that the chiavdf wheels can use to specify how to build. The service that the 23 | Timelord uses to run the VDF and prove the Proof of Time is `vdf_client` and 24 | `vdf_bench` is a utility to get a sense of a given CPU's iterations per second. 25 | 26 | - To build vdf_client set the environment variable BUILD_VDF_CLIENT to "Y". 27 | `export BUILD_VDF_CLIENT=Y`. 28 | - Similarly, to build vdf_bench set the environment variable BUILD_VDF_BENCH 29 | to "Y". `export BUILD_VDF_BENCH=Y`. 30 | 31 | Building and running Timelords in Windows x86-64 is not yet supported. 32 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | Install instructions have been moved to the [INSTALL](https://github.com/Chia-Network/chia-blockchain/wiki/INSTALL) section of the repository [Wiki](https://github.com/Chia-Network/chia-blockchain/wiki). 4 | 5 | After installing, follow the remaining instructions in the 6 | [Quick Start Guide](https://github.com/Chia-Network/chia-blockchain/wiki/Quick-Start-Guide) 7 | to run the software. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Read Before Installing 2 | 3 | For those of you that participated in the testnet I thank you. You will need to completely remove the previous version of Avocado. Delete the .avocado folder and the avocado-blockchain folder. 4 | 5 | - Windows: c:\users\%username%\.avocado and c:\users\%username%\AppData\local\avocado-blockchain 6 | - Linux: Wherever you git cloned 7 | 8 | ## Updates 9 | 10 | - Difficulty has been brought down from testnet high. Hopefully a good compromise. 11 | - PNG/SVGs have been updated. I'd give them a C grade. Sorry not a graphic designer. 12 | - rpc_port: 6759 has been changed to rpc_port: 6749 due to conflix with flax - thank you alsipsclar from discord 13 | - Premine is 250,000 14 | 15 | ## Windows Installation 16 | 17 | - https://github.com/Avocado-Network/avocado-blockchain/releases/tag/Mainnet 18 | 19 | ## Linux Installation 20 | 21 | ```sh 22 | git clone https://github.com/avocado-network/avocado-blockchain 23 | cd avocado-blockchain 24 | sh install.sh 25 | . ./activate 26 | avocado init 27 | ``` 28 | ## Add Gui 29 | ```sh 30 | sh install-gui.sh 31 | cd avocado-blockchain-gui 32 | npm run electron & 33 | ``` 34 | ## Expectations 35 | 36 | Most likely the blockchain will be rocky in the beginning. I will have 3 fast timelords running at launch. Please be patient if we experience issues. Of course everyone that participates in Avocado wants it to be worth something but the reality is you could have 1000 AVO and it be worth the same as someone with 0 AVO. 37 | 38 | 39 | ## Why Premine? 40 | 41 | I have spent and will continue to spend many hours building Avocado, but time is not the only cost. I also have monthly server costs that go into running the chain. At launch there will be a total of 6 separate servers helping run the chain. I would also like to give back to those that helped with testnet and find fun ways to give back to the community as a whole. 42 | 43 | ## Nodes 44 | 45 | - avocadot1.avocadonetwork.net:6865 46 | - avocadot2.avocadonetwork.net:6865 47 | - avocadot3.avocadonetwork.net:6865 48 | 49 | -------------------------------------------------------------------------------- /avocado/__init__.py: -------------------------------------------------------------------------------- 1 | from pkg_resources import DistributionNotFound, get_distribution, resource_filename 2 | 3 | try: 4 | __version__ = get_distribution("avocado-blockchain").version 5 | except DistributionNotFound: 6 | # package is not installed 7 | __version__ = "unknown" 8 | 9 | PYINSTALLER_SPEC_PATH = resource_filename("avocado", "pyinstaller.spec") 10 | -------------------------------------------------------------------------------- /avocado/clvm/singleton.py: -------------------------------------------------------------------------------- 1 | from avocado.wallet.puzzles.load_clvm import load_clvm 2 | 3 | P2_SINGLETON_MOD = load_clvm("p2_singleton.clvm") 4 | SINGLETON_TOP_LAYER_MOD = load_clvm("singleton_top_layer.clvm") 5 | SINGLETON_LAUNCHER = load_clvm("singleton_launcher.clvm") 6 | -------------------------------------------------------------------------------- /avocado/cmds/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/cmds/__init__.py -------------------------------------------------------------------------------- /avocado/cmds/init.py: -------------------------------------------------------------------------------- 1 | import click 2 | 3 | 4 | @click.command("init", short_help="Create or migrate the configuration") 5 | @click.option( 6 | "--create-certs", 7 | "-c", 8 | default=None, 9 | help="Create new SSL certificates based on CA in [directory]", 10 | type=click.Path(), 11 | ) 12 | @click.pass_context 13 | def init_cmd(ctx: click.Context, create_certs: str): 14 | """ 15 | Create a new configuration or migrate from previous versions to current 16 | 17 | \b 18 | Follow these steps to create new certificates for a remote harvester: 19 | - Make a copy of your Farming Machine CA directory: ~/.avocado/[version]/config/ssl/ca 20 | - Shut down all avocado daemon processes with `avocado stop all -d` 21 | - Run `avocado init -c [directory]` on your remote harvester, 22 | where [directory] is the the copy of your Farming Machine CA directory 23 | - Get more details on remote harvester on Avocado wiki: 24 | https://github.com/Avocado-Network/avocado-blockchain/wiki/Farming-on-many-machines 25 | """ 26 | from pathlib import Path 27 | from .init_funcs import init 28 | 29 | init(Path(create_certs) if create_certs is not None else None, ctx.obj["root_path"]) 30 | 31 | 32 | if __name__ == "__main__": 33 | from .init_funcs import avocado_init 34 | from avocado.util.default_root import DEFAULT_ROOT_PATH 35 | 36 | avocado_init(DEFAULT_ROOT_PATH) 37 | -------------------------------------------------------------------------------- /avocado/cmds/netspace.py: -------------------------------------------------------------------------------- 1 | import click 2 | 3 | 4 | @click.command("netspace", short_help="Estimate total farmed space on the network") 5 | @click.option( 6 | "-p", 7 | "--rpc-port", 8 | help=( 9 | "Set the port where the Full Node is hosting the RPC interface. " 10 | "See the rpc_port under full_node in config.yaml. " 11 | "[default: 7544]" 12 | ), 13 | type=int, 14 | default=None, 15 | ) 16 | @click.option( 17 | "-d", 18 | "--delta-block-height", 19 | help=( 20 | "Compare a block X blocks older to estimate total network space. " 21 | "Defaults to 4608 blocks (~1 day) and Peak block as the starting block. " 22 | "Use --start BLOCK_HEIGHT to specify starting block. " 23 | "Use 192 blocks to estimate over the last hour." 24 | ), 25 | type=str, 26 | default="4608", 27 | ) 28 | @click.option( 29 | "-s", 30 | "--start", 31 | help="Newest block used to calculate estimated total network space. Defaults to Peak block.", 32 | type=str, 33 | default="", 34 | ) 35 | def netspace_cmd(rpc_port: int, delta_block_height: str, start: str) -> None: 36 | """ 37 | Calculates the estimated space on the network given two block header hashes. 38 | """ 39 | import asyncio 40 | from .netspace_funcs import netstorge_async 41 | 42 | asyncio.run(netstorge_async(rpc_port, delta_block_height, start)) 43 | -------------------------------------------------------------------------------- /avocado/cmds/start.py: -------------------------------------------------------------------------------- 1 | import click 2 | 3 | from avocado.util.service_groups import all_groups 4 | 5 | 6 | @click.command("start", short_help="Start service groups") 7 | @click.option("-r", "--restart", is_flag=True, type=bool, help="Restart running services") 8 | @click.argument("group", type=click.Choice(all_groups()), nargs=-1, required=True) 9 | @click.pass_context 10 | def start_cmd(ctx: click.Context, restart: bool, group: str) -> None: 11 | import asyncio 12 | from .start_funcs import async_start 13 | 14 | asyncio.get_event_loop().run_until_complete(async_start(ctx.obj["root_path"], group, restart)) 15 | -------------------------------------------------------------------------------- /avocado/cmds/stop.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from pathlib import Path 3 | 4 | import click 5 | 6 | from avocado.util.service_groups import all_groups, services_for_groups 7 | 8 | 9 | async def async_stop(root_path: Path, group: str, stop_daemon: bool) -> int: 10 | from avocado.daemon.client import connect_to_daemon_and_validate 11 | 12 | daemon = await connect_to_daemon_and_validate(root_path) 13 | if daemon is None: 14 | print("Couldn't connect to avocado daemon") 15 | return 1 16 | 17 | if stop_daemon: 18 | r = await daemon.exit() 19 | await daemon.close() 20 | print(f"daemon: {r}") 21 | return 0 22 | 23 | return_val = 0 24 | 25 | for service in services_for_groups(group): 26 | print(f"{service}: ", end="", flush=True) 27 | if not await daemon.is_running(service_name=service): 28 | print("Not running") 29 | elif await daemon.stop_service(service_name=service): 30 | print("Stopped") 31 | else: 32 | print("Stop failed") 33 | return_val = 1 34 | 35 | await daemon.close() 36 | return return_val 37 | 38 | 39 | @click.command("stop", short_help="Stop services") 40 | @click.option("-d", "--daemon", is_flag=True, type=bool, help="Stop daemon") 41 | @click.argument("group", type=click.Choice(all_groups()), nargs=-1, required=True) 42 | @click.pass_context 43 | def stop_cmd(ctx: click.Context, daemon: bool, group: str) -> None: 44 | import asyncio 45 | 46 | sys.exit(asyncio.get_event_loop().run_until_complete(async_stop(ctx.obj["root_path"], group, daemon))) 47 | -------------------------------------------------------------------------------- /avocado/cmds/units.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | # The rest of the codebase uses slices everywhere. 4 | # Only use these units for user facing interfaces. 5 | units: Dict[str, int] = { 6 | "avocado": 10 ** 12, # 1 avocado (AVO) is 1,000,000,000,000 slice (1 trillion) 7 | "slice:": 1, 8 | "colouredcoin": 10 ** 3, # 1 coloured coin is 1000 colouredcoin slices 9 | } 10 | -------------------------------------------------------------------------------- /avocado/consensus/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/consensus/__init__.py -------------------------------------------------------------------------------- /avocado/consensus/block_root_validation.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List, Optional 2 | 3 | from avocado.types.blockchain_format.coin import Coin, hash_coin_list 4 | from avocado.types.blockchain_format.sized_bytes import bytes32 5 | from avocado.util.errors import Err 6 | from avocado.util.merkle_set import MerkleSet 7 | 8 | 9 | def validate_block_merkle_roots( 10 | block_additions_root: bytes32, 11 | block_removals_root: bytes32, 12 | tx_additions: List[Coin] = None, 13 | tx_removals: List[bytes32] = None, 14 | ) -> Optional[Err]: 15 | if tx_removals is None: 16 | tx_removals = [] 17 | if tx_additions is None: 18 | tx_additions = [] 19 | removal_merkle_set = MerkleSet() 20 | addition_merkle_set = MerkleSet() 21 | 22 | # Create removal Merkle set 23 | for coin_name in tx_removals: 24 | removal_merkle_set.add_already_hashed(coin_name) 25 | 26 | # Create addition Merkle set 27 | puzzlehash_coins_map: Dict[bytes32, List[Coin]] = {} 28 | 29 | for coin in tx_additions: 30 | if coin.puzzle_hash in puzzlehash_coins_map: 31 | puzzlehash_coins_map[coin.puzzle_hash].append(coin) 32 | else: 33 | puzzlehash_coins_map[coin.puzzle_hash] = [coin] 34 | 35 | # Addition Merkle set contains puzzlehash and hash of all coins with that puzzlehash 36 | for puzzle, coins in puzzlehash_coins_map.items(): 37 | addition_merkle_set.add_already_hashed(puzzle) 38 | addition_merkle_set.add_already_hashed(hash_coin_list(coins)) 39 | 40 | additions_root = addition_merkle_set.get_root() 41 | removals_root = removal_merkle_set.get_root() 42 | 43 | if block_additions_root != additions_root: 44 | return Err.BAD_ADDITION_ROOT 45 | if block_removals_root != removals_root: 46 | return Err.BAD_REMOVAL_ROOT 47 | 48 | return None 49 | -------------------------------------------------------------------------------- /avocado/consensus/coinbase.py: -------------------------------------------------------------------------------- 1 | from blspy import G1Element 2 | 3 | from avocado.types.blockchain_format.coin import Coin 4 | from avocado.types.blockchain_format.sized_bytes import bytes32 5 | from avocado.util.ints import uint32, uint64 6 | from avocado.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import puzzle_for_pk 7 | 8 | 9 | def create_puzzlehash_for_pk(pub_key: G1Element) -> bytes32: 10 | return puzzle_for_pk(pub_key).get_tree_hash() 11 | 12 | 13 | def pool_parent_id(block_height: uint32, genesis_challenge: bytes32) -> bytes32: 14 | return bytes32(genesis_challenge[:16] + block_height.to_bytes(16, "big")) 15 | 16 | 17 | def farmer_parent_id(block_height: uint32, genesis_challenge: bytes32) -> uint32: 18 | return bytes32(genesis_challenge[16:] + block_height.to_bytes(16, "big")) 19 | 20 | 21 | def create_pool_coin(block_height: uint32, puzzle_hash: bytes32, reward: uint64, genesis_challenge: bytes32): 22 | parent_id = pool_parent_id(block_height, genesis_challenge) 23 | return Coin(parent_id, puzzle_hash, reward) 24 | 25 | 26 | def create_farmer_coin(block_height: uint32, puzzle_hash: bytes32, reward: uint64, genesis_challenge: bytes32): 27 | parent_id = farmer_parent_id(block_height, genesis_challenge) 28 | return Coin(parent_id, puzzle_hash, reward) 29 | -------------------------------------------------------------------------------- /avocado/consensus/condition_costs.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class ConditionCost(Enum): 5 | # Condition Costs 6 | AGG_SIG = 1200000 # the cost of one G1 subgroup check + aggregated signature validation 7 | CREATE_COIN = 1800000 8 | ASSERT_MY_COIN_ID = 0 9 | ASSERT_MY_PARENT_ID = 0 10 | ASSERT_MY_PUZZLEHASH = 0 11 | ASSERT_MY_AMOUNT = 0 12 | ASSERT_SECONDS_RELATIVE = 0 13 | ASSERT_SECONDS_ABSOLUTE = 0 14 | ASSERT_HEIGHT_RELATIVE = 0 15 | ASSERT_HEIGHT_ABSOLUTE = 0 16 | RESERVE_FEE = 0 17 | CREATE_COIN_ANNOUNCEMENT = 0 18 | ASSERT_COIN_ANNOUNCEMENT = 0 19 | CREATE_PUZZLE_ANNOUNCEMENT = 0 20 | ASSERT_PUZZLE_ANNOUNCEMENT = 0 21 | -------------------------------------------------------------------------------- /avocado/consensus/find_fork_point.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from avocado.consensus.block_record import BlockRecord 4 | from avocado.consensus.blockchain_interface import BlockchainInterface 5 | from avocado.types.header_block import HeaderBlock 6 | 7 | 8 | def find_fork_point_in_chain( 9 | blocks: BlockchainInterface, 10 | block_1: Union[BlockRecord, HeaderBlock], 11 | block_2: Union[BlockRecord, HeaderBlock], 12 | ) -> int: 13 | """Tries to find height where new chain (block_2) diverged from block_1 (assuming prev blocks 14 | are all included in chain) 15 | Returns -1 if chains have no common ancestor 16 | * assumes the fork point is loaded in blocks 17 | """ 18 | while block_2.height > 0 or block_1.height > 0: 19 | if block_2.height > block_1.height: 20 | block_2 = blocks.block_record(block_2.prev_hash) 21 | elif block_1.height > block_2.height: 22 | block_1 = blocks.block_record(block_1.prev_hash) 23 | else: 24 | if block_2.header_hash == block_1.header_hash: 25 | return block_2.height 26 | block_2 = blocks.block_record(block_2.prev_hash) 27 | block_1 = blocks.block_record(block_1.prev_hash) 28 | if block_2 != block_1: 29 | # All blocks are different 30 | return -1 31 | 32 | # First block is the same 33 | return 0 34 | -------------------------------------------------------------------------------- /avocado/consensus/network_type.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class NetworkType(IntEnum): 5 | MAINNET = 0 6 | TESTNET = 1 7 | -------------------------------------------------------------------------------- /avocado/consensus/pos_quality.py: -------------------------------------------------------------------------------- 1 | from avocado.util.ints import uint64 2 | 3 | # The actual space in bytes of a plot, is _expected_plot_size(k) * UI_ACTUAL_SPACE_CONSTANT_FACTO 4 | # This is not used in consensus, only for display purposes 5 | UI_ACTUAL_SPACE_CONSTANT_FACTOR = 0.762 6 | 7 | 8 | def _expected_plot_size(k: int) -> uint64: 9 | """ 10 | Given the plot size parameter k (which is between 32 and 59), computes the 11 | expected size of the plot in bytes (times a constant factor). This is based on efficient encoding 12 | of the plot, and aims to be scale agnostic, so larger plots don't 13 | necessarily get more rewards per byte. The +1 is added to give half a bit more space per entry, which 14 | is necessary to store the entries in the plot. 15 | """ 16 | 17 | return ((2 * k) + 1) * (2 ** (k - 1)) 18 | -------------------------------------------------------------------------------- /avocado/daemon/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/daemon/__init__.py -------------------------------------------------------------------------------- /avocado/daemon/windows_signal.py: -------------------------------------------------------------------------------- 1 | """ 2 | Code taken from Stack Overflow Eryk Sun. 3 | https://stackoverflow.com/questions/35772001/how-to-handle-the-signal-in-python-on-windows-machine 4 | """ 5 | 6 | import os 7 | import signal 8 | import sys 9 | 10 | if sys.platform != "win32" and sys.platform != "cygwin": 11 | kill = os.kill 12 | else: 13 | # adapt the conflated API on Windows. 14 | import threading 15 | 16 | sigmap = { 17 | signal.SIGINT: signal.CTRL_C_EVENT, # pylint: disable=E1101 18 | signal.SIGBREAK: signal.CTRL_BREAK_EVENT, # pylint: disable=E1101 19 | } 20 | 21 | def kill(pid, signum): 22 | if signum in sigmap and pid == os.getpid(): 23 | # we don't know if the current process is a 24 | # process group leader, so just broadcast 25 | # to all processes attached to this console. 26 | pid = 0 27 | thread = threading.current_thread() 28 | handler = signal.getsignal(signum) 29 | # work around the synchronization problem when calling 30 | # kill from the main thread. 31 | if signum in sigmap and thread.name == "MainThread" and callable(handler) and pid == 0: 32 | event = threading.Event() 33 | 34 | def handler_set_event(signum, frame): 35 | event.set() 36 | return handler(signum, frame) 37 | 38 | signal.signal(signum, handler_set_event) 39 | try: 40 | os.kill(pid, sigmap[signum]) 41 | # busy wait because we can't block in the main 42 | # thread, else the signal handler can't execute. 43 | while not event.is_set(): 44 | pass 45 | finally: 46 | signal.signal(signum, handler) 47 | else: 48 | os.kill(pid, sigmap.get(signum, signum)) 49 | -------------------------------------------------------------------------------- /avocado/farmer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/farmer/__init__.py -------------------------------------------------------------------------------- /avocado/full_node/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/full_node/__init__.py -------------------------------------------------------------------------------- /avocado/full_node/signage_point.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from avocado.types.blockchain_format.vdf import VDFInfo, VDFProof 5 | from avocado.util.streamable import Streamable, streamable 6 | 7 | 8 | @dataclass(frozen=True) 9 | @streamable 10 | class SignagePoint(Streamable): 11 | cc_vdf: Optional[VDFInfo] 12 | cc_proof: Optional[VDFProof] 13 | rc_vdf: Optional[VDFInfo] 14 | rc_proof: Optional[VDFProof] 15 | -------------------------------------------------------------------------------- /avocado/harvester/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/harvester/__init__.py -------------------------------------------------------------------------------- /avocado/introducer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/introducer/__init__.py -------------------------------------------------------------------------------- /avocado/introducer/introducer_api.py: -------------------------------------------------------------------------------- 1 | from typing import Callable, Optional 2 | 3 | from avocado.introducer.introducer import Introducer 4 | from avocado.protocols.introducer_protocol import RequestPeersIntroducer, RespondPeersIntroducer 5 | from avocado.protocols.protocol_message_types import ProtocolMessageTypes 6 | from avocado.server.outbound_message import Message, make_msg 7 | from avocado.server.ws_connection import WSAvocadoConnection 8 | from avocado.types.peer_info import TimestampedPeerInfo 9 | from avocado.util.api_decorators import api_request, peer_required 10 | from avocado.util.ints import uint64 11 | 12 | 13 | class IntroducerAPI: 14 | introducer: Introducer 15 | 16 | def __init__(self, introducer) -> None: 17 | self.introducer = introducer 18 | 19 | def _set_state_changed_callback(self, callback: Callable): 20 | pass 21 | 22 | @peer_required 23 | @api_request 24 | async def request_peers_introducer( 25 | self, 26 | request: RequestPeersIntroducer, 27 | peer: WSAvocadoConnection, 28 | ) -> Optional[Message]: 29 | max_peers = self.introducer.max_peers_to_send 30 | if self.introducer.server is None or self.introducer.server.introducer_peers is None: 31 | return None 32 | rawpeers = self.introducer.server.introducer_peers.get_peers( 33 | max_peers * 5, True, self.introducer.recent_peer_threshold 34 | ) 35 | 36 | peers = [] 37 | for r_peer in rawpeers: 38 | if r_peer.vetted <= 0: 39 | continue 40 | 41 | if r_peer.host == peer.peer_host and r_peer.port == peer.peer_server_port: 42 | continue 43 | peer_without_timestamp = TimestampedPeerInfo( 44 | r_peer.host, 45 | r_peer.port, 46 | uint64(0), 47 | ) 48 | peers.append(peer_without_timestamp) 49 | 50 | if len(peers) >= max_peers: 51 | break 52 | 53 | self.introducer.log.info(f"Sending vetted {peers}") 54 | 55 | msg = make_msg(ProtocolMessageTypes.respond_peers_introducer, RespondPeersIntroducer(peers)) 56 | return msg 57 | -------------------------------------------------------------------------------- /avocado/pools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/pools/__init__.py -------------------------------------------------------------------------------- /avocado/protocols/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/protocols/__init__.py -------------------------------------------------------------------------------- /avocado/protocols/farmer_protocol.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from blspy import G2Element 5 | 6 | from avocado.types.blockchain_format.pool_target import PoolTarget 7 | from avocado.types.blockchain_format.proof_of_space import ProofOfSpace 8 | from avocado.types.blockchain_format.sized_bytes import bytes32 9 | from avocado.util.ints import uint8, uint32, uint64 10 | from avocado.util.streamable import Streamable, streamable 11 | 12 | """ 13 | Protocol between farmer and full node. 14 | Note: When changing this file, also change protocol_message_types.py, and the protocol version in shared_protocol.py 15 | """ 16 | 17 | 18 | @dataclass(frozen=True) 19 | @streamable 20 | class NewSignagePoint(Streamable): 21 | challenge_hash: bytes32 22 | challenge_chain_sp: bytes32 23 | reward_chain_sp: bytes32 24 | difficulty: uint64 25 | sub_slot_iters: uint64 26 | signage_point_index: uint8 27 | 28 | 29 | @dataclass(frozen=True) 30 | @streamable 31 | class DeclareProofOfSpace(Streamable): 32 | challenge_hash: bytes32 33 | challenge_chain_sp: bytes32 34 | signage_point_index: uint8 35 | reward_chain_sp: bytes32 36 | proof_of_space: ProofOfSpace 37 | challenge_chain_sp_signature: G2Element 38 | reward_chain_sp_signature: G2Element 39 | farmer_puzzle_hash: bytes32 40 | pool_target: Optional[PoolTarget] 41 | pool_signature: Optional[G2Element] 42 | 43 | 44 | @dataclass(frozen=True) 45 | @streamable 46 | class RequestSignedValues(Streamable): 47 | quality_string: bytes32 48 | foliage_block_data_hash: bytes32 49 | foliage_transaction_block_hash: bytes32 50 | 51 | 52 | @dataclass(frozen=True) 53 | @streamable 54 | class FarmingInfo(Streamable): 55 | challenge_hash: bytes32 56 | sp_hash: bytes32 57 | timestamp: uint64 58 | passed: uint32 59 | proofs: uint32 60 | total_plots: uint32 61 | 62 | 63 | @dataclass(frozen=True) 64 | @streamable 65 | class SignedValues(Streamable): 66 | quality_string: bytes32 67 | foliage_block_data_signature: G2Element 68 | foliage_transaction_block_signature: G2Element 69 | -------------------------------------------------------------------------------- /avocado/protocols/introducer_protocol.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | 4 | from avocado.types.peer_info import TimestampedPeerInfo 5 | from avocado.util.streamable import Streamable, streamable 6 | 7 | """ 8 | Protocol to introducer 9 | Note: When changing this file, also change protocol_message_types.py, and the protocol version in shared_protocol.py 10 | """ 11 | 12 | 13 | @dataclass(frozen=True) 14 | @streamable 15 | class RequestPeersIntroducer(Streamable): 16 | """ 17 | Return full list of peers 18 | """ 19 | 20 | 21 | @dataclass(frozen=True) 22 | @streamable 23 | class RespondPeersIntroducer(Streamable): 24 | peer_list: List[TimestampedPeerInfo] 25 | -------------------------------------------------------------------------------- /avocado/protocols/shared_protocol.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from enum import IntEnum 3 | from typing import List, Tuple 4 | 5 | from avocado.util.ints import uint8, uint16 6 | from avocado.util.streamable import Streamable, streamable 7 | 8 | protocol_version = "0.0.32" 9 | 10 | """ 11 | Handshake when establishing a connection between two servers. 12 | Note: When changing this file, also change protocol_message_types.py 13 | """ 14 | 15 | 16 | # Capabilities can be added here when new features are added to the protocol 17 | # These are passed in as uint16 into the Handshake 18 | class Capability(IntEnum): 19 | BASE = 1 # Base capability just means it supports the avocado protocol at mainnet 20 | 21 | 22 | @dataclass(frozen=True) 23 | @streamable 24 | class Handshake(Streamable): 25 | network_id: str 26 | protocol_version: str 27 | software_version: str 28 | server_port: uint16 29 | node_type: uint8 30 | capabilities: List[Tuple[uint16, str]] 31 | -------------------------------------------------------------------------------- /avocado/rpc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/rpc/__init__.py -------------------------------------------------------------------------------- /avocado/rpc/harvester_rpc_client.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, List 2 | 3 | from avocado.rpc.rpc_client import RpcClient 4 | 5 | 6 | class HarvesterRpcClient(RpcClient): 7 | """ 8 | Client to Avocado RPC, connects to a local harvester. Uses HTTP/JSON, and converts back from 9 | JSON into native python objects before returning. All api calls use POST requests. 10 | Note that this is not the same as the peer protocol, or wallet protocol (which run Avocado's 11 | protocol on top of TCP), it's a separate protocol on top of HTTP thats provides easy access 12 | to the full node. 13 | """ 14 | 15 | async def get_plots(self) -> Dict[str, Any]: 16 | return await self.fetch("get_plots", {}) 17 | 18 | async def refresh_plots(self) -> None: 19 | await self.fetch("refresh_plots", {}) 20 | 21 | async def delete_plot(self, filename: str) -> bool: 22 | return await self.fetch("delete_plot", {"filename": filename}) 23 | 24 | async def add_plot_directory(self, dirname: str) -> bool: 25 | return (await self.fetch("add_plot_directory", {"dirname": dirname}))["success"] 26 | 27 | async def get_plot_directories(self) -> List[str]: 28 | return (await self.fetch("get_plot_directories", {}))["directories"] 29 | 30 | async def remove_plot_directory(self, dirname: str) -> bool: 31 | return (await self.fetch("remove_plot_directory", {"dirname": dirname}))["success"] 32 | -------------------------------------------------------------------------------- /avocado/server/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/server/__init__.py -------------------------------------------------------------------------------- /avocado/server/outbound_message.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from enum import IntEnum 3 | from typing import Any, Optional 4 | 5 | from avocado.protocols.protocol_message_types import ProtocolMessageTypes 6 | from avocado.util.ints import uint8, uint16 7 | from avocado.util.streamable import Streamable, streamable 8 | 9 | 10 | class NodeType(IntEnum): 11 | FULL_NODE = 1 12 | HARVESTER = 2 13 | FARMER = 3 14 | TIMELORD = 4 15 | INTRODUCER = 5 16 | WALLET = 6 17 | 18 | 19 | class Delivery(IntEnum): 20 | # A message is sent to the same peer that we received a message from 21 | RESPOND = 1 22 | # A message is sent to all peers 23 | BROADCAST = 2 24 | # A message is sent to all peers except the one from which we received the API call 25 | BROADCAST_TO_OTHERS = 3 26 | # A message is sent to a random peer 27 | RANDOM = 4 28 | # Pseudo-message to close the current connection 29 | CLOSE = 5 30 | # A message is sent to a speicific peer 31 | SPECIFIC = 6 32 | 33 | 34 | @dataclass(frozen=True) 35 | @streamable 36 | class Message(Streamable): 37 | type: uint8 # one of ProtocolMessageTypes 38 | # message id 39 | id: Optional[uint16] 40 | # Message data for that type 41 | data: bytes 42 | 43 | 44 | def make_msg(msg_type: ProtocolMessageTypes, data: Any) -> Message: 45 | return Message(uint8(msg_type.value), None, bytes(data)) 46 | -------------------------------------------------------------------------------- /avocado/server/reconnect_task.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import socket 3 | 4 | from avocado.server.server import AvocadoServer 5 | from avocado.types.peer_info import PeerInfo 6 | 7 | 8 | def start_reconnect_task(server: AvocadoServer, peer_info_arg: PeerInfo, log, auth: bool): 9 | """ 10 | Start a background task that checks connection and reconnects periodically to a peer. 11 | """ 12 | peer_info = PeerInfo(socket.gethostbyname(peer_info_arg.host), peer_info_arg.port) 13 | 14 | async def connection_check(): 15 | while True: 16 | peer_retry = True 17 | for _, connection in server.all_connections.items(): 18 | if connection.get_peer_info() == peer_info or connection.get_peer_info() == peer_info_arg: 19 | peer_retry = False 20 | if peer_retry: 21 | log.info(f"Reconnecting to peer {peer_info}") 22 | try: 23 | await server.start_client(peer_info, None, auth=auth) 24 | except Exception as e: 25 | log.info(f"Failed to connect to {peer_info} {e}") 26 | await asyncio.sleep(3) 27 | 28 | return asyncio.create_task(connection_check()) 29 | -------------------------------------------------------------------------------- /avocado/server/ssl_context.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from typing import Dict 3 | 4 | 5 | def public_ssl_paths(path: Path, config: Dict): 6 | return ( 7 | path / config["ssl"]["public_crt"], 8 | path / config["ssl"]["public_key"], 9 | ) 10 | 11 | 12 | def private_ssl_paths(path: Path, config: Dict): 13 | return ( 14 | path / config["ssl"]["private_crt"], 15 | path / config["ssl"]["private_key"], 16 | ) 17 | 18 | 19 | def private_ssl_ca_paths(path: Path, config: Dict): 20 | return ( 21 | path / config["private_ssl_ca"]["crt"], 22 | path / config["private_ssl_ca"]["key"], 23 | ) 24 | 25 | 26 | def avocado_ssl_ca_paths(path: Path, config: Dict): 27 | return ( 28 | path / config["avocado_ssl_ca"]["crt"], 29 | path / config["avocado_ssl_ca"]["key"], 30 | ) 31 | -------------------------------------------------------------------------------- /avocado/server/start_introducer.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | from typing import Dict 3 | 4 | from avocado.introducer.introducer import Introducer 5 | from avocado.introducer.introducer_api import IntroducerAPI 6 | from avocado.server.outbound_message import NodeType 7 | from avocado.server.start_service import run_service 8 | from avocado.util.config import load_config_cli 9 | from avocado.util.default_root import DEFAULT_ROOT_PATH 10 | 11 | # See: https://bugs.python.org/issue29288 12 | "".encode("idna") 13 | 14 | SERVICE_NAME = "introducer" 15 | 16 | 17 | def service_kwargs_for_introducer( 18 | root_path: pathlib.Path, 19 | config: Dict, 20 | ) -> Dict: 21 | introducer = Introducer(config["max_peers_to_send"], config["recent_peer_threshold"]) 22 | node__api = IntroducerAPI(introducer) 23 | network_id = config["selected_network"] 24 | kwargs = dict( 25 | root_path=root_path, 26 | node=introducer, 27 | peer_api=node__api, 28 | node_type=NodeType.INTRODUCER, 29 | advertised_port=config["port"], 30 | service_name=SERVICE_NAME, 31 | server_listen_ports=[config["port"]], 32 | network_id=network_id, 33 | ) 34 | return kwargs 35 | 36 | 37 | def main() -> None: 38 | config = load_config_cli(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME) 39 | kwargs = service_kwargs_for_introducer(DEFAULT_ROOT_PATH, config) 40 | return run_service(**kwargs) 41 | 42 | 43 | if __name__ == "__main__": 44 | main() 45 | -------------------------------------------------------------------------------- /avocado/server/start_timelord.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import pathlib 3 | from typing import Dict 4 | 5 | from avocado.consensus.constants import ConsensusConstants 6 | from avocado.consensus.default_constants import DEFAULT_CONSTANTS 7 | from avocado.server.outbound_message import NodeType 8 | from avocado.server.start_service import run_service 9 | from avocado.timelord.timelord import Timelord 10 | from avocado.timelord.timelord_api import TimelordAPI 11 | from avocado.types.peer_info import PeerInfo 12 | from avocado.util.config import load_config_cli 13 | from avocado.util.default_root import DEFAULT_ROOT_PATH 14 | 15 | # See: https://bugs.python.org/issue29288 16 | "".encode("idna") 17 | 18 | SERVICE_NAME = "timelord" 19 | 20 | 21 | log = logging.getLogger(__name__) 22 | 23 | 24 | def service_kwargs_for_timelord( 25 | root_path: pathlib.Path, 26 | config: Dict, 27 | constants: ConsensusConstants, 28 | ) -> Dict: 29 | 30 | connect_peers = [PeerInfo(config["full_node_peer"]["host"], config["full_node_peer"]["port"])] 31 | overrides = config["network_overrides"]["constants"][config["selected_network"]] 32 | updated_constants = constants.replace_str_to_bytes(**overrides) 33 | 34 | node = Timelord(root_path, config, updated_constants) 35 | peer_api = TimelordAPI(node) 36 | network_id = config["selected_network"] 37 | kwargs = dict( 38 | root_path=root_path, 39 | peer_api=peer_api, 40 | node=node, 41 | node_type=NodeType.TIMELORD, 42 | advertised_port=config["port"], 43 | service_name=SERVICE_NAME, 44 | server_listen_ports=[config["port"]], 45 | connect_peers=connect_peers, 46 | auth_connect_peers=False, 47 | network_id=network_id, 48 | ) 49 | return kwargs 50 | 51 | 52 | def main() -> None: 53 | config = load_config_cli(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME) 54 | kwargs = service_kwargs_for_timelord(DEFAULT_ROOT_PATH, config, DEFAULT_CONSTANTS) 55 | return run_service(**kwargs) 56 | 57 | 58 | if __name__ == "__main__": 59 | main() 60 | -------------------------------------------------------------------------------- /avocado/simulator/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/simulator/__init__.py -------------------------------------------------------------------------------- /avocado/simulator/simulator_constants.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | from tests.block_tools import BlockTools, test_constants 3 | from avocado.util.default_root import DEFAULT_ROOT_PATH 4 | 5 | # TODO: mariano: fix this with new consensus 6 | bt = BlockTools(root_path=DEFAULT_ROOT_PATH) 7 | new_genesis_block = bt.create_genesis_block(test_constants, b"0") 8 | 9 | print(bytes(new_genesis_block)) 10 | -------------------------------------------------------------------------------- /avocado/simulator/simulator_protocol.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from avocado.types.blockchain_format.sized_bytes import bytes32 4 | from avocado.util.ints import uint32 5 | from avocado.util.streamable import Streamable, streamable 6 | 7 | 8 | @dataclass(frozen=True) 9 | @streamable 10 | class FarmNewBlockProtocol(Streamable): 11 | puzzle_hash: bytes32 12 | 13 | 14 | @dataclass(frozen=True) 15 | @streamable 16 | class ReorgProtocol(Streamable): 17 | old_index: uint32 18 | new_index: uint32 19 | puzzle_hash: bytes32 20 | -------------------------------------------------------------------------------- /avocado/ssl/avocado_ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFsTCCA5mgAwIBAgIUWI7gKjOcmhZyGU/LEZlDVv7isCEwDQYJKoZIhvcNAQEL 3 | BQAwaDELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0Zsb3JpZGExEDAOBgNVBAcMB09y 4 | bGFuZG8xGDAWBgNVBAoMD0F2b2NhZG8gTmV0d29yazEbMBkGA1UEAwwSYXZvY2Fk 5 | b25ldHdvcmsubmV0MB4XDTIxMDcwNTIzNTIxNFoXDTMxMDcwMzIzNTIxNFowaDEL 6 | MAkGA1UEBhMCVVMxEDAOBgNVBAgMB0Zsb3JpZGExEDAOBgNVBAcMB09ybGFuZG8x 7 | GDAWBgNVBAoMD0F2b2NhZG8gTmV0d29yazEbMBkGA1UEAwwSYXZvY2Fkb25ldHdv 8 | cmsubmV0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtv8Hfgo8P0ZM 9 | gVs3L8Iom6X/yZydMcQU/JMlRS/kcO5sYamqEl057E0KSlyNuCX9tQJKoD2DwyQB 10 | z24fNLxpOjyY1clJOImUiIVjQayuH/I1qm1b22jZa3szZfv1FlIhRJVqgHNHdQ+8 11 | FxgARSBp5OsBqTv20OeHCNJCUDHmB/QDnZR+Jk6G4hqURuoFVkRwjAoDCWbrB9DZ 12 | WoAjo3ChXYPNUSY2AsRderhqLDLMkyLs+bC2vF5xd+v7i2S2hfd9wrz2fW/Oqok7 13 | 0NsFDYuugxtgSO2U9oJ7G6eFLkGQ5JGJhyufG2ICcp3SGj5RONf0b4ZaT3wqiWTN 14 | GQCIUL1I+bZ6smViD8XPpsgPQUh4DyWKW/AZPUjIXC+h1UFA5TckUYozpf7bCPfh 15 | a7YMjsPY/0rx0nX5AkoqmvKTkHrHkS+WX08KwpoWmKrxlOcnm5JLJT5JzMgftNIw 16 | 1m/320IJjBt0AiEPI9Ry1qjtvGHjY4cqyM1nn3a+eOlcJAOQtS5zuQQnT5Nh+68B 17 | IC2GGhOBvq5FocmEYnncqmskaiX+W6MhIjvi0dd8m4VkC0gYBlEQr3TWBlzC9O21 18 | iuzCZi05pV1aHs3f/sIFx7P5T4+1kK5DTjBkH6ZdsOLdpVbaG5eaSwqhe593VHAV 19 | 9cllH/pmVe+HLaCxCH6z25hGgRdBK3kCAwEAAaNTMFEwHQYDVR0OBBYEFGQ7DRJ6 20 | FMjt+GkcO9XXBiYekrHhMB8GA1UdIwQYMBaAFGQ7DRJ6FMjt+GkcO9XXBiYekrHh 21 | MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAIOkJD84hC1+2uGZ 22 | EUpQNyI+1qYF1RFmaXv9iYOKy3ZPz4BPomdA3X+lVh91pGef82voLjkZXAak1aLa 23 | 4je/I6BNVjEbRyfRgnr8H4gkVoHo6CmFVB0wyYEfRkupnTowZ4U4cpfNAaYODxQ8 24 | bk6O0xNq51OopjJfr0rCTyJLSfocd6jnReyscPfCTP/S8Ao6ZSTstx6Ifk2RYN9y 25 | JrySyLmZJGcnPh3/f5mqs88v9oHT2FOj+q6c9hwMO88KIYhpLWl+xpslEPT7z291 26 | lbpmvpH5uUuJ3AjeEF7GPAmC5O4ykYQWkNG+Vm6hfK+Dhjm6fVHnaiwXmEwVthq0 27 | 6eqyzWx9Hv8u94odqHh0Kx7aDT3QIPsWmSeI0bL/MnN1nT1CgTruo7ajBQOvRx43 28 | Je5NUfW8eHFxP3B19n3cNwOF81hklAhNNn2QsQ40olWgWN7scS80FuYSBwkO1uxR 29 | Q7cR8pSURe4w37bUavgGJC15GmSEH6HHoYHVW3leq5rDoo64m/CL66EXtu2y8pAw 30 | krhCD948WGu6mbC8TX4iCLFDbsix9E/+sCRYQsHDsnfc1H/QCJqz3iuxz0ZVKREJ 31 | xX/VONAFRYZAOW9uaYckzBZLDRw16R2e3/uq2jAc9LSkv+jefnwWzXHJ6Hkvw9bb 32 | fIOEqXDdfrUg+R9doQHm+8ItRNPT 33 | -----END CERTIFICATE----- 34 | -------------------------------------------------------------------------------- /avocado/ssl/dst_root_ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ 3 | MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT 4 | DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow 5 | PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD 6 | Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB 7 | AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O 8 | rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq 9 | OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b 10 | xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw 11 | 7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD 12 | aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV 13 | HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG 14 | SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 15 | ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr 16 | AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz 17 | R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 18 | JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo 19 | Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /avocado/timelord/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/timelord/__init__.py -------------------------------------------------------------------------------- /avocado/timelord/iters_from_block.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Tuple, Union 2 | 3 | from avocado.consensus.pot_iterations import calculate_ip_iters, calculate_iterations_quality, calculate_sp_iters 4 | from avocado.types.blockchain_format.reward_chain_block import RewardChainBlock, RewardChainBlockUnfinished 5 | from avocado.types.blockchain_format.sized_bytes import bytes32 6 | from avocado.util.ints import uint64 7 | 8 | 9 | def iters_from_block( 10 | constants, 11 | reward_chain_block: Union[RewardChainBlock, RewardChainBlockUnfinished], 12 | sub_slot_iters: uint64, 13 | difficulty: uint64, 14 | ) -> Tuple[uint64, uint64]: 15 | if reward_chain_block.challenge_chain_sp_vdf is None: 16 | assert reward_chain_block.signage_point_index == 0 17 | cc_sp: bytes32 = reward_chain_block.pos_ss_cc_challenge_hash 18 | else: 19 | cc_sp = reward_chain_block.challenge_chain_sp_vdf.output.get_hash() 20 | 21 | quality_string: Optional[bytes32] = reward_chain_block.proof_of_space.verify_and_get_quality_string( 22 | constants, 23 | reward_chain_block.pos_ss_cc_challenge_hash, 24 | cc_sp, 25 | ) 26 | assert quality_string is not None 27 | 28 | required_iters: uint64 = calculate_iterations_quality( 29 | constants.DIFFICULTY_CONSTANT_FACTOR, 30 | quality_string, 31 | reward_chain_block.proof_of_space.size, 32 | difficulty, 33 | cc_sp, 34 | ) 35 | return ( 36 | calculate_sp_iters(constants, sub_slot_iters, reward_chain_block.signage_point_index), 37 | calculate_ip_iters( 38 | constants, 39 | sub_slot_iters, 40 | reward_chain_block.signage_point_index, 41 | required_iters, 42 | ), 43 | ) 44 | -------------------------------------------------------------------------------- /avocado/timelord/types.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class Chain(Enum): 5 | CHALLENGE_CHAIN = 1 6 | REWARD_CHAIN = 2 7 | INFUSED_CHALLENGE_CHAIN = 3 8 | BLUEBOX = 4 9 | 10 | 11 | class IterationType(Enum): 12 | SIGNAGE_POINT = 1 13 | INFUSION_POINT = 2 14 | END_OF_SUBSLOT = 3 15 | 16 | 17 | class StateType(Enum): 18 | PEAK = 1 19 | END_OF_SUB_SLOT = 2 20 | FIRST_SUB_SLOT = 3 21 | -------------------------------------------------------------------------------- /avocado/types/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/types/__init__.py -------------------------------------------------------------------------------- /avocado/types/announcement.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from avocado.types.blockchain_format.sized_bytes import bytes32 4 | from avocado.util.hash import std_hash 5 | 6 | 7 | @dataclass(frozen=True) 8 | class Announcement: 9 | origin_info: bytes32 10 | message: bytes 11 | 12 | def name(self) -> bytes32: 13 | return std_hash(bytes(self.origin_info + self.message)) 14 | -------------------------------------------------------------------------------- /avocado/types/blockchain_format/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/types/blockchain_format/__init__.py -------------------------------------------------------------------------------- /avocado/types/blockchain_format/classgroup.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from avocado.consensus.constants import ConsensusConstants 4 | from avocado.types.blockchain_format.sized_bytes import bytes100 5 | from avocado.util.streamable import Streamable, streamable 6 | 7 | 8 | @dataclass(frozen=True) 9 | @streamable 10 | class ClassgroupElement(Streamable): 11 | """ 12 | Represents a classgroup element (a,b,c) where a, b, and c are 512 bit signed integers. However this is using 13 | a compressed representation. VDF outputs are a single classgroup element. VDF proofs can also be one classgroup 14 | element (or multiple). 15 | """ 16 | 17 | data: bytes100 18 | 19 | @staticmethod 20 | def from_bytes(data) -> "ClassgroupElement": 21 | if len(data) < 100: 22 | data += b"\x00" * (100 - len(data)) 23 | return ClassgroupElement(bytes100(data)) 24 | 25 | @staticmethod 26 | def get_default_element() -> "ClassgroupElement": 27 | # Bit 3 in the first byte of serialized compressed form indicates if 28 | # it's the default generator element. 29 | return ClassgroupElement.from_bytes(b"\x08") 30 | 31 | @staticmethod 32 | def get_size(constants: ConsensusConstants): 33 | return 100 34 | -------------------------------------------------------------------------------- /avocado/types/blockchain_format/pool_target.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from avocado.types.blockchain_format.sized_bytes import bytes32 4 | from avocado.util.ints import uint32 5 | from avocado.util.streamable import Streamable, streamable 6 | 7 | 8 | @dataclass(frozen=True) 9 | @streamable 10 | class PoolTarget(Streamable): 11 | puzzle_hash: bytes32 12 | max_height: uint32 # A max height of 0 means it is valid forever 13 | -------------------------------------------------------------------------------- /avocado/types/blockchain_format/reward_chain_block.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from blspy import G2Element 5 | 6 | from avocado.types.blockchain_format.proof_of_space import ProofOfSpace 7 | from avocado.types.blockchain_format.sized_bytes import bytes32 8 | from avocado.types.blockchain_format.vdf import VDFInfo 9 | from avocado.util.ints import uint8, uint32, uint128 10 | from avocado.util.streamable import Streamable, streamable 11 | 12 | 13 | @dataclass(frozen=True) 14 | @streamable 15 | class RewardChainBlockUnfinished(Streamable): 16 | total_iters: uint128 17 | signage_point_index: uint8 18 | pos_ss_cc_challenge_hash: bytes32 19 | proof_of_space: ProofOfSpace 20 | challenge_chain_sp_vdf: Optional[VDFInfo] # Not present for first sp in slot 21 | challenge_chain_sp_signature: G2Element 22 | reward_chain_sp_vdf: Optional[VDFInfo] # Not present for first sp in slot 23 | reward_chain_sp_signature: G2Element 24 | 25 | 26 | @dataclass(frozen=True) 27 | @streamable 28 | class RewardChainBlock(Streamable): 29 | weight: uint128 30 | height: uint32 31 | total_iters: uint128 32 | signage_point_index: uint8 33 | pos_ss_cc_challenge_hash: bytes32 34 | proof_of_space: ProofOfSpace 35 | challenge_chain_sp_vdf: Optional[VDFInfo] # Not present for first sp in slot 36 | challenge_chain_sp_signature: G2Element 37 | challenge_chain_ip_vdf: VDFInfo 38 | reward_chain_sp_vdf: Optional[VDFInfo] # Not present for first sp in slot 39 | reward_chain_sp_signature: G2Element 40 | reward_chain_ip_vdf: VDFInfo 41 | infused_challenge_chain_ip_vdf: Optional[VDFInfo] # Iff deficit < 16 42 | is_transaction_block: bool 43 | 44 | def get_unfinished(self) -> RewardChainBlockUnfinished: 45 | return RewardChainBlockUnfinished( 46 | self.total_iters, 47 | self.signage_point_index, 48 | self.pos_ss_cc_challenge_hash, 49 | self.proof_of_space, 50 | self.challenge_chain_sp_vdf, 51 | self.challenge_chain_sp_signature, 52 | self.reward_chain_sp_vdf, 53 | self.reward_chain_sp_signature, 54 | ) 55 | -------------------------------------------------------------------------------- /avocado/types/blockchain_format/sized_bytes.py: -------------------------------------------------------------------------------- 1 | from avocado.util.byte_types import make_sized_bytes 2 | 3 | bytes4 = make_sized_bytes(4) 4 | bytes8 = make_sized_bytes(8) 5 | bytes32 = make_sized_bytes(32) 6 | bytes48 = make_sized_bytes(48) 7 | bytes96 = make_sized_bytes(96) 8 | bytes100 = make_sized_bytes(100) 9 | bytes480 = make_sized_bytes(480) 10 | -------------------------------------------------------------------------------- /avocado/types/blockchain_format/slots.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from blspy import G2Element 5 | 6 | from avocado.types.blockchain_format.proof_of_space import ProofOfSpace 7 | from avocado.types.blockchain_format.sized_bytes import bytes32 8 | from avocado.types.blockchain_format.vdf import VDFInfo, VDFProof 9 | from avocado.util.ints import uint8, uint64 10 | from avocado.util.streamable import Streamable, streamable 11 | 12 | 13 | @dataclass(frozen=True) 14 | @streamable 15 | class ChallengeBlockInfo(Streamable): # The hash of this is used as the challenge_hash for the ICC VDF 16 | proof_of_space: ProofOfSpace 17 | challenge_chain_sp_vdf: Optional[VDFInfo] # Only present if not the first sp 18 | challenge_chain_sp_signature: G2Element 19 | challenge_chain_ip_vdf: VDFInfo 20 | 21 | 22 | @dataclass(frozen=True) 23 | @streamable 24 | class ChallengeChainSubSlot(Streamable): 25 | challenge_chain_end_of_slot_vdf: VDFInfo 26 | infused_challenge_chain_sub_slot_hash: Optional[bytes32] # Only at the end of a slot 27 | subepoch_summary_hash: Optional[bytes32] # Only once per sub-epoch, and one sub-epoch delayed 28 | new_sub_slot_iters: Optional[uint64] # Only at the end of epoch, sub-epoch, and slot 29 | new_difficulty: Optional[uint64] # Only at the end of epoch, sub-epoch, and slot 30 | 31 | 32 | @dataclass(frozen=True) 33 | @streamable 34 | class InfusedChallengeChainSubSlot(Streamable): 35 | infused_challenge_chain_end_of_slot_vdf: VDFInfo 36 | 37 | 38 | @dataclass(frozen=True) 39 | @streamable 40 | class RewardChainSubSlot(Streamable): 41 | end_of_slot_vdf: VDFInfo 42 | challenge_chain_sub_slot_hash: bytes32 43 | infused_challenge_chain_sub_slot_hash: Optional[bytes32] 44 | deficit: uint8 # 16 or less. usually zero 45 | 46 | 47 | @dataclass(frozen=True) 48 | @streamable 49 | class SubSlotProofs(Streamable): 50 | challenge_chain_slot_proof: VDFProof 51 | infused_challenge_chain_slot_proof: Optional[VDFProof] 52 | reward_chain_slot_proof: VDFProof 53 | -------------------------------------------------------------------------------- /avocado/types/blockchain_format/sub_epoch_summary.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from avocado.types.blockchain_format.sized_bytes import bytes32 5 | from avocado.util.ints import uint8, uint64 6 | from avocado.util.streamable import Streamable, streamable 7 | 8 | 9 | @dataclass(frozen=True) 10 | @streamable 11 | class SubEpochSummary(Streamable): 12 | prev_subepoch_summary_hash: bytes32 13 | reward_chain_hash: bytes32 # hash of reward chain at end of last segment 14 | num_blocks_overflow: uint8 # How many more blocks than 384*(N-1) 15 | new_difficulty: Optional[uint64] # Only once per epoch (diff adjustment) 16 | new_sub_slot_iters: Optional[uint64] # Only once per epoch (diff adjustment) 17 | -------------------------------------------------------------------------------- /avocado/types/blockchain_format/tree_hash.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is an implementation of `sha256_treehash`, used to calculate 3 | puzzle hashes in clvm. 4 | 5 | This implementation goes to great pains to be non-recursive so we don't 6 | have to worry about blowing out the python stack. 7 | """ 8 | 9 | from typing import Optional, Set 10 | 11 | from clvm import CLVMObject 12 | 13 | from avocado.types.blockchain_format.sized_bytes import bytes32 14 | from avocado.util.hash import std_hash 15 | 16 | 17 | def sha256_treehash(sexp: CLVMObject, precalculated: Optional[Set[bytes32]] = None) -> bytes32: 18 | """ 19 | Hash values in `precalculated` are presumed to have been hashed already. 20 | """ 21 | 22 | if precalculated is None: 23 | precalculated = set() 24 | 25 | def handle_sexp(sexp_stack, op_stack, precalculated: Set[bytes32]) -> None: 26 | sexp = sexp_stack.pop() 27 | if sexp.pair: 28 | p0, p1 = sexp.pair 29 | sexp_stack.append(p0) 30 | sexp_stack.append(p1) 31 | op_stack.append(handle_pair) 32 | op_stack.append(handle_sexp) 33 | op_stack.append(roll) 34 | op_stack.append(handle_sexp) 35 | else: 36 | if sexp.atom in precalculated: 37 | r = sexp.atom 38 | else: 39 | r = std_hash(b"\1" + sexp.atom) 40 | sexp_stack.append(r) 41 | 42 | def handle_pair(sexp_stack, op_stack, precalculated) -> None: 43 | p0 = sexp_stack.pop() 44 | p1 = sexp_stack.pop() 45 | sexp_stack.append(std_hash(b"\2" + p0 + p1)) 46 | 47 | def roll(sexp_stack, op_stack, precalculated) -> None: 48 | p0 = sexp_stack.pop() 49 | p1 = sexp_stack.pop() 50 | sexp_stack.append(p0) 51 | sexp_stack.append(p1) 52 | 53 | sexp_stack = [sexp] 54 | op_stack = [handle_sexp] 55 | while len(op_stack) > 0: 56 | op = op_stack.pop() 57 | op(sexp_stack, op_stack, precalculated) 58 | return bytes32(sexp_stack[0]) 59 | -------------------------------------------------------------------------------- /avocado/types/coin_record.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from avocado.types.blockchain_format.coin import Coin 4 | from avocado.types.blockchain_format.sized_bytes import bytes32 5 | from avocado.util.ints import uint32, uint64 6 | from avocado.util.streamable import Streamable, streamable 7 | 8 | 9 | @dataclass(frozen=True) 10 | @streamable 11 | class CoinRecord(Streamable): 12 | """ 13 | These are values that correspond to a CoinName that are used 14 | in keeping track of the unspent database. 15 | """ 16 | 17 | coin: Coin 18 | confirmed_block_index: uint32 19 | spent_block_index: uint32 20 | spent: bool 21 | coinbase: bool 22 | timestamp: uint64 # Timestamp of the block at height confirmed_block_index 23 | 24 | @property 25 | def name(self) -> bytes32: 26 | return self.coin.name() 27 | -------------------------------------------------------------------------------- /avocado/types/coin_solution.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | 4 | from avocado.types.blockchain_format.coin import Coin 5 | from avocado.types.blockchain_format.program import SerializedProgram, INFINITE_COST 6 | from avocado.util.chain_utils import additions_for_solution 7 | from avocado.util.streamable import Streamable, streamable 8 | 9 | 10 | @dataclass(frozen=True) 11 | @streamable 12 | class CoinSolution(Streamable): 13 | """ 14 | This is a rather disparate data structure that validates coin transfers. It's generally populated 15 | with data from different sources, since burned coins are identified by name, so it is built up 16 | more often that it is streamed. 17 | """ 18 | 19 | coin: Coin 20 | puzzle_reveal: SerializedProgram 21 | solution: SerializedProgram 22 | 23 | def additions(self) -> List[Coin]: 24 | return additions_for_solution(self.coin.name(), self.puzzle_reveal, self.solution, INFINITE_COST) 25 | -------------------------------------------------------------------------------- /avocado/types/condition_opcodes.py: -------------------------------------------------------------------------------- 1 | import enum 2 | from typing import Any 3 | 4 | 5 | # See avocado/wallet/puzzles/condition_codes.clvm 6 | class ConditionOpcode(bytes, enum.Enum): 7 | # UNKNOWN is ascii "0" 8 | UNKNOWN = bytes([48]) 9 | 10 | # AGG_SIG is ascii "1" 11 | 12 | # the conditions below require bls12-381 signatures 13 | 14 | AGG_SIG_UNSAFE = bytes([49]) 15 | AGG_SIG_ME = bytes([50]) 16 | 17 | # the conditions below reserve coin amounts and have to be accounted for in output totals 18 | 19 | CREATE_COIN = bytes([51]) 20 | RESERVE_FEE = bytes([52]) 21 | 22 | # the conditions below deal with announcements, for inter-coin communication 23 | 24 | CREATE_COIN_ANNOUNCEMENT = bytes([60]) 25 | ASSERT_COIN_ANNOUNCEMENT = bytes([61]) 26 | CREATE_PUZZLE_ANNOUNCEMENT = bytes([62]) 27 | ASSERT_PUZZLE_ANNOUNCEMENT = bytes([63]) 28 | 29 | # the conditions below let coins inquire about themselves 30 | 31 | ASSERT_MY_COIN_ID = bytes([70]) 32 | ASSERT_MY_PARENT_ID = bytes([71]) 33 | ASSERT_MY_PUZZLEHASH = bytes([72]) 34 | ASSERT_MY_AMOUNT = bytes([73]) 35 | 36 | # the conditions below ensure that we're "far enough" in the future 37 | 38 | # wall-clock time 39 | ASSERT_SECONDS_RELATIVE = bytes([80]) 40 | ASSERT_SECONDS_ABSOLUTE = bytes([81]) 41 | 42 | # block index 43 | ASSERT_HEIGHT_RELATIVE = bytes([82]) 44 | ASSERT_HEIGHT_ABSOLUTE = bytes([83]) 45 | 46 | def __bytes__(self) -> bytes: 47 | return bytes(self.value) 48 | 49 | @classmethod 50 | def from_bytes(cls: Any, blob: bytes) -> Any: 51 | assert len(blob) == 1 52 | return cls(blob) 53 | -------------------------------------------------------------------------------- /avocado/types/condition_with_args.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | 4 | from avocado.types.condition_opcodes import ConditionOpcode 5 | from avocado.util.streamable import Streamable, streamable 6 | 7 | 8 | @dataclass(frozen=True) 9 | @streamable 10 | class ConditionWithArgs(Streamable): 11 | """ 12 | This structure is used to store parsed CLVM conditions 13 | Conditions in CLVM have either format of (opcode, var1) or (opcode, var1, var2) 14 | """ 15 | 16 | opcode: ConditionOpcode 17 | vars: List[bytes] 18 | -------------------------------------------------------------------------------- /avocado/types/end_of_slot_bundle.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from avocado.types.blockchain_format.slots import ( 5 | ChallengeChainSubSlot, 6 | InfusedChallengeChainSubSlot, 7 | RewardChainSubSlot, 8 | SubSlotProofs, 9 | ) 10 | from avocado.util.streamable import Streamable, streamable 11 | 12 | 13 | @dataclass(frozen=True) 14 | @streamable 15 | class EndOfSubSlotBundle(Streamable): 16 | challenge_chain: ChallengeChainSubSlot 17 | infused_challenge_chain: Optional[InfusedChallengeChainSubSlot] 18 | reward_chain: RewardChainSubSlot 19 | proofs: SubSlotProofs 20 | -------------------------------------------------------------------------------- /avocado/types/generator_types.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | from avocado.types.blockchain_format.program import SerializedProgram 4 | from avocado.util.ints import uint32 5 | from avocado.util.streamable import Streamable, streamable 6 | 7 | 8 | class GeneratorBlockCacheInterface: 9 | def get_generator_for_block_height(self, height: uint32) -> SerializedProgram: 10 | # Requested block must be a transaction block 11 | pass 12 | 13 | 14 | @dataclass(frozen=True) 15 | @streamable 16 | class GeneratorArg(Streamable): 17 | """`GeneratorArg` contains data from already-buried blocks in the blockchain""" 18 | 19 | block_height: uint32 20 | generator: SerializedProgram 21 | 22 | 23 | @dataclass(frozen=True) 24 | class CompressorArg: 25 | """`CompressorArg` is used as input to the Block Compressor""" 26 | 27 | block_height: uint32 28 | generator: SerializedProgram 29 | start: int 30 | end: int 31 | 32 | 33 | @dataclass(frozen=True) 34 | @streamable 35 | class BlockGenerator(Streamable): 36 | program: SerializedProgram 37 | generator_args: List[GeneratorArg] 38 | 39 | def block_height_list(self) -> List[uint32]: 40 | return [a.block_height for a in self.generator_args] 41 | 42 | def generator_refs(self) -> List[SerializedProgram]: 43 | return [a.generator for a in self.generator_args] 44 | -------------------------------------------------------------------------------- /avocado/types/mempool_inclusion_status.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class MempoolInclusionStatus(IntEnum): 5 | SUCCESS = 1 # Transaction added to mempool 6 | PENDING = 2 # Transaction not yet added to mempool 7 | FAILED = 3 # Transaction was invalid and dropped 8 | -------------------------------------------------------------------------------- /avocado/types/mempool_item.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | 4 | from avocado.consensus.cost_calculator import NPCResult 5 | from avocado.types.blockchain_format.coin import Coin 6 | from avocado.types.blockchain_format.program import SerializedProgram 7 | from avocado.types.blockchain_format.sized_bytes import bytes32 8 | from avocado.types.spend_bundle import SpendBundle 9 | from avocado.util.ints import uint64 10 | from avocado.util.streamable import Streamable, streamable 11 | 12 | 13 | @dataclass(frozen=True) 14 | @streamable 15 | class MempoolItem(Streamable): 16 | spend_bundle: SpendBundle 17 | fee: uint64 18 | npc_result: NPCResult 19 | cost: uint64 20 | spend_bundle_name: bytes32 21 | additions: List[Coin] 22 | removals: List[Coin] 23 | program: SerializedProgram 24 | 25 | def __lt__(self, other): 26 | return self.fee_per_cost < other.fee_per_cost 27 | 28 | @property 29 | def fee_per_cost(self) -> float: 30 | return int(self.fee) / int(self.cost) 31 | 32 | @property 33 | def name(self) -> bytes32: 34 | return self.spend_bundle_name 35 | -------------------------------------------------------------------------------- /avocado/types/name_puzzle_condition.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Dict, List, Tuple 3 | 4 | from avocado.types.blockchain_format.sized_bytes import bytes32 5 | from avocado.types.condition_with_args import ConditionWithArgs 6 | from avocado.util.condition_tools import ConditionOpcode 7 | from avocado.util.streamable import Streamable, streamable 8 | 9 | 10 | @dataclass(frozen=True) 11 | @streamable 12 | class NPC(Streamable): 13 | coin_name: bytes32 14 | puzzle_hash: bytes32 15 | conditions: List[Tuple[ConditionOpcode, List[ConditionWithArgs]]] 16 | 17 | @property 18 | def condition_dict(self): 19 | d: Dict[ConditionOpcode, List[ConditionWithArgs]] = {} 20 | for opcode, l in self.conditions: 21 | d[opcode] = l 22 | return d 23 | -------------------------------------------------------------------------------- /avocado/types/peer_info.py: -------------------------------------------------------------------------------- 1 | import ipaddress 2 | from dataclasses import dataclass 3 | from typing import Optional, Union 4 | 5 | from avocado.util.ints import uint16, uint64 6 | from avocado.util.streamable import Streamable, streamable 7 | 8 | 9 | @dataclass(frozen=True) 10 | @streamable 11 | class PeerInfo(Streamable): 12 | host: str 13 | port: uint16 14 | 15 | def is_valid(self, allow_private_subnets=False) -> bool: 16 | ip: Optional[Union[ipaddress.IPv6Address, ipaddress.IPv4Address]] = None 17 | try: 18 | ip = ipaddress.IPv6Address(self.host) 19 | except ValueError: 20 | ip = None 21 | if ip is not None: 22 | if ip.is_private and not allow_private_subnets: 23 | return False 24 | return True 25 | 26 | try: 27 | ip = ipaddress.IPv4Address(self.host) 28 | except ValueError: 29 | ip = None 30 | if ip is not None: 31 | if ip.is_private and not allow_private_subnets: 32 | return False 33 | return True 34 | return False 35 | 36 | # Functions related to peer bucketing in new/tried tables. 37 | def get_key(self): 38 | try: 39 | ip = ipaddress.IPv6Address(self.host) 40 | except ValueError: 41 | ip_v4 = ipaddress.IPv4Address(self.host) 42 | ip = ipaddress.IPv6Address(int(ipaddress.IPv6Address("2002::")) | (int(ip_v4) << 80)) 43 | key = ip.packed 44 | key += bytes([self.port // 0x100, self.port & 0x0FF]) 45 | return key 46 | 47 | def get_group(self): 48 | # TODO: Port everything from Bitcoin. 49 | ipv4 = 1 50 | try: 51 | ip = ipaddress.IPv4Address(self.host) 52 | except ValueError: 53 | ip = ipaddress.IPv6Address(self.host) 54 | ipv4 = 0 55 | if ipv4: 56 | group = bytes([1]) + ip.packed[:2] 57 | else: 58 | group = bytes([0]) + ip.packed[:4] 59 | return group 60 | 61 | 62 | @dataclass(frozen=True) 63 | @streamable 64 | class TimestampedPeerInfo(Streamable): 65 | host: str 66 | port: uint16 67 | timestamp: uint64 68 | -------------------------------------------------------------------------------- /avocado/types/unfinished_block.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Optional 3 | 4 | from avocado.types.blockchain_format.foliage import Foliage, FoliageTransactionBlock, TransactionsInfo 5 | from avocado.types.blockchain_format.program import SerializedProgram 6 | from avocado.types.blockchain_format.reward_chain_block import RewardChainBlockUnfinished 7 | from avocado.types.blockchain_format.vdf import VDFProof 8 | from avocado.types.end_of_slot_bundle import EndOfSubSlotBundle 9 | from avocado.util.ints import uint32 10 | from avocado.util.streamable import Streamable, streamable 11 | 12 | 13 | @dataclass(frozen=True) 14 | @streamable 15 | class UnfinishedBlock(Streamable): 16 | # Full block, without the final VDFs 17 | finished_sub_slots: List[EndOfSubSlotBundle] # If first sb 18 | reward_chain_block: RewardChainBlockUnfinished # Reward chain trunk data 19 | challenge_chain_sp_proof: Optional[VDFProof] # If not first sp in sub-slot 20 | reward_chain_sp_proof: Optional[VDFProof] # If not first sp in sub-slot 21 | foliage: Foliage # Reward chain foliage data 22 | foliage_transaction_block: Optional[FoliageTransactionBlock] # Reward chain foliage data (tx block) 23 | transactions_info: Optional[TransactionsInfo] # Reward chain foliage data (tx block additional) 24 | transactions_generator: Optional[SerializedProgram] # Program that generates transactions 25 | transactions_generator_ref_list: List[ 26 | uint32 27 | ] # List of block heights of previous generators referenced in this block 28 | 29 | @property 30 | def prev_header_hash(self): 31 | return self.foliage.prev_block_hash 32 | 33 | @property 34 | def partial_hash(self): 35 | return self.reward_chain_block.get_hash() 36 | 37 | def is_transaction_block(self) -> bool: 38 | return self.foliage.foliage_transaction_block_hash is not None 39 | 40 | @property 41 | def total_iters(self): 42 | return self.reward_chain_block.total_iters 43 | -------------------------------------------------------------------------------- /avocado/types/unfinished_header_block.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Optional 3 | 4 | from avocado.types.blockchain_format.foliage import Foliage, FoliageTransactionBlock 5 | from avocado.types.blockchain_format.reward_chain_block import RewardChainBlockUnfinished 6 | from avocado.types.blockchain_format.vdf import VDFProof 7 | from avocado.types.end_of_slot_bundle import EndOfSubSlotBundle 8 | from avocado.util.streamable import Streamable, streamable 9 | 10 | 11 | @dataclass(frozen=True) 12 | @streamable 13 | class UnfinishedHeaderBlock(Streamable): 14 | # Same as a FullBlock but without TransactionInfo and Generator, used by light clients 15 | finished_sub_slots: List[EndOfSubSlotBundle] # If first sb 16 | reward_chain_block: RewardChainBlockUnfinished # Reward chain trunk data 17 | challenge_chain_sp_proof: Optional[VDFProof] # If not first sp in sub-slot 18 | reward_chain_sp_proof: Optional[VDFProof] # If not first sp in sub-slot 19 | foliage: Foliage # Reward chain foliage data 20 | foliage_transaction_block: Optional[FoliageTransactionBlock] # Reward chain foliage data (tx block) 21 | transactions_filter: bytes # Filter for block transactions 22 | 23 | @property 24 | def prev_header_hash(self): 25 | return self.foliage.prev_block_hash 26 | 27 | @property 28 | def header_hash(self): 29 | return self.foliage.get_hash() 30 | 31 | @property 32 | def total_iters(self): 33 | return self.reward_chain_block.total_iters 34 | -------------------------------------------------------------------------------- /avocado/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/util/__init__.py -------------------------------------------------------------------------------- /avocado/util/api_decorators.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import logging 3 | from inspect import signature 4 | 5 | from avocado.util.streamable import Streamable 6 | 7 | log = logging.getLogger(__name__) 8 | 9 | 10 | def api_request(f): 11 | @functools.wraps(f) 12 | def f_substitute(*args, **kwargs): 13 | sig = signature(f) 14 | binding = sig.bind(*args, **kwargs) 15 | binding.apply_defaults() 16 | inter = dict(binding.arguments) 17 | 18 | # Converts each parameter from a Python dictionary, into an instance of the object 19 | # specified by the type annotation (signature) of the function that is being called (f) 20 | # The method can also be called with the target type instead of a dictionary. 21 | for param_name, param_class in f.__annotations__.items(): 22 | if param_name != "return" and isinstance(inter[param_name], Streamable): 23 | if param_class.__name__ == "bytes": 24 | continue 25 | if hasattr(f, "bytes_required"): 26 | inter[f"{param_name}_bytes"] = bytes(inter[param_name]) 27 | continue 28 | if param_name != "return" and isinstance(inter[param_name], bytes): 29 | if param_class.__name__ == "bytes": 30 | continue 31 | if hasattr(f, "bytes_required"): 32 | inter[f"{param_name}_bytes"] = inter[param_name] 33 | inter[param_name] = param_class.from_bytes(inter[param_name]) 34 | return f(**inter) 35 | 36 | setattr(f_substitute, "api_function", True) 37 | return f_substitute 38 | 39 | 40 | def peer_required(func): 41 | def inner(): 42 | setattr(func, "peer_required", True) 43 | return func 44 | 45 | return inner() 46 | 47 | 48 | def bytes_required(func): 49 | def inner(): 50 | setattr(func, "bytes_required", True) 51 | return func 52 | 53 | return inner() 54 | 55 | 56 | def execute_task(func): 57 | def inner(): 58 | setattr(func, "execute_task", True) 59 | return func 60 | 61 | return inner() 62 | -------------------------------------------------------------------------------- /avocado/util/byte_types.py: -------------------------------------------------------------------------------- 1 | import io 2 | from typing import Any, BinaryIO 3 | 4 | 5 | def hexstr_to_bytes(input_str: str) -> bytes: 6 | """ 7 | Converts a hex string into bytes, removing the 0x if it's present. 8 | """ 9 | if input_str.startswith("0x") or input_str.startswith("0X"): 10 | return bytes.fromhex(input_str[2:]) 11 | return bytes.fromhex(input_str) 12 | 13 | 14 | def make_sized_bytes(size: int): 15 | """ 16 | Create a streamable type that subclasses "bytes" but requires instances 17 | to be a certain, fixed size. 18 | """ 19 | name = "bytes%d" % size 20 | 21 | def __new__(cls, v): 22 | v = bytes(v) 23 | if not isinstance(v, bytes) or len(v) != size: 24 | raise ValueError("bad %s initializer %s" % (name, v)) 25 | return bytes.__new__(cls, v) # type: ignore 26 | 27 | @classmethod # type: ignore 28 | def parse(cls, f: BinaryIO) -> Any: 29 | b = f.read(size) 30 | assert len(b) == size 31 | return cls(b) 32 | 33 | def stream(self, f): 34 | f.write(self) 35 | 36 | @classmethod # type: ignore 37 | def from_bytes(cls: Any, blob: bytes) -> Any: 38 | # pylint: disable=no-member 39 | f = io.BytesIO(blob) 40 | result = cls.parse(f) 41 | assert f.read() == b"" 42 | return result 43 | 44 | def __bytes__(self: Any) -> bytes: 45 | f = io.BytesIO() 46 | self.stream(f) 47 | return bytes(f.getvalue()) 48 | 49 | def __str__(self): 50 | return self.hex() 51 | 52 | def __repr__(self): 53 | return "<%s: %s>" % (self.__class__.__name__, str(self)) 54 | 55 | namespace = dict( 56 | __new__=__new__, 57 | parse=parse, 58 | stream=stream, 59 | from_bytes=from_bytes, 60 | __bytes__=__bytes__, 61 | __str__=__str__, 62 | __repr__=__repr__, 63 | ) 64 | 65 | return type(name, (bytes,), namespace) 66 | -------------------------------------------------------------------------------- /avocado/util/chain_utils.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from avocado.types.blockchain_format.coin import Coin 4 | from avocado.types.blockchain_format.program import SerializedProgram 5 | from avocado.types.blockchain_format.sized_bytes import bytes32 6 | from avocado.util.condition_tools import ( 7 | conditions_dict_for_solution, 8 | created_outputs_for_conditions_dict, 9 | ) 10 | 11 | 12 | def additions_for_solution( 13 | coin_name: bytes32, puzzle_reveal: SerializedProgram, solution: SerializedProgram, max_cost: int 14 | ) -> List[Coin]: 15 | """ 16 | Checks the conditions created by CoinSolution and returns the list of all coins created 17 | """ 18 | err, dic, cost = conditions_dict_for_solution(puzzle_reveal, solution, max_cost) 19 | if err or dic is None: 20 | return [] 21 | return created_outputs_for_conditions_dict(dic, coin_name) 22 | -------------------------------------------------------------------------------- /avocado/util/clvm.py: -------------------------------------------------------------------------------- 1 | from clvm.casts import int_from_bytes, int_to_bytes # noqa 2 | -------------------------------------------------------------------------------- /avocado/util/db_wrapper.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | import aiosqlite 4 | 5 | 6 | class DBWrapper: 7 | """ 8 | This object handles HeaderBlocks and Blocks stored in DB used by wallet. 9 | """ 10 | 11 | db: aiosqlite.Connection 12 | lock: asyncio.Lock 13 | 14 | def __init__(self, connection: aiosqlite.Connection): 15 | self.db = connection 16 | self.lock = asyncio.Lock() 17 | 18 | async def begin_transaction(self): 19 | cursor = await self.db.execute("BEGIN TRANSACTION") 20 | await cursor.close() 21 | 22 | async def rollback_transaction(self): 23 | # Also rolls back the coin store, since both stores must be updated at once 24 | if self.db.in_transaction: 25 | cursor = await self.db.execute("ROLLBACK") 26 | await cursor.close() 27 | 28 | async def commit_transaction(self): 29 | await self.db.commit() 30 | -------------------------------------------------------------------------------- /avocado/util/default_root.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | 4 | DEFAULT_ROOT_PATH = Path(os.path.expanduser(os.getenv("AVOCADO_ROOT", "~/.avocado/mainnet"))).resolve() 5 | -------------------------------------------------------------------------------- /avocado/util/hash.py: -------------------------------------------------------------------------------- 1 | import blspy 2 | 3 | from avocado.types.blockchain_format.sized_bytes import bytes32 4 | 5 | 6 | def std_hash(b) -> bytes32: 7 | """ 8 | The standard hash used in many places. 9 | """ 10 | return bytes32(blspy.Util.hash256(bytes(b))) 11 | -------------------------------------------------------------------------------- /avocado/util/json_util.py: -------------------------------------------------------------------------------- 1 | import dataclasses 2 | import json 3 | from typing import Any 4 | 5 | from aiohttp import web 6 | 7 | from avocado.wallet.util.wallet_types import WalletType 8 | 9 | 10 | class EnhancedJSONEncoder(json.JSONEncoder): 11 | """ 12 | Encodes bytes as hex strings with 0x, and converts all dataclasses to json. 13 | """ 14 | 15 | def default(self, o: Any): 16 | if dataclasses.is_dataclass(o): 17 | return o.to_json_dict() 18 | elif isinstance(o, WalletType): 19 | return o.name 20 | elif hasattr(type(o), "__bytes__"): 21 | return f"0x{bytes(o).hex()}" 22 | elif isinstance(o, bytes): 23 | return f"0x{o.hex()}" 24 | return super().default(o) 25 | 26 | 27 | def dict_to_json_str(o: Any) -> str: 28 | """ 29 | Converts a python object into json. 30 | """ 31 | json_str = json.dumps(o, cls=EnhancedJSONEncoder, sort_keys=True) 32 | return json_str 33 | 34 | 35 | def obj_to_response(o: Any) -> web.Response: 36 | """ 37 | Converts a python object into json. Used for RPC server which returns JSON. 38 | """ 39 | json_str = dict_to_json_str(o) 40 | return web.Response(body=json_str, content_type="application/json") 41 | -------------------------------------------------------------------------------- /avocado/util/lru_cache.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | from typing import Any, Optional 3 | 4 | 5 | class LRUCache: 6 | def __init__(self, capacity: int): 7 | self.cache: OrderedDict = OrderedDict() 8 | self.capacity = capacity 9 | 10 | def get(self, key: Any) -> Optional[Any]: 11 | if key not in self.cache: 12 | return None 13 | else: 14 | self.cache.move_to_end(key) 15 | return self.cache[key] 16 | 17 | def put(self, key: Any, value: Any) -> None: 18 | self.cache[key] = value 19 | self.cache.move_to_end(key) 20 | if len(self.cache) > self.capacity: 21 | self.cache.popitem(last=False) 22 | 23 | def remove(self, key: Any) -> None: 24 | self.cache.pop(key) 25 | -------------------------------------------------------------------------------- /avocado/util/make_test_constants.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | from avocado.consensus.default_constants import DEFAULT_CONSTANTS, ConsensusConstants 4 | 5 | 6 | def make_test_constants(test_constants_overrides: Dict) -> ConsensusConstants: 7 | return DEFAULT_CONSTANTS.replace(**test_constants_overrides) 8 | -------------------------------------------------------------------------------- /avocado/util/network.py: -------------------------------------------------------------------------------- 1 | from ipaddress import ip_address, IPv4Network, IPv6Network 2 | from typing import Iterable, Union, Any 3 | from avocado.server.outbound_message import NodeType 4 | 5 | 6 | def is_in_network(peer_host: str, networks: Iterable[Union[IPv4Network, IPv6Network]]) -> bool: 7 | try: 8 | peer_host_ip = ip_address(peer_host) 9 | return any(peer_host_ip in network for network in networks) 10 | except ValueError: 11 | return False 12 | 13 | 14 | def is_localhost(peer_host: str) -> bool: 15 | return peer_host == "127.0.0.1" or peer_host == "localhost" or peer_host == "::1" or peer_host == "0:0:0:0:0:0:0:1" 16 | 17 | 18 | def class_for_type(type: NodeType) -> Any: 19 | if type is NodeType.FULL_NODE: 20 | from avocado.full_node.full_node_api import FullNodeAPI 21 | 22 | return FullNodeAPI 23 | elif type is NodeType.WALLET: 24 | from avocado.wallet.wallet_node_api import WalletNodeAPI 25 | 26 | return WalletNodeAPI 27 | elif type is NodeType.INTRODUCER: 28 | from avocado.introducer.introducer_api import IntroducerAPI 29 | 30 | return IntroducerAPI 31 | elif type is NodeType.TIMELORD: 32 | from avocado.timelord.timelord_api import TimelordAPI 33 | 34 | return TimelordAPI 35 | elif type is NodeType.FARMER: 36 | from avocado.farmer.farmer_api import FarmerAPI 37 | 38 | return FarmerAPI 39 | elif type is NodeType.HARVESTER: 40 | from avocado.harvester.harvester_api import HarvesterAPI 41 | 42 | return HarvesterAPI 43 | raise ValueError("No class for type") 44 | -------------------------------------------------------------------------------- /avocado/util/partial_func.py: -------------------------------------------------------------------------------- 1 | def partial_async_gen(f, *args): 2 | """ 3 | Returns an async generator function which is equalivalent to the passed in function, 4 | but only takes in one parameter (the first one). 5 | """ 6 | 7 | async def inner(first_param): 8 | async for x in f(first_param, *args): 9 | yield x 10 | 11 | return inner 12 | 13 | 14 | def partial_async(f, *args): 15 | """ 16 | Returns an async function which is equalivalent to the passed in function, 17 | but only takes in one parameter (the first one). 18 | """ 19 | 20 | async def inner(first_param): 21 | return await f(first_param, *args) 22 | 23 | return inner 24 | -------------------------------------------------------------------------------- /avocado/util/path.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | from typing import Union 4 | 5 | 6 | def path_from_root(root: Path, path_str: Union[str, Path]) -> Path: 7 | """ 8 | If path is relative, prepend root 9 | If path is absolute, return it directly. 10 | """ 11 | root = Path(os.path.expanduser(str(root))) 12 | path = Path(path_str) 13 | if not path.is_absolute(): 14 | path = root / path 15 | return path.resolve() 16 | 17 | 18 | def mkdir(path_str: Union[str, Path]) -> None: 19 | """ 20 | Create the existing directory (and its parents) if necessary. 21 | """ 22 | path = Path(path_str) 23 | path.mkdir(parents=True, exist_ok=True) 24 | 25 | 26 | def make_path_relative(path_str: Union[str, Path], root: Path) -> Path: 27 | """ 28 | Try to make the given path relative, given the default root. 29 | """ 30 | path = Path(path_str) 31 | try: 32 | path = path.relative_to(root) 33 | except ValueError: 34 | pass 35 | return path 36 | -------------------------------------------------------------------------------- /avocado/util/pip_import.py: -------------------------------------------------------------------------------- 1 | "Import a package and install it with PIP if it doesn't exist." 2 | 3 | import subprocess 4 | import sys 5 | 6 | 7 | def pip_import(module, pypi_name=None): 8 | """ 9 | Return None if we can't import or install it. 10 | """ 11 | try: 12 | return __import__(module) 13 | except ImportError: 14 | pass 15 | 16 | subprocess.call([sys.executable, "-m", "pip", "install", pypi_name or module]) 17 | return __import__(module) 18 | -------------------------------------------------------------------------------- /avocado/util/prev_transaction_block.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | from avocado.consensus.block_record import BlockRecord 4 | from avocado.consensus.blockchain_interface import BlockchainInterface 5 | from avocado.util.ints import uint128 6 | 7 | 8 | def get_prev_transaction_block( 9 | curr: BlockRecord, 10 | blocks: BlockchainInterface, 11 | total_iters_sp: uint128, 12 | ) -> Tuple[bool, BlockRecord]: 13 | prev_transaction_block = curr 14 | while not curr.is_transaction_block: 15 | curr = blocks.block_record(curr.prev_hash) 16 | if total_iters_sp > curr.total_iters: 17 | prev_transaction_block = curr 18 | is_transaction_block = True 19 | else: 20 | is_transaction_block = False 21 | return is_transaction_block, prev_transaction_block 22 | -------------------------------------------------------------------------------- /avocado/util/recursive_replace.py: -------------------------------------------------------------------------------- 1 | from dataclasses import replace 2 | from typing import Any 3 | 4 | 5 | def recursive_replace(root_obj: Any, replace_str: str, replace_with: Any) -> Any: 6 | split_str = replace_str.split(".") 7 | if len(split_str) == 1: 8 | return replace(root_obj, **{split_str[0]: replace_with}) 9 | sub_obj = recursive_replace(getattr(root_obj, split_str[0]), ".".join(split_str[1:]), replace_with) 10 | return replace(root_obj, **{split_str[0]: sub_obj}) 11 | -------------------------------------------------------------------------------- /avocado/util/safe_cancel_task.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | from typing import Optional 4 | 5 | 6 | def cancel_task_safe(task: Optional[asyncio.Task], log: Optional[logging.Logger] = None): 7 | if task is not None: 8 | try: 9 | task.cancel() 10 | except Exception as e: 11 | if log is not None: 12 | log.error(f"Error while canceling task.{e} {task}") 13 | -------------------------------------------------------------------------------- /avocado/util/service_groups.py: -------------------------------------------------------------------------------- 1 | from typing import KeysView, Generator 2 | 3 | SERVICES_FOR_GROUP = { 4 | "all": "avocado_harvester avocado_timelord_launcher avocado_timelord avocado_farmer avocado_full_node avocado_wallet".split(), 5 | "node": "avocado_full_node".split(), 6 | "harvester": "avocado_harvester".split(), 7 | "farmer": "avocado_harvester avocado_farmer avocado_full_node avocado_wallet".split(), 8 | "farmer-no-wallet": "avocado_harvester avocado_farmer avocado_full_node".split(), 9 | "farmer-only": "avocado_farmer".split(), 10 | "timelord": "avocado_timelord_launcher avocado_timelord avocado_full_node".split(), 11 | "timelord-only": "avocado_timelord".split(), 12 | "timelord-launcher-only": "avocado_timelord_launcher".split(), 13 | "wallet": "avocado_wallet avocado_full_node".split(), 14 | "wallet-only": "avocado_wallet".split(), 15 | "introducer": "avocado_introducer".split(), 16 | "simulator": "avocado_full_node_simulator".split(), 17 | } 18 | 19 | 20 | def all_groups() -> KeysView[str]: 21 | return SERVICES_FOR_GROUP.keys() 22 | 23 | 24 | def services_for_groups(groups) -> Generator[str, None, None]: 25 | for group in groups: 26 | for service in SERVICES_FOR_GROUP[group]: 27 | yield service 28 | 29 | 30 | def validate_service(service: str) -> bool: 31 | return any(service in _ for _ in SERVICES_FOR_GROUP.values()) 32 | -------------------------------------------------------------------------------- /avocado/util/setproctitle.py: -------------------------------------------------------------------------------- 1 | try: 2 | import setproctitle as pysetproctitle 3 | 4 | no_setproctitle = False 5 | except Exception: 6 | no_setproctitle = True 7 | 8 | 9 | def setproctitle(ps_name: str) -> None: 10 | if no_setproctitle is False: 11 | pysetproctitle.setproctitle(ps_name) 12 | -------------------------------------------------------------------------------- /avocado/util/significant_bits.py: -------------------------------------------------------------------------------- 1 | def truncate_to_significant_bits(input_x: int, num_significant_bits: int) -> int: 2 | """ 3 | Truncates the number such that only the top num_significant_bits contain 1s. 4 | and the rest of the number is 0s (in binary). Ignores decimals and leading 5 | zeroes. For example, -0b011110101 and 2, returns -0b11000000. 6 | """ 7 | x = abs(input_x) 8 | if num_significant_bits > x.bit_length(): 9 | return x 10 | lower = x.bit_length() - num_significant_bits 11 | mask = (1 << (x.bit_length())) - 1 - ((1 << lower) - 1) 12 | if input_x < 0: 13 | return -(x & mask) 14 | else: 15 | return x & mask 16 | 17 | 18 | def count_significant_bits(input_x: int) -> int: 19 | """ 20 | Counts the number of significant bits of an integer, ignoring negative signs 21 | and leading zeroes. For example, for -0b000110010000, returns 5. 22 | """ 23 | x = input_x 24 | for i in range(x.bit_length()): 25 | if x & (1 << i) > 0: 26 | return x.bit_length() - i 27 | return 0 28 | -------------------------------------------------------------------------------- /avocado/util/struct_stream.py: -------------------------------------------------------------------------------- 1 | import io 2 | import struct 3 | from typing import Any, BinaryIO 4 | 5 | 6 | class StructStream(int): 7 | PACK = "" 8 | 9 | """ 10 | Create a class that can parse and stream itself based on a struct.pack template string. 11 | """ 12 | 13 | def __new__(cls: Any, value: int): 14 | value = int(value) 15 | try: 16 | v1 = struct.unpack(cls.PACK, struct.pack(cls.PACK, value))[0] 17 | if value != v1: 18 | raise ValueError(f"Value {value} does not fit into {cls.__name__}") 19 | except Exception: 20 | bits = struct.calcsize(cls.PACK) * 8 21 | raise ValueError( 22 | f"Value {value} of size {value.bit_length()} does not fit into " f"{cls.__name__} of size {bits}" 23 | ) 24 | return int.__new__(cls, value) # type: ignore 25 | 26 | @classmethod 27 | def parse(cls: Any, f: BinaryIO) -> Any: 28 | bytes_to_read = struct.calcsize(cls.PACK) 29 | read_bytes = f.read(bytes_to_read) 30 | assert read_bytes is not None and len(read_bytes) == bytes_to_read 31 | return cls(*struct.unpack(cls.PACK, read_bytes)) 32 | 33 | def stream(self, f): 34 | f.write(struct.pack(self.PACK, self)) 35 | 36 | @classmethod 37 | def from_bytes(cls: Any, blob: bytes) -> Any: # type: ignore 38 | f = io.BytesIO(blob) 39 | result = cls.parse(f) 40 | assert f.read() == b"" 41 | return result 42 | 43 | def __bytes__(self: Any) -> bytes: 44 | f = io.BytesIO() 45 | self.stream(f) 46 | return bytes(f.getvalue()) 47 | -------------------------------------------------------------------------------- /avocado/util/validate_alert.py: -------------------------------------------------------------------------------- 1 | import json 2 | from pathlib import Path 3 | 4 | from blspy import AugSchemeMPL, PublicKeyMPL, SignatureMPL 5 | 6 | from avocado.util.byte_types import hexstr_to_bytes 7 | from avocado.util.hash import std_hash 8 | 9 | 10 | def validate_alert_file(file_path: Path, pubkey: str) -> bool: 11 | text = file_path.read_text() 12 | validated = validate_alert(text, pubkey) 13 | return validated 14 | 15 | 16 | def validate_alert(text: str, pubkey: str) -> bool: 17 | json_obj = json.loads(text) 18 | data = json_obj["data"] 19 | message = bytes(data, "UTF-8") 20 | signature = json_obj["signature"] 21 | signature = SignatureMPL.from_bytes(hexstr_to_bytes(signature)) 22 | pubkey_bls = PublicKeyMPL.from_bytes(hexstr_to_bytes(pubkey)) 23 | sig_match_my = AugSchemeMPL.verify(pubkey_bls, message, signature) 24 | 25 | return sig_match_my 26 | 27 | 28 | def create_alert_file(alert_file_path: Path, key, genesis_challenge_preimage: str): 29 | bytes_preimage = bytes(genesis_challenge_preimage, "UTF-8") 30 | genesis_challenge = std_hash(bytes_preimage) 31 | file_dict = { 32 | "ready": True, 33 | "genesis_challenge": genesis_challenge.hex(), 34 | "genesis_challenge_preimage": genesis_challenge_preimage, 35 | } 36 | data: str = json.dumps(file_dict) 37 | signature = AugSchemeMPL.sign(key, bytes(data, "utf-8")) 38 | file_data = {"data": data, "signature": f"{signature}"} 39 | file_data_json = json.dumps(file_data) 40 | alert_file_path.write_text(file_data_json) 41 | 42 | 43 | def create_not_ready_alert_file(alert_file_path: Path, key): 44 | file_dict = { 45 | "ready": False, 46 | } 47 | data: str = json.dumps(file_dict) 48 | signature = AugSchemeMPL.sign(key, bytes(data, "utf-8")) 49 | file_data = {"data": data, "signature": f"{signature}"} 50 | file_data_json = json.dumps(file_data) 51 | alert_file_path.write_text(file_data_json) 52 | -------------------------------------------------------------------------------- /avocado/util/vdf_prover.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | from chiavdf import prove 4 | 5 | from avocado.consensus.constants import ConsensusConstants 6 | from avocado.types.blockchain_format.classgroup import ClassgroupElement 7 | from avocado.types.blockchain_format.sized_bytes import bytes32 8 | from avocado.types.blockchain_format.vdf import VDFInfo, VDFProof 9 | from avocado.util.ints import uint8, uint64 10 | 11 | 12 | def get_vdf_info_and_proof( 13 | constants: ConsensusConstants, 14 | vdf_input: ClassgroupElement, 15 | challenge_hash: bytes32, 16 | number_iters: uint64, 17 | normalized_to_identity: bool = False, 18 | ) -> Tuple[VDFInfo, VDFProof]: 19 | form_size = ClassgroupElement.get_size(constants) 20 | result: bytes = prove( 21 | bytes(challenge_hash), 22 | vdf_input.data, 23 | constants.DISCRIMINANT_SIZE_BITS, 24 | number_iters, 25 | ) 26 | 27 | output = ClassgroupElement.from_bytes(result[:form_size]) 28 | proof_bytes = result[form_size : 2 * form_size] 29 | return VDFInfo(challenge_hash, number_iters, output), VDFProof(uint8(0), proof_bytes, normalized_to_identity) 30 | -------------------------------------------------------------------------------- /avocado/util/ws_message.py: -------------------------------------------------------------------------------- 1 | from secrets import token_bytes 2 | from typing import Any, Dict 3 | 4 | from avocado.util.json_util import dict_to_json_str 5 | 6 | try: 7 | from typings import TypedDict 8 | except ImportError: 9 | from typing_extensions import TypedDict 10 | 11 | 12 | # Messages must follow this format 13 | # Message = { "command" "command_name", 14 | # "data" : {...}, 15 | # "request_id": "bytes_32", 16 | # "destination": "service_name", 17 | # "origin": "service_name" 18 | # } 19 | 20 | 21 | class WsRpcMessage(TypedDict): 22 | command: str 23 | ack: bool 24 | data: Dict[str, Any] 25 | request_id: str 26 | destination: str 27 | origin: str 28 | 29 | 30 | def format_response(incoming_msg: WsRpcMessage, response_data: Dict[str, Any]) -> str: 31 | """ 32 | Formats the response into standard format. 33 | """ 34 | response = { 35 | "command": incoming_msg["command"], 36 | "ack": True, 37 | "data": response_data, 38 | "request_id": incoming_msg["request_id"], 39 | "destination": incoming_msg["origin"], 40 | "origin": incoming_msg["destination"], 41 | } 42 | 43 | json_str = dict_to_json_str(response) 44 | return json_str 45 | 46 | 47 | def create_payload(command: str, data: Dict[str, Any], origin: str, destination: str) -> str: 48 | response = create_payload_dict(command, data, origin, destination) 49 | return dict_to_json_str(response) 50 | 51 | 52 | def create_payload_dict(command: str, data: Dict[str, Any], origin: str, destination: str) -> WsRpcMessage: 53 | return WsRpcMessage( 54 | command=command, 55 | ack=False, 56 | data=data, 57 | request_id=token_bytes().hex(), 58 | destination=destination, 59 | origin=origin, 60 | ) 61 | 62 | 63 | def pong() -> Dict[str, Any]: 64 | response = {"success": True} 65 | return response 66 | -------------------------------------------------------------------------------- /avocado/wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/wallet/__init__.py -------------------------------------------------------------------------------- /avocado/wallet/block_record.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | 4 | from avocado.types.blockchain_format.coin import Coin 5 | from avocado.types.header_block import HeaderBlock 6 | from avocado.util.streamable import Streamable, streamable 7 | 8 | 9 | @dataclass(frozen=True) 10 | @streamable 11 | class HeaderBlockRecord(Streamable): 12 | """ 13 | These are values that are stored in the wallet database, corresponding to information 14 | that the wallet cares about in each block 15 | """ 16 | 17 | header: HeaderBlock 18 | additions: List[Coin] # A block record without additions is not finished 19 | removals: List[Coin] # A block record without removals is not finished 20 | 21 | @property 22 | def header_hash(self): 23 | return self.header.header_hash 24 | 25 | @property 26 | def prev_header_hash(self): 27 | return self.header.prev_header_hash 28 | 29 | @property 30 | def height(self): 31 | return self.header.height 32 | 33 | @property 34 | def transactions_filter(self): 35 | return self.header.transactions_filter 36 | -------------------------------------------------------------------------------- /avocado/wallet/cc_wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/wallet/cc_wallet/__init__.py -------------------------------------------------------------------------------- /avocado/wallet/cc_wallet/cc_info.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Optional, Tuple 3 | 4 | from avocado.types.blockchain_format.program import Program 5 | from avocado.types.blockchain_format.sized_bytes import bytes32 6 | from avocado.util.streamable import Streamable, streamable 7 | 8 | 9 | @dataclass(frozen=True) 10 | @streamable 11 | class CCInfo(Streamable): 12 | my_genesis_checker: Optional[Program] # this is the program 13 | lineage_proofs: List[Tuple[bytes32, Optional[Program]]] # {coin.name(): lineage_proof} 14 | -------------------------------------------------------------------------------- /avocado/wallet/derivation_record.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from blspy import G1Element 4 | 5 | from avocado.types.blockchain_format.sized_bytes import bytes32 6 | from avocado.util.ints import uint32 7 | from avocado.wallet.util.wallet_types import WalletType 8 | 9 | 10 | @dataclass(frozen=True) 11 | class DerivationRecord: 12 | """ 13 | These are records representing a puzzle hash, which is generated from a 14 | public key, derivation index, and wallet type. Stored in the puzzle_store. 15 | """ 16 | 17 | index: uint32 18 | puzzle_hash: bytes32 19 | pubkey: G1Element 20 | wallet_type: WalletType 21 | wallet_id: uint32 22 | -------------------------------------------------------------------------------- /avocado/wallet/did_wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/wallet/did_wallet/__init__.py -------------------------------------------------------------------------------- /avocado/wallet/did_wallet/did_info.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Optional, Tuple 3 | 4 | from avocado.types.blockchain_format.sized_bytes import bytes32 5 | from avocado.util.ints import uint64 6 | from avocado.util.streamable import streamable, Streamable 7 | from avocado.wallet.lineage_proof import LineageProof 8 | from avocado.types.blockchain_format.program import Program 9 | from avocado.types.blockchain_format.coin import Coin 10 | 11 | 12 | @dataclass(frozen=True) 13 | @streamable 14 | class DIDInfo(Streamable): 15 | origin_coin: Optional[Coin] # puzzlehash of this coin is our DID 16 | backup_ids: List[bytes] 17 | num_of_backup_ids_needed: uint64 18 | parent_info: List[Tuple[bytes32, Optional[LineageProof]]] # {coin.name(): LineageProof} 19 | current_inner: Optional[Program] # represents a Program as bytes 20 | temp_coin: Optional[Coin] # partially recovered wallet uses these to hold info 21 | temp_puzhash: Optional[bytes32] 22 | temp_pubkey: Optional[bytes] 23 | -------------------------------------------------------------------------------- /avocado/wallet/lineage_proof.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from avocado.types.blockchain_format.sized_bytes import bytes32 5 | from avocado.util.ints import uint64 6 | from avocado.util.streamable import Streamable, streamable 7 | 8 | 9 | @dataclass(frozen=True) 10 | @streamable 11 | class LineageProof(Streamable): 12 | parent_name: bytes32 13 | inner_puzzle_hash: Optional[bytes32] 14 | amount: uint64 15 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/wallet/puzzles/__init__.py -------------------------------------------------------------------------------- /avocado/wallet/puzzles/block_program_zero.clvm: -------------------------------------------------------------------------------- 1 | 2 | ; TODO convert generators arg to list of generators 3 | 4 | (mod (decompress_puzzle decompress_coin_solution_entry start end compressed_cses deserialize gen_list reserved_arg) 5 | 6 | (defun decompress_cses (decompress_puzzle decompress_coin_solution_entry cses deserialize puzzle_prefix) 7 | (if cses 8 | (c (a decompress_coin_solution_entry (list deserialize decompress_puzzle puzzle_prefix (f cses))) 9 | (decompress_cses decompress_puzzle decompress_coin_solution_entry (r cses) deserialize puzzle_prefix )) 10 | ()) ) 11 | 12 | (list (decompress_cses decompress_puzzle decompress_coin_solution_entry compressed_cses deserialize (substr (f gen_list) start end))) 13 | 14 | ) 15 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/block_program_zero.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff02ff02ffff04ff02ffff04ff05ffff04ff0bffff04ff5fffff04ff81bfffff04ffff0cff82027fff17ff2f80ff8080808080808080ff8080ffff04ffff01ff02ffff03ff17ffff01ff04ffff02ff0bffff04ff2fffff04ff05ffff04ff5fffff04ff27ff808080808080ffff02ff02ffff04ff02ffff04ff05ffff04ff0bffff04ff37ffff04ff2fffff04ff5fff808080808080808080ff8080ff0180ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/block_program_zero.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | f0a38c8efe58895ae527c65c37f700a4238504691b83990e5dd91bd8b3c30eae 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/calculate_synthetic_public_key.clvm: -------------------------------------------------------------------------------- 1 | (mod 2 | (public_key hidden_puzzle_hash) 3 | 4 | (point_add public_key (pubkey_for_exp (sha256 public_key hidden_puzzle_hash))) 5 | ) 6 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/calculate_synthetic_public_key.clvm.hex: -------------------------------------------------------------------------------- 1 | ff1dff02ffff1effff0bff02ff05808080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/calculate_synthetic_public_key.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 624c5d5704d0decadfc0503e71bbffb6cdfe45025bce7cf3e6864d1eafe8f65e 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/cc.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | d4596fa7aa6eaa267ebce8d527546827de083d58fb4e14f4137c2448f7252e5c 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/cc_loader.py: -------------------------------------------------------------------------------- 1 | from avocado.wallet.puzzles.load_clvm import load_clvm 2 | 3 | CC_MOD = load_clvm("cc.clvm", package_or_requirement=__name__) 4 | LOCK_INNER_PUZZLE = load_clvm("lock.inner.puzzle.clvm", package_or_requirement=__name__) 5 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/chialisp_deserialisation.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff05ffff02ff3effff04ff02ffff04ff05ff8080808080ffff04ffff01ffffff81ff7fff81df81bfffffff02ffff03ffff09ff0bffff01818080ffff01ff04ff80ffff04ff05ff808080ffff01ff02ffff03ffff0aff0bff1880ffff01ff02ff1affff04ff02ffff04ffff02ffff03ffff0aff0bff1c80ffff01ff02ffff03ffff0aff0bff1480ffff01ff0880ffff01ff04ffff0effff18ffff011fff0b80ffff0cff05ff80ffff01018080ffff04ffff0cff05ffff010180ff80808080ff0180ffff01ff04ffff18ffff013fff0b80ffff04ff05ff80808080ff0180ff80808080ffff01ff04ff0bffff04ff05ff80808080ff018080ff0180ff04ffff0cff15ff80ff0980ffff04ffff0cff15ff0980ff808080ffff04ffff04ff05ff1380ffff04ff2bff808080ffff02ff16ffff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ff15ff80808080ff8080808080ff02ffff03ffff09ffff0cff05ff80ffff010180ff1080ffff01ff02ff2effff04ff02ffff04ffff02ff3effff04ff02ffff04ffff0cff05ffff010180ff80808080ff80808080ffff01ff02ff12ffff04ff02ffff04ffff0cff05ffff010180ffff04ffff0cff05ff80ffff010180ff808080808080ff0180ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/chialisp_deserialisation.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 94ec19077f9a34e0b11ad2456af0170f4cc03f11230ca42e3f82e6e644ac4f5d 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/condition_codes.clvm: -------------------------------------------------------------------------------- 1 | ; See avocado/types/condition_opcodes.py 2 | 3 | ( 4 | (defconstant AGG_SIG_UNSAFE 49) 5 | (defconstant AGG_SIG_ME 50) 6 | 7 | ; the conditions below reserve coin amounts and have to be accounted for in output totals 8 | 9 | (defconstant CREATE_COIN 51) 10 | (defconstant RESERVE_FEE 52) 11 | 12 | ; the conditions below deal with announcements, for inter-coin communication 13 | 14 | ; coin announcements 15 | (defconstant CREATE_COIN_ANNOUNCEMENT 60) 16 | (defconstant ASSERT_COIN_ANNOUNCEMENT 61) 17 | 18 | ; puzzle announcements 19 | (defconstant CREATE_PUZZLE_ANNOUNCEMENT 62) 20 | (defconstant ASSERT_PUZZLE_ANNOUNCEMENT 63) 21 | 22 | ; the conditions below let coins inquire about themselves 23 | 24 | (defconstant ASSERT_MY_COIN_ID 70) 25 | (defconstant ASSERT_MY_PARENT_ID 71) 26 | (defconstant ASSERT_MY_PUZZLEHASH 72) 27 | (defconstant ASSERT_MY_AMOUNT 73) 28 | 29 | ; the conditions below ensure that we're "far enough" in the future 30 | 31 | ; wall-clock time 32 | (defconstant ASSERT_SECONDS_RELATIVE 80) 33 | (defconstant ASSERT_SECONDS_ABSOLUTE 81) 34 | 35 | ; block index 36 | (defconstant ASSERT_HEIGHT_RELATIVE 82) 37 | (defconstant ASSERT_HEIGHT_ABSOLUTE 83) 38 | ) 39 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/create-lock-puzzlehash.clvm: -------------------------------------------------------------------------------- 1 | ; This puzzle evaluates to an empty list , which means no conditions need to be satisfied; 2 | ; The puzzle can never evaluate to my-id. 3 | ; my-id is there on a discarded branch of the tree as a signal to another piece of code 4 | ; that will be checking if a coin whose puzzle is of this form, was created or spent. 5 | ( 6 | (defun-inline create-lock-puzzlehash (my-id) 7 | (sha256tree (list r 8 | (list c 9 | (list q 10 | my-id) 11 | (q (q ())))))) 12 | ) -------------------------------------------------------------------------------- /avocado/wallet/puzzles/create-lock-puzzlehash.clvm.hex.sha256tree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/wallet/puzzles/create-lock-puzzlehash.clvm.hex.sha256tree -------------------------------------------------------------------------------- /avocado/wallet/puzzles/decompress_coin_solution_entry.clvm: -------------------------------------------------------------------------------- 1 | (mod (deserialize decompress_puzzle puzzle_prefix suffix cse) 2 | 3 | ; decompress a single compressed standard transaction 4 | (c (f cse) (c (a decompress_puzzle (list deserialize puzzle_prefix (f (f (r cse))) suffix)) (c (f (r (f cse))) (r (f (r cse)))))) 5 | ) 6 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/decompress_coin_solution_entry.clvm.hex: -------------------------------------------------------------------------------- 1 | ff04ff4fffff04ffff02ff05ffff04ff02ffff04ff0bffff04ff82012fffff04ff17ff808080808080ffff04ff82014fff8201af808080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/decompress_coin_solution_entry.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 9d98ed08770d31be4bd1bde4705dab388db5e7e9c349f5a76fc3c347aa3a0b79 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/decompress_coin_solution_entry_with_prefix.clvm: -------------------------------------------------------------------------------- 1 | (mod (deserialize decompress_puzzle puzzle_prefix cse) 2 | 3 | ; decompress a single compressed standard transaction 4 | 5 | (c (f (f cse)) (c (a decompress_puzzle (list deserialize puzzle_prefix (f (f (r cse))) (q . 0xff018080))) (c (f (r (f cse))) (r (f (r cse)))))) 6 | 7 | ) 8 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/decompress_coin_solution_entry_with_prefix.clvm.hex: -------------------------------------------------------------------------------- 1 | ff04ff47ffff04ffff02ff05ffff04ff02ffff04ff0bffff04ff8197ffff01ff84ff0180808080808080ffff04ff81a7ff81d7808080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/decompress_coin_solution_entry_with_prefix.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 92aa4bc8060a8836355a1884075141b4791ce1b67ae6092bb166b2845954bc89 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/decompress_puzzle.clvm: -------------------------------------------------------------------------------- 1 | (mod (deserialize puzzle_prefix pubkey suffix) 2 | 3 | (a deserialize (list (concat puzzle_prefix pubkey suffix))) 4 | 5 | ) 6 | 7 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/decompress_puzzle.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ff02ffff04ffff0eff05ff0bff1780ff808080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/decompress_puzzle.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | fe94c58f1117afe315e0450daca1c62460ec1a1c439cd4018d79967a5d7d1370 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/did_innerpuz.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | f2356bc00a27abf46c72b809ba7d1d53bde533d94a7a3da8954155afe54304c4 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/generator_for_single_coin.clvm: -------------------------------------------------------------------------------- 1 | (mod (block_program block_ref coinname) 2 | 3 | (defconstant local_deserialize_mod 4 | ;; this monstrosity is the assembly output of `chialisp_deserialisation.clvm` 5 | ;; it's pasted in here because the compiler doesn't yet support nested `mod` 6 | ;; my apologies -- RK 7 | 8 | (a (q 5 (a 62 (c 2 (c 5 ())))) 9 | (c (q ((-1 . 127) -33 . -65) ((a (i (= 11 (q . -128)) (q 4 () (c 5 ())) (q 2 (i (>s 11 24) (q 2 26 (c 2 (c (a (i (>s 11 28) (q 2 (i (>s 11 20) (q 8) (q 4 (concat (logand (q . 31) 11) (substr 5 () (q . 1))) (c (substr 5 (q . 1)) ()))) 1) (q 4 (logand (q . 63) 11) (c 5 ()))) 1) ()))) (q 4 11 (c 5 ()))) 1)) 1) 4 (substr 21 () 9) (c (substr 21 9) ())) (c (c 5 19) (c 43 ())) (a 22 (c 2 (c 9 (c (a 62 (c 2 (c 21 ()))) ())))) 2 (i (= (substr 5 () (q . 1)) 16) (q 2 46 (c 2 (c (a 62 (c 2 (c (substr 5 (q . 1)) ()))) ()))) (q 2 18 (c 2 (c (substr 5 (q . 1)) (c (substr 5 () (q . 1)) ()))))) 1) 10 | 1)) 11 | ) 12 | 13 | ; takes a lisp tree and returns the hash of it 14 | (defun sha256tree1 (TREE) 15 | (if (l TREE) 16 | (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE))) 17 | (sha256 1 TREE))) 18 | 19 | (defun check_coin_solution ((parent puzzle amount solution) coinname) 20 | (= (sha256 parent (sha256tree1 puzzle) amount) coinname) 21 | ) 22 | 23 | (defun check_for_coinname (coin_solutions coinname) 24 | (if coin_solutions 25 | (if (check_coin_solution (f coin_solutions) coinname) 26 | (list (f (r (f coin_solutions))) (f (r (r (r (f coin_solutions)))))) 27 | (check_for_coinname (r coin_solutions) coinname) 28 | ) 29 | (x) 30 | ) 31 | ) 32 | 33 | ; main 34 | (check_for_coinname (f (a block_program (list local_deserialize_mod block_ref))) coinname) 35 | ) 36 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/generator_for_single_coin.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ff0cffff04ff02ffff04ffff05ffff02ff05ffff04ff0affff04ff0bff8080808080ffff04ff17ff8080808080ffff04ffff01ffffff09ffff0bff09ffff02ff0effff04ff02ffff04ff15ff80808080ff2d80ff0b80ff02ffff03ff05ffff01ff02ffff03ffff02ff08ffff04ff02ffff04ff09ffff04ff0bff8080808080ffff01ff04ff29ffff04ff81b9ff808080ffff01ff02ff0cffff04ff02ffff04ff0dffff04ff0bff808080808080ff0180ffff01ff088080ff0180ffff02ffff01ff05ffff02ff3effff04ff02ffff04ff05ff8080808080ffff04ffff01ffffff81ff7fff81df81bfffffff02ffff03ffff09ff0bffff01818080ffff01ff04ff80ffff04ff05ff808080ffff01ff02ffff03ffff0aff0bff1880ffff01ff02ff1affff04ff02ffff04ffff02ffff03ffff0aff0bff1c80ffff01ff02ffff03ffff0aff0bff1480ffff01ff0880ffff01ff04ffff0effff18ffff011fff0b80ffff0cff05ff80ffff01018080ffff04ffff0cff05ffff010180ff80808080ff0180ffff01ff04ffff18ffff013fff0b80ffff04ff05ff80808080ff0180ff80808080ffff01ff04ff0bffff04ff05ff80808080ff018080ff0180ff04ffff0cff15ff80ff0980ffff04ffff0cff15ff0980ff808080ffff04ffff04ff05ff1380ffff04ff2bff808080ffff02ff16ffff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ff15ff80808080ff8080808080ff02ffff03ffff09ffff0cff05ff80ffff010180ff1080ffff01ff02ff2effff04ff02ffff04ffff02ff3effff04ff02ffff04ffff0cff05ffff010180ff80808080ff80808080ffff01ff02ff12ffff04ff02ffff04ffff0cff05ffff010180ffff04ffff0cff05ff80ffff010180ff808080808080ff0180ff018080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff0effff04ff02ffff04ff09ff80808080ffff02ff0effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/generator_for_single_coin.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 303e2eeba68fd2d490a4af51dc9d175fcb33ae97a0ed242f9f08abc92c21898e 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/generator_loader.py: -------------------------------------------------------------------------------- 1 | from avocado.wallet.puzzles.load_clvm import load_serialized_clvm 2 | 3 | GENERATOR_FOR_SINGLE_COIN_MOD = load_serialized_clvm("generator_for_single_coin.clvm", package_or_requirement=__name__) 4 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/genesis-by-coin-id-with-0.clvm: -------------------------------------------------------------------------------- 1 | ; This is a "genesis checker" for use with cc.clvm. 2 | ; 3 | ; This checker allows new ccs to be created if they have a particular 4 | ; coin id as parent; or created by anyone if their value is 0. 5 | 6 | (mod ( 7 | genesis-id 8 | lineage-proof-parameters 9 | my-coin-info 10 | (parent-coin zero-parent-inner-puzzle-hash) 11 | ) 12 | 13 | ;; boolean or macro 14 | ;; This lets you write something like (if (or COND1 COND2 COND3) (do-something) (do-something-else)) 15 | (defmacro or ARGS 16 | (if ARGS 17 | (qq (if (unquote (f ARGS)) 18 | 1 19 | (unquote (c or (r ARGS))) 20 | )) 21 | 0) 22 | ) 23 | 24 | (defun-inline main ( 25 | genesis-id 26 | my-coin-info 27 | ) 28 | 29 | (or 30 | (= (f (r (r my-coin-info))) 0) 31 | (= (f my-coin-info) genesis-id) 32 | ) 33 | ) 34 | 35 | (main 36 | genesis-id 37 | my-coin-info 38 | ) 39 | ) -------------------------------------------------------------------------------- /avocado/wallet/puzzles/genesis-by-coin-id-with-0.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff03ffff09ff5bff8080ffff01ff0101ffff01ff02ffff03ffff09ff13ff0280ffff01ff0101ff8080ff018080ff0180 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/genesis-by-coin-id-with-0.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 258008f81f21c270f4b58488b108a46a35e5df43ca5b0313ac83e900a5e44a5f 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/genesis-by-puzzle-hash-with-0.clvm: -------------------------------------------------------------------------------- 1 | ; This is a "genesis checker" for use with cc.clvm. 2 | ; 3 | ; This checker allows new ccs to be created if their parent has a particular 4 | ; puzzle hash; or created by anyone if their value is 0. 5 | 6 | (mod ( 7 | genesis-puzzle-hash 8 | lineage-proof-parameters 9 | my-coin-info 10 | (parent-coin zero-parent-inner-puzzle-hash) 11 | ) 12 | 13 | ;; boolean and macro 14 | ;; This lets you write something like (if (and COND1 COND2 COND3) (do-something) (do-something-else)) 15 | (defmacro and ARGS 16 | (if ARGS 17 | (qq (if (unquote (f ARGS)) 18 | (unquote (c and (r ARGS))) 19 | () 20 | )) 21 | 1) 22 | ) 23 | 24 | ;; boolean or macro 25 | ;; This lets you write something like (if (or COND1 COND2 COND3) (do-something) (do-something-else)) 26 | (defmacro or ARGS 27 | (if ARGS 28 | (qq (if (unquote (f ARGS)) 29 | 1 30 | (unquote (c or (r ARGS))) 31 | )) 32 | 0) 33 | ) 34 | 35 | (defun-inline main ( 36 | genesis-puzzle-hash 37 | my-coin-info 38 | parent-coin 39 | ) 40 | 41 | (or 42 | (= (f (r (r my-coin-info))) 0) 43 | (and 44 | (= (sha256 (f parent-coin) (f (r parent-coin)) (f (r (r parent-coin)))) (f my-coin-info)) 45 | (= (f (r parent-coin)) genesis-puzzle-hash) 46 | ) 47 | ) 48 | ) 49 | 50 | (main 51 | genesis-puzzle-hash 52 | my-coin-info 53 | parent-coin 54 | ) 55 | ) -------------------------------------------------------------------------------- /avocado/wallet/puzzles/genesis-by-puzzle-hash-with-0.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff03ffff09ff5bff8080ffff01ff0101ffff01ff02ffff03ffff02ffff03ffff09ffff0bff47ff81a7ff82016780ff1380ffff01ff02ffff03ffff09ff81a7ff0280ffff01ff0101ff8080ff0180ff8080ff0180ffff01ff0101ff8080ff018080ff0180 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/genesis-by-puzzle-hash-with-0.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 795964e0324fbc08e8383d67659194a70455956ad1ebd2329ccf20008da00936 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/genesis_by_coin_id_with_0.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from avocado.types.blockchain_format.coin import Coin 4 | from avocado.types.blockchain_format.program import Program 5 | from avocado.types.blockchain_format.sized_bytes import bytes32 6 | from avocado.wallet.puzzles.load_clvm import load_clvm 7 | 8 | MOD = load_clvm("genesis-by-coin-id-with-0.clvm", package_or_requirement=__name__) 9 | 10 | 11 | def create_genesis_or_zero_coin_checker(genesis_coin_id: bytes32) -> Program: 12 | """ 13 | Given a specific genesis coin id, create a `genesis_coin_mod` that allows 14 | both that coin id to issue a cc, or anyone to create a cc with amount 0. 15 | """ 16 | genesis_coin_mod = MOD 17 | return genesis_coin_mod.curry(genesis_coin_id) 18 | 19 | 20 | def genesis_coin_id_for_genesis_coin_checker( 21 | genesis_coin_checker: Program, 22 | ) -> Optional[bytes32]: 23 | """ 24 | Given a `genesis_coin_checker` program, pull out the genesis coin id. 25 | """ 26 | r = genesis_coin_checker.uncurry() 27 | if r is None: 28 | return r 29 | f, args = r 30 | if f != MOD: 31 | return None 32 | return args.first().as_atom() 33 | 34 | 35 | def lineage_proof_for_genesis(parent_coin: Coin) -> Program: 36 | return Program.to((0, [parent_coin.as_list(), 0])) 37 | 38 | 39 | def lineage_proof_for_zero(parent_coin: Coin) -> Program: 40 | return Program.to((0, [parent_coin.as_list(), 1])) 41 | 42 | 43 | def lineage_proof_for_coin(parent_coin: Coin) -> Program: 44 | if parent_coin.amount == 0: 45 | return lineage_proof_for_zero(parent_coin) 46 | return lineage_proof_for_genesis(parent_coin) 47 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/genesis_by_puzzle_hash_with_0.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from avocado.types.blockchain_format.coin import Coin 4 | from avocado.types.blockchain_format.program import Program 5 | from avocado.types.blockchain_format.sized_bytes import bytes32 6 | from avocado.wallet.puzzles.load_clvm import load_clvm 7 | 8 | MOD = load_clvm("genesis-by-puzzle-hash-with-0.clvm", package_or_requirement=__name__) 9 | 10 | 11 | def create_genesis_puzzle_or_zero_coin_checker(genesis_puzzle_hash: bytes32) -> Program: 12 | """ 13 | Given a specific genesis coin id, create a `genesis_coin_mod` that allows 14 | both that coin id to issue a cc, or anyone to create a cc with amount 0. 15 | """ 16 | genesis_coin_mod = MOD 17 | return genesis_coin_mod.curry(genesis_puzzle_hash) 18 | 19 | 20 | def genesis_puzzle_hash_for_genesis_coin_checker( 21 | genesis_coin_checker: Program, 22 | ) -> Optional[bytes32]: 23 | """ 24 | Given a `genesis_coin_checker` program, pull out the genesis puzzle hash. 25 | """ 26 | r = genesis_coin_checker.uncurry() 27 | if r is None: 28 | return r 29 | f, args = r 30 | if f != MOD: 31 | return None 32 | return args.first().as_atom() 33 | 34 | 35 | def lineage_proof_for_genesis_puzzle(parent_coin: Coin) -> Program: 36 | return Program.to((0, [parent_coin.as_list(), 0])) 37 | 38 | 39 | def lineage_proof_for_zero(parent_coin: Coin) -> Program: 40 | return Program.to((0, [parent_coin.as_list(), 1])) 41 | 42 | 43 | def lineage_proof_for_coin(parent_coin: Coin) -> Program: 44 | if parent_coin.amount == 0: 45 | return lineage_proof_for_zero(parent_coin) 46 | return lineage_proof_for_genesis_puzzle(parent_coin) 47 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/load_clvm.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | 3 | import pkg_resources 4 | from clvm_tools.clvmc import compile_clvm 5 | 6 | from avocado.types.blockchain_format.program import Program, SerializedProgram 7 | 8 | 9 | def load_serialized_clvm(clvm_filename, package_or_requirement=__name__) -> SerializedProgram: 10 | """ 11 | This function takes a .clvm file in the given package and compiles it to a 12 | .clvm.hex file if the .hex file is missing or older than the .clvm file, then 13 | returns the contents of the .hex file as a `Program`. 14 | 15 | clvm_filename: file name 16 | package_or_requirement: usually `__name__` if the clvm file is in the same package 17 | """ 18 | 19 | hex_filename = f"{clvm_filename}.hex" 20 | 21 | try: 22 | if pkg_resources.resource_exists(package_or_requirement, clvm_filename): 23 | full_path = pathlib.Path(pkg_resources.resource_filename(package_or_requirement, clvm_filename)) 24 | output = full_path.parent / hex_filename 25 | compile_clvm(full_path, output, search_paths=[full_path.parent]) 26 | except NotImplementedError: 27 | # pyinstaller doesn't support `pkg_resources.resource_exists` 28 | # so we just fall through to loading the hex clvm 29 | pass 30 | 31 | clvm_hex = pkg_resources.resource_string(package_or_requirement, hex_filename).decode("utf8") 32 | clvm_blob = bytes.fromhex(clvm_hex) 33 | return SerializedProgram.from_bytes(clvm_blob) 34 | 35 | 36 | def load_clvm(clvm_filename, package_or_requirement=__name__) -> Program: 37 | return Program.from_bytes(bytes(load_serialized_clvm(clvm_filename, package_or_requirement=__name__))) 38 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/lock.inner.puzzle.clvm: -------------------------------------------------------------------------------- 1 | ; a trivial puzzle used as the core of a lock puzzle 2 | (mod args (q ())) 3 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/lock.inner.puzzle.clvm.hex: -------------------------------------------------------------------------------- 1 | ff01ff8080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/lock.inner.puzzle.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | f3a579254623f8094e07af862df2e45c9db5592b4105d34a256dd6c498416288 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_conditions.clvm: -------------------------------------------------------------------------------- 1 | (mod (conditions) 2 | (qq (q . (unquote conditions))) 3 | ) 4 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_conditions.clvm.hex: -------------------------------------------------------------------------------- 1 | ff04ffff0101ff0280 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_conditions.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 1c77d7d5efde60a7a1d2d27db6d746bc8e568aea1ef8586ca967a0d60b83cc36 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_conditions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Pay to conditions 3 | 4 | In this puzzle program, the solution is ignored. The reveal of the puzzle 5 | returns a fixed list of conditions. This roughly corresponds to OP_SECURETHEBAG 6 | in bitcoin. 7 | 8 | This is a pretty useless most of the time. But some (most?) solutions 9 | require a delegated puzzle program, so in those cases, this is just what 10 | the doctor ordered. 11 | """ 12 | 13 | from avocado.types.blockchain_format.program import Program 14 | 15 | from .load_clvm import load_clvm 16 | 17 | MOD = load_clvm("p2_conditions.clvm") 18 | 19 | 20 | def puzzle_for_conditions(conditions) -> Program: 21 | return MOD.run([conditions]) 22 | 23 | 24 | def solution_for_conditions(conditions) -> Program: 25 | return Program.to([puzzle_for_conditions(conditions), 0]) 26 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_delegated_conditions.clvm: -------------------------------------------------------------------------------- 1 | (mod 2 | (public_key conditions) 3 | 4 | (include condition_codes.clvm) 5 | 6 | ;; hash a tree 7 | ;; This is used to calculate a puzzle hash given a puzzle program. 8 | (defun sha256tree1 9 | (TREE) 10 | (if (l TREE) 11 | (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE))) 12 | (sha256 1 TREE) 13 | ) 14 | ) 15 | 16 | (c (list AGG_SIG_ME public_key (sha256tree1 conditions)) conditions) 17 | 18 | ) 19 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_delegated_conditions.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff0bff80808080ff80808080ff0b80ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_delegated_conditions.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 0ff94726f1a8dea5c3f70d3121945190778d3b2b3fcda3735a1f290977e98341 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_delegated_conditions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Pay to delegated conditions 3 | 4 | In this puzzle program, the solution must be a signed list of conditions, which 5 | is returned literally. 6 | """ 7 | 8 | 9 | from avocado.types.blockchain_format.program import Program 10 | 11 | from .load_clvm import load_clvm 12 | 13 | MOD = load_clvm("p2_delegated_conditions.clvm") 14 | 15 | 16 | def puzzle_for_pk(public_key: Program) -> Program: 17 | return MOD.curry(public_key) 18 | 19 | 20 | def solution_for_conditions(conditions: Program) -> Program: 21 | return conditions.to([conditions]) 22 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_delegated_puzzle.clvm: -------------------------------------------------------------------------------- 1 | (mod 2 | 3 | (public_key delegated_puzzle delegated_puzzle_solution) 4 | 5 | (include condition_codes.clvm) 6 | 7 | ;; hash a tree 8 | ;; This is used to calculate a puzzle hash given a puzzle program. 9 | (defun sha256tree1 10 | (TREE) 11 | (if (l TREE) 12 | (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE))) 13 | (sha256 1 TREE) 14 | ) 15 | ) 16 | 17 | (c (list AGG_SIG_ME public_key (sha256tree1 delegated_puzzle)) 18 | (a delegated_puzzle delegated_puzzle_solution)) 19 | ) 20 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_delegated_puzzle.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff0bff80808080ff80808080ffff02ff0bff178080ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_delegated_puzzle.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 542cde70d1102cd1b763220990873efc8ab15625ded7eae22cc11e21ef2e2f7c 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_delegated_puzzle.py: -------------------------------------------------------------------------------- 1 | """ 2 | Pay to delegated puzzle 3 | 4 | In this puzzle program, the solution must be a signed delegated puzzle, along with 5 | its (unsigned) solution. The delegated puzzle is executed, passing in the solution. 6 | This obviously could be done recursively, arbitrarily deep (as long as the maximum 7 | cost is not exceeded). 8 | 9 | If you want to specify the conditions directly (thus terminating the potential recursion), 10 | you can use p2_conditions. 11 | 12 | This roughly corresponds to bitcoin's graftroot. 13 | """ 14 | 15 | from avocado.types.blockchain_format.program import Program 16 | 17 | from . import p2_conditions 18 | from .load_clvm import load_clvm 19 | 20 | MOD = load_clvm("p2_delegated_puzzle.clvm") 21 | 22 | 23 | def puzzle_for_pk(public_key: bytes) -> Program: 24 | return MOD.curry(public_key) 25 | 26 | 27 | def solution_for_conditions(conditions) -> Program: 28 | delegated_puzzle = p2_conditions.puzzle_for_conditions(conditions) 29 | return solution_for_delegated_puzzle(delegated_puzzle, Program.to(0)) 30 | 31 | 32 | def solution_for_delegated_puzzle(delegated_puzzle: Program, delegated_solution: Program) -> Program: 33 | return delegated_puzzle.to([delegated_puzzle, delegated_solution]) 34 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff05ffff1dff0bffff1effff0bff0bffff02ff06ffff04ff02ffff04ff17ff8080808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff17ff80808080ff80808080ffff02ff17ff2f808080ff0180ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | e9aaa49f45bad5c889b86ee3341550c155cfdd10c3a6757de618d20612fffd52 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_m_of_n_delegate_direct.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ffff09ff05ffff02ff16ffff04ff02ffff04ff17ff8080808080ffff01ff02ff0cffff04ff02ffff04ffff02ff0affff04ff02ffff04ff17ffff04ff0bff8080808080ffff04ffff02ff1effff04ff02ffff04ff2fff80808080ffff04ff2fffff04ff5fff80808080808080ffff01ff088080ff0180ffff04ffff01ffff31ff02ffff03ff05ffff01ff04ffff04ff08ffff04ff09ffff04ff0bff80808080ffff02ff0cffff04ff02ffff04ff0dffff04ff0bffff04ff17ffff04ff2fff8080808080808080ffff01ff02ff17ff2f8080ff0180ffff02ffff03ff05ffff01ff02ffff03ff09ffff01ff04ff13ffff02ff0affff04ff02ffff04ff0dffff04ff1bff808080808080ffff01ff02ff0affff04ff02ffff04ff0dffff04ff1bff808080808080ff0180ff8080ff0180ffff02ffff03ff05ffff01ff10ffff02ff16ffff04ff02ffff04ff0dff80808080ffff02ffff03ff09ffff01ff0101ff8080ff018080ff8080ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_m_of_n_delegate_direct.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 0f199d5263ac1a62b077c159404a71abd3f9691cc57520bf1d4c5cb501504457 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_m_of_n_delegate_direct.py: -------------------------------------------------------------------------------- 1 | """ 2 | Pay to m of n direct 3 | 4 | This puzzle program is like p2_delegated_puzzle except instead of one public key, 5 | it includes N public keys, any M of which needs to sign the delegated puzzle. 6 | """ 7 | 8 | from avocado.types.blockchain_format.program import Program 9 | 10 | from .load_clvm import load_clvm 11 | 12 | MOD = load_clvm("p2_m_of_n_delegate_direct.clvm") 13 | 14 | 15 | def puzzle_for_m_of_public_key_list(m, public_key_list) -> Program: 16 | return MOD.curry(m, public_key_list) 17 | 18 | 19 | def solution_for_delegated_puzzle(m, selectors, puzzle, solution) -> Program: 20 | return Program.to([selectors, puzzle, solution]) 21 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_puzzle_hash.clvm: -------------------------------------------------------------------------------- 1 | (mod 2 | (inner_puzzle_hash inner_puzzle inner_puzzle_solution) 3 | 4 | ;; hash a tree 5 | ;; This is used to calculate a puzzle hash given a puzzle program. 6 | (defun sha256tree1 7 | (TREE) 8 | (if (l TREE) 9 | (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE))) 10 | (sha256 1 TREE) 11 | ) 12 | ) 13 | 14 | (if (= inner_puzzle_hash (sha256tree1 inner_puzzle)) 15 | (a inner_puzzle inner_puzzle_solution) 16 | (x) 17 | ) 18 | ) -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_puzzle_hash.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ffff09ff05ffff02ff02ffff04ff02ffff04ff0bff8080808080ffff01ff02ff0bff1780ffff01ff088080ff0180ffff04ffff01ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff02ffff04ff02ffff04ff09ff80808080ffff02ff02ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_puzzle_hash.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 13e29a62b42cd2ef72a79e4bacdc59733ca6310d65af83d349360d36ec622363 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_puzzle_hash.py: -------------------------------------------------------------------------------- 1 | """ 2 | Pay to puzzle hash 3 | 4 | In this puzzle program, the solution must be a reveal of the puzzle with the given 5 | hash along with its solution. 6 | """ 7 | 8 | from avocado.types.blockchain_format.program import Program 9 | from avocado.types.blockchain_format.sized_bytes import bytes32 10 | 11 | from .load_clvm import load_clvm 12 | 13 | MOD = load_clvm("p2_puzzle_hash.clvm") 14 | 15 | 16 | def puzzle_for_inner_puzzle_hash(inner_puzzle_hash: bytes32) -> Program: 17 | program = MOD.curry(inner_puzzle_hash) 18 | return program 19 | 20 | 21 | def puzzle_for_inner_puzzle(inner_puzzle: Program) -> Program: 22 | return puzzle_for_inner_puzzle_hash(inner_puzzle.get_tree_hash()) 23 | 24 | 25 | def solution_for_inner_puzzle_and_inner_solution(inner_puzzle: Program, inner_puzzle_solution: Program) -> Program: 26 | return Program.to([inner_puzzle, inner_puzzle_solution]) 27 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_singleton.clvm: -------------------------------------------------------------------------------- 1 | (mod (SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH singleton_inner_puzzle_hash my_id) 2 | 3 | ; SINGLETON_MOD_HASH is the mod-hash for the singleton_top_layer puzzle 4 | ; LAUNCHER_ID is the ID of the singleton we are commited to paying to 5 | ; LAUNCHER_PUZZLE_HASH is the puzzle hash of the launcher 6 | ; singleton_inner_puzzle_hash is the innerpuzzlehash for our singleton at the current time 7 | ; my_id is the coin_id of the coin that this puzzle is locked into 8 | 9 | (include condition_codes.clvm) 10 | (include curry-and-treehash.clinc) 11 | 12 | ; takes a lisp tree and returns the hash of it 13 | (defun sha256tree (TREE) 14 | (if (l TREE) 15 | (sha256 2 (sha256tree (f TREE)) (sha256tree (r TREE))) 16 | (sha256 1 TREE) 17 | ) 18 | ) 19 | 20 | ;; return the full puzzlehash for a singleton with the innerpuzzle curried in 21 | ; puzzle-hash-of-curried-function is imported from curry-and-treehash.clinc 22 | (defun-inline calculate_full_puzzle_hash (SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH inner_puzzle_hash) 23 | (puzzle-hash-of-curried-function SINGLETON_MOD_HASH 24 | inner_puzzle_hash 25 | (sha256tree (c SINGLETON_MOD_HASH (c LAUNCHER_ID LAUNCHER_PUZZLE_HASH))) 26 | ) 27 | ) 28 | 29 | (defun-inline claim_rewards (SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH singleton_inner_puzzle_hash my_id) 30 | (list 31 | (list ASSERT_PUZZLE_ANNOUNCEMENT (sha256 (calculate_full_puzzle_hash SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH singleton_inner_puzzle_hash) my_id)) 32 | (list CREATE_COIN_ANNOUNCEMENT '$') 33 | (list ASSERT_MY_COIN_ID my_id)) 34 | ) 35 | 36 | ; main 37 | (claim_rewards SINGLETON_MOD_HASH LAUNCHER_ID LAUNCHER_PUZZLE_HASH singleton_inner_puzzle_hash my_id) 38 | ) 39 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_singleton.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff04ff18ffff04ffff0bffff02ff2effff04ff02ffff04ff05ffff04ff2fffff04ffff02ff3effff04ff02ffff04ffff04ff05ffff04ff0bff178080ff80808080ff808080808080ff5f80ff808080ffff04ffff04ff2cffff01ff248080ffff04ffff04ff10ffff04ff5fff808080ff80808080ffff04ffff01ffffff463fff02ff3c04ffff01ff0102ffff02ffff03ff05ffff01ff02ff16ffff04ff02ffff04ff0dffff04ffff0bff3affff0bff12ff3c80ffff0bff3affff0bff3affff0bff12ff2a80ff0980ffff0bff3aff0bffff0bff12ff8080808080ff8080808080ffff010b80ff0180ffff0bff3affff0bff12ff1480ffff0bff3affff0bff3affff0bff12ff2a80ff0580ffff0bff3affff02ff16ffff04ff02ffff04ff07ffff04ffff0bff12ff1280ff8080808080ffff0bff12ff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_singleton.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 40f828d8dd55603f4ff9fbf6b73271e904e69406982f4fbefae2c8dcceaf9834 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_singleton_or_delayed_puzhash.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ff82017fffff01ff04ffff04ff38ffff04ffff0bffff02ff2effff04ff02ffff04ff05ffff04ff81bfffff04ffff02ff3effff04ff02ffff04ffff04ff05ffff04ff0bff178080ff80808080ff808080808080ff82017f80ff808080ffff04ffff04ff3cffff01ff248080ffff04ffff04ff28ffff04ff82017fff808080ff80808080ffff01ff04ffff04ff24ffff04ff2fff808080ffff04ffff04ff2cffff04ff5fffff04ff81bfff80808080ffff04ffff04ff10ffff04ff81bfff808080ff8080808080ff0180ffff04ffff01ffffff49ff463fffff5002ff333cffff04ff0101ffff02ff02ffff03ff05ffff01ff02ff36ffff04ff02ffff04ff0dffff04ffff0bff26ffff0bff2aff1280ffff0bff26ffff0bff26ffff0bff2aff3a80ff0980ffff0bff26ff0bffff0bff2aff8080808080ff8080808080ffff010b80ff0180ffff0bff26ffff0bff2aff3480ffff0bff26ffff0bff26ffff0bff2aff3a80ff0580ffff0bff26ffff02ff36ffff04ff02ffff04ff07ffff04ffff0bff2aff2a80ff8080808080ffff0bff2aff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/p2_singleton_or_delayed_puzhash.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | adb656e0211e2ab4f42069a4c5efc80dc907e7062be08bf1628c8e5b6d94d25b 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/pool_member_innerpuz.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ff8202ffffff01ff02ff16ffff04ff02ffff04ff05ffff04ff8204bfffff04ff8206bfffff04ff82017fffff04ffff0bffff19ff2fffff18ffff019100ffffffffffffffffffffffffffffffffff8202ff8080ff0bff82017f80ff8080808080808080ffff01ff04ffff04ff08ffff04ff17ffff04ffff02ff1effff04ff02ffff04ff82017fff80808080ff80808080ffff04ffff04ff1cffff04ff5fffff04ff8206bfff80808080ff80808080ff0180ffff04ffff01ffff32ff3d33ff3effff04ffff04ff1cffff04ff0bffff04ff17ff80808080ffff04ffff04ff1cffff04ff05ffff04ff2fff80808080ffff04ffff04ff0affff04ff5fff808080ffff04ffff04ff14ffff04ffff0bff5fffff012480ff808080ff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/pool_member_innerpuz.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | a8490702e333ddd831a3ac9c22d0fa26d2bfeaf2d33608deb22f0e0123eb0494 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/pool_waitingroom_innerpuz.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ff82017fffff01ff04ffff04ff1cffff04ff5fff808080ffff04ffff04ff12ffff04ff8205ffffff04ff8206bfff80808080ffff04ffff04ff08ffff04ff17ffff04ffff02ff1effff04ff02ffff04ffff04ff8205ffffff04ff8202ffff808080ff80808080ff80808080ff80808080ffff01ff02ff16ffff04ff02ffff04ff05ffff04ff8204bfffff04ff8206bfffff04ff8202ffffff04ffff0bffff19ff2fffff18ffff019100ffffffffffffffffffffffffffffffffff8205ff8080ff0bff8202ff80ff808080808080808080ff0180ffff04ffff01ffff32ff3d52ffff333effff04ffff04ff12ffff04ff0bffff04ff17ff80808080ffff04ffff04ff12ffff04ff05ffff04ff2fff80808080ffff04ffff04ff1affff04ff5fff808080ffff04ffff04ff14ffff04ffff0bff5fffff012480ff808080ff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/pool_waitingroom_innerpuz.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | a317541a765bf8375e1c6e7c13503d0d2cbf56cacad5182befe947e78e2c0307 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/puzzle_utils.py: -------------------------------------------------------------------------------- 1 | from avocado.util.condition_tools import ConditionOpcode 2 | 3 | 4 | def make_create_coin_condition(puzzle_hash, amount): 5 | return [ConditionOpcode.CREATE_COIN, puzzle_hash, amount] 6 | 7 | 8 | def make_assert_aggsig_condition(pubkey): 9 | return [ConditionOpcode.AGG_SIG_UNSAFE, pubkey] 10 | 11 | 12 | def make_assert_my_coin_id_condition(coin_name): 13 | return [ConditionOpcode.ASSERT_MY_COIN_ID, coin_name] 14 | 15 | 16 | def make_assert_absolute_height_exceeds_condition(block_index): 17 | return [ConditionOpcode.ASSERT_HEIGHT_ABSOLUTE, block_index] 18 | 19 | 20 | def make_assert_relative_height_exceeds_condition(block_index): 21 | return [ConditionOpcode.ASSERT_HEIGHT_RELATIVE, block_index] 22 | 23 | 24 | def make_assert_absolute_seconds_exceeds_condition(time): 25 | return [ConditionOpcode.ASSERT_SECONDS_ABSOLUTE, time] 26 | 27 | 28 | def make_assert_relative_seconds_exceeds_condition(time): 29 | return [ConditionOpcode.ASSERT_SECONDS_RELATIVE, time] 30 | 31 | 32 | def make_reserve_fee_condition(fee): 33 | return [ConditionOpcode.RESERVE_FEE, fee] 34 | 35 | 36 | def make_assert_coin_announcement(announcement_hash): 37 | return [ConditionOpcode.ASSERT_COIN_ANNOUNCEMENT, announcement_hash] 38 | 39 | 40 | def make_assert_puzzle_announcement(announcement_hash): 41 | return [ConditionOpcode.ASSERT_PUZZLE_ANNOUNCEMENT, announcement_hash] 42 | 43 | 44 | def make_create_coin_announcement(message): 45 | return [ConditionOpcode.CREATE_COIN_ANNOUNCEMENT, message] 46 | 47 | 48 | def make_create_puzzle_announcement(message): 49 | return [ConditionOpcode.CREATE_PUZZLE_ANNOUNCEMENT, message] 50 | 51 | 52 | def make_assert_my_parent_id(parent_id): 53 | return [ConditionOpcode.ASSERT_MY_PARENT_ID, parent_id] 54 | 55 | 56 | def make_assert_my_puzzlehash(puzzlehash): 57 | return [ConditionOpcode.ASSERT_MY_PUZZLEHASH, puzzlehash] 58 | 59 | 60 | def make_assert_my_amount(amount): 61 | return [ConditionOpcode.ASSERT_MY_AMOUNT, amount] 62 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/recompile-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This hack is a quick way to recompile everything in this directory 4 | 5 | #BASE_DIR=`pwd | dirname` 6 | 7 | FILES=$(ls ./*.clvm) 8 | echo "$FILES" 9 | 10 | INCLUDE_DIR=$(pwd) 11 | 12 | for FILE in $FILES 13 | do 14 | echo "run -d -i $INCLUDE_DIR $FILE > $FILE.hex" 15 | # run -d -i $INCLUDE_DIR $FILE > $FILE.hex 16 | done 17 | 18 | for FILE in $FILES 19 | do 20 | echo "opd -H $FILE.hex | head -1 > $FILE.hex.sha256tree" 21 | done 22 | 23 | echo 24 | echo "Copy & paste the above to the shell to recompile" 25 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/rl.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ffff09ff81bfff2480ffff01ff04ffff04ff30ffff04ff5fffff04ffff02ff3effff04ff02ffff04ffff04ff81bfff81ff80ff80808080ff80808080ff81ff80ffff01ff04ffff04ff30ffff04ff05ffff04ffff02ff3effff04ff02ffff04ffff04ff81bfff81ff80ff80808080ff80808080ffff02ffff03ffff09ff81bfff3c80ffff01ff02ff2effff04ff02ffff04ff0bffff04ff17ffff04ff2fffff04ff81ffff80808080808080ffff01ff02ff22ffff04ff02ffff04ff2fffff04ff81ffff808080808080ff01808080ff0180ffff04ffff01ffffffffff02ffff03ffff15ff05ff0b80ffff01ff0101ffff01ff02ffff03ffff09ff05ff0b80ffff01ff0101ff8080ff018080ff018031ff5246ffff0333ff3c01ffffffff02ffff03ffff02ffff03ffff09ffff0bff820bfbff13ff8205fb80ff82017b80ffff01ff0101ffff01ff02ffff03ffff09ff05ff82017b80ffff01ff0101ff8080ff018080ff0180ffff01ff04ffff02ff26ffff04ff02ffff04ff82017bffff04ff13ffff04ff8202fbff808080808080ffff04ffff02ff2affff04ff02ffff04ff2bffff04ff5bffff04ff81bbff808080808080ffff04ffff02ff3affff04ff02ffff04ff13ffff04ffff10ff81bbff8202fb80ff8080808080ff80808080ffff01ffff08808080ff0180ff04ff34ffff04ff05ffff04ffff11ff0bffff10ff17ff2f8080ff80808080ffff04ff2cffff04ffff0bff05ff0bff1780ff808080ff04ff34ffff04ff05ffff04ff0bff80808080ffffff04ff38ffff04ffff0bff05ff0bff1780ff808080ff02ffff03ffff02ff20ffff04ff02ffff04ffff12ff05ff1780ffff04ffff12ff0bff2f80ff8080808080ffff01ff04ff28ffff04ff05ff808080ffff01ffff08808080ff0180ffff02ffff03ffff02ffff03ffff09ffff0bff8217efff81afff822fef80ff4f80ffff01ff0101ffff01ff02ffff03ffff09ff17ff4f80ffff01ff0101ff8080ff018080ff0180ffff01ff04ffff02ff36ffff04ff02ffff04ff820befffff04ff8205efffff04ff05ffff04ff0bff80808080808080ffff04ffff02ff32ffff04ff02ffff04ff81afffff04ff82016fffff04ff8205efffff04ff825fefff80808080808080ffff04ffff02ff26ffff04ff02ffff04ff4fffff04ff81afffff04ff82016fff808080808080ffff04ffff02ff3affff04ff02ffff04ff8202efffff04ff8205efff8080808080ff8080808080ffff01ffff08808080ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/rl.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | f663796a8c522b85bd9472cbea2bf7f138e8351e8e4032706fc0539e87f94faf 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/rl_aggregation.clvm: -------------------------------------------------------------------------------- 1 | (mod (wallet_puzzle 2 | my-id 3 | wallet-coin-primary-input 4 | wallet-coin-amount) 5 | 6 | (include condition_codes.clvm) 7 | 8 | (defun sha256tree (tree) 9 | (if (l tree) 10 | (sha256 2 (sha256tree (f tree)) (sha256tree (r tree))) 11 | (sha256 1 tree))) 12 | 13 | (defun-inline create-my-id-condition () 14 | (list ASSERT_MY_COIN_ID my-id)) 15 | 16 | (include create-lock-puzzlehash.clvm) 17 | 18 | (defun-inline parent-coin-id () 19 | (sha256 wallet-coin-primary-input wallet_puzzle wallet-coin-amount)) 20 | 21 | (defun-inline input-of-lock () 22 | (list ASSERT_COIN_ANNOUNCEMENT (sha256 (parent-coin-id) my-id))) 23 | 24 | (list (create-my-id-condition) 25 | (input-of-lock)) 26 | ) 27 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/rl_aggregation.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff04ff06ffff04ff0bff808080ffff04ffff04ff04ffff04ffff0bffff0bff17ff05ff2f80ff0b80ff808080ff808080ffff04ffff01ff3d46ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/rl_aggregation.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 007400187f63927ee023a7172bb88f14d49aaa4beb790ecaf7dde7c1a79b6481 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/rom_bootstrap_generator.clvm: -------------------------------------------------------------------------------- 1 | (mod (block_decompresser_program (historical_blocks_tree)) 2 | 3 | (defconstant local_deserialize_mod 4 | ;; this monstrosity is the assembly output of `chialisp_deserialisation.clvm` 5 | ;; it's pasted in here because the compiler doesn't yet support nested `mod` 6 | ;; my apologies -- RK 7 | 8 | (a (q 5 (a 62 (c 2 (c 5 ())))) 9 | (c (q ((-1 . 127) -33 . -65) ((a (i (= 11 (q . -128)) (q 4 () (c 5 ())) (q 2 (i (>s 11 24) (q 2 26 (c 2 (c (a (i (>s 11 28) (q 2 (i (>s 11 20) (q 8) (q 4 (concat (logand (q . 31) 11) (substr 5 () (q . 1))) (c (substr 5 (q . 1)) ()))) 1) (q 4 (logand (q . 63) 11) (c 5 ()))) 1) ()))) (q 4 11 (c 5 ()))) 1)) 1) 4 (substr 21 () 9) (c (substr 21 9) ())) (c (c 5 19) (c 43 ())) (a 22 (c 2 (c 9 (c (a 62 (c 2 (c 21 ()))) ())))) 2 (i (= (substr 5 () (q . 1)) 16) (q 2 46 (c 2 (c (a 62 (c 2 (c (substr 5 (q . 1)) ()))) ()))) (q 2 18 (c 2 (c (substr 5 (q . 1)) (c (substr 5 () (q . 1)) ()))))) 1) 10 | 1)) 11 | ) 12 | 13 | (defun sha256tree 14 | (TREE) 15 | (if (l TREE) 16 | (sha256 2 (sha256tree (f TREE)) (sha256tree (r TREE))) 17 | (sha256 1 TREE) 18 | ) 19 | ) 20 | 21 | (defun process_coin_solution ((parent puzzle amount solution . spend_level_extras)) 22 | (c parent (c (sha256tree puzzle) (c amount (c (a puzzle solution) spend_level_extras)))) 23 | ) 24 | 25 | (defun recurse (coin_solutions) 26 | (if coin_solutions 27 | (c (process_coin_solution (f coin_solutions)) (recurse (r coin_solutions))) 28 | 0 29 | ) 30 | ) 31 | 32 | (defun process-decompressor ((coin_solutions . block-level-extras)) 33 | (c (recurse coin_solutions) block-level-extras) 34 | ) 35 | 36 | (process-decompressor (a block_decompresser_program (list local_deserialize_mod historical_blocks_tree)))) 37 | ) 38 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/rom_bootstrap_generator.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ff0cffff04ff02ffff04ffff02ff05ffff04ff08ffff04ff13ff80808080ff80808080ffff04ffff01ffffff02ffff01ff05ffff02ff3effff04ff02ffff04ff05ff8080808080ffff04ffff01ffffff81ff7fff81df81bfffffff02ffff03ffff09ff0bffff01818080ffff01ff04ff80ffff04ff05ff808080ffff01ff02ffff03ffff0aff0bff1880ffff01ff02ff1affff04ff02ffff04ffff02ffff03ffff0aff0bff1c80ffff01ff02ffff03ffff0aff0bff1480ffff01ff0880ffff01ff04ffff0effff18ffff011fff0b80ffff0cff05ff80ffff01018080ffff04ffff0cff05ffff010180ff80808080ff0180ffff01ff04ffff18ffff013fff0b80ffff04ff05ff80808080ff0180ff80808080ffff01ff04ff0bffff04ff05ff80808080ff018080ff0180ff04ffff0cff15ff80ff0980ffff04ffff0cff15ff0980ff808080ffff04ffff04ff05ff1380ffff04ff2bff808080ffff02ff16ffff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ff15ff80808080ff8080808080ff02ffff03ffff09ffff0cff05ff80ffff010180ff1080ffff01ff02ff2effff04ff02ffff04ffff02ff3effff04ff02ffff04ffff0cff05ffff010180ff80808080ff80808080ffff01ff02ff12ffff04ff02ffff04ffff0cff05ffff010180ffff04ffff0cff05ff80ffff010180ff808080808080ff0180ff018080ff04ffff02ff16ffff04ff02ffff04ff09ff80808080ff0d80ffff04ff09ffff04ffff02ff1effff04ff02ffff04ff15ff80808080ffff04ff2dffff04ffff02ff15ff5d80ff7d80808080ffff02ffff03ff05ffff01ff04ffff02ff0affff04ff02ffff04ff09ff80808080ffff02ff16ffff04ff02ffff04ff0dff8080808080ff8080ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/rom_bootstrap_generator.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 161bade1f822dcd62ab712ebaf30f3922a301e48a639e4295c5685f8bece7bd9 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/rom_bootstrap_generator.py: -------------------------------------------------------------------------------- 1 | from avocado.types.blockchain_format.program import SerializedProgram 2 | 3 | from .load_clvm import load_clvm 4 | 5 | MOD = SerializedProgram.from_bytes(load_clvm("rom_bootstrap_generator.clvm").as_bin()) 6 | 7 | 8 | def get_generator(): 9 | return MOD 10 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/sha256tree_module.clvm: -------------------------------------------------------------------------------- 1 | ( 2 | mod (program) 3 | 4 | ;; hash a tree 5 | ;; This is used to calculate a puzzle hash given a puzzle program. 6 | (defun sha256tree 7 | (TREE) 8 | (if (l TREE) 9 | (sha256 2 (sha256tree (f TREE)) (sha256tree (r TREE))) 10 | (sha256 1 TREE) 11 | ) 12 | ) 13 | 14 | (sha256tree program) 15 | ) -------------------------------------------------------------------------------- /avocado/wallet/puzzles/sha256tree_module.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ff02ffff04ff02ffff04ff05ff80808080ffff04ffff01ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff02ffff04ff02ffff04ff09ff80808080ffff02ff02ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/sha256tree_module.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | eb4ead6576048c9d730b5ced00646c7fdd390649cfdf48a00de1590cdd8ee18f 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/singleton_launcher.clvm: -------------------------------------------------------------------------------- 1 | (mod (singleton_full_puzzle_hash amount key_value_list) 2 | 3 | (include condition_codes.clvm) 4 | 5 | ; takes a lisp tree and returns the hash of it 6 | (defun sha256tree1 (TREE) 7 | (if (l TREE) 8 | (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE))) 9 | (sha256 1 TREE) 10 | ) 11 | ) 12 | 13 | ; main 14 | (list (list CREATE_COIN singleton_full_puzzle_hash amount) 15 | (list CREATE_COIN_ANNOUNCEMENT (sha256tree1 (list singleton_full_puzzle_hash amount key_value_list)))) 16 | ) 17 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/singleton_launcher.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff04ff04ffff04ff05ffff04ff0bff80808080ffff04ffff04ff0affff04ffff02ff0effff04ff02ffff04ffff04ff05ffff04ff0bffff04ff17ff80808080ff80808080ff808080ff808080ffff04ffff01ff33ff3cff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff0effff04ff02ffff04ff09ff80808080ffff02ff0effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/singleton_launcher.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | eff07522495060c066f66f32acc2a77e3a3e737aca8baea4d1a64ea4cdc13da9 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/singleton_top_layer.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 24e044101e57b3d8c908b8a38ad57848afd29d3eecc439dba45f4412df4954fd 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/singleton_truths.clib: -------------------------------------------------------------------------------- 1 | ( 2 | (defun-inline truth_data_to_truth_struct (my_id full_puzhash innerpuzhash my_amount lineage_proof singleton_struct) (c (c my_id full_puzhash) (c (c innerpuzhash my_amount) (c lineage_proof singleton_struct)))) 3 | 4 | (defun-inline my_id_truth (Truths) (f (f Truths))) 5 | (defun-inline my_full_puzzle_hash_truth (Truths) (r (f Truths))) 6 | (defun-inline my_inner_puzzle_hash_truth (Truths) (f (f (r Truths)))) 7 | (defun-inline my_amount_truth (Truths) (r (f (r Truths)))) 8 | (defun-inline my_lineage_proof_truth (Truths) (f (r (r Truths)))) 9 | (defun-inline singleton_struct_truth (Truths) (r (r (r Truths)))) 10 | 11 | (defun-inline singleton_mod_hash_truth (Truths) (f (singleton_struct_truth Truths))) 12 | (defun-inline singleton_launcher_id_truth (Truths) (f (r (singleton_struct_truth Truths)))) 13 | (defun-inline singleton_launcher_puzzle_hash_truth (Truths) (f (r (r (singleton_struct_truth Truths))))) 14 | 15 | (defun-inline parent_info_for_lineage_proof (lineage_proof) (f lineage_proof)) 16 | (defun-inline puzzle_hash_for_lineage_proof (lineage_proof) (f (r lineage_proof))) 17 | (defun-inline amount_for_lineage_proof (lineage_proof) (f (r (r lineage_proof)))) 18 | (defun-inline is_not_eve_proof (lineage_proof) (r (r lineage_proof))) 19 | (defun-inline parent_info_for_eve_proof (lineage_proof) (f lineage_proof)) 20 | (defun-inline amount_for_eve_proof (lineage_proof) (f (r lineage_proof))) 21 | ) -------------------------------------------------------------------------------- /avocado/wallet/puzzles/test_generator_deserialize.clvm: -------------------------------------------------------------------------------- 1 | (mod (deserializer generator_list reserved_arg) 2 | (a deserializer (list reserved_arg)) 3 | ) 4 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/test_generator_deserialize.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ff02ffff04ff0bff808080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/test_generator_deserialize.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 52add794fc76e89512e4a063c383418bda084c8a78c74055abe80179e4a7832c 2 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/test_multiple_generator_input_arguments.clvm: -------------------------------------------------------------------------------- 1 | 2 | (mod (decompress_puzzle decompress_coin_solution_entry start1 end1 start2 end2 compressed_cses deserialize gen_list reserved_arg) 3 | 4 | (defun decompress_cses (decompress_puzzle decompress_coin_solution_entry cses deserialize puzzle_prefix) 5 | (if cses 6 | (c (a decompress_coin_solution_entry (list deserialize decompress_puzzle puzzle_prefix (f cses))) 7 | (decompress_cses decompress_puzzle decompress_coin_solution_entry (r cses) deserialize puzzle_prefix )) 8 | ()) ) 9 | 10 | (defun join_gen_args (generators start1 end1 start2 end2) 11 | (concat 12 | (substr (f generators) start1 end1) 13 | (substr (f (r generators)) start2 end2) 14 | ) 15 | ) 16 | 17 | (list (decompress_cses decompress_puzzle decompress_coin_solution_entry compressed_cses deserialize (join_gen_args gen_list start1 end1 start2 end2))) 18 | 19 | ) 20 | -------------------------------------------------------------------------------- /avocado/wallet/puzzles/test_multiple_generator_input_arguments.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff02ff04ffff04ff02ffff04ff05ffff04ff0bffff04ff82017fffff04ff8202ffffff04ffff02ff06ffff04ff02ffff04ff8205ffffff04ff17ffff04ff2fffff04ff5fffff04ff81bfff8080808080808080ff8080808080808080ff8080ffff04ffff01ffff02ffff03ff17ffff01ff04ffff02ff0bffff04ff2fffff04ff05ffff04ff5fffff04ff27ff808080808080ffff02ff04ffff04ff02ffff04ff05ffff04ff0bffff04ff37ffff04ff2fffff04ff5fff808080808080808080ff8080ff0180ff0effff0cff09ff0bff1780ffff0cff15ff2fff5f8080ff018080 -------------------------------------------------------------------------------- /avocado/wallet/puzzles/test_multiple_generator_input_arguments.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 156dafbddc3e1d3bfe1f2a84e48e5e46b287b8358bf65c3c091c93e855fbfc5b 2 | -------------------------------------------------------------------------------- /avocado/wallet/rl_wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/wallet/rl_wallet/__init__.py -------------------------------------------------------------------------------- /avocado/wallet/secret_key_store.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | from blspy import G1Element, PrivateKey 4 | 5 | GROUP_ORDER = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001 6 | 7 | 8 | class SecretKeyStore: 9 | _pk2sk: Dict[G1Element, PrivateKey] 10 | 11 | def __init__(self): 12 | self._pk2sk = {} 13 | 14 | def save_secret_key(self, secret_key: PrivateKey): 15 | public_key = secret_key.get_g1() 16 | self._pk2sk[bytes(public_key)] = secret_key 17 | 18 | def secret_key_for_public_key(self, public_key: G1Element) -> Optional[PrivateKey]: 19 | return self._pk2sk.get(bytes(public_key)) 20 | -------------------------------------------------------------------------------- /avocado/wallet/settings/default_settings.py: -------------------------------------------------------------------------------- 1 | from avocado.wallet.settings.settings_objects import BackupInitialized 2 | 3 | default_backup_initialized = BackupInitialized(False, False, False, True) 4 | 5 | default_settings = {BackupInitialized.__name__: default_backup_initialized} 6 | -------------------------------------------------------------------------------- /avocado/wallet/settings/settings_objects.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from avocado.util.streamable import Streamable, streamable 4 | 5 | 6 | @dataclass(frozen=True) 7 | @streamable 8 | class BackupInitialized(Streamable): 9 | """ 10 | Stores user decision regarding import of backup info 11 | """ 12 | 13 | user_initialized: bool # Stores if user made a selection in UI. (Skip vs Import backup) 14 | user_skipped: bool # Stores if user decided to skip import of backup info 15 | backup_info_imported: bool # Stores if backup info has been imported 16 | new_wallet: bool # Stores if this wallet is newly created / not restored from backup 17 | -------------------------------------------------------------------------------- /avocado/wallet/trade_record.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Optional, Tuple 3 | 4 | from avocado.types.blockchain_format.coin import Coin 5 | from avocado.types.blockchain_format.sized_bytes import bytes32 6 | from avocado.types.spend_bundle import SpendBundle 7 | from avocado.util.ints import uint8, uint32, uint64 8 | from avocado.util.streamable import Streamable, streamable 9 | 10 | 11 | @dataclass(frozen=True) 12 | @streamable 13 | class TradeRecord(Streamable): 14 | """ 15 | Used for storing transaction data and status in wallets. 16 | """ 17 | 18 | confirmed_at_index: uint32 19 | accepted_at_time: Optional[uint64] 20 | created_at_time: uint64 21 | my_offer: bool 22 | sent: uint32 23 | spend_bundle: SpendBundle # This in not complete spendbundle 24 | tx_spend_bundle: Optional[SpendBundle] # this is full trade 25 | additions: List[Coin] 26 | removals: List[Coin] 27 | trade_id: bytes32 28 | status: uint32 # TradeStatus, enum not streamable 29 | sent_to: List[Tuple[str, uint8, Optional[str]]] 30 | -------------------------------------------------------------------------------- /avocado/wallet/trading/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/wallet/trading/__init__.py -------------------------------------------------------------------------------- /avocado/wallet/trading/trade_status.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class TradeStatus(Enum): 5 | PENDING_ACCEPT = 0 6 | PENDING_CONFIRM = 1 7 | PENDING_CANCEL = 2 8 | CANCELED = 3 9 | CONFIRMED = 4 10 | FAILED = 5 11 | -------------------------------------------------------------------------------- /avocado/wallet/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/avocado/wallet/util/__init__.py -------------------------------------------------------------------------------- /avocado/wallet/util/transaction_type.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class TransactionType(IntEnum): 5 | INCOMING_TX = 0 6 | OUTGOING_TX = 1 7 | COINBASE_REWARD = 2 8 | FEE_REWARD = 3 9 | INCOMING_TRADE = 4 10 | OUTGOING_TRADE = 5 11 | -------------------------------------------------------------------------------- /avocado/wallet/util/wallet_types.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class WalletType(IntEnum): 5 | # Wallet Types 6 | STANDARD_WALLET = 0 7 | RATE_LIMITED = 1 8 | ATOMIC_SWAP = 2 9 | AUTHORIZED_PAYEE = 3 10 | MULTI_SIG = 4 11 | CUSTODY = 5 12 | COLOURED_COIN = 6 13 | RECOVERABLE = 7 14 | DISTRIBUTED_ID = 8 15 | POOLING_WALLET = 9 16 | -------------------------------------------------------------------------------- /avocado/wallet/wallet_action.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from avocado.util.ints import uint32 5 | from avocado.wallet.util.wallet_types import WalletType 6 | 7 | 8 | @dataclass(frozen=True) 9 | class WalletAction: 10 | """ 11 | This object represents the wallet action as it is stored in the database. 12 | 13 | Purpose: 14 | Some wallets require wallet node to perform a certain action when event happens. 15 | For Example, coloured coin wallet needs to fetch solutions once it receives a coin. 16 | In order to be safe from losing connection, closing the app, etc, those actions need to be persisted. 17 | 18 | id: auto-incremented for every added action 19 | name: Specified by the wallet 20 | Wallet_id: ID of the wallet that created this action 21 | type: Type of the wallet that created this action 22 | wallet_callback: Name of the callback function in the wallet that created this action, if specified it will 23 | get called when action has been performed. 24 | done: Indicates if the action has been performed 25 | data: JSON encoded string containing any data wallet or a wallet_node needs for this specific action. 26 | """ 27 | 28 | id: uint32 29 | name: str 30 | wallet_id: int 31 | type: WalletType 32 | wallet_callback: Optional[str] 33 | done: bool 34 | data: str 35 | -------------------------------------------------------------------------------- /avocado/wallet/wallet_coin_record.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from avocado.types.blockchain_format.coin import Coin 4 | from avocado.types.blockchain_format.sized_bytes import bytes32 5 | from avocado.util.ints import uint32 6 | from avocado.wallet.util.wallet_types import WalletType 7 | 8 | 9 | @dataclass(frozen=True) 10 | class WalletCoinRecord: 11 | """ 12 | These are values that correspond to a CoinName that are used 13 | in keeping track of the unspent database. 14 | """ 15 | 16 | coin: Coin 17 | confirmed_block_height: uint32 18 | spent_block_height: uint32 19 | spent: bool 20 | coinbase: bool 21 | wallet_type: WalletType 22 | wallet_id: int 23 | 24 | def name(self) -> bytes32: 25 | return self.coin.name() 26 | -------------------------------------------------------------------------------- /avocado/wallet/wallet_info.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | 4 | from avocado.util.ints import uint8, uint32 5 | from avocado.util.streamable import Streamable, streamable 6 | 7 | 8 | @dataclass(frozen=True) 9 | @streamable 10 | class WalletInfo(Streamable): 11 | """ 12 | This object represents the wallet data as it is stored in DB. 13 | ID: Main wallet (Standard) is stored at index 1, every wallet created after done has auto incremented id. 14 | Name: can be a user provided or default generated name. (can be modified) 15 | Type: is specified during wallet creation and should never be changed. 16 | Data: this filed is intended to be used for storing any wallet specific information required for it. 17 | (RL wallet stores origin_id, admin/user pubkey, rate limit, etc.) 18 | This data should be json encoded string. 19 | """ 20 | 21 | id: uint32 22 | name: str 23 | type: uint8 # WalletType(type) 24 | data: str 25 | 26 | 27 | @dataclass(frozen=True) 28 | @streamable 29 | class WalletInfoBackup(Streamable): 30 | """ 31 | Used for transforming list of WalletInfo objects into bytes. 32 | """ 33 | 34 | wallet_list: List[WalletInfo] 35 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | ignore_missing_imports = True 3 | 4 | [mypy - lib] 5 | ignore_errors = True 6 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=4.1.2"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [tool.setuptools_scm] 6 | local_scheme = "no-local-version" 7 | 8 | [tool.black] 9 | line-length = 120 10 | -------------------------------------------------------------------------------- /run-py-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | python3 -m venv venv 4 | # shellcheck disable=SC1091 5 | . ./activate 6 | pip3 install ".[dev]" 7 | 8 | py.test ./tests/blockchain -s -v 9 | py.test ./tests/core -s -v 10 | py.test ./tests/wallet -s -v 11 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/__init__.py -------------------------------------------------------------------------------- /tests/avocado-start-sim: -------------------------------------------------------------------------------- 1 | _kill_servers() { 2 | PROCS=`ps -e | grep -E 'avocado|vdf_client' -v "avocado-start-sim" | awk '!/grep/' | awk '{print $1}'` 3 | if [ -n "$PROCS" ]; then 4 | echo "$PROCS" | xargs -L1 kill -KILL 5 | fi 6 | } 7 | 8 | _kill_servers 9 | 10 | BG_PIDS="" 11 | _run_bg_cmd() { 12 | "$@" & 13 | BG_PIDS="$BG_PIDS $!" 14 | } 15 | 16 | 17 | _term() { 18 | echo "Caught TERM or INT signal, killing all servers." 19 | for PID in $BG_PIDS; do 20 | kill -TERM "$PID" 21 | done 22 | _kill_servers 23 | } 24 | 25 | echo "Starting local blockchain simulation. Runs a local introducer and avocado system." 26 | echo "Note that this simulation will not work if connected to external nodes." 27 | 28 | # Starts a harvester, farmer, timelord, introducer, and 3 full nodes, locally. 29 | # Please note that the simulation is meant to be run locally and not connected to external nodes. 30 | # NOTE: you must run install.sh when changing this file 31 | 32 | _run_bg_cmd avocado_farmer --logging.log_stdout=True --logging.log_level=INFO 33 | _run_bg_cmd avocado_harvester --logging.log_stdout=True --logging.log_level=INFO 34 | _run_bg_cmd avocado_timelord --logging.log_stdout=True --logging.log_level=INFO 35 | _run_bg_cmd avocado_timelord_launcher --logging.log_stdout=True --logging.log_level=INFO 36 | _run_bg_cmd avocado_introducer --logging.log_stdout=True --logging.log_level=INFO 37 | _run_bg_cmd avocado_full_node --port=6865 --database_path="simulation_1.db" --rpc_port=8555 --introducer_peer.host="127.0.0.1" --introducer_peer.port=7745 --logging.log_stdout=True --logging.log_level=INFO --logging.log_level=INFO 38 | sleep 1 39 | _run_bg_cmd avocado_full_node --port=8002 --database_path="simulation_2.db" --rpc_port=8556 --introducer_peer.host="127.0.0.1" --introducer_peer.port=7745 --logging.log_stdout=True --logging.log_level=INFO 40 | _run_bg_cmd python -m avocado.daemon.server --logging.log_stdout=True --logging.log_level=INFO 41 | 42 | wait 43 | -------------------------------------------------------------------------------- /tests/blockchain/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/blockchain/__init__.py -------------------------------------------------------------------------------- /tests/blockchain/config.py: -------------------------------------------------------------------------------- 1 | job_timeout = 60 2 | -------------------------------------------------------------------------------- /tests/check_pytest_monitor_output.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | 4 | ret = 0 5 | 6 | # example input line 7 | # test_non_tx_aggregate_limits 0.997759588095738 1.45325589179993 554.45703125 8 | for ln in sys.stdin: 9 | line = ln.strip().split() 10 | 11 | print(f"{float(line[1]) * 100.0: 8.1f}% CPU {float(line[2]):7.1f}s {float(line[3]): 8.2f} MB RAM {line[0]}") 12 | if float(line[3]) > 800: 13 | print(" ERROR: ^^ exceeded RAM limit ^^ \n") 14 | ret += 1 15 | 16 | if ret > 0: 17 | print("some tests used too much RAM") 18 | 19 | sys.exit(ret) 20 | -------------------------------------------------------------------------------- /tests/chia-start-sim: -------------------------------------------------------------------------------- 1 | _kill_servers() { 2 | PROCS=`ps -e | grep -E 'chia|vdf_client' -v "chia-start-sim" | awk '!/grep/' | awk '{print $1}'` 3 | if [ -n "$PROCS" ]; then 4 | echo "$PROCS" | xargs -L1 kill -KILL 5 | fi 6 | } 7 | 8 | _kill_servers 9 | 10 | BG_PIDS="" 11 | _run_bg_cmd() { 12 | "$@" & 13 | BG_PIDS="$BG_PIDS $!" 14 | } 15 | 16 | 17 | _term() { 18 | echo "Caught TERM or INT signal, killing all servers." 19 | for PID in $BG_PIDS; do 20 | kill -TERM "$PID" 21 | done 22 | _kill_servers 23 | } 24 | 25 | echo "Starting local blockchain simulation. Runs a local introducer and chia system." 26 | echo "Note that this simulation will not work if connected to external nodes." 27 | 28 | # Starts a harvester, farmer, timelord, introducer, and 3 full nodes, locally. 29 | # Please note that the simulation is meant to be run locally and not connected to external nodes. 30 | # NOTE: you must run install.sh when changing this file 31 | 32 | _run_bg_cmd chia_farmer --logging.log_stdout=True --logging.log_level=INFO 33 | _run_bg_cmd chia_harvester --logging.log_stdout=True --logging.log_level=INFO 34 | _run_bg_cmd chia_timelord --logging.log_stdout=True --logging.log_level=INFO 35 | _run_bg_cmd chia_timelord_launcher --logging.log_stdout=True --logging.log_level=INFO 36 | _run_bg_cmd chia_introducer --logging.log_stdout=True --logging.log_level=INFO 37 | _run_bg_cmd chia_full_node --port=8444 --database_path="simulation_1.db" --rpc_port=8555 --introducer_peer.host="127.0.0.1" --introducer_peer.port=8445 --logging.log_stdout=True --logging.log_level=INFO --logging.log_level=INFO 38 | sleep 1 39 | _run_bg_cmd chia_full_node --port=8002 --database_path="simulation_2.db" --rpc_port=8556 --introducer_peer.host="127.0.0.1" --introducer_peer.port=8445 --logging.log_stdout=True --logging.log_level=INFO 40 | _run_bg_cmd python -m chia.daemon.server --logging.log_stdout=True --logging.log_level=INFO 41 | 42 | wait 43 | -------------------------------------------------------------------------------- /tests/clvm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/clvm/__init__.py -------------------------------------------------------------------------------- /tests/clvm/config.py: -------------------------------------------------------------------------------- 1 | parallel = True 2 | checkout_blocks_and_plots = False 3 | install_timelord = False 4 | -------------------------------------------------------------------------------- /tests/clvm/test_serialized_program.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from chia.types.blockchain_format.program import Program, SerializedProgram, INFINITE_COST 4 | from chia.wallet.puzzles.load_clvm import load_clvm 5 | 6 | SHA256TREE_MOD = load_clvm("sha256tree_module.clvm") 7 | 8 | 9 | # TODO: test multiple args 10 | class TestSerializedProgram(TestCase): 11 | def test_tree_hash(self): 12 | p = SHA256TREE_MOD 13 | s = SerializedProgram.from_bytes(bytes(SHA256TREE_MOD)) 14 | self.assertEqual(s.get_tree_hash(), p.get_tree_hash()) 15 | 16 | def test_program_execution(self): 17 | p_result = SHA256TREE_MOD.run(SHA256TREE_MOD) 18 | sp = SerializedProgram.from_bytes(bytes(SHA256TREE_MOD)) 19 | cost, sp_result = sp.run_with_cost(INFINITE_COST, sp) 20 | self.assertEqual(p_result, sp_result) 21 | 22 | def test_serialization(self): 23 | s0 = SerializedProgram.from_bytes(b"\x00") 24 | p0 = Program.from_bytes(b"\x00") 25 | print(s0, p0) 26 | # TODO: enable when clvm updated for minimal encoding of zero 27 | # self.assertEqual(bytes(p0), bytes(s0)) 28 | -------------------------------------------------------------------------------- /tests/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/core/__init__.py -------------------------------------------------------------------------------- /tests/core/consensus/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/core/consensus/__init__.py -------------------------------------------------------------------------------- /tests/core/full_node/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/core/full_node/__init__.py -------------------------------------------------------------------------------- /tests/core/full_node/config.py: -------------------------------------------------------------------------------- 1 | job_timeout = 60 2 | -------------------------------------------------------------------------------- /tests/core/full_node/dos/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/core/full_node/dos/__init__.py -------------------------------------------------------------------------------- /tests/core/full_node/dos/config.py: -------------------------------------------------------------------------------- 1 | job_timeout = 60 2 | -------------------------------------------------------------------------------- /tests/core/full_node/full_sync/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/core/full_node/full_sync/__init__.py -------------------------------------------------------------------------------- /tests/core/full_node/full_sync/config.py: -------------------------------------------------------------------------------- 1 | job_timeout = 60 2 | -------------------------------------------------------------------------------- /tests/core/full_node/ram_db.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import aiosqlite 4 | 5 | from chia.consensus.blockchain import Blockchain 6 | from chia.consensus.constants import ConsensusConstants 7 | from chia.full_node.block_store import BlockStore 8 | from chia.full_node.coin_store import CoinStore 9 | from chia.util.db_wrapper import DBWrapper 10 | 11 | 12 | async def create_ram_blockchain(consensus_constants: ConsensusConstants) -> Tuple[aiosqlite.Connection, Blockchain]: 13 | connection = await aiosqlite.connect(":memory:") 14 | db_wrapper = DBWrapper(connection) 15 | block_store = await BlockStore.create(db_wrapper) 16 | coin_store = await CoinStore.create(db_wrapper) 17 | blockchain = await Blockchain.create(coin_store, block_store, consensus_constants) 18 | return connection, blockchain 19 | -------------------------------------------------------------------------------- /tests/core/full_node/test_node_load.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import time 3 | 4 | import pytest 5 | 6 | from chia.protocols import full_node_protocol 7 | from chia.types.peer_info import PeerInfo 8 | from chia.util.ints import uint16 9 | from tests.connection_utils import connect_and_get_peer 10 | from tests.setup_nodes import bt, self_hostname, setup_two_nodes, test_constants 11 | from tests.time_out_assert import time_out_assert 12 | 13 | 14 | @pytest.fixture(scope="session") 15 | def event_loop(): 16 | loop = asyncio.get_event_loop() 17 | yield loop 18 | 19 | 20 | class TestNodeLoad: 21 | @pytest.fixture(scope="function") 22 | async def two_nodes(self): 23 | async for _ in setup_two_nodes(test_constants): 24 | yield _ 25 | 26 | @pytest.mark.asyncio 27 | async def test_blocks_load(self, two_nodes): 28 | num_blocks = 50 29 | full_node_1, full_node_2, server_1, server_2 = two_nodes 30 | blocks = bt.get_consecutive_blocks(num_blocks) 31 | peer = await connect_and_get_peer(server_1, server_2) 32 | await full_node_1.full_node.respond_block(full_node_protocol.RespondBlock(blocks[0]), peer) 33 | 34 | await server_2.start_client(PeerInfo(self_hostname, uint16(server_1._port)), None) 35 | 36 | async def num_connections(): 37 | return len(server_2.get_connections()) 38 | 39 | await time_out_assert(10, num_connections, 1) 40 | 41 | start_unf = time.time() 42 | for i in range(1, num_blocks): 43 | await full_node_1.full_node.respond_block(full_node_protocol.RespondBlock(blocks[i])) 44 | await full_node_2.full_node.respond_block(full_node_protocol.RespondBlock(blocks[i])) 45 | print(f"Time taken to process {num_blocks} is {time.time() - start_unf}") 46 | assert time.time() - start_unf < 100 47 | -------------------------------------------------------------------------------- /tests/core/node_height.py: -------------------------------------------------------------------------------- 1 | def node_height_at_least(node, h): 2 | if node.full_node.blockchain.get_peak() is not None: 3 | return node.full_node.blockchain.get_peak().height >= h 4 | return False 5 | 6 | 7 | def node_height_exactly(node, h): 8 | if node.full_node.blockchain.get_peak() is not None: 9 | return node.full_node.blockchain.get_peak().height == h 10 | return False 11 | 12 | 13 | def node_height_between(node, h1, h2): 14 | if node.full_node.blockchain.get_peak() is not None: 15 | height = node.full_node.blockchain.get_peak().height 16 | return h1 <= height <= h2 17 | return False 18 | -------------------------------------------------------------------------------- /tests/core/test_filter.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from typing import List 3 | 4 | import pytest 5 | from chiabip158 import PyBIP158 6 | 7 | from tests.setup_nodes import setup_simulators_and_wallets, bt 8 | 9 | 10 | @pytest.fixture(scope="module") 11 | def event_loop(): 12 | loop = asyncio.get_event_loop() 13 | yield loop 14 | 15 | 16 | class TestFilter: 17 | @pytest.fixture(scope="function") 18 | async def wallet_and_node(self): 19 | async for _ in setup_simulators_and_wallets(1, 1, {}): 20 | yield _ 21 | 22 | @pytest.mark.asyncio 23 | async def test_basic_filter_test(self, wallet_and_node): 24 | full_nodes, wallets = wallet_and_node 25 | wallet_node, server_2 = wallets[0] 26 | wallet = wallet_node.wallet_state_manager.main_wallet 27 | 28 | num_blocks = 2 29 | ph = await wallet.get_new_puzzlehash() 30 | blocks = bt.get_consecutive_blocks( 31 | 10, 32 | guarantee_transaction_block=True, 33 | farmer_reward_puzzle_hash=ph, 34 | pool_reward_puzzle_hash=ph, 35 | ) 36 | for i in range(1, num_blocks): 37 | byte_array_tx: List[bytes] = [] 38 | block = blocks[i] 39 | coins = list(block.get_included_reward_coins()) 40 | coin_0 = bytearray(coins[0].puzzle_hash) 41 | coin_1 = bytearray(coins[1].puzzle_hash) 42 | byte_array_tx.append(coin_0) 43 | byte_array_tx.append(coin_1) 44 | 45 | pl = PyBIP158(byte_array_tx) 46 | present = pl.Match(coin_0) 47 | fee_present = pl.Match(coin_1) 48 | 49 | assert present 50 | assert fee_present 51 | -------------------------------------------------------------------------------- /tests/core/test_merkle_set.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import itertools 3 | 4 | import pytest 5 | 6 | from chia.util.merkle_set import MerkleSet, confirm_included_already_hashed 7 | from tests.setup_nodes import bt 8 | 9 | 10 | @pytest.fixture(scope="module") 11 | def event_loop(): 12 | loop = asyncio.get_event_loop() 13 | yield loop 14 | 15 | 16 | class TestMerkleSet: 17 | @pytest.mark.asyncio 18 | async def test_basics(self): 19 | num_blocks = 20 20 | blocks = bt.get_consecutive_blocks(num_blocks) 21 | 22 | merkle_set = MerkleSet() 23 | merkle_set_reverse = MerkleSet() 24 | coins = list(itertools.chain.from_iterable(map(lambda block: block.get_included_reward_coins(), blocks))) 25 | 26 | # excluded coin (not present in 'coins' and Merkle sets) 27 | excl_coin = coins.pop() 28 | 29 | for coin in reversed(coins): 30 | merkle_set_reverse.add_already_hashed(coin.name()) 31 | 32 | for coin in coins: 33 | merkle_set.add_already_hashed(coin.name()) 34 | 35 | for coin in coins: 36 | result, proof = merkle_set.is_included_already_hashed(coin.name()) 37 | assert result is True 38 | result_excl, proof_excl = merkle_set.is_included_already_hashed(excl_coin.name()) 39 | assert result_excl is False 40 | validate_proof = confirm_included_already_hashed(merkle_set.get_root(), coin.name(), proof) 41 | validate_proof_excl = confirm_included_already_hashed(merkle_set.get_root(), excl_coin.name(), proof_excl) 42 | assert validate_proof is True 43 | assert validate_proof_excl is False 44 | 45 | # Test if the order of adding items changes the outcome 46 | assert merkle_set.get_root() == merkle_set_reverse.get_root() 47 | -------------------------------------------------------------------------------- /tests/core/test_setproctitle.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from chia.util.setproctitle import setproctitle 4 | 5 | 6 | class TestSetProcTitle(unittest.TestCase): 7 | def test_does_not_crash(self): 8 | setproctitle("chia test title") 9 | -------------------------------------------------------------------------------- /tests/core/types/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/core/types/__init__.py -------------------------------------------------------------------------------- /tests/core/types/test_coin.py: -------------------------------------------------------------------------------- 1 | from chia.types.blockchain_format.coin import Coin 2 | from chia.types.blockchain_format.sized_bytes import bytes32 3 | from chia.util.ints import uint64 4 | from chia.util.hash import std_hash 5 | import io 6 | 7 | 8 | def coin_serialize(amount: uint64, clvm_serialize: bytes, full_serialize: bytes): 9 | 10 | c = Coin(bytes32(b"a" * 32), bytes32(b"b" * 32), amount) 11 | expected_hash = (b"a" * 32) + (b"b" * 32) + clvm_serialize 12 | 13 | expected_serialization = (b"a" * 32) + (b"b" * 32) + full_serialize 14 | 15 | assert c.get_hash() == std_hash(expected_hash) 16 | assert c.name() == std_hash(expected_hash) 17 | f = io.BytesIO() 18 | c.stream(f) 19 | assert bytes(f.getvalue()) == expected_serialization 20 | 21 | # make sure the serialization round-trips 22 | f = io.BytesIO(expected_serialization) 23 | c2 = Coin.parse(f) 24 | assert c2 == c 25 | 26 | 27 | class TestCoin: 28 | def test_coin_serialization(self): 29 | 30 | coin_serialize(uint64(0xFFFF), bytes([0, 0xFF, 0xFF]), bytes([0, 0, 0, 0, 0, 0, 0xFF, 0xFF])) 31 | coin_serialize(uint64(1337000000), bytes([0x4F, 0xB1, 0x00, 0x40]), bytes([0, 0, 0, 0, 0x4F, 0xB1, 0x00, 0x40])) 32 | 33 | # if the amount is 0, the amount is omitted in the "short" format, 34 | # that's hashed 35 | coin_serialize(uint64(0), b"", bytes([0, 0, 0, 0, 0, 0, 0, 0])) 36 | 37 | # when amount is > INT64_MAX, the "short" serialization format is 1 byte 38 | # longer, since it needs a leading zero to make it positive 39 | coin_serialize( 40 | uint64(0xFFFFFFFFFFFFFFFF), 41 | bytes([0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), 42 | bytes([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), 43 | ) 44 | -------------------------------------------------------------------------------- /tests/core/types/test_proof_of_space.py: -------------------------------------------------------------------------------- 1 | from secrets import token_bytes 2 | 3 | from chia.consensus.default_constants import DEFAULT_CONSTANTS 4 | from chia.types.blockchain_format.proof_of_space import ProofOfSpace # pylint: disable=E0401 5 | 6 | 7 | class TestProofOfSpace: 8 | def test_can_create_proof(self): 9 | """ 10 | Tests that the change of getting a correct proof is exactly 1/target_filter. 11 | """ 12 | num_trials = 100000 13 | success_count = 0 14 | target_filter = 2 ** DEFAULT_CONSTANTS.NUMBER_ZERO_BITS_PLOT_FILTER 15 | for _ in range(num_trials): 16 | challenge_hash = token_bytes(32) 17 | plot_id = token_bytes(32) 18 | sp_output = token_bytes(32) 19 | 20 | if ProofOfSpace.passes_plot_filter(DEFAULT_CONSTANTS, plot_id, challenge_hash, sp_output): 21 | success_count += 1 22 | 23 | assert abs((success_count * target_filter / num_trials) - 1) < 0.35 24 | -------------------------------------------------------------------------------- /tests/core/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/core/util/__init__.py -------------------------------------------------------------------------------- /tests/core/util/test_lru_cache.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from chia.util.lru_cache import LRUCache 4 | 5 | 6 | class TestLRUCache(unittest.TestCase): 7 | def test_lru_cache(self): 8 | cache = LRUCache(5) 9 | 10 | assert cache.get(b"0") is None 11 | 12 | assert len(cache.cache) == 0 13 | cache.put(b"0", 1) 14 | assert len(cache.cache) == 1 15 | assert cache.get(b"0") == 1 16 | cache.put(b"0", 2) 17 | cache.put(b"0", 3) 18 | cache.put(b"0", 4) 19 | cache.put(b"0", 6) 20 | assert cache.get(b"0") == 6 21 | assert len(cache.cache) == 1 22 | 23 | cache.put(b"1", 1) 24 | assert len(cache.cache) == 2 25 | assert cache.get(b"0") == 6 26 | assert cache.get(b"1") == 1 27 | cache.put(b"2", 2) 28 | assert len(cache.cache) == 3 29 | assert cache.get(b"0") == 6 30 | assert cache.get(b"1") == 1 31 | assert cache.get(b"2") == 2 32 | cache.put(b"3", 3) 33 | assert len(cache.cache) == 4 34 | assert cache.get(b"0") == 6 35 | assert cache.get(b"1") == 1 36 | assert cache.get(b"2") == 2 37 | assert cache.get(b"3") == 3 38 | cache.put(b"4", 4) 39 | assert len(cache.cache) == 5 40 | assert cache.get(b"0") == 6 41 | assert cache.get(b"1") == 1 42 | assert cache.get(b"2") == 2 43 | assert cache.get(b"4") == 4 44 | cache.put(b"5", 5) 45 | assert cache.get(b"5") == 5 46 | assert len(cache.cache) == 5 47 | print(cache.cache) 48 | assert cache.get(b"3") is None # 3 is least recently used 49 | assert cache.get(b"1") == 1 50 | assert cache.get(b"2") == 2 51 | cache.put(b"7", 7) 52 | assert len(cache.cache) == 5 53 | assert cache.get(b"0") is None 54 | assert cache.get(b"1") == 1 55 | -------------------------------------------------------------------------------- /tests/core/util/test_significant_bits.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from chia.util.significant_bits import count_significant_bits, truncate_to_significant_bits 4 | 5 | 6 | class TestSignificantBits(unittest.TestCase): 7 | def test_truncate_to_significant_bits(self): 8 | a = -0b001101 9 | assert truncate_to_significant_bits(a, 2) == -0b1100 10 | a = -0b001111 11 | assert truncate_to_significant_bits(a, 2) == -0b1100 12 | a = 0b1111 13 | assert truncate_to_significant_bits(a, 2) == 0b1100 14 | a = 0b1000000111 15 | assert truncate_to_significant_bits(a, 8) == 0b1000000100 16 | a = 0b1000000111 17 | assert truncate_to_significant_bits(a, 0) == 0b0 18 | a = 0b1000000111 19 | assert truncate_to_significant_bits(a, 500) == a 20 | a = 0b10101 21 | assert truncate_to_significant_bits(a, 5) == a 22 | a = 0b10101 23 | assert truncate_to_significant_bits(a, 4) == 0b10100 24 | 25 | def test_count_significant_bits(self): 26 | assert count_significant_bits(0b0001) == 1 27 | assert count_significant_bits(0b00010) == 1 28 | assert count_significant_bits(0b01010) == 3 29 | assert count_significant_bits(-0b01010) == 3 30 | assert count_significant_bits(0b0) == 0 31 | assert count_significant_bits(0b1) == 1 32 | assert count_significant_bits(0b1000010101010000) == 12 33 | 34 | 35 | if __name__ == "__main__": 36 | unittest.main() 37 | -------------------------------------------------------------------------------- /tests/pools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/pools/__init__.py -------------------------------------------------------------------------------- /tests/pools/test_pool_config.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa: E501 2 | from pathlib import Path 3 | 4 | from blspy import AugSchemeMPL, PrivateKey 5 | 6 | from chia.pools.pool_config import PoolWalletConfig 7 | from chia.util.config import load_config, save_config, create_default_chia_config 8 | 9 | 10 | def test_pool_config(): 11 | test_root = Path("/tmp") 12 | test_path = Path("/tmp/config") 13 | eg_config = test_path / "config.yaml" 14 | to_config = test_path / "test_pool_config.yaml" 15 | 16 | create_default_chia_config(test_root, ["config.yaml"]) 17 | assert eg_config.exists() 18 | eg_config.rename(to_config) 19 | config = load_config(test_root, "test_pool_config.yaml") 20 | 21 | auth_sk: PrivateKey = AugSchemeMPL.key_gen(b"1" * 32) 22 | d = { 23 | "authentication_public_key": bytes(auth_sk.get_g1()).hex(), 24 | "owner_public_key": "84c3fcf9d5581c1ddc702cb0f3b4a06043303b334dd993ab42b2c320ebfa98e5ce558448615b3f69638ba92cf7f43da5", 25 | "p2_singleton_puzzle_hash": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", 26 | "payout_instructions": "c2b08e41d766da4116e388357ed957d04ad754623a915f3fd65188a8746cf3e8", 27 | "pool_url": "localhost", 28 | "launcher_id": "ae4ef3b9bfe68949691281a015a9c16630fc8f66d48c19ca548fb80768791afa", 29 | "target_puzzle_hash": "344587cf06a39db471d2cc027504e8688a0a67cce961253500c956c73603fd58", 30 | } 31 | 32 | pwc = PoolWalletConfig.from_json_dict(d) 33 | 34 | config_a = config.copy() 35 | config_b = config.copy() 36 | 37 | config_a["wallet"]["pool_list"] = [d] 38 | config_b["wallet"]["pool_list"] = [pwc.to_json_dict()] 39 | 40 | print(config["wallet"]["pool_list"]) 41 | save_config(test_root, "test_pool_config_a.yaml", config_a) 42 | save_config(test_root, "test_pool_config_b.yaml", config_b) 43 | assert config_a == config_b 44 | -------------------------------------------------------------------------------- /tests/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | ; logging options 3 | log_cli = 1 4 | log_level = WARNING 5 | log_format = %(asctime)s %(name)s: %(levelname)s %(message)s 6 | -------------------------------------------------------------------------------- /tests/runner-templates/checkout-test-plots.include.yml: -------------------------------------------------------------------------------- 1 | - name: Checkout test blocks and plots 2 | uses: actions/checkout@v2 3 | with: 4 | repository: 'Chia-Network/test-cache' 5 | path: '.chia' 6 | ref: '0.27.0' 7 | fetch-depth: 1 8 | 9 | -------------------------------------------------------------------------------- /tests/runner-templates/install-timelord.include.yml: -------------------------------------------------------------------------------- 1 | - name: Install timelord 2 | run: | 3 | . ./activate 4 | sh install-timelord.sh 5 | ./vdf_bench square_asm 400000 6 | -------------------------------------------------------------------------------- /tests/simulation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/simulation/__init__.py -------------------------------------------------------------------------------- /tests/simulation/config.py: -------------------------------------------------------------------------------- 1 | job_timeout = 60 2 | -------------------------------------------------------------------------------- /tests/testconfig.py: -------------------------------------------------------------------------------- 1 | # Github actions template config. 2 | oses = ["ubuntu", "macos"] 3 | root_test_dirs = ["blockchain", "clvm", "core", "generator", "pools", "simulation", "wallet"] 4 | 5 | # Defaults are conservative. 6 | parallel = False 7 | checkout_blocks_and_plots = True 8 | install_timelord = True 9 | job_timeout = 30 10 | -------------------------------------------------------------------------------- /tests/time_out_assert.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | import time 4 | from typing import Callable 5 | 6 | from chia.protocols.protocol_message_types import ProtocolMessageTypes 7 | 8 | log = logging.getLogger(__name__) 9 | 10 | 11 | async def time_out_assert_custom_interval(timeout: int, interval, function, value=True, *args, **kwargs): 12 | start = time.time() 13 | while time.time() - start < timeout: 14 | if asyncio.iscoroutinefunction(function): 15 | f_res = await function(*args, **kwargs) 16 | else: 17 | f_res = function(*args, **kwargs) 18 | if value == f_res: 19 | return None 20 | await asyncio.sleep(interval) 21 | assert False, "Timed assertion timed out" 22 | 23 | 24 | async def time_out_assert(timeout: int, function, value=True, *args, **kwargs): 25 | await time_out_assert_custom_interval(timeout, 0.05, function, value, *args, *kwargs) 26 | 27 | 28 | async def time_out_assert_not_none(timeout: int, function, *args, **kwargs): 29 | start = time.time() 30 | while time.time() - start < timeout: 31 | if asyncio.iscoroutinefunction(function): 32 | f_res = await function(*args, **kwargs) 33 | else: 34 | f_res = function(*args, **kwargs) 35 | if f_res is not None: 36 | return None 37 | await asyncio.sleep(0.05) 38 | assert False, "Timed assertion timed out" 39 | 40 | 41 | def time_out_messages(incoming_queue: asyncio.Queue, msg_name: str, count: int = 1) -> Callable: 42 | async def bool_f(): 43 | if incoming_queue.qsize() < count: 44 | return False 45 | for _ in range(count): 46 | response = (await incoming_queue.get())[0].type 47 | if ProtocolMessageTypes(response).name != msg_name: 48 | # log.warning(f"time_out_message: found {response} instead of {msg_name}") 49 | return False 50 | return True 51 | 52 | return bool_f 53 | -------------------------------------------------------------------------------- /tests/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/util/__init__.py -------------------------------------------------------------------------------- /tests/util/config.py: -------------------------------------------------------------------------------- 1 | job_timeout = 60 2 | -------------------------------------------------------------------------------- /tests/util/generator_tools_testing.py: -------------------------------------------------------------------------------- 1 | from typing import List, Tuple 2 | 3 | from chia.full_node.mempool_check_conditions import get_name_puzzle_conditions 4 | from chia.types.blockchain_format.coin import Coin 5 | from chia.types.blockchain_format.sized_bytes import bytes32 6 | from chia.types.full_block import FullBlock 7 | from chia.types.generator_types import BlockGenerator 8 | from chia.util.generator_tools import additions_for_npc 9 | 10 | 11 | def run_and_get_removals_and_additions( 12 | block: FullBlock, max_cost: int, cost_per_byte: int, safe_mode=False 13 | ) -> Tuple[List[bytes32], List[Coin]]: 14 | removals: List[bytes32] = [] 15 | additions: List[Coin] = [] 16 | 17 | assert len(block.transactions_generator_ref_list) == 0 18 | if not block.is_transaction_block(): 19 | return [], [] 20 | 21 | if block.transactions_generator is not None: 22 | npc_result = get_name_puzzle_conditions( 23 | BlockGenerator(block.transactions_generator, []), max_cost, cost_per_byte=cost_per_byte, safe_mode=safe_mode 24 | ) 25 | # build removals list 26 | for npc in npc_result.npc_list: 27 | removals.append(npc.coin_name) 28 | additions.extend(additions_for_npc(npc_result.npc_list)) 29 | 30 | rewards = block.get_included_reward_coins() 31 | additions.extend(rewards) 32 | return removals, additions 33 | -------------------------------------------------------------------------------- /tests/util/key_tool.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from blspy import AugSchemeMPL, G2Element, PrivateKey 4 | 5 | from chia.types.blockchain_format.sized_bytes import bytes32 6 | from chia.types.coin_solution import CoinSolution 7 | from chia.util.condition_tools import conditions_by_opcode, conditions_for_solution, pkm_pairs_for_conditions_dict 8 | from tests.core.make_block_generator import GROUP_ORDER, int_to_public_key 9 | from tests.block_tools import test_constants 10 | 11 | 12 | class KeyTool(dict): 13 | @classmethod 14 | def __new__(cls, *args): 15 | return dict.__new__(*args) 16 | 17 | def add_secret_exponents(self, secret_exponents: List[int]) -> None: 18 | for _ in secret_exponents: 19 | self[bytes(int_to_public_key(_))] = _ % GROUP_ORDER 20 | 21 | def sign(self, public_key: bytes, message_hash: bytes32) -> G2Element: 22 | secret_exponent = self.get(public_key) 23 | if not secret_exponent: 24 | raise ValueError("unknown pubkey %s" % public_key.hex()) 25 | bls_private_key = PrivateKey.from_bytes(secret_exponent.to_bytes(32, "big")) 26 | return AugSchemeMPL.sign(bls_private_key, message_hash) 27 | 28 | def signature_for_solution(self, coin_solution: CoinSolution, additional_data: bytes) -> AugSchemeMPL: 29 | signatures = [] 30 | err, conditions, cost = conditions_for_solution( 31 | coin_solution.puzzle_reveal, coin_solution.solution, test_constants.MAX_BLOCK_COST_CLVM 32 | ) 33 | assert conditions is not None 34 | conditions_dict = conditions_by_opcode(conditions) 35 | for public_key, message_hash in pkm_pairs_for_conditions_dict( 36 | conditions_dict, coin_solution.coin.name(), additional_data 37 | ): 38 | signature = self.sign(bytes(public_key), message_hash) 39 | signatures.append(signature) 40 | return AugSchemeMPL.aggregate(signatures) 41 | -------------------------------------------------------------------------------- /tests/wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/wallet/__init__.py -------------------------------------------------------------------------------- /tests/wallet/cc_wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/wallet/cc_wallet/__init__.py -------------------------------------------------------------------------------- /tests/wallet/rl_wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/wallet/rl_wallet/__init__.py -------------------------------------------------------------------------------- /tests/wallet/rpc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/wallet/rpc/__init__.py -------------------------------------------------------------------------------- /tests/wallet/sync/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Avocado-Network/avocado-blockchain/9b483e459c524fc97e78fa6d426780fb7371a96e/tests/wallet/sync/__init__.py -------------------------------------------------------------------------------- /tests/wallet/sync/config.py: -------------------------------------------------------------------------------- 1 | job_timeout = 60 2 | -------------------------------------------------------------------------------- /tests/wallet/test_bech32m.py: -------------------------------------------------------------------------------- 1 | # Based on this specification from Pieter Wuille: 2 | # https://github.com/sipa/bips/blob/bip-bech32m/bip-bech32m.mediawiki 3 | 4 | from chia.util.bech32m import bech32_decode 5 | 6 | 7 | def test_valid_imports(): 8 | test_strings = [ 9 | "A1LQFN3A", 10 | "a1lqfn3a", 11 | "an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6", 12 | "abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx", 13 | "11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8", 14 | "split1checkupstagehandshakeupstreamerranterredcaperredlc445v", 15 | "?1v759aa", 16 | ] 17 | for test_str in test_strings: 18 | hrp, data = bech32_decode(test_str) 19 | assert data is not None 20 | 21 | 22 | def test_invalid_imports(): 23 | test_strings = [ 24 | f"{0x20}1xj0phk", 25 | f"{0x7F}1g6xzxy", 26 | f"{0x80}1vctc34", 27 | "an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4", 28 | "qyrz8wqd2c9m", 29 | "1qyrz8wqd2c9m", 30 | "y1b0jsk6g", 31 | "lt1igcx5c0", 32 | "in1muywd", 33 | "mm1crxm3i", 34 | "au1s5cgom", 35 | "M1VUXWEZ", 36 | "16plkw9", 37 | "1p2gdwpf", 38 | ] 39 | for test_str in test_strings: 40 | hrp, data = bech32_decode(test_str) 41 | assert data is None 42 | -------------------------------------------------------------------------------- /tests/wallet/test_taproot.py: -------------------------------------------------------------------------------- 1 | from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import ( 2 | DEFAULT_HIDDEN_PUZZLE, 3 | calculate_synthetic_offset, 4 | calculate_synthetic_public_key, 5 | ) 6 | from tests.core.make_block_generator import int_to_public_key 7 | 8 | 9 | class TestTaproot: 10 | def test_1(self): 11 | for main_secret_exponent in range(500, 600): 12 | hidden_puzzle_hash = DEFAULT_HIDDEN_PUZZLE.get_tree_hash() 13 | main_pubkey = int_to_public_key(main_secret_exponent) 14 | offset = calculate_synthetic_offset(main_pubkey, hidden_puzzle_hash) 15 | offset_pubkey = int_to_public_key(offset) 16 | spk1 = main_pubkey + offset_pubkey 17 | spk2 = calculate_synthetic_public_key(main_pubkey, hidden_puzzle_hash) 18 | assert spk1 == spk2 19 | 20 | return 0 21 | --------------------------------------------------------------------------------