├── .flake8 ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── config.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-windows-installer.yml ├── .gitignore ├── .gitmodules ├── .isort.cfg ├── .pre-commit-config.yaml ├── BUILD_TIMELORD.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── INSTALL.md ├── Install-gui.ps1 ├── Install.ps1 ├── LICENSE ├── README.md ├── azure-pipelines.yml ├── benchmarks └── coin_store.py ├── build_scripts ├── build_linux_deb.sh ├── build_linux_rpm.sh ├── build_macos.sh ├── build_macos_m1.sh ├── build_windows.ps1 ├── clean-runner.sh └── installer-version.py ├── install-gui.sh ├── install-timelord.sh ├── install.sh ├── installhelper.py ├── mint ├── __init__.py ├── clvm │ ├── singleton.py │ └── spend_sim.py ├── cmds │ ├── __init__.py │ ├── configure.py │ ├── farm.py │ ├── farm_funcs.py │ ├── init.py │ ├── init_funcs.py │ ├── keys.py │ ├── keys_funcs.py │ ├── mint.py │ ├── netspace.py │ ├── netspace_funcs.py │ ├── passphrase.py │ ├── passphrase_funcs.py │ ├── plotnft.py │ ├── plotnft_funcs.py │ ├── plots.py │ ├── plotters.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 │ ├── keychain_proxy.py │ ├── keychain_server.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 │ ├── hint_store.py │ ├── lock_queue.py │ ├── mempool.py │ ├── mempool_check_conditions.py │ ├── mempool_manager.py │ ├── pending_tx_cache.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 ├── plotters │ ├── __init__.py │ ├── bladebit.py │ ├── chiapos.py │ ├── install_plotter.py │ ├── madmax.py │ ├── plotters.py │ └── plotters_util.py ├── plotting │ ├── check_plots.py │ ├── create_plots.py │ ├── manager.py │ └── util.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 │ ├── protocol_state_machine.py │ ├── protocol_timing.py │ ├── shared_protocol.py │ ├── timelord_protocol.py │ └── wallet_protocol.py ├── py.typed ├── 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 │ ├── create_ssl.py │ ├── dst_root_ca.pem │ ├── mint_ca.crt │ └── mint_ca.key ├── 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 │ ├── coin_spend.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 │ ├── transaction_queue_entry.py │ ├── unfinished_block.py │ ├── unfinished_header_block.py │ └── weight_proof.py ├── util │ ├── __init__.py │ ├── api_decorators.py │ ├── bech32m.py │ ├── block_cache.py │ ├── byte_types.py │ ├── cached_bls.py │ ├── chain_utils.py │ ├── check_fork_next_block.py │ ├── clvm.py │ ├── condition_tools.py │ ├── config.py │ ├── create_alert_file.py │ ├── db_synchronous.py │ ├── db_wrapper.py │ ├── default_root.py │ ├── dump_keyring.py │ ├── english.txt │ ├── errors.py │ ├── file_keyring.py │ ├── generator_tools.py │ ├── hash.py │ ├── initial-config.yaml │ ├── ints.py │ ├── json_util.py │ ├── keychain.py │ ├── keyring_wrapper.py │ ├── lru_cache.py │ ├── make_test_constants.py │ ├── merkle_set.py │ ├── mint_logging.py │ ├── misc.py │ ├── network.py │ ├── partial_func.py │ ├── path.py │ ├── permissions.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 │ ├── ssl_check.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_spend_entry.clvm │ ├── decompress_coin_spend_entry.clvm.hex │ ├── decompress_coin_spend_entry.clvm.hex.sha256tree │ ├── decompress_coin_spend_entry_with_prefix.clvm │ ├── decompress_coin_spend_entry_with_prefix.clvm.hex │ ├── decompress_coin_spend_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_spends.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 ├── mypy.ini ├── pyproject.toml ├── run-py-tests.sh ├── setup.py └── tests ├── README.md ├── __init__.py ├── block_tools.py ├── blockchain ├── __init__.py ├── config.py ├── test_blockchain.py └── test_blockchain_transactions.py ├── build-workflows.py ├── check_pytest_monitor_output.py ├── clvm ├── __init__.py ├── coin_store.py ├── config.py ├── test_chialisp_deserialization.py ├── test_clvm_compilation.py ├── test_program.py ├── test_puzzles.py ├── test_serialized_program.py ├── test_singletons.py └── test_spend_sim.py ├── conftest.py ├── connection_utils.py ├── core ├── __init__.py ├── consensus │ ├── __init__.py │ └── test_pot_iterations.py ├── custom_types │ ├── __init__.py │ ├── test_coin.py │ ├── test_proof_of_space.py │ └── test_spend_bundle.py ├── daemon │ └── test_daemon.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_hint_store.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 └── util │ ├── __init__.py │ ├── test_cached_bls.py │ ├── test_config.py │ ├── test_file_keyring_synchronization.py │ ├── test_keychain.py │ ├── test_keyring_wrapper.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 ├── mint-start-sim ├── pools ├── __init__.py ├── test_pool_cmdline.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 ├── blockchain.py ├── config.py ├── db_connection.py ├── generator_tools_testing.py ├── key_tool.py ├── keyring.py ├── misc.py ├── test_lock_queue.py └── test_struct_stream.py ├── wallet ├── __init__.py ├── cc_wallet │ ├── __init__.py │ ├── test_cc_wallet.py │ └── test_trades.py ├── did_wallet │ ├── test_did.py │ └── test_did_rpc.py ├── rl_wallet │ ├── __init__.py │ ├── test_rl_rpc.py │ └── test_rl_wallet.py ├── rpc │ ├── __init__.py │ └── test_wallet_rpc.py ├── simple_sync │ └── test_simple_sync_protocol.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 | 12 | 13 | **To Reproduce** 14 | 15 | Steps to reproduce the behavior: 16 | 17 | 1. Go to '...' 18 | 2. Click on '....' 19 | 3. Scroll down to '....' 20 | 4. See error 21 | 22 | **Expected behavior** 23 | 24 | 25 | **Screenshots** 26 | 27 | 28 | **Desktop** 29 | 30 | 31 | - OS: 32 | - OS Version/Flavor: 33 | - CPU: 34 | 35 | **Additional context** 36 | 37 | -------------------------------------------------------------------------------- /.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/MintNetwork/mint-blockchain/issues 6 | - about: Request a new feature or idea here 7 | name: Make a Request 8 | url: >- 9 | https://github.com/MintNetwork/mint-blockchain/pulls 10 | - about: Get support on the Mint Discord chat channels. 11 | name: Join the Discord support chat 12 | url: 'https://discord.gg/rAtQwUJ9Ac' -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | mint-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 | mint-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 | # mint-blockchain-gui/src/dev_config.js 92 | # React built app 93 | mint-blockchain-gui/.eslintcache 94 | mint-blockchain-gui/build 95 | build_scripts/dist 96 | build_scripts/*.Dmg 97 | mint-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 "mozilla-ca"] 2 | path = mozilla-ca 3 | url = https://github.com/Chia-Network/mozilla-ca.git 4 | [submodule "mint-blockchain-gui"] 5 | path = mint-blockchain-gui 6 | url = https://github.com/MintNetwork/mint-blockchain-gui 7 | -------------------------------------------------------------------------------- /.isort.cfg: -------------------------------------------------------------------------------- 1 | .github/linters/.isort.cfg -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.0.1 4 | hooks: 5 | - id: check-yaml 6 | - id: end-of-file-fixer 7 | exclude: ".*?(.hex|.clvm|.clib)" 8 | - id: trailing-whitespace 9 | - id: check-merge-conflict 10 | - id: check-ast 11 | - id: debug-statements 12 | - repo: https://github.com/psf/black 13 | rev: 21.8b0 14 | hooks: 15 | - id: black 16 | - repo: https://gitlab.com/pycqa/flake8 17 | rev: 3.9.2 18 | hooks: 19 | - id: flake8 20 | - repo: https://github.com/pre-commit/mirrors-mypy 21 | rev: v0.910 22 | hooks: 23 | - id: mypy 24 | additional_dependencies: [types-setuptools, types-PyYAML] 25 | -------------------------------------------------------------------------------- /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/MintNetwork/mint-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/MintNetwork/mint-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/MintNetwork/mint-blockchain/wiki/INSTALL) section of the repository [Wiki](https://github.com/MintNetwork/mint-blockchain/wiki). 4 | 5 | After installing, follow the remaining instructions in the 6 | [Quick Start Guide](https://github.com/MintNetwork/mint-blockchain/wiki/Quick-Start-Guide) 7 | to run the software. 8 | -------------------------------------------------------------------------------- /Install-gui.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | 3 | if ($null -eq (Get-ChildItem env:VIRTUAL_ENV -ErrorAction SilentlyContinue)) 4 | { 5 | Write-Output "This script requires that the Mint Python virtual environment is activated." 6 | Write-Output "Execute '.\venv\Scripts\Activate.ps1' before running." 7 | Exit 1 8 | } 9 | 10 | if ($null -eq (Get-Command node -ErrorAction SilentlyContinue)) 11 | { 12 | Write-Output "Unable to find Node.js" 13 | Exit 1 14 | } 15 | 16 | Write-Output "Running 'git submodule update --init --recursive'." 17 | Write-Output "" 18 | git submodule update --init --recursive 19 | 20 | Push-Location 21 | try { 22 | Set-Location mint-blockchain-gui 23 | 24 | $ErrorActionPreference = "SilentlyContinue" 25 | npm install --loglevel=error 26 | npm audit fix 27 | npm run build 28 | py ..\installhelper.py 29 | 30 | Write-Output "" 31 | Write-Output "Mint blockchain Install-gui.ps1 completed." 32 | Write-Output "" 33 | Write-Output "Type 'cd mint-blockchain-gui' and then 'npm run electron' to start the GUI." 34 | } finally { 35 | Pop-Location 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mint-blockchain 2 | 3 | **Mint** is a modern community-centric green cryptocurrency based on a proof-of-space-and-time consensus algorithm. It is a community-supported fork of the [Chia Network](https://github.com/Chia-Network/chia-blockchain) codebase. 4 | 5 | For more information, see our website and downloads at https://mintnet.work. 6 | -------------------------------------------------------------------------------- /build_scripts/clean-runner.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Cleans up files/directories that may be left over from previous runs for a clean slate before starting a new build 3 | 4 | PWD=$(pwd) 5 | 6 | rm -rf ../venv || true 7 | rm -rf venv || true 8 | rm -rf mint_blockchain.egg-info || true 9 | rm -rf build_scripts/final_installer || true 10 | rm -rf build_scripts/dist || true 11 | rm -rf build_scripts/pyinstaller || true 12 | rm -rf mint-blockchain-gui/build || true 13 | rm -rf mint-blockchain-gui/daemon || true 14 | rm -rf mint-blockchain-gui/node_modules || true 15 | rm mint-blockchain-gui/temp.json || true 16 | ( cd "$PWD/mint-blockchain-gui" && git checkout HEAD -- package-lock.json ) || true 17 | cd "$PWD" || true 18 | 19 | # Do our best to get rid of any globally installed notarize-cli versions so the version in the current build script is 20 | # installed without conflicting with the other version that might be installed 21 | PATH=$(brew --prefix node@14)/bin:$PATH || true 22 | export PATH 23 | npm uninstall -g notarize-cli || true 24 | npm uninstall -g @mint-network/notarize-cli || true 25 | npm uninstall -g electron-installer-dmg || true 26 | npm uninstall -g electron-packager || true 27 | npm uninstall -g electron/electron-osx-sign || true -------------------------------------------------------------------------------- /mint/__init__.py: -------------------------------------------------------------------------------- 1 | from pkg_resources import DistributionNotFound, get_distribution, resource_filename 2 | 3 | try: 4 | __version__ = get_distribution("mint-blockchain").version 5 | except DistributionNotFound: 6 | # package is not installed 7 | __version__ = "unknown" 8 | 9 | PYINSTALLER_SPEC_PATH = resource_filename("mint", "pyinstaller.spec") 10 | -------------------------------------------------------------------------------- /mint/clvm/singleton.py: -------------------------------------------------------------------------------- 1 | from mint.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 | -------------------------------------------------------------------------------- /mint/cmds/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/cmds/__init__.py -------------------------------------------------------------------------------- /mint/cmds/netspace.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import click 4 | 5 | 6 | @click.command("netspace", short_help="Estimate total farmed space on the network") 7 | @click.option( 8 | "-p", 9 | "--rpc-port", 10 | help=( 11 | "Set the port where the Full Node is hosting the RPC interface. " 12 | "See the rpc_port under full_node in config.yaml. " 13 | "[default: 8555]" 14 | ), 15 | type=int, 16 | default=None, 17 | ) 18 | @click.option( 19 | "-d", 20 | "--delta-block-height", 21 | help=( 22 | "Compare a block X blocks older to estimate total network space. " 23 | "Defaults to 4608 blocks (~1 day) and Peak block as the starting block. " 24 | "Use --start BLOCK_HEIGHT to specify starting block. " 25 | "Use 192 blocks to estimate over the last hour." 26 | ), 27 | type=str, 28 | default="4608", 29 | ) 30 | @click.option( 31 | "-s", 32 | "--start", 33 | help="Newest block used to calculate estimated total network space. Defaults to Peak block.", 34 | type=str, 35 | default="", 36 | ) 37 | def netspace_cmd(rpc_port: Optional[int], delta_block_height: str, start: str) -> None: 38 | """ 39 | Calculates the estimated space on the network given two block header hashes. 40 | """ 41 | import asyncio 42 | from .netspace_funcs import netstorge_async 43 | 44 | asyncio.run(netstorge_async(rpc_port, delta_block_height, start)) 45 | -------------------------------------------------------------------------------- /mint/cmds/plotnft.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/cmds/plotnft.py -------------------------------------------------------------------------------- /mint/cmds/plotters.py: -------------------------------------------------------------------------------- 1 | import click 2 | from mint.plotters.plotters import call_plotters 3 | 4 | 5 | @click.command( 6 | "plotters", 7 | short_help="Advanced plotting options", 8 | context_settings={"ignore_unknown_options": True}, 9 | add_help_option=False, 10 | ) 11 | @click.pass_context 12 | @click.argument("args", nargs=-1) 13 | def plotters_cmd(ctx: click.Context, args): 14 | call_plotters(ctx.obj["root_path"], args) 15 | -------------------------------------------------------------------------------- /mint/cmds/start.py: -------------------------------------------------------------------------------- 1 | import click 2 | 3 | from mint.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(list(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 | -------------------------------------------------------------------------------- /mint/cmds/stop.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from pathlib import Path 3 | 4 | import click 5 | 6 | from mint.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 mint.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 mint 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(list(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 | -------------------------------------------------------------------------------- /mint/cmds/units.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | # The rest of the codebase uses mojos everywhere. 4 | # Only use these units for user facing interfaces. 5 | units: Dict[str, int] = { 6 | "mint": 10 ** 12, # 1 mint (XKM) is 1,000,000,000,000 mojo (1 trillion) 7 | "mojo": 1, 8 | "colouredcoin": 10 ** 3, # 1 coloured coin is 1000 colouredcoin mojos 9 | } 10 | -------------------------------------------------------------------------------- /mint/consensus/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/consensus/__init__.py -------------------------------------------------------------------------------- /mint/consensus/block_root_validation.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List, Optional 2 | 3 | from mint.types.blockchain_format.coin import Coin, hash_coin_list 4 | from mint.types.blockchain_format.sized_bytes import bytes32 5 | from mint.util.errors import Err 6 | from mint.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 | -------------------------------------------------------------------------------- /mint/consensus/coinbase.py: -------------------------------------------------------------------------------- 1 | from blspy import G1Element 2 | 3 | from mint.types.blockchain_format.coin import Coin 4 | from mint.types.blockchain_format.sized_bytes import bytes32 5 | from mint.util.ints import uint32, uint64 6 | from mint.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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/consensus/find_fork_point.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from mint.consensus.block_record import BlockRecord 4 | from mint.consensus.blockchain_interface import BlockchainInterface 5 | from mint.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 | -------------------------------------------------------------------------------- /mint/consensus/network_type.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class NetworkType(IntEnum): 5 | MAINNET = 0 6 | TESTNET = 1 7 | -------------------------------------------------------------------------------- /mint/consensus/pos_quality.py: -------------------------------------------------------------------------------- 1 | from mint.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 | -------------------------------------------------------------------------------- /mint/daemon/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/daemon/__init__.py -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/farmer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/farmer/__init__.py -------------------------------------------------------------------------------- /mint/full_node/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/full_node/__init__.py -------------------------------------------------------------------------------- /mint/full_node/hint_store.py: -------------------------------------------------------------------------------- 1 | from typing import List, Tuple 2 | import aiosqlite 3 | from mint.types.blockchain_format.sized_bytes import bytes32 4 | from mint.util.db_wrapper import DBWrapper 5 | import logging 6 | 7 | log = logging.getLogger(__name__) 8 | 9 | 10 | class HintStore: 11 | coin_record_db: aiosqlite.Connection 12 | db_wrapper: DBWrapper 13 | 14 | @classmethod 15 | async def create(cls, db_wrapper: DBWrapper): 16 | self = cls() 17 | self.db_wrapper = db_wrapper 18 | self.coin_record_db = db_wrapper.db 19 | await self.coin_record_db.execute( 20 | "CREATE TABLE IF NOT EXISTS hints(id INTEGER PRIMARY KEY AUTOINCREMENT, coin_id blob, hint blob)" 21 | ) 22 | await self.coin_record_db.execute("CREATE INDEX IF NOT EXISTS hint_index on hints(hint)") 23 | await self.coin_record_db.commit() 24 | return self 25 | 26 | async def get_coin_ids(self, hint: bytes) -> List[bytes32]: 27 | cursor = await self.coin_record_db.execute("SELECT * from hints WHERE hint=?", (hint,)) 28 | rows = await cursor.fetchall() 29 | await cursor.close() 30 | coin_ids = [] 31 | for row in rows: 32 | coin_ids.append(row[1]) 33 | return coin_ids 34 | 35 | async def add_hints(self, coin_hint_list: List[Tuple[bytes32, bytes]]) -> None: 36 | cursor = await self.coin_record_db.executemany( 37 | "INSERT INTO hints VALUES(?, ?, ?)", 38 | [(None,) + record for record in coin_hint_list], 39 | ) 40 | await cursor.close() 41 | -------------------------------------------------------------------------------- /mint/full_node/pending_tx_cache.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | from mint.types.blockchain_format.sized_bytes import bytes32 4 | from mint.types.mempool_item import MempoolItem 5 | 6 | 7 | class PendingTxCache: 8 | _cache_max_total_cost: int 9 | _cache_cost: int 10 | _txs: Dict[bytes32, MempoolItem] 11 | 12 | def __init__(self, cost_limit: int): 13 | self._cache_max_total_cost = cost_limit 14 | self._cache_cost = 0 15 | self._txs = {} 16 | 17 | def add(self, item: MempoolItem): 18 | """ 19 | Adds SpendBundles that have failed to be added to the pool in potential tx set. 20 | This is later used to retry to add them. 21 | """ 22 | if item.spend_bundle_name in self._txs: 23 | return None 24 | 25 | self._txs[item.spend_bundle_name] = item 26 | self._cache_cost += item.cost 27 | 28 | while self._cache_cost > self._cache_max_total_cost: 29 | first_in = list(self._txs.keys())[0] 30 | self._cache_cost -= self._txs[first_in].cost 31 | self._txs.pop(first_in) 32 | 33 | def drain(self) -> Dict[bytes32, MempoolItem]: 34 | ret = self._txs 35 | self._txs = {} 36 | self._cache_cost = 0 37 | return ret 38 | 39 | def cost(self) -> int: 40 | return self._cache_cost 41 | -------------------------------------------------------------------------------- /mint/full_node/signage_point.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from mint.types.blockchain_format.vdf import VDFInfo, VDFProof 5 | from mint.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 | -------------------------------------------------------------------------------- /mint/harvester/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/harvester/__init__.py -------------------------------------------------------------------------------- /mint/introducer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/introducer/__init__.py -------------------------------------------------------------------------------- /mint/plotters/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/plotters/__init__.py -------------------------------------------------------------------------------- /mint/plotters/install_plotter.py: -------------------------------------------------------------------------------- 1 | import os 2 | from mint.plotters.bladebit import install_bladebit 3 | from mint.plotters.madmax import install_madmax 4 | 5 | 6 | def install_plotter(plotter, root_path): 7 | if plotter == "chiapos": 8 | print("Chiapos already installed. No action taken.") 9 | return 10 | elif plotter == "madmax": 11 | if not os.path.exists(root_path / "madmax-plotter/build/mint_plot"): 12 | print("Installing madmax plotter.") 13 | try: 14 | install_madmax(root_path) 15 | except Exception as e: 16 | print(f"Exception while installing madmax plotter: {e}") 17 | return 18 | else: 19 | print("Madmax plotter already installed.") 20 | elif plotter == "bladebit": 21 | if not os.path.exists(root_path / "bladebit/.bin/release/bladebit"): 22 | print("Installing bladebit plotter.") 23 | try: 24 | install_bladebit(root_path) 25 | except Exception as e: 26 | print(f"Exception while installing bladebit plotter: {e}") 27 | return 28 | else: 29 | print("Bladebit plotter already installed.") 30 | else: 31 | print("Unknown plotter. No action taken.") 32 | return 33 | -------------------------------------------------------------------------------- /mint/pools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/pools/__init__.py -------------------------------------------------------------------------------- /mint/protocols/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/protocols/__init__.py -------------------------------------------------------------------------------- /mint/protocols/introducer_protocol.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | 4 | from mint.types.peer_info import TimestampedPeerInfo 5 | from mint.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 | -------------------------------------------------------------------------------- /mint/protocols/protocol_timing.py: -------------------------------------------------------------------------------- 1 | # These settings should not be end-user configurable 2 | INVALID_PROTOCOL_BAN_SECONDS = 10 3 | API_EXCEPTION_BAN_SECONDS = 10 4 | INTERNAL_PROTOCOL_ERROR_BAN_SECONDS = 10 # Don't flap if our client is at fault 5 | -------------------------------------------------------------------------------- /mint/protocols/shared_protocol.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from enum import IntEnum 3 | from typing import List, Tuple 4 | 5 | from mint.util.ints import uint8, uint16 6 | from mint.util.streamable import Streamable, streamable 7 | 8 | protocol_version = "0.0.33" 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 mint 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 | -------------------------------------------------------------------------------- /mint/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/py.typed -------------------------------------------------------------------------------- /mint/rpc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/rpc/__init__.py -------------------------------------------------------------------------------- /mint/rpc/harvester_rpc_client.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, List 2 | 3 | from mint.rpc.rpc_client import RpcClient 4 | 5 | 6 | class HarvesterRpcClient(RpcClient): 7 | """ 8 | Client to Mint 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 Mint'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 | -------------------------------------------------------------------------------- /mint/server/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/server/__init__.py -------------------------------------------------------------------------------- /mint/server/outbound_message.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from enum import IntEnum 3 | from typing import Any, Optional 4 | 5 | from mint.protocols.protocol_message_types import ProtocolMessageTypes 6 | from mint.util.ints import uint8, uint16 7 | from mint.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 | -------------------------------------------------------------------------------- /mint/server/reconnect_task.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import socket 3 | 4 | from mint.server.server import MintServer 5 | from mint.types.peer_info import PeerInfo 6 | 7 | 8 | def start_reconnect_task(server: MintServer, peer_info_arg: PeerInfo, log, auth: bool): 9 | """ 10 | Start a background task that checks connection and reconnects periodically to a peer. 11 | """ 12 | # If peer_info_arg is already an address, use it, otherwise resolve it here. 13 | if peer_info_arg.is_valid(): 14 | peer_info = peer_info_arg 15 | else: 16 | peer_info = PeerInfo(socket.gethostbyname(peer_info_arg.host), peer_info_arg.port) 17 | 18 | async def connection_check(): 19 | while True: 20 | peer_retry = True 21 | for _, connection in server.all_connections.items(): 22 | if connection.get_peer_info() == peer_info or connection.get_peer_info() == peer_info_arg: 23 | peer_retry = False 24 | if peer_retry: 25 | log.info(f"Reconnecting to peer {peer_info}") 26 | try: 27 | await server.start_client(peer_info, None, auth=auth) 28 | except Exception as e: 29 | log.info(f"Failed to connect to {peer_info} {e}") 30 | await asyncio.sleep(3) 31 | 32 | return asyncio.create_task(connection_check()) 33 | -------------------------------------------------------------------------------- /mint/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 mint_ssl_ca_paths(path: Path, config: Dict): 27 | return ( 28 | path / config["mint_ssl_ca"]["crt"], 29 | path / config["mint_ssl_ca"]["key"], 30 | ) 31 | -------------------------------------------------------------------------------- /mint/server/start_introducer.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | from typing import Dict 3 | 4 | from mint.introducer.introducer import Introducer 5 | from mint.introducer.introducer_api import IntroducerAPI 6 | from mint.server.outbound_message import NodeType 7 | from mint.server.start_service import run_service 8 | from mint.util.config import load_config_cli 9 | from mint.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 | -------------------------------------------------------------------------------- /mint/server/start_timelord.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import pathlib 3 | from typing import Dict 4 | 5 | from mint.consensus.constants import ConsensusConstants 6 | from mint.consensus.default_constants import DEFAULT_CONSTANTS 7 | from mint.server.outbound_message import NodeType 8 | from mint.server.start_service import run_service 9 | from mint.timelord.timelord import Timelord 10 | from mint.timelord.timelord_api import TimelordAPI 11 | from mint.types.peer_info import PeerInfo 12 | from mint.util.config import load_config_cli 13 | from mint.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 | -------------------------------------------------------------------------------- /mint/simulator/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/simulator/__init__.py -------------------------------------------------------------------------------- /mint/simulator/simulator_constants.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | from tests.block_tools import create_block_tools, test_constants 3 | from tests.util.keyring import TempKeyring 4 | from mint.util.default_root import DEFAULT_ROOT_PATH 5 | 6 | with TempKeyring() as keychain: 7 | # TODO: mariano: fix this with new consensus 8 | bt = create_block_tools(root_path=DEFAULT_ROOT_PATH, keychain=keychain) 9 | new_genesis_block = bt.create_genesis_block(test_constants, b"0") 10 | 11 | print(bytes(new_genesis_block)) 12 | -------------------------------------------------------------------------------- /mint/simulator/simulator_protocol.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from mint.types.blockchain_format.sized_bytes import bytes32 4 | from mint.util.ints import uint32 5 | from mint.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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/ssl/mint_ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDKTCCAhGgAwIBAgIUNgtAPGy+jcZhwAivtrGUIkIQ89EwDQYJKoZIhvcNAQEL 3 | BQAwRDENMAsGA1UECgwERmxheDEQMA4GA1UEAwwHRmxheCBDQTEhMB8GA1UECwwY 4 | T3JnYW5pYyBGYXJtaW5nIERpdmlzaW9uMB4XDTIxMDYxNTEwMDE0NloXDTMxMDYx 5 | MzEwMDE0NlowRDENMAsGA1UECgwERmxheDEQMA4GA1UEAwwHRmxheCBDQTEhMB8G 6 | A1UECwwYT3JnYW5pYyBGYXJtaW5nIERpdmlzaW9uMIIBIjANBgkqhkiG9w0BAQEF 7 | AAOCAQ8AMIIBCgKCAQEAmqcnpRQBo8bcIF35HuwcuuLEtOVTEM+ZW8kWy6SWyBIG 8 | jd10AuldbSPgXoN6Gez/vVWXWpJkc5pGc4KgdMtSUalaQutJglqMEKz0B+0MLpiR 9 | pBY7vE0aPuRAsIdtnjzrEzkeiw4GdfjBa2IOz+aheJReXlQgAxiR0lEhj7fHqCQY 10 | gQ7TZnCnQ+rMKH5c72RYzbSitC614rqa1pgDheHSnZAF0Z6AByZCExCcz3EC0hJI 11 | Az8ln2HVGt3xurb8JmZGRlxZtU4ei3ZIyYjKfE2ApFQkZ8NR8IMbBgODvuL+c7kH 12 | 2rDfM4mgix+1tRAYJsh/9YjXYgv/hjjXgh7WrkyA7QIDAQABoxMwETAPBgNVHRMB 13 | Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBZGE0C3YSWWZ/wxYCeZU+tgjGM 14 | pvUxrdKZmnuf8ErK048U1y+AD4a5LwcJIcwiIL/S5EKHAbL2C+kMrUzGYI3eAqNt 15 | fMcFvh/izpENUa86X0zLiW0H55zKCLK1CynI0uJ+JbpfuIDQkU+fLtSXhAMvu1Ow 16 | P+F3umj1RzVVhDAYWfq5yuainceyYAZVex2B++K/L6FGP+Sp6erEamKIwbTJ6Lvb 17 | B/GS927CXVmi/fmKDs8CvuREJB7VB70PW1ZapsBx/NKmCYEjvCr46aE3VhF2/8wp 18 | fk4F/oveThwsZwyV2kqmx7EEFLYZrZtCGG0IX4hyqYBDEZ8m0pNoqZIM2lzv 19 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /mint/ssl/mint_ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAmqcnpRQBo8bcIF35HuwcuuLEtOVTEM+ZW8kWy6SWyBIGjd10 3 | AuldbSPgXoN6Gez/vVWXWpJkc5pGc4KgdMtSUalaQutJglqMEKz0B+0MLpiRpBY7 4 | vE0aPuRAsIdtnjzrEzkeiw4GdfjBa2IOz+aheJReXlQgAxiR0lEhj7fHqCQYgQ7T 5 | ZnCnQ+rMKH5c72RYzbSitC614rqa1pgDheHSnZAF0Z6AByZCExCcz3EC0hJIAz8l 6 | n2HVGt3xurb8JmZGRlxZtU4ei3ZIyYjKfE2ApFQkZ8NR8IMbBgODvuL+c7kH2rDf 7 | M4mgix+1tRAYJsh/9YjXYgv/hjjXgh7WrkyA7QIDAQABAoIBACroa6hyZ44QE2zr 8 | hb3dlo8Hcboa0jQc1RjRLwDrNmZmEel0YsaYBrLMPGkco1jkF4RpZefcLACi8h8E 9 | RA6DhuBfU0qzyx5ejvPleINmcnXPIMFc5c/1uG1wmL4hpPk9P5+CvoWoK4S5srhf 10 | aWqnO2+gApq7TnJtc6/dkKk2PS/Z/YLrVm2dbGtR7gblKJhUPouY/r0YEh6nnuH6 11 | q0/iQFXFRnuzI+ucOYDAyQ+SMCZRQ5VeE0XPUKVYJQb2V2EMUTndJ+dI1TxFJIgw 12 | wB2fA4IiJsNdYlSl5xrQtGpbUoiM5FND3CC/NsjKgDrsIbiMy1eLdmMhN1lbqJjj 13 | EZSd56ECgYEAyXcDA5Ah9CJw4OlQcJN34ZQG7rDilahwAKsXL7M6lJVXgD4eiQ9Q 14 | pYxt3zn5R79UggkRWTI1dFBZ50dKrlKd9PkI0xIDcfXdjOoH0RZQ0tuimFqHubyC 15 | dHN3yNuU95rIzwyT3wMU0AS2DN4m8JGBrTYn6+15k+N0oUCX1U0XT/kCgYEAxIQy 16 | yr2901G0zo5biFk1bOEgp3eX4edI57khjNeoUsUyHLrFkB+36sOCdbgc4eHTIfmm 17 | ETC5O6CI72OtbdZvApVV3cf8Sd/bxGZ53CahG02XP7GMNzY84m019P3OKXvXapKO 18 | X8N+UxSQs1YnBeysH69b/jblpjX2ks3fVLt53ZUCgYAzem+Qt4GVij9hmPxu55+Y 19 | SmTDFPuw1gtYgF86Vwe+87IaGMVgrEMlKg7hHUUvKhqD56FBM20pPWbbjAHvLTkj 20 | YYb5t/6dXf+whBRfPt6EIo8Xcvp/YUXMT7zp3AHiivCIx2P5diYZSTrjath0XBnQ 21 | kqf8xv9r5JDmq0SgwkQUsQKBgQCCXLwg+Du7umD6AT/BNISXZMS3s0MjDb20UoBq 22 | IQm9VqlGm7PBRvlHmEir9OXcBmV8DVNX5f2LC5SrUXFUAsMDcLNUe3zmOMVeBSjj 23 | nRCUvyUNkKdWXPmIry/zBIdFx6yAOxaNem8LiAHxpb4fVQBdyIN7IUm4t+WJP17e 24 | o7tU/QKBgBZ+ejP5SWtjtzFLMbAAgKlBp/f/ErUb7omrsyCL3e/tzveDgLorUunk 25 | 0211k7+VvueLich7grUOXjvpL30gem9HD4rpnNH3R6l3HtL3AA0/ZjUNIDvuB12y 26 | Kzs0SeTE4Nj3k5vTexoR4WXoIy6l0leIq4rAIym1WWtC6SR8VJRg 27 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /mint/timelord/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/timelord/__init__.py -------------------------------------------------------------------------------- /mint/timelord/iters_from_block.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Tuple, Union 2 | 3 | from mint.consensus.pot_iterations import calculate_ip_iters, calculate_iterations_quality, calculate_sp_iters 4 | from mint.types.blockchain_format.reward_chain_block import RewardChainBlock, RewardChainBlockUnfinished 5 | from mint.types.blockchain_format.sized_bytes import bytes32 6 | from mint.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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/types/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/types/__init__.py -------------------------------------------------------------------------------- /mint/types/announcement.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from mint.types.blockchain_format.sized_bytes import bytes32 4 | from mint.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 | 15 | def __str__(self): 16 | return self.name().decode("utf-8") 17 | -------------------------------------------------------------------------------- /mint/types/blockchain_format/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/types/blockchain_format/__init__.py -------------------------------------------------------------------------------- /mint/types/blockchain_format/classgroup.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from mint.consensus.constants import ConsensusConstants 4 | from mint.types.blockchain_format.sized_bytes import bytes100 5 | from mint.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 | -------------------------------------------------------------------------------- /mint/types/blockchain_format/pool_target.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from mint.types.blockchain_format.sized_bytes import bytes32 4 | from mint.util.ints import uint32 5 | from mint.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 | -------------------------------------------------------------------------------- /mint/types/blockchain_format/sized_bytes.py: -------------------------------------------------------------------------------- 1 | from mint.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 | -------------------------------------------------------------------------------- /mint/types/blockchain_format/slots.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from blspy import G2Element 5 | 6 | from mint.types.blockchain_format.proof_of_space import ProofOfSpace 7 | from mint.types.blockchain_format.sized_bytes import bytes32 8 | from mint.types.blockchain_format.vdf import VDFInfo, VDFProof 9 | from mint.util.ints import uint8, uint64 10 | from mint.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 | -------------------------------------------------------------------------------- /mint/types/blockchain_format/sub_epoch_summary.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from mint.types.blockchain_format.sized_bytes import bytes32 5 | from mint.util.ints import uint8, uint64 6 | from mint.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 | -------------------------------------------------------------------------------- /mint/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 mint.types.blockchain_format.sized_bytes import bytes32 14 | from mint.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 | -------------------------------------------------------------------------------- /mint/types/coin_record.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from mint.protocols.wallet_protocol import CoinState 5 | from mint.types.blockchain_format.coin import Coin 6 | from mint.types.blockchain_format.sized_bytes import bytes32 7 | from mint.util.ints import uint32, uint64 8 | from mint.util.streamable import Streamable, streamable 9 | 10 | 11 | @dataclass(frozen=True) 12 | @streamable 13 | class CoinRecord(Streamable): 14 | """ 15 | These are values that correspond to a CoinName that are used 16 | in keeping track of the unspent database. 17 | """ 18 | 19 | coin: Coin 20 | confirmed_block_index: uint32 21 | spent_block_index: uint32 22 | spent: bool 23 | coinbase: bool 24 | timestamp: uint64 # Timestamp of the block at height confirmed_block_index 25 | 26 | @property 27 | def name(self) -> bytes32: 28 | return self.coin.name() 29 | 30 | @property 31 | def coin_state(self) -> CoinState: 32 | spent_h = None 33 | if self.spent: 34 | spent_h = self.spent_block_index 35 | confirmed_height: Optional[uint32] = self.confirmed_block_index 36 | if self.confirmed_block_index == 0 and self.timestamp == 0: 37 | confirmed_height = None 38 | return CoinState(self.coin, spent_h, confirmed_height) 39 | -------------------------------------------------------------------------------- /mint/types/coin_solution.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | from .coin_spend import CoinSpend as CoinSolution # noqa 4 | 5 | 6 | warnings.warn("`CoinSolution` is now `CoinSpend`") 7 | -------------------------------------------------------------------------------- /mint/types/coin_spend.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | 4 | from mint.types.blockchain_format.coin import Coin 5 | from mint.types.blockchain_format.program import SerializedProgram, INFINITE_COST 6 | from mint.util.chain_utils import additions_for_solution, fee_for_solution 7 | from mint.util.streamable import Streamable, streamable 8 | 9 | 10 | @dataclass(frozen=True) 11 | @streamable 12 | class CoinSpend(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 | 26 | def reserved_fee(self) -> int: 27 | return fee_for_solution(self.puzzle_reveal, self.solution, INFINITE_COST) 28 | -------------------------------------------------------------------------------- /mint/types/condition_opcodes.py: -------------------------------------------------------------------------------- 1 | import enum 2 | from typing import Any 3 | 4 | 5 | # See mint/wallet/puzzles/condition_codes.clvm 6 | class ConditionOpcode(bytes, enum.Enum): 7 | # AGG_SIG is ascii "1" 8 | 9 | # the conditions below require bls12-381 signatures 10 | 11 | AGG_SIG_UNSAFE = bytes([49]) 12 | AGG_SIG_ME = bytes([50]) 13 | 14 | # the conditions below reserve coin amounts and have to be accounted for in output totals 15 | 16 | CREATE_COIN = bytes([51]) 17 | RESERVE_FEE = bytes([52]) 18 | 19 | # the conditions below deal with announcements, for inter-coin communication 20 | 21 | CREATE_COIN_ANNOUNCEMENT = bytes([60]) 22 | ASSERT_COIN_ANNOUNCEMENT = bytes([61]) 23 | CREATE_PUZZLE_ANNOUNCEMENT = bytes([62]) 24 | ASSERT_PUZZLE_ANNOUNCEMENT = bytes([63]) 25 | 26 | # the conditions below let coins inquire about themselves 27 | 28 | ASSERT_MY_COIN_ID = bytes([70]) 29 | ASSERT_MY_PARENT_ID = bytes([71]) 30 | ASSERT_MY_PUZZLEHASH = bytes([72]) 31 | ASSERT_MY_AMOUNT = bytes([73]) 32 | 33 | # the conditions below ensure that we're "far enough" in the future 34 | 35 | # wall-clock time 36 | ASSERT_SECONDS_RELATIVE = bytes([80]) 37 | ASSERT_SECONDS_ABSOLUTE = bytes([81]) 38 | 39 | # block index 40 | ASSERT_HEIGHT_RELATIVE = bytes([82]) 41 | ASSERT_HEIGHT_ABSOLUTE = bytes([83]) 42 | 43 | def __bytes__(self) -> bytes: 44 | return bytes(self.value) 45 | 46 | @classmethod 47 | def from_bytes(cls: Any, blob: bytes) -> Any: 48 | assert len(blob) == 1 49 | return cls(blob) 50 | -------------------------------------------------------------------------------- /mint/types/condition_with_args.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | 4 | from mint.types.condition_opcodes import ConditionOpcode 5 | from mint.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 | -------------------------------------------------------------------------------- /mint/types/end_of_slot_bundle.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from mint.types.blockchain_format.slots import ( 5 | ChallengeChainSubSlot, 6 | InfusedChallengeChainSubSlot, 7 | RewardChainSubSlot, 8 | SubSlotProofs, 9 | ) 10 | from mint.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 | -------------------------------------------------------------------------------- /mint/types/generator_types.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | from mint.types.blockchain_format.program import SerializedProgram 4 | from mint.util.ints import uint32 5 | from mint.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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/types/mempool_item.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | 4 | from mint.consensus.cost_calculator import NPCResult 5 | from mint.types.blockchain_format.coin import Coin 6 | from mint.types.blockchain_format.program import SerializedProgram 7 | from mint.types.blockchain_format.sized_bytes import bytes32 8 | from mint.types.spend_bundle import SpendBundle 9 | from mint.util.ints import uint64 10 | from mint.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 | -------------------------------------------------------------------------------- /mint/types/name_puzzle_condition.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Dict, List, Tuple 3 | 4 | from mint.types.blockchain_format.sized_bytes import bytes32 5 | from mint.types.condition_with_args import ConditionWithArgs 6 | from mint.types.condition_opcodes import ConditionOpcode 7 | from mint.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 | assert opcode not in d 22 | d[opcode] = l 23 | return d 24 | -------------------------------------------------------------------------------- /mint/types/transaction_queue_entry.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from mint.server.ws_connection import WSMintConnection 5 | from mint.types.blockchain_format.sized_bytes import bytes32 6 | from mint.types.spend_bundle import SpendBundle 7 | 8 | 9 | @dataclass(frozen=True) 10 | class TransactionQueueEntry: 11 | """ 12 | A transaction received from peer. This is put into a queue, and not yet in the mempool. 13 | """ 14 | 15 | transaction: SpendBundle 16 | transaction_bytes: Optional[bytes] 17 | spend_name: bytes32 18 | peer: Optional[WSMintConnection] 19 | test: bool 20 | 21 | def __lt__(self, other): 22 | return self.spend_name < other.spend_name 23 | 24 | def __le__(self, other): 25 | return self.spend_name <= other.spend_name 26 | 27 | def __gt__(self, other): 28 | return self.spend_name > other.spend_name 29 | 30 | def __ge__(self, other): 31 | return self.spend_name >= other.spend_name 32 | -------------------------------------------------------------------------------- /mint/types/unfinished_block.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Optional 3 | 4 | from mint.types.blockchain_format.foliage import Foliage, FoliageTransactionBlock, TransactionsInfo 5 | from mint.types.blockchain_format.program import SerializedProgram 6 | from mint.types.blockchain_format.reward_chain_block import RewardChainBlockUnfinished 7 | from mint.types.blockchain_format.vdf import VDFProof 8 | from mint.types.end_of_slot_bundle import EndOfSubSlotBundle 9 | from mint.util.ints import uint32 10 | from mint.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 | -------------------------------------------------------------------------------- /mint/types/unfinished_header_block.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Optional 3 | 4 | from mint.types.blockchain_format.foliage import Foliage, FoliageTransactionBlock 5 | from mint.types.blockchain_format.reward_chain_block import RewardChainBlockUnfinished 6 | from mint.types.blockchain_format.vdf import VDFProof 7 | from mint.types.end_of_slot_bundle import EndOfSubSlotBundle 8 | from mint.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 | -------------------------------------------------------------------------------- /mint/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/util/__init__.py -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/util/chain_utils.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from clvm.casts import int_from_bytes 4 | 5 | from mint.types.blockchain_format.coin import Coin 6 | from mint.types.blockchain_format.program import SerializedProgram 7 | from mint.types.blockchain_format.sized_bytes import bytes32 8 | from mint.types.condition_opcodes import ConditionOpcode 9 | from mint.util.condition_tools import ( 10 | conditions_dict_for_solution, 11 | created_outputs_for_conditions_dict, 12 | ) 13 | 14 | 15 | def additions_for_solution( 16 | coin_name: bytes32, puzzle_reveal: SerializedProgram, solution: SerializedProgram, max_cost: int 17 | ) -> List[Coin]: 18 | """ 19 | Checks the conditions created by CoinSpend and returns the list of all coins created 20 | """ 21 | err, dic, cost = conditions_dict_for_solution(puzzle_reveal, solution, max_cost) 22 | if err or dic is None: 23 | return [] 24 | return created_outputs_for_conditions_dict(dic, coin_name) 25 | 26 | 27 | def fee_for_solution(puzzle_reveal: SerializedProgram, solution: SerializedProgram, max_cost: int) -> int: 28 | err, dic, cost = conditions_dict_for_solution(puzzle_reveal, solution, max_cost) 29 | if err or dic is None: 30 | return 0 31 | 32 | total = 0 33 | for cvp in dic.get(ConditionOpcode.RESERVE_FEE, []): 34 | amount_bin = cvp.vars[0] 35 | amount = int_from_bytes(amount_bin) 36 | total += amount 37 | return total 38 | -------------------------------------------------------------------------------- /mint/util/check_fork_next_block.py: -------------------------------------------------------------------------------- 1 | from typing import List, Callable 2 | 3 | from mint.consensus.blockchain_interface import BlockchainInterface 4 | from mint.util.ints import uint32 5 | 6 | 7 | async def check_fork_next_block( 8 | blockchain: BlockchainInterface, fork_point_height: uint32, peers_with_peak: List, check_block_future: Callable 9 | ): 10 | our_peak_height = blockchain.get_peak_height() 11 | ses_heigths = blockchain.get_ses_heights() 12 | if len(ses_heigths) > 2 and our_peak_height is not None: 13 | ses_heigths.sort() 14 | max_fork_ses_height = ses_heigths[-3] 15 | potential_peek = uint32(our_peak_height + 1) 16 | # This is the fork point in SES in the case where no fork was detected 17 | if blockchain.get_peak_height() is not None and fork_point_height == max_fork_ses_height: 18 | for peer in peers_with_peak: 19 | if peer.closed: 20 | peers_with_peak.remove(peer) 21 | continue 22 | # Grab a block at peak + 1 and check if fork point is actually our current height 23 | if await check_block_future(peer, potential_peek, blockchain): 24 | fork_point_height = our_peak_height 25 | break 26 | return fork_point_height 27 | -------------------------------------------------------------------------------- /mint/util/clvm.py: -------------------------------------------------------------------------------- 1 | from clvm.casts import int_from_bytes, int_to_bytes # noqa 2 | -------------------------------------------------------------------------------- /mint/util/db_synchronous.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | 4 | def db_synchronous_on(setting: str, db_path: Path) -> str: 5 | if setting == "on": 6 | return "NORMAL" 7 | if setting == "off": 8 | return "OFF" 9 | if setting == "full": 10 | return "FULL" 11 | 12 | # for now, default to synchronous=FULL mode. This can be made more 13 | # sophisticated in the future. There are still material performance 14 | # improvements to be had in cases where the risks are low. 15 | 16 | # e.g. 17 | # type = GetDriveTypeW(db_path) 18 | # if type == DRIVE_FIXED or type == DRIVE_RAMDISK: 19 | # return "OFF" 20 | 21 | return "FULL" 22 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/util/default_root.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | 4 | DEFAULT_ROOT_PATH = Path(os.path.expanduser(os.getenv("MINT_ROOT", "~/.mint/mainnet"))).resolve() 5 | 6 | DEFAULT_KEYS_ROOT_PATH = Path(os.path.expanduser(os.getenv("MINT_KEYS_ROOT", "~/.mint_keys"))).resolve() 7 | -------------------------------------------------------------------------------- /mint/util/hash.py: -------------------------------------------------------------------------------- 1 | import blspy 2 | 3 | from mint.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 | -------------------------------------------------------------------------------- /mint/util/json_util.py: -------------------------------------------------------------------------------- 1 | import dataclasses 2 | import json 3 | from typing import Any 4 | 5 | from aiohttp import web 6 | 7 | from mint.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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/util/make_test_constants.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | from mint.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 | -------------------------------------------------------------------------------- /mint/util/network.py: -------------------------------------------------------------------------------- 1 | from ipaddress import ip_address, IPv4Network, IPv6Network 2 | from typing import Iterable, Union, Any 3 | from mint.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 mint.full_node.full_node_api import FullNodeAPI 21 | 22 | return FullNodeAPI 23 | elif type is NodeType.WALLET: 24 | from mint.wallet.wallet_node_api import WalletNodeAPI 25 | 26 | return WalletNodeAPI 27 | elif type is NodeType.INTRODUCER: 28 | from mint.introducer.introducer_api import IntroducerAPI 29 | 30 | return IntroducerAPI 31 | elif type is NodeType.TIMELORD: 32 | from mint.timelord.timelord_api import TimelordAPI 33 | 34 | return TimelordAPI 35 | elif type is NodeType.FARMER: 36 | from mint.farmer.farmer_api import FarmerAPI 37 | 38 | return FarmerAPI 39 | elif type is NodeType.HARVESTER: 40 | from mint.harvester.harvester_api import HarvesterAPI 41 | 42 | return HarvesterAPI 43 | raise ValueError("No class for type") 44 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/util/permissions.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | from typing import Tuple 4 | 5 | 6 | def verify_file_permissions(path: Path, mask: int) -> Tuple[bool, int]: 7 | """ 8 | Check that the file's permissions are properly restricted, as compared to the 9 | permission mask 10 | """ 11 | if not path.exists(): 12 | raise Exception(f"file {path} does not exist") 13 | 14 | mode = os.stat(path).st_mode & 0o777 15 | return (mode & mask == 0, mode) 16 | 17 | 18 | def octal_mode_string(mode: int) -> str: 19 | """Yields a permission mode string: e.g. 0644""" 20 | return f"0{oct(mode)[-3:]}" 21 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/util/prev_transaction_block.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | from mint.consensus.block_record import BlockRecord 4 | from mint.consensus.blockchain_interface import BlockchainInterface 5 | from mint.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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/util/service_groups.py: -------------------------------------------------------------------------------- 1 | from typing import KeysView, Generator 2 | 3 | SERVICES_FOR_GROUP = { 4 | "all": "mint_harvester mint_timelord_launcher mint_timelord mint_farmer mint_full_node mint_wallet".split(), 5 | "node": "mint_full_node".split(), 6 | "harvester": "mint_harvester".split(), 7 | "farmer": "mint_harvester mint_farmer mint_full_node mint_wallet".split(), 8 | "farmer-no-wallet": "mint_harvester mint_farmer mint_full_node".split(), 9 | "farmer-only": "mint_farmer".split(), 10 | "timelord": "mint_timelord_launcher mint_timelord mint_full_node".split(), 11 | "timelord-only": "mint_timelord".split(), 12 | "timelord-launcher-only": "mint_timelord_launcher".split(), 13 | "wallet": "mint_wallet mint_full_node".split(), 14 | "wallet-only": "mint_wallet".split(), 15 | "introducer": "mint_introducer".split(), 16 | "simulator": "mint_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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/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 input_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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/util/validate_alert.py: -------------------------------------------------------------------------------- 1 | import json 2 | from pathlib import Path 3 | 4 | from blspy import AugSchemeMPL, PublicKeyMPL, SignatureMPL 5 | 6 | from mint.util.byte_types import hexstr_to_bytes 7 | from mint.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 | -------------------------------------------------------------------------------- /mint/util/vdf_prover.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | from chiavdf import prove 4 | 5 | from mint.consensus.constants import ConsensusConstants 6 | from mint.types.blockchain_format.classgroup import ClassgroupElement 7 | from mint.types.blockchain_format.sized_bytes import bytes32 8 | from mint.types.blockchain_format.vdf import VDFInfo, VDFProof 9 | from mint.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 | -------------------------------------------------------------------------------- /mint/util/ws_message.py: -------------------------------------------------------------------------------- 1 | from secrets import token_bytes 2 | from typing import Any, Dict 3 | 4 | from mint.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 | -------------------------------------------------------------------------------- /mint/wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/wallet/__init__.py -------------------------------------------------------------------------------- /mint/wallet/block_record.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | 4 | from mint.types.blockchain_format.coin import Coin 5 | from mint.types.header_block import HeaderBlock 6 | from mint.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 | -------------------------------------------------------------------------------- /mint/wallet/cc_wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/wallet/cc_wallet/__init__.py -------------------------------------------------------------------------------- /mint/wallet/cc_wallet/cc_info.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Optional, Tuple 3 | 4 | from mint.types.blockchain_format.program import Program 5 | from mint.types.blockchain_format.sized_bytes import bytes32 6 | from mint.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 | -------------------------------------------------------------------------------- /mint/wallet/derivation_record.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from blspy import G1Element 4 | 5 | from mint.types.blockchain_format.sized_bytes import bytes32 6 | from mint.util.ints import uint32 7 | from mint.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 | -------------------------------------------------------------------------------- /mint/wallet/did_wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/wallet/did_wallet/__init__.py -------------------------------------------------------------------------------- /mint/wallet/did_wallet/did_info.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Optional, Tuple 3 | 4 | from mint.types.blockchain_format.sized_bytes import bytes32 5 | from mint.util.ints import uint64 6 | from mint.util.streamable import streamable, Streamable 7 | from mint.wallet.lineage_proof import LineageProof 8 | from mint.types.blockchain_format.program import Program 9 | from mint.types.blockchain_format.coin import Coin 10 | 11 | 12 | @dataclass(frozen=True) 13 | @streamable 14 | class DIDInfo(Streamable): 15 | origin_coin: Optional[Coin] # Coin ID 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 | sent_recovery_transaction: bool 24 | -------------------------------------------------------------------------------- /mint/wallet/lineage_proof.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from mint.types.blockchain_format.sized_bytes import bytes32 5 | from mint.util.ints import uint64 6 | from mint.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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/wallet/puzzles/__init__.py -------------------------------------------------------------------------------- /mint/wallet/puzzles/block_program_zero.clvm: -------------------------------------------------------------------------------- 1 | 2 | ; TODO convert generators arg to list of generators 3 | 4 | (mod (decompress_puzzle decompress_coin_spend_entry start end compressed_cses deserialize gen_list reserved_arg) 5 | 6 | (defun decompress_cses (decompress_puzzle decompress_coin_spend_entry cses deserialize puzzle_prefix) 7 | (if cses 8 | (c (a decompress_coin_spend_entry (list deserialize decompress_puzzle puzzle_prefix (f cses))) 9 | (decompress_cses decompress_puzzle decompress_coin_spend_entry (r cses) deserialize puzzle_prefix )) 10 | ()) ) 11 | 12 | (list (decompress_cses decompress_puzzle decompress_coin_spend_entry compressed_cses deserialize (substr (f gen_list) start end))) 13 | 14 | ) 15 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/block_program_zero.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff02ff02ffff04ff02ffff04ff05ffff04ff0bffff04ff5fffff04ff81bfffff04ffff0cff82027fff17ff2f80ff8080808080808080ff8080ffff04ffff01ff02ffff03ff17ffff01ff04ffff02ff0bffff04ff2fffff04ff05ffff04ff5fffff04ff27ff808080808080ffff02ff02ffff04ff02ffff04ff05ffff04ff0bffff04ff37ffff04ff2fffff04ff5fff808080808080808080ff8080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/block_program_zero.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | f0a38c8efe58895ae527c65c37f700a4238504691b83990e5dd91bd8b3c30eae 2 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/calculate_synthetic_public_key.clvm.hex: -------------------------------------------------------------------------------- 1 | ff1dff02ffff1effff0bff02ff05808080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/calculate_synthetic_public_key.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 624c5d5704d0decadfc0503e71bbffb6cdfe45025bce7cf3e6864d1eafe8f65e 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/cc.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | d4596fa7aa6eaa267ebce8d527546827de083d58fb4e14f4137c2448f7252e5c 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/cc_loader.py: -------------------------------------------------------------------------------- 1 | from mint.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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/chialisp_deserialisation.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff05ffff02ff3effff04ff02ffff04ff05ff8080808080ffff04ffff01ffffff81ff7fff81df81bfffffff02ffff03ffff09ff0bffff01818080ffff01ff04ff80ffff04ff05ff808080ffff01ff02ffff03ffff0aff0bff1880ffff01ff02ff1affff04ff02ffff04ffff02ffff03ffff0aff0bff1c80ffff01ff02ffff03ffff0aff0bff1480ffff01ff0880ffff01ff04ffff0effff18ffff011fff0b80ffff0cff05ff80ffff01018080ffff04ffff0cff05ffff010180ff80808080ff0180ffff01ff04ffff18ffff013fff0b80ffff04ff05ff80808080ff0180ff80808080ffff01ff04ff0bffff04ff05ff80808080ff018080ff0180ff04ffff0cff15ff80ff0980ffff04ffff0cff15ff0980ff808080ffff04ffff04ff05ff1380ffff04ff2bff808080ffff02ff16ffff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ff15ff80808080ff8080808080ff02ffff03ffff09ffff0cff05ff80ffff010180ff1080ffff01ff02ff2effff04ff02ffff04ffff02ff3effff04ff02ffff04ffff0cff05ffff010180ff80808080ff80808080ffff01ff02ff12ffff04ff02ffff04ffff0cff05ffff010180ffff04ffff0cff05ff80ffff010180ff808080808080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/chialisp_deserialisation.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 94ec19077f9a34e0b11ad2456af0170f4cc03f11230ca42e3f82e6e644ac4f5d 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/condition_codes.clvm: -------------------------------------------------------------------------------- 1 | ; See mint/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 | -------------------------------------------------------------------------------- /mint/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 | ) -------------------------------------------------------------------------------- /mint/wallet/puzzles/create-lock-puzzlehash.clvm.hex.sha256tree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/wallet/puzzles/create-lock-puzzlehash.clvm.hex.sha256tree -------------------------------------------------------------------------------- /mint/wallet/puzzles/decompress_coin_spend_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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/decompress_coin_spend_entry.clvm.hex: -------------------------------------------------------------------------------- 1 | ff04ff4fffff04ffff02ff05ffff04ff02ffff04ff0bffff04ff82012fffff04ff17ff808080808080ffff04ff82014fff8201af808080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/decompress_coin_spend_entry.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 9d98ed08770d31be4bd1bde4705dab388db5e7e9c349f5a76fc3c347aa3a0b79 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/decompress_coin_spend_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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/decompress_coin_spend_entry_with_prefix.clvm.hex: -------------------------------------------------------------------------------- 1 | ff04ff47ffff04ffff02ff05ffff04ff02ffff04ff0bffff04ff8197ffff01ff84ff0180808080808080ffff04ff81a7ff81d7808080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/decompress_coin_spend_entry_with_prefix.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 92aa4bc8060a8836355a1884075141b4791ce1b67ae6092bb166b2845954bc89 2 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/decompress_puzzle.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ff02ffff04ffff0eff05ff0bff1780ff808080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/decompress_puzzle.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | fe94c58f1117afe315e0450daca1c62460ec1a1c439cd4018d79967a5d7d1370 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/did_innerpuz.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | ef41902d9964f6050f87de98b5c4e34512b7d2abded3fe700f7850ff20323bf2 2 | -------------------------------------------------------------------------------- /mint/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_spend ((parent puzzle amount solution) coinname) 20 | (= (sha256 parent (sha256tree1 puzzle) amount) coinname) 21 | ) 22 | 23 | (defun check_for_coinname (coin_spends coinname) 24 | (if coin_spends 25 | (if (check_coin_spend (f coin_spends) coinname) 26 | (list (f (r (f coin_spends))) (f (r (r (r (f coin_spends)))))) 27 | (check_for_coinname (r coin_spends) 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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/generator_for_single_coin.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ff0cffff04ff02ffff04ffff05ffff02ff05ffff04ff0affff04ff13ff8080808080ffff04ff17ff8080808080ffff04ffff01ffffff09ffff0bff09ffff02ff0effff04ff02ffff04ff15ff80808080ff2d80ff0b80ff02ffff03ff05ffff01ff02ffff03ffff02ff08ffff04ff02ffff04ff09ffff04ff0bff8080808080ffff01ff04ff29ffff04ff81b9ff808080ffff01ff02ff0cffff04ff02ffff04ff0dffff04ff0bff808080808080ff0180ffff01ff088080ff0180ffff02ffff01ff05ffff02ff3effff04ff02ffff04ff05ff8080808080ffff04ffff01ffffff81ff7fff81df81bfffffff02ffff03ffff09ff0bffff01818080ffff01ff04ff80ffff04ff05ff808080ffff01ff02ffff03ffff0aff0bff1880ffff01ff02ff1affff04ff02ffff04ffff02ffff03ffff0aff0bff1c80ffff01ff02ffff03ffff0aff0bff1480ffff01ff0880ffff01ff04ffff0effff18ffff011fff0b80ffff0cff05ff80ffff01018080ffff04ffff0cff05ffff010180ff80808080ff0180ffff01ff04ffff18ffff013fff0b80ffff04ff05ff80808080ff0180ff80808080ffff01ff04ff0bffff04ff05ff80808080ff018080ff0180ff04ffff0cff15ff80ff0980ffff04ffff0cff15ff0980ff808080ffff04ffff04ff05ff1380ffff04ff2bff808080ffff02ff16ffff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ff15ff80808080ff8080808080ff02ffff03ffff09ffff0cff05ff80ffff010180ff1080ffff01ff02ff2effff04ff02ffff04ffff02ff3effff04ff02ffff04ffff0cff05ffff010180ff80808080ff80808080ffff01ff02ff12ffff04ff02ffff04ffff0cff05ffff010180ffff04ffff0cff05ff80ffff010180ff808080808080ff0180ff018080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff0effff04ff02ffff04ff09ff80808080ffff02ff0effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/generator_for_single_coin.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 9eb0d58814fff6aec8e9eb9522c08a68d8f004bf1506e6c98388758beee2f80e 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/generator_loader.py: -------------------------------------------------------------------------------- 1 | from mint.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 | -------------------------------------------------------------------------------- /mint/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 | ) -------------------------------------------------------------------------------- /mint/wallet/puzzles/genesis-by-coin-id-with-0.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff03ffff09ff5bff8080ffff01ff0101ffff01ff02ffff03ffff09ff13ff0280ffff01ff0101ff8080ff018080ff0180 -------------------------------------------------------------------------------- /mint/wallet/puzzles/genesis-by-coin-id-with-0.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 258008f81f21c270f4b58488b108a46a35e5df43ca5b0313ac83e900a5e44a5f 2 | -------------------------------------------------------------------------------- /mint/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 | ) -------------------------------------------------------------------------------- /mint/wallet/puzzles/genesis-by-puzzle-hash-with-0.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff03ffff09ff5bff8080ffff01ff0101ffff01ff02ffff03ffff02ffff03ffff09ffff0bff47ff81a7ff82016780ff1380ffff01ff02ffff03ffff09ff81a7ff0280ffff01ff0101ff8080ff0180ff8080ff0180ffff01ff0101ff8080ff018080ff0180 -------------------------------------------------------------------------------- /mint/wallet/puzzles/genesis-by-puzzle-hash-with-0.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 795964e0324fbc08e8383d67659194a70455956ad1ebd2329ccf20008da00936 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/genesis_by_coin_id_with_0.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from mint.types.blockchain_format.coin import Coin 4 | from mint.types.blockchain_format.program import Program 5 | from mint.types.blockchain_format.sized_bytes import bytes32 6 | from mint.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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/genesis_by_puzzle_hash_with_0.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from mint.types.blockchain_format.coin import Coin 4 | from mint.types.blockchain_format.program import Program 5 | from mint.types.blockchain_format.sized_bytes import bytes32 6 | from mint.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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/lock.inner.puzzle.clvm: -------------------------------------------------------------------------------- 1 | ; a trivial puzzle used as the core of a lock puzzle 2 | (mod args (q ())) 3 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/lock.inner.puzzle.clvm.hex: -------------------------------------------------------------------------------- 1 | ff01ff8080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/lock.inner.puzzle.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | f3a579254623f8094e07af862df2e45c9db5592b4105d34a256dd6c498416288 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_conditions.clvm: -------------------------------------------------------------------------------- 1 | (mod (conditions) 2 | (qq (q . (unquote conditions))) 3 | ) 4 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_conditions.clvm.hex: -------------------------------------------------------------------------------- 1 | ff04ffff0101ff0280 -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_conditions.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 1c77d7d5efde60a7a1d2d27db6d746bc8e568aea1ef8586ca967a0d60b83cc36 2 | -------------------------------------------------------------------------------- /mint/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 mint.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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_delegated_conditions.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff0bff80808080ff80808080ff0b80ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_delegated_conditions.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 0ff94726f1a8dea5c3f70d3121945190778d3b2b3fcda3735a1f290977e98341 2 | -------------------------------------------------------------------------------- /mint/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 mint.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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_delegated_puzzle.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff0bff80808080ff80808080ffff02ff0bff178080ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_delegated_puzzle.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 542cde70d1102cd1b763220990873efc8ab15625ded7eae22cc11e21ef2e2f7c 2 | -------------------------------------------------------------------------------- /mint/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 mint.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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ff0bffff01ff02ffff03ffff09ff05ffff1dff0bffff1effff0bff0bffff02ff06ffff04ff02ffff04ff17ff8080808080808080ffff01ff02ff17ff2f80ffff01ff088080ff0180ffff01ff04ffff04ff04ffff04ff05ffff04ffff02ff06ffff04ff02ffff04ff17ff80808080ff80808080ffff02ff17ff2f808080ff0180ffff04ffff01ff32ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff06ffff04ff02ffff04ff09ff80808080ffff02ff06ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | e9aaa49f45bad5c889b86ee3341550c155cfdd10c3a6757de618d20612fffd52 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_m_of_n_delegate_direct.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ffff09ff05ffff02ff16ffff04ff02ffff04ff17ff8080808080ffff01ff02ff0cffff04ff02ffff04ffff02ff0affff04ff02ffff04ff17ffff04ff0bff8080808080ffff04ffff02ff1effff04ff02ffff04ff2fff80808080ffff04ff2fffff04ff5fff80808080808080ffff01ff088080ff0180ffff04ffff01ffff31ff02ffff03ff05ffff01ff04ffff04ff08ffff04ff09ffff04ff0bff80808080ffff02ff0cffff04ff02ffff04ff0dffff04ff0bffff04ff17ffff04ff2fff8080808080808080ffff01ff02ff17ff2f8080ff0180ffff02ffff03ff05ffff01ff02ffff03ff09ffff01ff04ff13ffff02ff0affff04ff02ffff04ff0dffff04ff1bff808080808080ffff01ff02ff0affff04ff02ffff04ff0dffff04ff1bff808080808080ff0180ff8080ff0180ffff02ffff03ff05ffff01ff10ffff02ff16ffff04ff02ffff04ff0dff80808080ffff02ffff03ff09ffff01ff0101ff8080ff018080ff8080ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_m_of_n_delegate_direct.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 0f199d5263ac1a62b077c159404a71abd3f9691cc57520bf1d4c5cb501504457 2 | -------------------------------------------------------------------------------- /mint/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 mint.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 | -------------------------------------------------------------------------------- /mint/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 | ) -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_puzzle_hash.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ffff09ff05ffff02ff02ffff04ff02ffff04ff0bff8080808080ffff01ff02ff0bff1780ffff01ff088080ff0180ffff04ffff01ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff02ffff04ff02ffff04ff09ff80808080ffff02ff02ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_puzzle_hash.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 13e29a62b42cd2ef72a79e4bacdc59733ca6310d65af83d349360d36ec622363 2 | -------------------------------------------------------------------------------- /mint/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 mint.types.blockchain_format.program import Program 9 | from mint.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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_singleton.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff04ff18ffff04ffff0bffff02ff2effff04ff02ffff04ff05ffff04ff2fffff04ffff02ff3effff04ff02ffff04ffff04ff05ffff04ff0bff178080ff80808080ff808080808080ff5f80ff808080ffff04ffff04ff2cffff01ff248080ffff04ffff04ff10ffff04ff5fff808080ff80808080ffff04ffff01ffffff463fff02ff3c04ffff01ff0102ffff02ffff03ff05ffff01ff02ff16ffff04ff02ffff04ff0dffff04ffff0bff3affff0bff12ff3c80ffff0bff3affff0bff3affff0bff12ff2a80ff0980ffff0bff3aff0bffff0bff12ff8080808080ff8080808080ffff010b80ff0180ffff0bff3affff0bff12ff1480ffff0bff3affff0bff3affff0bff12ff2a80ff0580ffff0bff3affff02ff16ffff04ff02ffff04ff07ffff04ffff0bff12ff1280ff8080808080ffff0bff12ff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_singleton.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 40f828d8dd55603f4ff9fbf6b73271e904e69406982f4fbefae2c8dcceaf9834 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_singleton_or_delayed_puzhash.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ff82017fffff01ff04ffff04ff38ffff04ffff0bffff02ff2effff04ff02ffff04ff05ffff04ff81bfffff04ffff02ff3effff04ff02ffff04ffff04ff05ffff04ff0bff178080ff80808080ff808080808080ff82017f80ff808080ffff04ffff04ff3cffff01ff248080ffff04ffff04ff28ffff04ff82017fff808080ff80808080ffff01ff04ffff04ff24ffff04ff2fff808080ffff04ffff04ff2cffff04ff5fffff04ff81bfff80808080ffff04ffff04ff10ffff04ff81bfff808080ff8080808080ff0180ffff04ffff01ffffff49ff463fffff5002ff333cffff04ff0101ffff02ff02ffff03ff05ffff01ff02ff36ffff04ff02ffff04ff0dffff04ffff0bff26ffff0bff2aff1280ffff0bff26ffff0bff26ffff0bff2aff3a80ff0980ffff0bff26ff0bffff0bff2aff8080808080ff8080808080ffff010b80ff0180ffff0bff26ffff0bff2aff3480ffff0bff26ffff0bff26ffff0bff2aff3a80ff0580ffff0bff26ffff02ff36ffff04ff02ffff04ff07ffff04ffff0bff2aff2a80ff8080808080ffff0bff2aff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/p2_singleton_or_delayed_puzhash.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | adb656e0211e2ab4f42069a4c5efc80dc907e7062be08bf1628c8e5b6d94d25b 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/pool_member_innerpuz.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ff8202ffffff01ff02ff16ffff04ff02ffff04ff05ffff04ff8204bfffff04ff8206bfffff04ff82017fffff04ffff0bffff19ff2fffff18ffff019100ffffffffffffffffffffffffffffffffff8202ff8080ff0bff82017f80ff8080808080808080ffff01ff04ffff04ff08ffff04ff17ffff04ffff02ff1effff04ff02ffff04ff82017fff80808080ff80808080ffff04ffff04ff1cffff04ff5fffff04ff8206bfff80808080ff80808080ff0180ffff04ffff01ffff32ff3d33ff3effff04ffff04ff1cffff04ff0bffff04ff17ff80808080ffff04ffff04ff1cffff04ff05ffff04ff2fff80808080ffff04ffff04ff0affff04ff5fff808080ffff04ffff04ff14ffff04ffff0bff5fffff012480ff808080ff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/pool_member_innerpuz.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | a8490702e333ddd831a3ac9c22d0fa26d2bfeaf2d33608deb22f0e0123eb0494 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/pool_waitingroom_innerpuz.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ff82017fffff01ff04ffff04ff1cffff04ff5fff808080ffff04ffff04ff12ffff04ff8205ffffff04ff8206bfff80808080ffff04ffff04ff08ffff04ff17ffff04ffff02ff1effff04ff02ffff04ffff04ff8205ffffff04ff8202ffff808080ff80808080ff80808080ff80808080ffff01ff02ff16ffff04ff02ffff04ff05ffff04ff8204bfffff04ff8206bfffff04ff8202ffffff04ffff0bffff19ff2fffff18ffff019100ffffffffffffffffffffffffffffffffff8205ff8080ff0bff8202ff80ff808080808080808080ff0180ffff04ffff01ffff32ff3d52ffff333effff04ffff04ff12ffff04ff0bffff04ff17ff80808080ffff04ffff04ff12ffff04ff05ffff04ff2fff80808080ffff04ffff04ff1affff04ff5fff808080ffff04ffff04ff14ffff04ffff0bff5fffff012480ff808080ff8080808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/pool_waitingroom_innerpuz.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | a317541a765bf8375e1c6e7c13503d0d2cbf56cacad5182befe947e78e2c0307 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/puzzle_utils.py: -------------------------------------------------------------------------------- 1 | from mint.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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/rl.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ffff03ffff09ff81bfff2480ffff01ff04ffff04ff30ffff04ff5fffff04ffff02ff3effff04ff02ffff04ffff04ff81bfff81ff80ff80808080ff80808080ff81ff80ffff01ff04ffff04ff30ffff04ff05ffff04ffff02ff3effff04ff02ffff04ffff04ff81bfff81ff80ff80808080ff80808080ffff02ffff03ffff09ff81bfff3c80ffff01ff02ff2effff04ff02ffff04ff0bffff04ff17ffff04ff2fffff04ff81ffff80808080808080ffff01ff02ff22ffff04ff02ffff04ff2fffff04ff81ffff808080808080ff01808080ff0180ffff04ffff01ffffffffff02ffff03ffff15ff05ff0b80ffff01ff0101ffff01ff02ffff03ffff09ff05ff0b80ffff01ff0101ff8080ff018080ff018031ff5246ffff0333ff3c01ffffffff02ffff03ffff02ffff03ffff09ffff0bff820bfbff13ff8205fb80ff82017b80ffff01ff0101ffff01ff02ffff03ffff09ff05ff82017b80ffff01ff0101ff8080ff018080ff0180ffff01ff04ffff02ff26ffff04ff02ffff04ff82017bffff04ff13ffff04ff8202fbff808080808080ffff04ffff02ff2affff04ff02ffff04ff2bffff04ff5bffff04ff81bbff808080808080ffff04ffff02ff3affff04ff02ffff04ff13ffff04ffff10ff81bbff8202fb80ff8080808080ff80808080ffff01ffff08808080ff0180ff04ff34ffff04ff05ffff04ffff11ff0bffff10ff17ff2f8080ff80808080ffff04ff2cffff04ffff0bff05ff0bff1780ff808080ff04ff34ffff04ff05ffff04ff0bff80808080ffffff04ff38ffff04ffff0bff05ff0bff1780ff808080ff02ffff03ffff02ff20ffff04ff02ffff04ffff12ff05ff1780ffff04ffff12ff0bff2f80ff8080808080ffff01ff04ff28ffff04ff05ff808080ffff01ffff08808080ff0180ffff02ffff03ffff02ffff03ffff09ffff0bff8217efff81afff822fef80ff4f80ffff01ff0101ffff01ff02ffff03ffff09ff17ff4f80ffff01ff0101ff8080ff018080ff0180ffff01ff04ffff02ff36ffff04ff02ffff04ff820befffff04ff8205efffff04ff05ffff04ff0bff80808080808080ffff04ffff02ff32ffff04ff02ffff04ff81afffff04ff82016fffff04ff8205efffff04ff825fefff80808080808080ffff04ffff02ff26ffff04ff02ffff04ff4fffff04ff81afffff04ff82016fff808080808080ffff04ffff02ff3affff04ff02ffff04ff8202efffff04ff8205efff8080808080ff8080808080ffff01ffff08808080ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/rl.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | f663796a8c522b85bd9472cbea2bf7f138e8351e8e4032706fc0539e87f94faf 2 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/rl_aggregation.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff04ff06ffff04ff0bff808080ffff04ffff04ff04ffff04ffff0bffff0bff17ff05ff2f80ff0b80ff808080ff808080ffff04ffff01ff3d46ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/rl_aggregation.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 007400187f63927ee023a7172bb88f14d49aaa4beb790ecaf7dde7c1a79b6481 2 | -------------------------------------------------------------------------------- /mint/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_spend ((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_spends) 26 | (if coin_spends 27 | (c (process_coin_spend (f coin_spends)) (recurse (r coin_spends))) 28 | 0 29 | ) 30 | ) 31 | 32 | (defun process-decompressor ((coin_spends . block-level-extras)) 33 | (c (recurse coin_spends) block-level-extras) 34 | ) 35 | 36 | (process-decompressor (a block_decompresser_program (list local_deserialize_mod historical_blocks_tree)))) 37 | ) 38 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/rom_bootstrap_generator.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ff0cffff04ff02ffff04ffff02ff05ffff04ff08ffff04ff13ff80808080ff80808080ffff04ffff01ffffff02ffff01ff05ffff02ff3effff04ff02ffff04ff05ff8080808080ffff04ffff01ffffff81ff7fff81df81bfffffff02ffff03ffff09ff0bffff01818080ffff01ff04ff80ffff04ff05ff808080ffff01ff02ffff03ffff0aff0bff1880ffff01ff02ff1affff04ff02ffff04ffff02ffff03ffff0aff0bff1c80ffff01ff02ffff03ffff0aff0bff1480ffff01ff0880ffff01ff04ffff0effff18ffff011fff0b80ffff0cff05ff80ffff01018080ffff04ffff0cff05ffff010180ff80808080ff0180ffff01ff04ffff18ffff013fff0b80ffff04ff05ff80808080ff0180ff80808080ffff01ff04ff0bffff04ff05ff80808080ff018080ff0180ff04ffff0cff15ff80ff0980ffff04ffff0cff15ff0980ff808080ffff04ffff04ff05ff1380ffff04ff2bff808080ffff02ff16ffff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ff15ff80808080ff8080808080ff02ffff03ffff09ffff0cff05ff80ffff010180ff1080ffff01ff02ff2effff04ff02ffff04ffff02ff3effff04ff02ffff04ffff0cff05ffff010180ff80808080ff80808080ffff01ff02ff12ffff04ff02ffff04ffff0cff05ffff010180ffff04ffff0cff05ff80ffff010180ff808080808080ff0180ff018080ff04ffff02ff16ffff04ff02ffff04ff09ff80808080ff0d80ffff04ff09ffff04ffff02ff1effff04ff02ffff04ff15ff80808080ffff04ff2dffff04ffff02ff15ff5d80ff7d80808080ffff02ffff03ff05ffff01ff04ffff02ff0affff04ff02ffff04ff09ff80808080ffff02ff16ffff04ff02ffff04ff0dff8080808080ff8080ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/rom_bootstrap_generator.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 161bade1f822dcd62ab712ebaf30f3922a301e48a639e4295c5685f8bece7bd9 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/rom_bootstrap_generator.py: -------------------------------------------------------------------------------- 1 | from mint.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 | -------------------------------------------------------------------------------- /mint/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 | ) -------------------------------------------------------------------------------- /mint/wallet/puzzles/sha256tree_module.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff02ff02ffff04ff02ffff04ff05ff80808080ffff04ffff01ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff02ffff04ff02ffff04ff09ff80808080ffff02ff02ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/sha256tree_module.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | eb4ead6576048c9d730b5ced00646c7fdd390649cfdf48a00de1590cdd8ee18f 2 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/singleton_launcher.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff04ff04ffff04ff05ffff04ff0bff80808080ffff04ffff04ff0affff04ffff02ff0effff04ff02ffff04ffff04ff05ffff04ff0bffff04ff17ff80808080ff80808080ff808080ff808080ffff04ffff01ff33ff3cff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff0effff04ff02ffff04ff09ff80808080ffff02ff0effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/singleton_launcher.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | eff07522495060c066f66f32acc2a77e3a3e737aca8baea4d1a64ea4cdc13da9 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/singleton_top_layer.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 24e044101e57b3d8c908b8a38ad57848afd29d3eecc439dba45f4412df4954fd 2 | -------------------------------------------------------------------------------- /mint/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 | ) -------------------------------------------------------------------------------- /mint/wallet/puzzles/test_generator_deserialize.clvm: -------------------------------------------------------------------------------- 1 | (mod (deserializer generator_list reserved_arg) 2 | (a deserializer (list reserved_arg)) 3 | ) 4 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/test_generator_deserialize.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ff02ffff04ff0bff808080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/test_generator_deserialize.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 52add794fc76e89512e4a063c383418bda084c8a78c74055abe80179e4a7832c 2 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/test_multiple_generator_input_arguments.clvm: -------------------------------------------------------------------------------- 1 | 2 | (mod (decompress_puzzle decompress_coin_spend_entry start1 end1 start2 end2 compressed_cses deserialize gen_list reserved_arg) 3 | 4 | (defun decompress_cses (decompress_puzzle decompress_coin_spend_entry cses deserialize puzzle_prefix) 5 | (if cses 6 | (c (a decompress_coin_spend_entry (list deserialize decompress_puzzle puzzle_prefix (f cses))) 7 | (decompress_cses decompress_puzzle decompress_coin_spend_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_spend_entry compressed_cses deserialize (join_gen_args gen_list start1 end1 start2 end2))) 18 | 19 | ) 20 | -------------------------------------------------------------------------------- /mint/wallet/puzzles/test_multiple_generator_input_arguments.clvm.hex: -------------------------------------------------------------------------------- 1 | ff02ffff01ff04ffff02ff04ffff04ff02ffff04ff05ffff04ff0bffff04ff82017fffff04ff8202ffffff04ffff02ff06ffff04ff02ffff04ff8205ffffff04ff17ffff04ff2fffff04ff5fffff04ff81bfff8080808080808080ff8080808080808080ff8080ffff04ffff01ffff02ffff03ff17ffff01ff04ffff02ff0bffff04ff2fffff04ff05ffff04ff5fffff04ff27ff808080808080ffff02ff04ffff04ff02ffff04ff05ffff04ff0bffff04ff37ffff04ff2fffff04ff5fff808080808080808080ff8080ff0180ff0effff0cff09ff0bff1780ffff0cff15ff2fff5f8080ff018080 -------------------------------------------------------------------------------- /mint/wallet/puzzles/test_multiple_generator_input_arguments.clvm.hex.sha256tree: -------------------------------------------------------------------------------- 1 | 156dafbddc3e1d3bfe1f2a84e48e5e46b287b8358bf65c3c091c93e855fbfc5b 2 | -------------------------------------------------------------------------------- /mint/wallet/rl_wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/wallet/rl_wallet/__init__.py -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/wallet/settings/default_settings.py: -------------------------------------------------------------------------------- 1 | from mint.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 | -------------------------------------------------------------------------------- /mint/wallet/settings/settings_objects.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from mint.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 | -------------------------------------------------------------------------------- /mint/wallet/trade_record.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Optional, Tuple 3 | 4 | from mint.types.blockchain_format.coin import Coin 5 | from mint.types.blockchain_format.sized_bytes import bytes32 6 | from mint.types.spend_bundle import SpendBundle 7 | from mint.util.ints import uint8, uint32, uint64 8 | from mint.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 | -------------------------------------------------------------------------------- /mint/wallet/trading/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/wallet/trading/__init__.py -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/wallet/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/mint/wallet/util/__init__.py -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/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 | -------------------------------------------------------------------------------- /mint/wallet/wallet_action.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Optional 3 | 4 | from mint.util.ints import uint32 5 | from mint.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 | -------------------------------------------------------------------------------- /mint/wallet/wallet_coin_record.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from mint.types.blockchain_format.coin import Coin 4 | from mint.types.blockchain_format.sized_bytes import bytes32 5 | from mint.util.ints import uint32 6 | from mint.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 | -------------------------------------------------------------------------------- /mint/wallet/wallet_info.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List 3 | 4 | from mint.util.ints import uint8, uint32 5 | from mint.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 | mypy --install-types 8 | 9 | py.test ./tests -s -v 10 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/tests/__init__.py -------------------------------------------------------------------------------- /tests/blockchain/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/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 | limit = 800 13 | 14 | # until this can be optimized, use higher limits 15 | if "test_duplicate_coin_announces" in line[0]: 16 | limit = 2200 17 | elif ( 18 | "test_duplicate_large_integer_substr" in line[0] 19 | or "test_duplicate_reserve_fee" in line[0] 20 | or "test_duplicate_large_integer_negative" in line[0] 21 | or "test_duplicate_large_integer" in line[0] 22 | ): 23 | limit = 1100 24 | 25 | if float(line[3]) > limit: 26 | print(" ERROR: ^^ exceeded RAM limit ^^ \n") 27 | ret += 1 28 | 29 | if ret > 0: 30 | print("some tests used too much RAM") 31 | 32 | sys.exit(ret) 33 | -------------------------------------------------------------------------------- /tests/clvm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/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_program.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from mint.types.blockchain_format.program import Program 4 | from clvm.EvalError import EvalError 5 | 6 | 7 | class TestProgram(TestCase): 8 | def test_at(self): 9 | p = Program.to([10, 20, 30, [15, 17], 40, 50]) 10 | 11 | self.assertEqual(p.first(), p.at("f")) 12 | self.assertEqual(Program.to(10), p.at("f")) 13 | 14 | self.assertEqual(p.rest(), p.at("r")) 15 | self.assertEqual(Program.to([20, 30, [15, 17], 40, 50]), p.at("r")) 16 | 17 | self.assertEqual(p.rest().rest().rest().first().rest().first(), p.at("rrrfrf")) 18 | self.assertEqual(Program.to(17), p.at("rrrfrf")) 19 | 20 | self.assertRaises(ValueError, lambda: p.at("q")) 21 | self.assertRaises(EvalError, lambda: p.at("ff")) 22 | -------------------------------------------------------------------------------- /tests/clvm/test_serialized_program.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | from mint.types.blockchain_format.program import Program, SerializedProgram, INFINITE_COST 4 | from mint.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/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/tests/core/__init__.py -------------------------------------------------------------------------------- /tests/core/consensus/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/tests/core/consensus/__init__.py -------------------------------------------------------------------------------- /tests/core/custom_types/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/tests/core/custom_types/__init__.py -------------------------------------------------------------------------------- /tests/core/custom_types/test_coin.py: -------------------------------------------------------------------------------- 1 | from mint.types.blockchain_format.coin import Coin 2 | from mint.types.blockchain_format.sized_bytes import bytes32 3 | from mint.util.ints import uint64 4 | from mint.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/custom_types/test_proof_of_space.py: -------------------------------------------------------------------------------- 1 | from secrets import token_bytes 2 | 3 | from mint.consensus.default_constants import DEFAULT_CONSTANTS 4 | from mint.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/full_node/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/tests/core/full_node/__init__.py -------------------------------------------------------------------------------- /tests/core/full_node/config.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa: E501 2 | job_timeout = 60 3 | CHECK_RESOURCE_USAGE = """ 4 | - name: Check resource usage 5 | run: | 6 | sqlite3 -readonly -separator " " .pymon "select item,cpu_usage,total_time,mem_usage from TEST_METRICS order by mem_usage desc;" >metrics.out 7 | ./tests/check_pytest_monitor_output.py Tuple[aiosqlite.Connection, Blockchain]: 14 | connection = await aiosqlite.connect(":memory:") 15 | db_wrapper = DBWrapper(connection) 16 | block_store = await BlockStore.create(db_wrapper) 17 | coin_store = await CoinStore.create(db_wrapper) 18 | hint_store = await HintStore.create(db_wrapper) 19 | blockchain = await Blockchain.create(coin_store, block_store, consensus_constants, hint_store) 20 | return connection, blockchain 21 | -------------------------------------------------------------------------------- /tests/core/full_node/test_node_load.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import time 3 | 4 | import pytest 5 | 6 | from mint.protocols import full_node_protocol 7 | from mint.types.peer_info import PeerInfo 8 | from mint.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 mint.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 mint.util.setproctitle import setproctitle 4 | 5 | 6 | class TestSetProcTitle(unittest.TestCase): 7 | def test_does_not_crash(self): 8 | setproctitle("mint test title") 9 | -------------------------------------------------------------------------------- /tests/core/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/tests/core/util/__init__.py -------------------------------------------------------------------------------- /tests/core/util/test_cached_bls.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from blspy import AugSchemeMPL, G1Element 3 | from mint.util import cached_bls 4 | from mint.util.lru_cache import LRUCache 5 | 6 | 7 | class TestCachedBLS(unittest.TestCase): 8 | def test_cached_bls(self): 9 | n_keys = 10 10 | seed = b"a" * 31 11 | sks = [AugSchemeMPL.key_gen(seed + bytes([i])) for i in range(n_keys)] 12 | pks = [bytes(sk.get_g1()) for sk in sks] 13 | 14 | msgs = [("msg-%d" % (i,)).encode() for i in range(n_keys)] 15 | sigs = [AugSchemeMPL.sign(sk, msg) for sk, msg in zip(sks, msgs)] 16 | agg_sig = AugSchemeMPL.aggregate(sigs) 17 | 18 | pks_half = pks[: n_keys // 2] 19 | msgs_half = msgs[: n_keys // 2] 20 | sigs_half = sigs[: n_keys // 2] 21 | agg_sig_half = AugSchemeMPL.aggregate(sigs_half) 22 | 23 | assert AugSchemeMPL.aggregate_verify([G1Element.from_bytes(pk) for pk in pks], msgs, agg_sig) 24 | 25 | # Verify with empty cache and populate it 26 | assert cached_bls.aggregate_verify(pks_half, msgs_half, agg_sig_half, True) 27 | # Verify with partial cache hit 28 | assert cached_bls.aggregate_verify(pks, msgs, agg_sig, True) 29 | # Verify with full cache hit 30 | assert cached_bls.aggregate_verify(pks, msgs, agg_sig) 31 | 32 | # Use a small cache which can not accommodate all pairings 33 | local_cache = LRUCache(n_keys // 2) 34 | # Verify signatures and cache pairings one at a time 35 | for pk, msg, sig in zip(pks_half, msgs_half, sigs_half): 36 | assert cached_bls.aggregate_verify([pk], [msg], sig, True, local_cache) 37 | # Verify the same messages with aggregated signature (full cache hit) 38 | assert cached_bls.aggregate_verify(pks_half, msgs_half, agg_sig_half, False, local_cache) 39 | # Verify more messages (partial cache hit) 40 | assert cached_bls.aggregate_verify(pks, msgs, agg_sig, False, local_cache) 41 | -------------------------------------------------------------------------------- /tests/core/util/test_lru_cache.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from mint.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 mint.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 = -0b1000000111 21 | assert truncate_to_significant_bits(a, 500) == a 22 | a = 0b10101 23 | assert truncate_to_significant_bits(a, 5) == a 24 | a = 0b10101 25 | assert truncate_to_significant_bits(a, 4) == 0b10100 26 | 27 | def test_count_significant_bits(self): 28 | assert count_significant_bits(0b0001) == 1 29 | assert count_significant_bits(0b00010) == 1 30 | assert count_significant_bits(0b01010) == 3 31 | assert count_significant_bits(-0b01010) == 3 32 | assert count_significant_bits(0b0) == 0 33 | assert count_significant_bits(0b1) == 1 34 | assert count_significant_bits(0b1000010101010000) == 12 35 | 36 | 37 | if __name__ == "__main__": 38 | unittest.main() 39 | -------------------------------------------------------------------------------- /tests/mint-start-sim: -------------------------------------------------------------------------------- 1 | _kill_servers() { 2 | PROCS=`ps -e | grep -E 'mint|vdf_client' -v "mint-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 mint 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 mint_farmer --logging.log_stdout=True --logging.log_level=INFO 33 | _run_bg_cmd mint_harvester --logging.log_stdout=True --logging.log_level=INFO 34 | _run_bg_cmd mint_timelord --logging.log_stdout=True --logging.log_level=INFO 35 | _run_bg_cmd mint_timelord_launcher --logging.log_stdout=True --logging.log_level=INFO 36 | _run_bg_cmd mint_introducer --logging.log_stdout=True --logging.log_level=INFO 37 | _run_bg_cmd mint_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 mint_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 mint.daemon.server --logging.log_stdout=True --logging.log_level=INFO 41 | 42 | wait 43 | -------------------------------------------------------------------------------- /tests/pools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/tests/pools/__init__.py -------------------------------------------------------------------------------- /tests/pools/test_pool_cmdline.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa: E501 2 | 3 | import click 4 | import pytest 5 | from click.testing import CliRunner, Result 6 | 7 | from mint.cmds.plotnft import validate_fee 8 | from mint.cmds.plotnft import create_cmd, show_cmd 9 | 10 | 11 | class TestPoolNFTCommands: 12 | def test_validate_fee(self): 13 | with pytest.raises(click.exceptions.BadParameter): 14 | r = validate_fee(None, "fee", "1.0") 15 | 16 | with pytest.raises(click.exceptions.BadParameter): 17 | r = validate_fee(None, "fee", "-1") 18 | 19 | r = validate_fee(None, "fee", "0") 20 | assert r == "0" 21 | 22 | r = validate_fee(None, "fee", "0.000000000001") 23 | assert r == "0.000000000001" 24 | 25 | r = validate_fee(None, "fee", "0.5") 26 | assert r == "0.5" 27 | 28 | def test_plotnft_show(self): 29 | runner = CliRunner() 30 | result: Result = runner.invoke(show_cmd, []) 31 | assert result.exit_code == 0 32 | 33 | def test_validate_fee_cmdline(self): 34 | runner = CliRunner() 35 | result: Result = runner.invoke(create_cmd, ["create", "-s", "local", "--fee", "0.005"]) 36 | assert result.exit_code != 0 37 | -------------------------------------------------------------------------------- /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 mint.pools.pool_config import PoolWalletConfig 7 | from mint.util.config import load_config, save_config, create_default_mint_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_mint_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: 'MintNetwork/test-cache' 5 | path: '.mint' 6 | ref: '0.27.0' 7 | fetch-depth: 1 8 | -------------------------------------------------------------------------------- /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/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/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 | custom_vars = ["CHECK_RESOURCE_USAGE"] 11 | -------------------------------------------------------------------------------- /tests/time_out_assert.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | import time 4 | from typing import Callable 5 | 6 | from mint.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/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/tests/util/__init__.py -------------------------------------------------------------------------------- /tests/util/config.py: -------------------------------------------------------------------------------- 1 | job_timeout = 60 2 | -------------------------------------------------------------------------------- /tests/util/db_connection.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from mint.util.db_wrapper import DBWrapper 3 | import tempfile 4 | import aiosqlite 5 | 6 | 7 | class DBConnection: 8 | async def __aenter__(self) -> DBWrapper: 9 | self.db_path = Path(tempfile.NamedTemporaryFile().name) 10 | if self.db_path.exists(): 11 | self.db_path.unlink() 12 | self.connection = await aiosqlite.connect(self.db_path) 13 | return DBWrapper(self.connection) 14 | 15 | async def __aexit__(self, exc_t, exc_v, exc_tb): 16 | await self.connection.close() 17 | self.db_path.unlink() 18 | -------------------------------------------------------------------------------- /tests/util/generator_tools_testing.py: -------------------------------------------------------------------------------- 1 | from typing import List, Tuple 2 | 3 | from mint.full_node.mempool_check_conditions import get_name_puzzle_conditions 4 | from mint.types.blockchain_format.coin import Coin 5 | from mint.types.blockchain_format.sized_bytes import bytes32 6 | from mint.types.full_block import FullBlock 7 | from mint.types.generator_types import BlockGenerator 8 | from mint.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, []), 24 | max_cost, 25 | cost_per_byte=cost_per_byte, 26 | safe_mode=safe_mode, 27 | ) 28 | # build removals list 29 | for npc in npc_result.npc_list: 30 | removals.append(npc.coin_name) 31 | additions.extend(additions_for_npc(npc_result.npc_list)) 32 | 33 | rewards = block.get_included_reward_coins() 34 | additions.extend(rewards) 35 | return removals, additions 36 | -------------------------------------------------------------------------------- /tests/util/key_tool.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from blspy import AugSchemeMPL, G2Element, PrivateKey 4 | 5 | from mint.types.blockchain_format.sized_bytes import bytes32 6 | from mint.types.coin_spend import CoinSpend 7 | from mint.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_spend: CoinSpend, additional_data: bytes) -> AugSchemeMPL: 29 | signatures = [] 30 | err, conditions, cost = conditions_for_solution( 31 | coin_spend.puzzle_reveal, coin_spend.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_spend.coin.name(), additional_data 37 | ): 38 | signature = self.sign(public_key, message_hash) 39 | signatures.append(signature) 40 | return AugSchemeMPL.aggregate(signatures) 41 | -------------------------------------------------------------------------------- /tests/wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/tests/wallet/__init__.py -------------------------------------------------------------------------------- /tests/wallet/cc_wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/tests/wallet/cc_wallet/__init__.py -------------------------------------------------------------------------------- /tests/wallet/rl_wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/tests/wallet/rl_wallet/__init__.py -------------------------------------------------------------------------------- /tests/wallet/rpc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/tests/wallet/rpc/__init__.py -------------------------------------------------------------------------------- /tests/wallet/sync/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MintNetwork/mint-blockchain/65ec05a015a07664ed25f83efa736065a17f7d7a/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 mint.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 mint.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 | --------------------------------------------------------------------------------