├── .codecov.yml ├── .coveragerc_full ├── .dockerignore ├── .editorconfig ├── .envrc ├── .github ├── CODEOWNERS ├── PULL_REQUEST_TEMPLATE │ ├── feature_branch_pr_template.md │ ├── release_candidate_pr_template.md │ └── release_pr_template.md ├── actions │ └── setup-hathor-env │ │ └── action.yml ├── pull_request_template.md └── workflows │ ├── TESTING.md │ ├── base_benchmarks.yml │ ├── docker.yml │ ├── main.yml │ └── pr_benchmarks.yml ├── .gitignore ├── .yamllint.yml ├── Dockerfile ├── LICENSE.txt ├── Makefile ├── README.md ├── SECURITY.md ├── changelogs └── unreleased │ ├── fix-output-negative-value.yml │ └── fix-ws-notification-broadcast.yml ├── docs ├── README.md ├── debugging.md ├── developing.md ├── event-queue-feature.md ├── legacy │ ├── Makefile │ ├── conf.py │ ├── conflict-resolution.rst │ ├── glossary.rst │ ├── images │ │ ├── syncing-example.png │ │ └── syncing-example.txt │ ├── index.rst │ ├── make.bat │ ├── quickstart.rst │ ├── ref │ │ ├── crypto.rst │ │ ├── index.rst │ │ ├── p2p.rst │ │ ├── pubsub.rst │ │ ├── transaction.rst │ │ └── wallet.rst │ ├── sync.rst │ └── tx-maleability.rst ├── metadocs-openapi-redoc-usage-guide.md └── rocksdb-indexes-feature.md ├── extras ├── README.md ├── __init__.py ├── bash_aliases ├── benchmarking │ └── sync_v2 │ │ ├── .env │ │ └── benchmark_sync_v2.sh ├── custom_checks.sh ├── custom_tests.sh ├── custom_tests │ ├── __init__.py │ └── side_dag │ │ ├── __init__.py │ │ ├── test_both_fail.py │ │ ├── test_one_fails.py │ │ └── utils.py ├── docker │ ├── Dockerfile │ ├── README.md │ ├── build_image │ ├── envvars.sample │ ├── install.sh │ ├── nginx.conf │ └── run.sh ├── gen_release_candidate_changes.py ├── github │ ├── __init__.py │ ├── docker.py │ └── test_docker.py ├── install.sh ├── install_admin.sh ├── install_node.sh ├── install_prometheus_exporter.sh ├── nginx.conf.template ├── nginx_docker │ ├── .gitignore │ ├── Dockerfile │ ├── Makefile │ ├── cors_params │ └── proxy_params ├── node_exporter.service ├── run_hathord.template ├── run_miner.template ├── supervisor.conf.template └── update_checkpoints.py ├── flake.lock ├── flake.nix ├── hathor-cli ├── hathor ├── __init__.py ├── __main__.py ├── api_util.py ├── builder │ ├── __init__.py │ ├── builder.py │ ├── cli_builder.py │ ├── resources_builder.py │ └── sysctl_builder.py ├── checkpoint.py ├── cli │ ├── __init__.py │ ├── db_export.py │ ├── db_import.py │ ├── events_simulator │ │ ├── __init__.py │ │ ├── event_forwarding_websocket_factory.py │ │ ├── event_forwarding_websocket_protocol.py │ │ ├── events_simulator.py │ │ └── scenario.py │ ├── generate_genesis.py │ ├── generate_poa_keys.py │ ├── generate_valid_words.py │ ├── load_from_logs.py │ ├── main.py │ ├── merged_mining.py │ ├── mining.py │ ├── multisig_address.py │ ├── multisig_signature.py │ ├── multisig_spend.py │ ├── nginx_config.py │ ├── openapi_files │ │ ├── .gitignore │ │ ├── __init__.py │ │ ├── openapi_base.json │ │ ├── openapi_components.json │ │ └── register.py │ ├── openapi_json.py │ ├── oracle_create_key.py │ ├── oracle_encode_data.py │ ├── oracle_get_pubkey.py │ ├── parse_logs.py │ ├── peer_id.py │ ├── quick_test.py │ ├── replay_logs.py │ ├── reset_event_queue.py │ ├── reset_feature_settings.py │ ├── run_node.py │ ├── run_node_args.py │ ├── shell.py │ ├── side_dag.py │ ├── stratum_mining.py │ ├── top.py │ ├── twin_tx.py │ ├── tx_generator.py │ ├── util.py │ └── wallet.py ├── client.py ├── conf │ ├── __init__.py │ ├── get_settings.py │ ├── localnet.yml │ ├── mainnet.py │ ├── mainnet.yml │ ├── nano_testnet.py │ ├── nano_testnet.yml │ ├── settings.py │ ├── testnet.py │ ├── testnet.yml │ ├── unittests.py │ └── unittests.yml ├── consensus │ ├── __init__.py │ ├── block_consensus.py │ ├── consensus.py │ ├── consensus_settings.py │ ├── context.py │ ├── poa │ │ ├── __init__.py │ │ ├── poa.py │ │ ├── poa_block_producer.py │ │ └── poa_signer.py │ └── transaction_consensus.py ├── crypto │ ├── __init__.py │ └── util.py ├── daa.py ├── dag_builder │ ├── __init__.py │ ├── artifacts.py │ ├── builder.py │ ├── cli.py │ ├── default_filler.py │ ├── tokenizer.py │ ├── types.py │ ├── utils.py │ └── vertex_exporter.py ├── debug_resources.py ├── difficulty.py ├── event │ ├── __init__.py │ ├── event_manager.py │ ├── model │ │ ├── __init__.py │ │ ├── base_event.py │ │ ├── event_data.py │ │ ├── event_type.py │ │ └── node_state.py │ ├── resources │ │ ├── __init__.py │ │ └── event.py │ ├── storage │ │ ├── __init__.py │ │ ├── event_storage.py │ │ └── rocksdb_storage.py │ └── websocket │ │ ├── __init__.py │ │ ├── factory.py │ │ ├── protocol.py │ │ ├── request.py │ │ └── response.py ├── exception.py ├── execution_manager.py ├── feature_activation │ ├── __init__.py │ ├── bit_signaling_service.py │ ├── feature.py │ ├── feature_service.py │ ├── model │ │ ├── __init__.py │ │ ├── criteria.py │ │ ├── feature_info.py │ │ └── feature_state.py │ ├── resources │ │ ├── __init__.py │ │ └── feature.py │ ├── settings.py │ └── storage │ │ ├── __init__.py │ │ └── feature_activation_storage.py ├── graphviz.py ├── healthcheck │ └── resources │ │ ├── __init__.py │ │ └── healthcheck.py ├── indexes │ ├── __init__.py │ ├── address_index.py │ ├── base_index.py │ ├── blueprint_history_index.py │ ├── blueprint_timestamp_index.py │ ├── height_index.py │ ├── info_index.py │ ├── manager.py │ ├── memory_info_index.py │ ├── memory_mempool_tips_index.py │ ├── memory_tips_index.py │ ├── mempool_tips_index.py │ ├── nc_creation_index.py │ ├── nc_history_index.py │ ├── partial_rocksdb_tips_index.py │ ├── rocksdb_address_index.py │ ├── rocksdb_blueprint_history_index.py │ ├── rocksdb_height_index.py │ ├── rocksdb_info_index.py │ ├── rocksdb_mempool_tips_index.py │ ├── rocksdb_nc_history_index.py │ ├── rocksdb_timestamp_index.py │ ├── rocksdb_tokens_index.py │ ├── rocksdb_tx_group_index.py │ ├── rocksdb_utils.py │ ├── rocksdb_utxo_index.py │ ├── rocksdb_vertex_timestamp_index.py │ ├── scope.py │ ├── timestamp_index.py │ ├── tips_index.py │ ├── tokens_index.py │ ├── tx_group_index.py │ ├── utxo_index.py │ └── vertex_timestamp_index.py ├── ipykernel.py ├── loganimation.py ├── manager.py ├── merged_mining │ ├── __init__.py │ ├── bitcoin.py │ ├── bitcoin_rpc.py │ ├── coordinator.py │ ├── debug_api.py │ ├── status_api.py │ └── util.py ├── metrics.py ├── mining │ ├── __init__.py │ ├── block_template.py │ ├── cpu_mining_service.py │ └── ws.py ├── nanocontracts │ ├── __init__.py │ ├── api_arguments_parser.py │ ├── balance_rules.py │ ├── blueprint.py │ ├── blueprint_env.py │ ├── blueprint_syntax_validation.py │ ├── blueprints │ │ └── __init__.py │ ├── catalog.py │ ├── context.py │ ├── custom_builtins.py │ ├── exception.py │ ├── fields │ │ ├── __init__.py │ │ ├── container_field.py │ │ ├── deque_field.py │ │ ├── dict_field.py │ │ ├── field.py │ │ ├── nc_type_field.py │ │ ├── set_field.py │ │ └── utils.py │ ├── metered_exec.py │ ├── method.py │ ├── nc_exec_logs.py │ ├── nc_types │ │ ├── __init__.py │ │ ├── address_nc_type.py │ │ ├── bool_nc_type.py │ │ ├── bytes_nc_type.py │ │ ├── collection_nc_type.py │ │ ├── dataclass_nc_type.py │ │ ├── fixed_size_bytes_nc_type.py │ │ ├── map_nc_type.py │ │ ├── namedtuple_nc_type.py │ │ ├── nc_type.py │ │ ├── null_nc_type.py │ │ ├── optional_nc_type.py │ │ ├── signed_data_nc_type.py │ │ ├── sized_int_nc_type.py │ │ ├── str_nc_type.py │ │ ├── token_uid_nc_type.py │ │ ├── tuple_nc_type.py │ │ ├── utils.py │ │ └── varint_nc_type.py │ ├── on_chain_blueprint.py │ ├── resources │ │ ├── __init__.py │ │ ├── blueprint.py │ │ ├── blueprint_source_code.py │ │ ├── builtin.py │ │ ├── history.py │ │ ├── nc_creation.py │ │ ├── nc_exec_logs.py │ │ ├── on_chain.py │ │ └── state.py │ ├── rng.py │ ├── runner │ │ ├── __init__.py │ │ ├── runner.py │ │ └── types.py │ ├── sorter │ │ ├── __init__.py │ │ ├── random_sorter.py │ │ ├── timestamp_sorter.py │ │ └── types.py │ ├── storage │ │ ├── __init__.py │ │ ├── backends.py │ │ ├── block_storage.py │ │ ├── changes_tracker.py │ │ ├── contract_storage.py │ │ ├── factory.py │ │ ├── maybedeleted_nc_type.py │ │ ├── node_nc_type.py │ │ ├── patricia_trie.py │ │ ├── token_proxy.py │ │ └── types.py │ ├── types.py │ ├── utils.py │ └── vertex_data.py ├── p2p │ ├── __init__.py │ ├── ca.crt │ ├── ca.key │ ├── factory.py │ ├── manager.py │ ├── messages.py │ ├── netfilter │ │ ├── __init__.py │ │ ├── chain.py │ │ ├── context.py │ │ ├── factory.py │ │ ├── instances.py │ │ ├── matches.py │ │ ├── matches_remote.py │ │ ├── rule.py │ │ ├── table.py │ │ ├── targets.py │ │ └── utils.py │ ├── peer.py │ ├── peer_discovery │ │ ├── __init__.py │ │ ├── bootstrap.py │ │ ├── dns.py │ │ └── peer_discovery.py │ ├── peer_endpoint.py │ ├── peer_id.py │ ├── peer_storage.py │ ├── protocol.py │ ├── rate_limiter.py │ ├── resources │ │ ├── __init__.py │ │ ├── add_peers.py │ │ ├── healthcheck.py │ │ ├── mining.py │ │ ├── mining_info.py │ │ ├── netfilter.py │ │ └── status.py │ ├── states │ │ ├── __init__.py │ │ ├── base.py │ │ ├── hello.py │ │ ├── peer_id.py │ │ └── ready.py │ ├── sync_agent.py │ ├── sync_factory.py │ ├── sync_v2 │ │ ├── __init__.py │ │ ├── agent.py │ │ ├── blockchain_streaming_client.py │ │ ├── exception.py │ │ ├── factory.py │ │ ├── mempool.py │ │ ├── payloads.py │ │ ├── streamers.py │ │ └── transaction_streaming_client.py │ ├── sync_version.py │ └── utils.py ├── profiler │ ├── __init__.py │ ├── cpu.py │ ├── resources │ │ ├── __init__.py │ │ ├── cpu_profiler.py │ │ └── profiler.py │ └── site.py ├── prometheus.py ├── pubsub.py ├── pycoin │ ├── __init__.py │ └── htr.py ├── reactor │ ├── __init__.py │ ├── reactor.py │ ├── reactor_core_protocol.py │ ├── reactor_protocol.py │ ├── reactor_tcp_protocol.py │ └── reactor_time_protocol.py ├── reward_lock │ ├── __init__.py │ └── reward_lock.py ├── serialization │ ├── __init__.py │ ├── adapters │ │ ├── __init__.py │ │ ├── generic_adapter.py │ │ └── max_bytes.py │ ├── bytes_deserializer.py │ ├── bytes_serializer.py │ ├── compound_encoding │ │ ├── __init__.py │ │ ├── collection.py │ │ ├── mapping.py │ │ ├── optional.py │ │ ├── signed_data.py │ │ └── tuple.py │ ├── consts.py │ ├── deserializer.py │ ├── encoding │ │ ├── __init__.py │ │ ├── bool.py │ │ ├── bytes.py │ │ ├── int.py │ │ ├── leb128.py │ │ ├── output_value.py │ │ └── utf8.py │ ├── exceptions.py │ ├── serializer.py │ └── types.py ├── simulator │ ├── __init__.py │ ├── clock.py │ ├── fake_connection.py │ ├── miner │ │ ├── __init__.py │ │ ├── abstract_miner.py │ │ └── geometric_miner.py │ ├── patches.py │ ├── simulator.py │ ├── trigger.py │ ├── tx_generator.py │ └── utils.py ├── storage │ ├── __init__.py │ └── rocksdb_storage.py ├── stratum │ ├── __init__.py │ ├── resources.py │ └── stratum.py ├── sysctl │ ├── __init__.py │ ├── core │ │ ├── __init__.py │ │ └── manager.py │ ├── exception.py │ ├── factory.py │ ├── feature_activation │ │ ├── __init__.py │ │ └── manager.py │ ├── init_file_loader.py │ ├── p2p │ │ ├── __init__.py │ │ └── manager.py │ ├── protocol.py │ ├── runner.py │ ├── sysctl.py │ └── websocket │ │ ├── __init__.py │ │ └── manager.py ├── transaction │ ├── __init__.py │ ├── aux_pow.py │ ├── base_transaction.py │ ├── block.py │ ├── exceptions.py │ ├── genesis.py │ ├── headers │ │ ├── __init__.py │ │ ├── base.py │ │ ├── nano_header.py │ │ └── types.py │ ├── merge_mined_block.py │ ├── nc_execution_state.py │ ├── poa │ │ ├── __init__.py │ │ └── poa_block.py │ ├── resources │ │ ├── __init__.py │ │ ├── block_at_height.py │ │ ├── create_tx.py │ │ ├── dashboard.py │ │ ├── decode_tx.py │ │ ├── graphviz.py │ │ ├── mempool.py │ │ ├── mining.py │ │ ├── push_tx.py │ │ ├── transaction.py │ │ ├── transaction_confirmation.py │ │ ├── tx_parents.py │ │ ├── utxo_search.py │ │ └── validate_address.py │ ├── scripts │ │ ├── __init__.py │ │ ├── base_script.py │ │ ├── construct.py │ │ ├── execute.py │ │ ├── hathor_script.py │ │ ├── multi_sig.py │ │ ├── nano_contract_match_values.py │ │ ├── opcode.py │ │ ├── p2pkh.py │ │ └── script_context.py │ ├── static_metadata.py │ ├── storage │ │ ├── __init__.py │ │ ├── cache_storage.py │ │ ├── exceptions.py │ │ ├── memory_storage.py │ │ ├── migrations │ │ │ ├── __init__.py │ │ │ ├── add_closest_ancestor_block.py │ │ │ ├── change_score_acc_weight_metadata.py │ │ │ └── include_funds_for_first_block.py │ │ ├── rocksdb_storage.py │ │ ├── transaction_storage.py │ │ ├── traversal.py │ │ ├── tx_allow_scope.py │ │ └── vertex_storage_protocol.py │ ├── token_creation_tx.py │ ├── transaction.py │ ├── transaction_metadata.py │ ├── types.py │ ├── util.py │ ├── validation_state.py │ └── vertex_parser.py ├── types.py ├── util.py ├── utils │ ├── __init__.py │ ├── api.py │ ├── dict.py │ ├── int.py │ ├── iter.py │ ├── leb128.py │ ├── list.py │ ├── named_tuple.py │ ├── pydantic.py │ ├── typing.py │ ├── weight.py │ ├── yaml.py │ └── zope.py ├── verification │ ├── __init__.py │ ├── block_verifier.py │ ├── merge_mined_block_verifier.py │ ├── nano_header_verifier.py │ ├── on_chain_blueprint_verifier.py │ ├── poa_block_verifier.py │ ├── token_creation_transaction_verifier.py │ ├── transaction_verifier.py │ ├── verification_service.py │ ├── vertex_verifier.py │ └── vertex_verifiers.py ├── version.py ├── version_resource.py ├── vertex_handler │ ├── __init__.py │ └── vertex_handler.py ├── wallet │ ├── __init__.py │ ├── base_wallet.py │ ├── exceptions.py │ ├── hd_wallet.py │ ├── keypair.py │ ├── resources │ │ ├── __init__.py │ │ ├── address.py │ │ ├── balance.py │ │ ├── history.py │ │ ├── lock.py │ │ ├── nano_contracts │ │ │ ├── __init__.py │ │ │ ├── decode.py │ │ │ ├── execute.py │ │ │ └── match_value.py │ │ ├── send_tokens.py │ │ ├── sign_tx.py │ │ ├── state.py │ │ ├── thin_wallet │ │ │ ├── __init__.py │ │ │ ├── address_balance.py │ │ │ ├── address_history.py │ │ │ ├── address_search.py │ │ │ ├── send_tokens.py │ │ │ ├── token_history.py │ │ │ └── tokens.py │ │ └── unlock.py │ ├── util.py │ └── wallet.py └── websocket │ ├── __init__.py │ ├── exception.py │ ├── factory.py │ ├── iterators.py │ ├── messages.py │ ├── protocol.py │ ├── resource.py │ └── streamer.py ├── poetry.lock ├── profiles ├── cprof2pdf └── pstats_console ├── pyproject.toml ├── setup.cfg ├── slow_tests ├── __init__.py └── test_simulator.py ├── tests ├── __init__.py ├── cli │ ├── __init__.py │ ├── test_cli_main.py │ ├── test_db_export.py │ ├── test_db_import.py │ ├── test_events_simulator.py │ ├── test_generate_tx.py │ ├── test_generate_words.py │ ├── test_multisig_address.py │ ├── test_multisig_signature.py │ ├── test_multisig_spend.py │ ├── test_peer_id.py │ ├── test_quick_test.py │ ├── test_run_node.py │ ├── test_shell.py │ ├── test_side_dag.py │ ├── test_sysctl_init.py │ ├── test_twin_tx.py │ └── test_wallet.py ├── conftest.py ├── consensus │ ├── __init__.py │ ├── test_consensus.py │ ├── test_consensus2.py │ ├── test_consensus3.py │ ├── test_consensus4.py │ ├── test_consensus5.py │ ├── test_first_block.py │ ├── test_soft_voided.py │ ├── test_soft_voided2.py │ ├── test_soft_voided3.py │ └── test_soft_voided4.py ├── crypto │ └── test_util.py ├── dag_builder │ ├── __init__.py │ ├── builder.py │ └── test_dag_builder.py ├── event │ ├── __init__.py │ ├── event_simulation_tester.py │ ├── test_base_event.py │ ├── test_event_manager.py │ ├── test_event_reorg.py │ ├── test_event_simulation_responses.py │ ├── test_event_simulation_scenarios.py │ ├── test_event_storage.py │ ├── test_tx_metadata.py │ └── websocket │ │ ├── __init__.py │ │ ├── test_factory.py │ │ └── test_protocol.py ├── execution_manager │ ├── __init__.py │ └── test_execution_manager.py ├── feature_activation │ ├── __init__.py │ ├── test_bit_signaling_service.py │ ├── test_criteria.py │ ├── test_feature_service.py │ ├── test_feature_simulation.py │ ├── test_mining_simulation.py │ └── test_settings.py ├── nanocontracts │ └── test_blueprints │ │ └── swap_demo.py ├── others │ ├── __init__.py │ ├── fixtures │ │ ├── invalid_byte_hathor_settings_fixture.yml │ │ ├── invalid_features_hathor_settings_fixture.yml │ │ ├── missing_hathor_settings_fixture.yml │ │ └── valid_hathor_settings_fixture.yml │ ├── test_api_utils.py │ ├── test_builder.py │ ├── test_cli_builder.py │ ├── test_hathor_settings.py │ ├── test_init_manager.py │ ├── test_metrics.py │ └── test_util.py ├── p2p │ ├── __init__.py │ ├── netfilter │ │ ├── __init__.py │ │ ├── test_factory.py │ │ ├── test_match.py │ │ ├── test_match_remote.py │ │ ├── test_tables.py │ │ └── test_utils.py │ ├── test_bootstrap.py │ ├── test_capabilities.py │ ├── test_connections.py │ ├── test_connectivity.py │ ├── test_double_spending.py │ ├── test_entrypoint.py │ ├── test_get_best_blockchain.py │ ├── test_peer_id.py │ ├── test_peer_storage.py │ ├── test_protocol.py │ ├── test_rate_limiter.py │ ├── test_split_brain.py │ ├── test_split_brain2.py │ ├── test_sync.py │ ├── test_sync_enabled.py │ ├── test_sync_mempool.py │ ├── test_sync_v2.py │ ├── test_twin_tx.py │ └── test_whitelist.py ├── peer_id_pool.json ├── poa │ ├── __init__.py │ ├── test_poa.py │ ├── test_poa_block_producer.py │ ├── test_poa_simulation.py │ ├── test_poa_verification.py │ └── utils.py ├── pubsub │ ├── __init__.py │ ├── test_pubsub.py │ └── test_pubsub2.py ├── resources │ ├── __init__.py │ ├── base_resource.py │ ├── event │ │ ├── __init__.py │ │ └── test_event.py │ ├── feature │ │ ├── __init__.py │ │ └── test_feature.py │ ├── healthcheck │ │ └── test_healthcheck.py │ ├── nanocontracts │ │ └── __init__.py │ ├── p2p │ │ ├── __init__.py │ │ ├── test_add_peer.py │ │ ├── test_mining.py │ │ ├── test_netfilter.py │ │ └── test_status.py │ ├── test_mining_info.py │ ├── test_profiler.py │ ├── test_stratum.py │ ├── test_version.py │ ├── transaction │ │ ├── __init__.py │ │ ├── test_block_at_height.py │ │ ├── test_create_tx.py │ │ ├── test_dashboard.py │ │ ├── test_decodetx.py │ │ ├── test_get_tx_parents.py │ │ ├── test_graphviz.py │ │ ├── test_mempool.py │ │ ├── test_mining.py │ │ ├── test_pushtx.py │ │ ├── test_transaction_confirmation.py │ │ ├── test_tx.py │ │ ├── test_utxo_search.py │ │ └── test_validate_address.py │ └── wallet │ │ ├── __init__.py │ │ ├── test_address.py │ │ ├── test_balance.py │ │ ├── test_history.py │ │ ├── test_lock.py │ │ ├── test_nano_contract.py │ │ ├── test_search_address.py │ │ ├── test_send_tokens.py │ │ ├── test_thin_wallet.py │ │ └── test_unlock.py ├── simulation │ ├── __init__.py │ ├── base.py │ ├── test_simulator.py │ ├── test_simulator_itself.py │ └── test_trigger.py ├── sysctl │ ├── __init__.py │ ├── test_core.py │ ├── test_feature_activation.py │ ├── test_p2p.py │ ├── test_runner.py │ ├── test_sysctl.py │ └── test_websocket.py ├── test_memory_reactor_clock.py ├── test_utils │ ├── __init__.py │ ├── test_api.py │ ├── test_leb128.py │ └── test_list.py ├── tx │ ├── __init__.py │ ├── test_accumulated_weight.py │ ├── test_block.py │ ├── test_blockchain.py │ ├── test_cache_storage.py │ ├── test_genesis.py │ ├── test_indexes.py │ ├── test_indexes3.py │ ├── test_indexes4.py │ ├── test_merged_mining.py │ ├── test_mining.py │ ├── test_multisig.py │ ├── test_nano_contracts.py │ ├── test_prometheus.py │ ├── test_reward_lock.py │ ├── test_scripts.py │ ├── test_static_metadata.py │ ├── test_stratum.py │ ├── test_timelock.py │ ├── test_tips.py │ ├── test_token_validation.py │ ├── test_tokens.py │ ├── test_traversal.py │ ├── test_tx.py │ ├── test_tx_deserialization.py │ ├── test_tx_serialization.py │ ├── test_tx_storage.py │ ├── test_validation_states.py │ └── test_verification.py ├── unittest.py ├── utils.py ├── utils_modules │ ├── __init__.py │ ├── fixtures │ │ ├── empty.yml │ │ ├── empty_extends.yml │ │ ├── invalid_extends.yml │ │ ├── mainnet_extends.yml │ │ ├── number.yml │ │ ├── self_extends.yml │ │ ├── valid.yml │ │ └── valid_extends.yml │ ├── test_named_tuple.py │ └── test_yaml.py ├── wallet │ ├── __init__.py │ ├── test_balance_update.py │ ├── test_index.py │ ├── test_wallet.py │ └── test_wallet_hd.py └── websocket │ ├── __init__.py │ ├── test_async_iterators.py │ ├── test_streamer.py │ └── test_websocket.py └── tools ├── run_local_measure_tx ├── run_local_mining └── speed-check.py /.codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | branch: master 3 | 4 | coverage: 5 | # https://docs.codecov.com/docs/coverage-configuration 6 | range: "80...90" 7 | # https://docs.codecov.io/docs/commit-status 8 | status: 9 | # TODO: re-enable patch in the future 10 | patch: false 11 | project: 12 | default: 13 | # minimum coverage ratio that the commit must meet to be considered a success 14 | target: 82% 15 | if_ci_failed: error 16 | only_pulls: true 17 | 18 | github_checks: 19 | annotations: true 20 | -------------------------------------------------------------------------------- /.coveragerc_full: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | omit = 4 | # No way to test top command. 5 | hathor/cli/top.py 6 | 7 | [report] 8 | exclude_lines = 9 | # Have to re-enable the standard pragma 10 | pragma: no cover 11 | 12 | # Don't complain about missing debug-only code: 13 | def __repr__ 14 | if self\.debug 15 | 16 | # Don't complain if tests don't hit defensive assertion code: 17 | raise AssertionError 18 | raise NotImplementedError 19 | 20 | # Don't complain if non-runnable code isn't run: 21 | if 0: 22 | if __name__ == .__main__.: 23 | 24 | ignore_errors = True 25 | 26 | [html] 27 | directory = coverage_html_report 28 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/*.pyc 2 | **/*.swp 3 | **/__pycache__ 4 | cover/ 5 | coverage*/ 6 | data*/ 7 | docs/ 8 | tmp/ 9 | *.egg-info 10 | .git 11 | .mypy_cache 12 | .pytest_cache 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.{py,md,rst,ini}] 12 | indent_style = space 13 | indent_size = 4 14 | max_line_length = 119 15 | 16 | [*.{yml,js,css,html,json}] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | [{Makefile,**.mk}] 21 | # Use tabs for indentation (Makefiles require tabs) 22 | indent_style = tab 23 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | if [[ $(type -t use_flake) != function ]]; then 2 | echo "ERROR: use_flake function missing." 3 | echo "Please update direnv to v2.30.0 or later." 4 | exit 1 5 | fi 6 | 7 | use flake 8 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @jansegre @msbrogli 2 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/feature_branch_pr_template.md: -------------------------------------------------------------------------------- 1 | ### Motivation 2 | 3 | What was the motivation for the changes in this PR? 4 | 5 | ### Acceptance Criteria 6 | 7 | - Include here all things that this PR should solve 8 | 9 | ### Checklist 10 | 11 | - [ ] If you are requesting a merge into `master`, confirm this code is production-ready and can be included in future releases as soon as it gets merged -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/release_candidate_pr_template.md: -------------------------------------------------------------------------------- 1 | # Changes 2 | 3 | Link here all the PRs that are included in this release candidate 4 | 5 | # Checklist 6 | 7 | - [ ] I've read and followed the release candidate process described in https://github.com/HathorNetwork/ops-tools/blob/master/docs/release-guides/hathor-core.md#release-candidate 8 | - [ ] I confirm this release candidate only includes production-ready changes -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/release_pr_template.md: -------------------------------------------------------------------------------- 1 | # Changes 2 | 3 | Link here all the PRs that are included in this release 4 | 5 | # Release-candidates 6 | 7 | Link here the release-candidates that were deployed as part of this release 8 | 9 | # Checklist 10 | 11 | - [ ] I've read and followed the release process described in https://github.com/HathorNetwork/ops-tools/blob/master/docs/release-guides/hathor-core.md#stable-release 12 | - [ ] The QA process was run successfully during the tests of the corresponding release-candidate(s) -------------------------------------------------------------------------------- /.github/actions/setup-hathor-env/action.yml: -------------------------------------------------------------------------------- 1 | name: setup-hathor-env 2 | description: Setup Hathor node environment 3 | inputs: 4 | python: 5 | description: The python version 6 | os: 7 | description: The OS name 8 | runs: 9 | using: composite 10 | steps: 11 | - name: Install Poetry 12 | shell: bash 13 | run: pipx install poetry 14 | 15 | - name: Set up Python ${{ inputs.python }} 16 | uses: actions/setup-python@v5 17 | with: 18 | python-version: ${{ inputs.python }} 19 | cache: 'poetry' 20 | 21 | - name: Install Ubuntu dependencies 22 | if: startsWith(inputs.os, 'ubuntu') 23 | run: | 24 | sudo apt-get -qy update 25 | sudo apt-get -qy install graphviz librocksdb-dev libsnappy-dev liblz4-dev 26 | shell: bash 27 | 28 | - name: Install macOS dependencies 29 | if: startsWith(inputs.os, 'macos') 30 | run: | 31 | brew cleanup -q 32 | # brew update -q 33 | brew install -q graphviz rocksdb pkg-config 34 | shell: bash 35 | 36 | - name: Install Poetry dependencies 37 | run: poetry install -n --no-root 38 | shell: bash 39 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Please go to the `Preview` tab and select the appropriate Pull Request template: 2 | 3 | * [Feature Branch](?expand=1&template=feature_branch_pr_template.md) - Use this PR template when you are merging a feature branch into `master` 4 | * [Release Candidate](?expand=1&template=release_candidate_pr_template.md) - Use this PR template when you are merging `master` into `release-candidate` 5 | * [Release](?expand=1&template=release_pr_template.md) - Use this PR template when you are merging `release-candidate` into `release` 6 | -------------------------------------------------------------------------------- /.github/workflows/TESTING.md: -------------------------------------------------------------------------------- 1 | # Testing Github Action workflows 2 | 3 | It's possible to test the Github Action workflows locally by using https://github.com/nektos/act 4 | 5 | You can start by listing all available jobs in our workflows: 6 | 7 | ```bash 8 | act -l 9 | ``` 10 | 11 | We have prepared examples on how to test some types of triggers in the `docker.yml` workflow, but it shouldn't be hard to adapt these examples to test other combinations of jobs and triggers. 12 | 13 | ## Testing a Tag Push 14 | 15 | To simulate the workflow being trigger by the push of a tag, first generate an event file like this: 16 | 17 | ```bash 18 | cat < event.json 19 | { 20 | "ref": "refs/tags/v0.53.0-rc.1" 21 | } 22 | EOF 23 | ``` 24 | 25 | You can change the tag in this event to simulate different types of tags. 26 | 27 | Then, run the `buildx` job with a `push` event providing the event context and a secret called `DOCKERHUB_IMAGE`: 28 | 29 | ```bash 30 | act push -e event.json -j buildx -s DOCKERHUB_IMAGE=testing_locally 31 | ``` 32 | 33 | ## Testing a Scheduled run 34 | 35 | Simulating a scheduled run is similar, just change the type of event: 36 | 37 | ```bash 38 | act schedule -j buildx -s DOCKERHUB_IMAGE=testing_locally 39 | ``` -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | __pycache__/ 4 | *.py[cod] 5 | 6 | *.swp 7 | 8 | docs/_build/ 9 | 10 | .coverage* 11 | cover/ 12 | /coverage* 13 | 14 | .mypy_cache 15 | .dmypy.json 16 | .pytest_cache 17 | 18 | extras/docker/_build/ 19 | extras/docker/envvars 20 | 21 | /build/ 22 | /dist/ 23 | /requirements.txt 24 | *.egg-info 25 | 26 | # Nix 27 | .direnv/ 28 | 29 | keys.json 30 | 31 | # Pycharm 32 | .idea 33 | -------------------------------------------------------------------------------- /.yamllint.yml: -------------------------------------------------------------------------------- 1 | extends: default 2 | 3 | rules: 4 | document-start: disable 5 | line-length: 6 | max: 100 7 | new-lines: 8 | type: platform 9 | comments: 10 | min-spaces-from-content: 1 11 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | Hathor Labs has a bounty program to encourage white hat hackers to collaborate in identifying security breaches and vulnerabilities in Hathor core. To know more about this, see [Bug bounty program at Hathor Network](https://hathor.network/bug-bounty/). 4 | -------------------------------------------------------------------------------- /changelogs/unreleased/fix-output-negative-value.yml: -------------------------------------------------------------------------------- 1 | --- 2 | title: Prevent outputs from accepting negative values 3 | merge_request: 303 4 | author: 5 | type: fix 6 | -------------------------------------------------------------------------------- /changelogs/unreleased/fix-ws-notification-broadcast.yml: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fixing ws message being sent to wrong user 3 | merge_request: 302 4 | author: 5 | type: fix 6 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | ## Directory overview 4 | 5 | This directory contains a miscellany of documents of Hathor core. 6 | 7 | Hathor core documentation is distributed over the following locations: 8 | - For users: [Hathor full node at Hathor docs](https://docs.hathor.network/pathways/components/full-node). 9 | - At the root of the `hathor-core` repository for default documents (license, readme, etc.). 10 | - [API documentation following Open API standard](../hathor/cli). 11 | - [RFCs](https://github.com/HathorNetwork/rfcs). 12 | - And finally, this directory for all other documents. 13 | 14 | ## Table of contents 15 | 16 | Documents in this directory: 17 | 18 | - [Developing](developing.md) 19 | - [Debugging](debugging.md) 20 | - [Feature: event queue](event-queue-feature.md) 21 | - [Feature: RocksDB index](rocksdb-index-feature.md) 22 | - [Legacy documentation of Hathor Network](legacy) 23 | - [Metadocs: Open API and Redoc usage guide](metadocs-openapi-redoc-usage-guide.md) 24 | -------------------------------------------------------------------------------- /docs/debugging.md: -------------------------------------------------------------------------------- 1 | # Debugging 2 | 3 | ## Purpose 4 | 5 | Here are some useful tips and tools for debugging. 6 | 7 | ## Profiling 8 | 9 | You can enable and disable profiling using the HTTP API, so you must use `--status 8080`. 10 | 11 | ### Start profiler 12 | 13 | curl --data '{"start": true}' "http://127.0.0.1:8080/v1a/profiler/" 14 | 15 | ### Stop profiler 16 | 17 | curl --data '{"stop": true, "filepath": "/full/path/to/output.prof"}' "http://127.0.0.1:8080/v1a/profiler/" 18 | 19 | ## Tools 20 | 21 | ### pudb 22 | 23 | You can use `--pudb` to enable pudb to stop execution when an unhandled exception is raised. 24 | 25 | Notice that you have to manually install the package `pudb`. 26 | 27 | Documentation: https://documen.tician.de/pudb/ 28 | 29 | 30 | ### objgraph 31 | 32 | You can use `objgraph` to draw object reference graphs using graphviz. For example, you can use 33 | `objgraph.show_backrefs(x)` to find out why an object has not been cleared by the garbage collector. 34 | 35 | Notice that you have to manually install `objgraph`. 36 | 37 | Documentation: https://mg.pov.lt/objgraph/ 38 | -------------------------------------------------------------------------------- /docs/developing.md: -------------------------------------------------------------------------------- 1 | # Developing 2 | 3 | ## Purpose 4 | 5 | Miscellany of relevant commands for developing Hathor core. 6 | 7 | ## Tests 8 | 9 | Check if code seems alright: 10 | 11 | ``` 12 | make check 13 | ``` 14 | 15 | Test and coverage: 16 | 17 | ``` 18 | make tests 19 | ``` 20 | 21 | ## Generate documentation 22 | 23 | Generate Sphinx docs: 24 | 25 | ``` 26 | cd docs 27 | make html 28 | make latexpdf 29 | ``` 30 | 31 | The output will be written to `docs/_build/html/`. 32 | 33 | 34 | Generate API docs: 35 | 36 | ``` 37 | hathor-cli generate_openapi_json 38 | redoc-cli bundle hathor/cli/openapi_files/openapi.json --output index.html 39 | ``` 40 | 41 | [open-issue]: https://github.com/HathorNetwork/hathor-core/issues/new 42 | [create-pr]: https://github.com/HathorNetwork/hathor-core/compare 43 | -------------------------------------------------------------------------------- /docs/legacy/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = HathorNetwork 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/legacy/images/syncing-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/docs/legacy/images/syncing-example.png -------------------------------------------------------------------------------- /docs/legacy/images/syncing-example.txt: -------------------------------------------------------------------------------- 1 | title Syncing Algorithm 2 | 3 | note over A,B: 4 | Suppose A and B are synced up to 5 | timestamp 500, i.e., they are synced 6 | at 500, but not synced at 501. 7 | 8 | Latest timestamp of A is 1006. 9 | Latest timestamp of B is 1000. 10 | end note 11 | 12 | A->+B: GET-TIPS 13 | B-->-A: TIPS(1000) 14 | loop exponential search starting at 1000 15 | A->+B: GET-TIPS(1000-2**i) 16 | B-->-A: TIPS(timestamp=2**i) 17 | end 18 | note over A,B: 19 | We're synced at 489 20 | and not synced at 745 21 | end note 22 | loop binary search between 489 and 745 23 | A->+B: GET-TIPS(mid) 24 | B-->-A: TIPS(mid) 25 | end 26 | note over A,B: 27 | We're synced at 500 28 | and not synced at 501 29 | end note 30 | loop download data 31 | A->+B: GET-NEXT(timestamp, offset) 32 | B-->-A: NEXT(hashes, next_timestamp, next_offset) 33 | A->B: GET-DATA(hash) 34 | A->B: GET-DATA(hash) 35 | B-->A: DATA(hash, bytes) 36 | B-->A: DATA(hash, bytes) 37 | -------------------------------------------------------------------------------- /docs/legacy/index.rst: -------------------------------------------------------------------------------- 1 | .. Hathor Network documentation master file, created by 2 | sphinx-quickstart on Wed Sep 5 11:06:42 2018. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Hathor Network's documentation! 7 | ========================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 3 11 | :numbered: 12 | :caption: Contents: 13 | 14 | quickstart 15 | glossary 16 | tx-maleability 17 | conflict-resolution 18 | sync 19 | ref/index 20 | 21 | 22 | Indices and tables 23 | ================== 24 | 25 | * :ref:`genindex` 26 | * :ref:`modindex` 27 | * :ref:`search` 28 | -------------------------------------------------------------------------------- /docs/legacy/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=HathorNetwork 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/legacy/ref/crypto.rst: -------------------------------------------------------------------------------- 1 | 2 | ================= 3 | ``hathor.crypto`` 4 | ================= 5 | 6 | .. currentmodule:: hathor.crypto 7 | 8 | 9 | ``hathor.crypto.util`` 10 | ========================= 11 | 12 | .. automodule:: hathor.crypto.util 13 | :members: 14 | :undoc-members: 15 | -------------------------------------------------------------------------------- /docs/legacy/ref/index.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | crypto 8 | p2p 9 | transaction 10 | wallet 11 | pubsub 12 | -------------------------------------------------------------------------------- /docs/legacy/ref/pubsub.rst: -------------------------------------------------------------------------------- 1 | 2 | ====================== 3 | ``hathor.pubsub`` 4 | ====================== 5 | 6 | .. currentmodule:: hathor.pubsub 7 | 8 | 9 | .. automodule:: hathor.pubsub 10 | :members: 11 | :undoc-members: 12 | -------------------------------------------------------------------------------- /docs/legacy/ref/transaction.rst: -------------------------------------------------------------------------------- 1 | 2 | ====================== 3 | ``hathor.transaction`` 4 | ====================== 5 | 6 | .. currentmodule:: hathor.transaction 7 | 8 | 9 | ``hathor.transaction`` 10 | ====================== 11 | 12 | .. automodule:: hathor.transaction.base_transaction 13 | :members: 14 | :undoc-members: 15 | 16 | .. automodule:: hathor.transaction.transaction 17 | :members: 18 | :undoc-members: 19 | 20 | .. automodule:: hathor.transaction.block 21 | :members: 22 | :undoc-members: 23 | 24 | 25 | ``hathor.transaction.storage`` 26 | ============================== 27 | 28 | .. automodule:: hathor.transaction.storage 29 | :members: 30 | :undoc-members: 31 | 32 | 33 | ``hathor.transaction.genesis`` 34 | ============================== 35 | 36 | .. automodule:: hathor.transaction.genesis 37 | :members: 38 | :undoc-members: 39 | -------------------------------------------------------------------------------- /docs/legacy/ref/wallet.rst: -------------------------------------------------------------------------------- 1 | 2 | ================= 3 | ``hathor.wallet`` 4 | ================= 5 | 6 | .. currentmodule:: hathor.wallet 7 | 8 | 9 | ``hathor.wallet.keypair`` 10 | ========================= 11 | 12 | .. automodule:: hathor.wallet.keypair 13 | :members: 14 | :undoc-members: 15 | 16 | 17 | ``hathor.wallet.wallet`` 18 | ======================== 19 | 20 | .. automodule:: hathor.wallet.wallet 21 | :members: 22 | :undoc-members: 23 | -------------------------------------------------------------------------------- /docs/legacy/tx-maleability.rst: -------------------------------------------------------------------------------- 1 | Transaction Maleability 2 | ======================= 3 | The digital signature of the inputs and outputs do not cover the parents and the nonce. On one hand, this is important to let the transactions be recoved in case of a split-brain, but, on the other hand, it makes possible to a malicious node to change the transaction hash, or to generate many conflicts. 4 | 5 | For example, a malicious node may receive new transactions, change their parents, solve the proof-of-work again, and propagate this new transaction. The original and the transactions will be in conflict because they are trying to spend the same output. At the same time, their inputs and outpus are exactly the same, and it does not matter which one wins the conflict resolution. 6 | 7 | When conflicting transactions have the same inputs and ouputs, they are called twin transactions. 8 | 9 | Therefore, users should never user the transaction hash to identify whether a transfer has been finished or not. Users must always use the hash of the signing part, which may not be changed by any node. 10 | -------------------------------------------------------------------------------- /docs/metadocs-openapi-redoc-usage-guide.md: -------------------------------------------------------------------------------- 1 | Openapi Docs 2 | ============ 3 | 4 | Installing ReDoc cli 5 | --------------------- 6 | 7 | Install via npm (https://github.com/Rebilly/ReDoc/blob/master/cli/README.md): 8 | 9 | npm install -g redoc-cli 10 | 11 | 12 | Run a ReDoc server 13 | ---------------- 14 | 15 | Run the server choosing your openapi file and the port where it will run (--watch can be used to watch for changes in openapi file during development) 16 | 17 | redoc-cli serve openapi.json --port 8081 18 | 19 | 20 | Adding new request to the docs 21 | ------------------------------ 22 | 23 | Each resources file has an attribute called openapi, which is a dict that will be used to create the json openapi file. All resource classes that must be added in api documentation page must have a decorator (register_resource). It's also important to make sure that all registered resource classes must be imported in get_registered_resources method. 24 | 25 | 26 | Adding new component 27 | -------------------- 28 | 29 | In case you need to add a new component to be used as a schema you need to edit the file `docs/api/openapi_components.json` and add the new schema. 30 | 31 | 32 | Updating openapi json 33 | --------------------- 34 | 35 | After adding new requests or components you need to generate a new openapi json, so your changes appear in the docs page. To do it just run 36 | 37 | ./hathor-cli generate_openapi_json -------------------------------------------------------------------------------- /extras/README.md: -------------------------------------------------------------------------------- 1 | ## Daemonizing with Supervisor 2 | 3 | Create a `run_hathord` with execution permission: 4 | 5 | ``` 6 | #!/bin/bash 7 | exec pipenv run hathor-cli run_node --hostname --listen tcp:40403 --status 8001 --testnet --peer peer_id.json 8 | ``` 9 | 10 | There follows a configuration template to Supervisor: 11 | 12 | ``` 13 | [program:hathord] 14 | command=/path/to/hathor-python/run_hathord 15 | user=ubuntu 16 | directory=/path/to/hathor-python/ 17 | stdout_logfile=/path/to/logs/hathord.log 18 | stderr_logfile=/path/to/logs/hathord.err 19 | ``` 20 | 21 | Recommended aliases to control `hathord`: 22 | 23 | ``` 24 | alias stop-hathord='sudo supervisorctl stop hathord' 25 | alias start-hathord='sudo supervisorctl start hathord' 26 | alias status-hathord='sudo supervisorctl status hathord' 27 | alias restart-hathord='sudo supervisorctl restart hathord' 28 | alias p2p-hathord='curl http://localhost:8001/' 29 | ``` 30 | -------------------------------------------------------------------------------- /extras/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/extras/__init__.py -------------------------------------------------------------------------------- /extras/bash_aliases: -------------------------------------------------------------------------------- 1 | alias stop-hathord='sudo supervisorctl stop hathord' 2 | alias start-hathord='sudo supervisorctl start hathord' 3 | alias status-hathord='sudo supervisorctl status hathord' 4 | alias restart-hathord='sudo supervisorctl restart hathord' 5 | -------------------------------------------------------------------------------- /extras/benchmarking/sync_v2/.env: -------------------------------------------------------------------------------- 1 | BENCH_DATA_FILE_NAME=ci_testnet_upto_20k 2 | BENCH_DATA_URL=https://hathor-public-files.s3.amazonaws.com/hathor-core-ci/ci_testnet_upto_20k.tar.gz 3 | N_BLOCKS=20000 4 | CACHE_SIZE=100000 5 | SERVER_DATA_DIR=server-data 6 | TCP_PORT=40403 7 | N_RUNS=2 8 | BENCH_FILE=testnet_upto_20k_results.json 9 | BENCH_DATA_DIR=bench-data 10 | -------------------------------------------------------------------------------- /extras/benchmarking/sync_v2/benchmark_sync_v2.sh: -------------------------------------------------------------------------------- 1 | hyperfine \ 2 | --warmup 1 \ 3 | --runs $N_RUNS \ 4 | --export-json $BENCH_FILE \ 5 | --command-name "sync-v2 (up to $N_BLOCKS blocks)" \ 6 | --prepare "rm -rf $BENCH_DATA_DIR && mkdir $BENCH_DATA_DIR" \ 7 | " 8 | poetry run hathor-cli quick_test \ 9 | --testnet \ 10 | --data $BENCH_DATA_DIR \ 11 | --cache \ 12 | --cache-size $CACHE_SIZE \ 13 | --x-localhost-only \ 14 | --bootstrap tcp://localhost:$TCP_PORT \ 15 | --quit-after-n-blocks $N_BLOCKS 16 | " 17 | -------------------------------------------------------------------------------- /extras/custom_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Define colors 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | BLUE='\033[0;34m' 7 | NC='\033[0m' # No Color 8 | 9 | TESTS_DIR="extras/custom_tests" 10 | 11 | # List of test scripts to be executed 12 | tests=( 13 | /side_dag/test_one_fails.py 14 | /side_dag/test_both_fail.py 15 | ) 16 | 17 | # Initialize a variable to track if any test fails 18 | any_test_failed=0 19 | 20 | # Loop over all tests 21 | for test in "${tests[@]}"; do 22 | echo -e "${BLUE}Testing $test${NC}" 23 | PYTHONPATH=$TESTS_DIR python $TESTS_DIR/$test 24 | result=$? 25 | if [ $result -ne 0 ]; then 26 | echo -e "${RED}Test $test FAILED${NC}" 27 | any_test_failed=1 28 | else 29 | echo -e "${GREEN}Test $test PASSED${NC}" 30 | fi 31 | done 32 | 33 | # Exit with code 0 if no test failed, otherwise exit with code 1 34 | if [ $any_test_failed -eq 0 ]; then 35 | echo -e "${GREEN}All tests PASSED${NC}" 36 | exit 0 37 | else 38 | echo -e "${RED}Some tests FAILED${NC}" 39 | exit 1 40 | fi 41 | -------------------------------------------------------------------------------- /extras/custom_tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/extras/custom_tests/__init__.py -------------------------------------------------------------------------------- /extras/custom_tests/side_dag/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/extras/custom_tests/side_dag/__init__.py -------------------------------------------------------------------------------- /extras/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | ENV HTR_PATH_DATA="/var/lib/hathor" \ 4 | HTR_PATH_HOME="/usr/share/hathor" \ 5 | HTR_PATH_LOGS="/var/log/hathor" 6 | 7 | WORKDIR $HTR_PATH_HOME 8 | 9 | COPY ./_build/requirements.txt /tmp/ 10 | 11 | RUN apt-get update && \ 12 | apt-get install -y --no-install-recommends python3 python3-setuptools python3-pip nginx && \ 13 | apt-get install -y --no-install-recommends python3-dev build-essential libssl-dev && \ 14 | pip3 install --no-cache-dir wheel && \ 15 | pip3 install --no-cache-dir -r /tmp/requirements.txt && \ 16 | apt-get purge -y --auto-remove build-essential python3-dev libssl-dev && \ 17 | rm -rf /var/lib/apt/lists/* 18 | 19 | COPY ./install.sh ./_build/hathor.tar.gz ./_build/hathor-webadmin.tar.gz /tmp/ 20 | 21 | RUN /tmp/install.sh && \ 22 | rm -f /tmp/install.sh /tmp/hathor.tar.gz /tmp/hathor-webadmin.tar.gz && \ 23 | rm -f /etc/nginx/sites-enabled/default 24 | 25 | COPY ./nginx.conf /etc/nginx/sites-available/hathor-webadmin 26 | COPY ./run.sh /run.sh 27 | 28 | 29 | EXPOSE 80 40403 30 | 31 | ENTRYPOINT ["/run.sh"] 32 | CMD [] 33 | -------------------------------------------------------------------------------- /extras/docker/README.md: -------------------------------------------------------------------------------- 1 | Docker 2 | ====== 3 | 4 | Run a full node in a Docker container. 5 | 6 | 7 | Build an image 8 | -------------- 9 | First, run `cp envvars.sample envvars` and change it according to your directories. 10 | 11 | Then, just run `./build_image`. 12 | 13 | The image name will be printed at the end of the build. For instance, "Successfully tagged hathor:v0.8.0-beta-26-g82ce1bd". The tag is gotten from `git describe` of the hathor-python repository. 14 | 15 | 16 | Run a container 17 | --------------- 18 | Run `docker run -p 10000:80 -ti hathor: `. Then, access `http://localhost:10000` in your browser. 19 | 20 | If you would like to connected to the testnet, you must pass the `--testnet` parameter. 21 | 22 | You can see the default parameters in the `run.sh` file. 23 | 24 | 25 | Debug an image 26 | -------------- 27 | Run `docker run --entrypoint /bin/bash -ti hathor:`. Then, it will give access to a bash inside the container. 28 | 29 | To get a bash in a running container, run `docker container exec -ti /bin/bash`. 30 | 31 | 32 | Useful commands 33 | --------------- 34 | 35 | - List docker images: `docker image ls` 36 | - List containers: `docker container ls` 37 | - Clean stopped containers: `docker container prune` 38 | - Clear dangling images: `docker image prune` 39 | -------------------------------------------------------------------------------- /extras/docker/build_image: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f envvars ]; then 4 | echo "Error. Can't load envvars. You can run \"cp envvars.sample envvars\" and configure it with your paths." 5 | exit 1 6 | fi 7 | 8 | source ./envvars 9 | 10 | BASEDIR=`pwd` 11 | 12 | echo WEBADMIN PATH: $WEBADMIN_PATH 13 | echo NODE PATH: $NODE_PATH 14 | 15 | mkdir -p _build/ 16 | 17 | cp ${NODE_PATH}/requirements.txt _build/ 18 | 19 | export REACT_APP_BASE_URL="/api/" 20 | export REACT_APP_WS_URL="/api/ws/" 21 | 22 | (cd ${WEBADMIN_PATH} && npm run build && tar cvzf ${BASEDIR}/_build/hathor-webadmin.tar.gz -C build/ .) 23 | (cd ${NODE_PATH} && python setup.py build sdist && cp dist/hathor-*.tar.gz ${BASEDIR}/_build/hathor.tar.gz) 24 | 25 | docker build --tag hathor:`git describe` . 26 | -------------------------------------------------------------------------------- /extras/docker/envvars.sample: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export WEBADMIN_PATH=~/Hathor/admin-frontend/ 4 | export NODE_PATH=~/Hathor/hathor-python/ 5 | -------------------------------------------------------------------------------- /extras/docker/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASEDIR=`pwd` 4 | 5 | HTR_PATH_DATA="/var/lib/hathor" 6 | HTR_PATH_HOME="/usr/share/hathor" 7 | HTR_PATH_LOGS="/var/log/hathor" 8 | 9 | # Create user, group, and directories. 10 | addgroup --system hathor && \ 11 | useradd --system -g hathor -s /bin/bash hathor && \ 12 | mkdir -p "$HTR_PATH_DATA" "$HTR_PATH_HOME" "$HTR_PATH_LOGS" "${HTR_PATH_HOME}/webadmin" && \ 13 | chown -R hathor:hathor "$HTR_PATH_DATA" "$HTR_PATH_HOME" "$HTR_PATH_LOGS" 14 | 15 | # Install hathor. 16 | pip3 install --no-cache-dir /tmp/hathor.tar.gz 17 | tar xvzf /tmp/hathor-webadmin.tar.gz -C "${HTR_PATH_HOME}/webadmin/" 18 | 19 | ln -s ../sites-available/hathor-webadmin /etc/nginx/sites-enabled/hathor-webadmin 20 | -------------------------------------------------------------------------------- /extras/docker/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | listen [::]:80 default_server; 4 | 5 | root /usr/share/hathor/webadmin/; 6 | index index.html; 7 | 8 | location / { 9 | try_files $uri /index.html =404; 10 | } 11 | 12 | location /api/ { 13 | proxy_pass http://localhost:8001/; 14 | proxy_set_header X-Real-IP $remote_addr; 15 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 16 | } 17 | 18 | location /api/ws/ { 19 | proxy_pass http://localhost:8001/ws/; 20 | proxy_set_header X-Real-IP $remote_addr; 21 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 22 | 23 | proxy_http_version 1.1; 24 | proxy_set_header Upgrade $http_upgrade; 25 | proxy_set_header Connection $connection_upgrade; 26 | 27 | proxy_buffering off; 28 | } 29 | 30 | } 31 | 32 | map $http_upgrade $connection_upgrade { 33 | default upgrade; 34 | '' close; 35 | } 36 | -------------------------------------------------------------------------------- /extras/docker/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | service nginx start 4 | 5 | # python3 gen_peer_id.py >peer_id.json 6 | 7 | WORDS='index talent enact review cherry lunch vacuum chef alone general rhythm banana helmet dash sudden tobacco income search magic bar crater lens caution coin' 8 | 9 | su hathor -c "exec hathor-cli run_node --status 8001 --words \"${WORDS}\" $@" 10 | -------------------------------------------------------------------------------- /extras/github/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/extras/github/__init__.py -------------------------------------------------------------------------------- /extras/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASENAME=`basename $0` 4 | 5 | if [ $# -ne 3 ]; then 6 | echo "usage: ${BASENAME} " 7 | exit 1 8 | fi 9 | 10 | INSTALL_DIR=$1 11 | NODE_HOST=$2 12 | DEPLOY_TOKEN=$3 13 | 14 | ./install_node.sh "${INSTALL_DIR}" "${NODE_HOST}" "${DEPLOY_TOKEN}" 15 | ./install_admin.sh "${INSTALL_DIR}" "${NODE_HOST}" "${DEPLOY_TOKEN}" 16 | -------------------------------------------------------------------------------- /extras/install_admin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASENAME=`basename $0` 4 | 5 | if [ $# -ne 3 ]; then 6 | echo "usage: ${BASENAME} " 7 | exit 1 8 | fi 9 | 10 | export INSTALL_DIR=$1 11 | export NODE_HOST=$2 12 | DEPLOY_TOKEN=$3 13 | 14 | BASEDIR=`pwd` 15 | 16 | cd ${INSTALL_DIR} 17 | 18 | git clone https://${DEPLOY_TOKEN}@gitlab.com/HathorNetwork/admin-frontend.git || exit 1 19 | 20 | sed -i -e 's#http://localhost:8080/#/api/#g' -e 's#ws://127.0.0.1:8080/ws/#wss://'${NODE_HOST}'/api/ws/#g' admin-frontend/src/constants.js 21 | 22 | sudo add-apt-repository -y ppa:certbot/certbot 23 | sudo apt update 24 | curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - 25 | sudo apt install -y nginx nodejs certbot 26 | 27 | sudo certbot certonly --agree-tos -m hathor@hathor.network --standalone --preferred-challenges http -d ${NODE_HOST} --pre-hook "/etc/init.d/nginx stop" --post-hook "/etc/init.d/nginx start" 28 | 29 | envsubst < ${BASEDIR}/nginx.conf.template > nginx.conf 30 | sudo ln -s ${INSTALL_DIR}/nginx.conf /etc/nginx/sites-enabled/${NODE_HOST} 31 | touch htpasswd 32 | sudo /etc/init.d/nginx reload 33 | 34 | cd admin-frontend/ 35 | npm install 36 | npm run-script build 37 | -------------------------------------------------------------------------------- /extras/install_node.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASENAME=`basename $0` 4 | 5 | if [ $# -ne 3 ]; then 6 | echo "usage: ${BASENAME} " 7 | exit 1 8 | fi 9 | 10 | export INSTALL_DIR=$1 11 | export NODE_HOST=$2 12 | DEPLOY_TOKEN=$3 13 | 14 | BASEDIR=`pwd` 15 | 16 | cd ${INSTALL_DIR} 17 | 18 | git clone https://${DEPLOY_TOKEN}@gitlab.com/HathorNetwork/hathor-python.git || exit 1 19 | 20 | sudo apt update 21 | sudo apt install -y python3 python3-dev python3-pip python3-venv build-essential graphviz libssl-dev 22 | sudo apt install -y supervisor 23 | 24 | envsubst < ${BASEDIR}/supervisor.conf.template > supervisor.conf 25 | sudo ln -s ${INSTALL_DIR}/supervisor.conf /etc/supervisor/conf.d/hathord.conf 26 | sudo /etc/init.d/supervisor restart 27 | 28 | mkdir logs/ 29 | mkdir data/ 30 | 31 | cd hathor-python/ 32 | python3 -m venv --prompt "venv/hathor" venv 33 | source ./venv/bin/activate 34 | pip install wheel 35 | pip install -r requirements.txt 36 | 37 | python gen_peer_id.py >peer_id.json 38 | 39 | export WALLET_WORDS=`python tools/generate_valid_words.py` 40 | 41 | envsubst < ${BASEDIR}/run_hathord.template > run_hathord 42 | envsubst < ${BASEDIR}/run_miner.template > run_miner 43 | 44 | chmod 744 run_hathord 45 | chmod 744 run_miner 46 | -------------------------------------------------------------------------------- /extras/install_prometheus_exporter.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo useradd --no-create-home --shell /bin/false node_exporter 4 | 5 | curl -LO https://github.com/prometheus/node_exporter/releases/download/v0.16.0/node_exporter-0.16.0.linux-amd64.tar.gz 6 | 7 | tar xvf node_exporter-0.16.0.linux-amd64.tar.gz 8 | 9 | sudo cp node_exporter-0.16.0.linux-amd64/node_exporter /usr/local/bin 10 | sudo chown node_exporter:node_exporter /usr/local/bin/node_exporter 11 | 12 | rm -rf node_exporter-0.16.0.linux-amd64.tar.gz node_exporter-0.16.0.linux-amd64/ 13 | 14 | sudo cp node_exporter.service /etc/systemd/system/ 15 | 16 | sudo systemctl daemon-reload 17 | sudo systemctl start node_exporter 18 | sudo systemctl status node_exporter 19 | 20 | echo "Remember to allow access to metrics.testnet.hathor.network at port 9100" 21 | -------------------------------------------------------------------------------- /extras/nginx_docker/.gitignore: -------------------------------------------------------------------------------- 1 | nginx.conf 2 | set_real_ip_from_cloudfront 3 | -------------------------------------------------------------------------------- /extras/nginx_docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:stable-alpine 2 | RUN rm /etc/nginx/conf.d/default.conf 3 | COPY cors_params /etc/nginx/cors_params 4 | COPY proxy_params /etc/nginx/proxy_params 5 | COPY set_real_ip_from_cloudfront /etc/nginx/set_real_ip_from_cloudfront 6 | COPY nginx.conf /etc/nginx/conf.d/hathor.conf 7 | -------------------------------------------------------------------------------- /extras/nginx_docker/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | all: docker 3 | 4 | tag = 769498303037.dkr.ecr.us-east-1.amazonaws.com/webtank:latest 5 | no_rate_limit_tag = 769498303037.dkr.ecr.us-east-1.amazonaws.com/webtank:no-rate-limit-latest 6 | 7 | .PHONY: docker 8 | docker: docker-default docker-no-rate-limit 9 | 10 | # Default Nginx Image 11 | .PHONY: docker-default 12 | docker-default: nginx.conf set_real_ip_from_cloudfront 13 | docker buildx build --pull --push --platform linux/arm64/v8,linux/amd64 --tag $(tag) . 14 | 15 | nginx.conf: export PYTHONPATH := ../.. 16 | nginx.conf: 17 | @python -c "import os; import hathor; print('Using hathor-core from:', os.path.dirname(hathor.__file__))" 18 | python -m hathor generate_nginx_config - > $@ 19 | 20 | # Nginx Image used for private use cases, with rate limits disabled 21 | .PHONY: docker-no-rate-limit 22 | docker-no-rate-limit: nginx_no_rate_limit.conf set_real_ip_from_cloudfront 23 | mv nginx_no_rate_limit.conf nginx.conf 24 | docker buildx build --pull --push --platform linux/arm64/v8,linux/amd64 --tag $(no_rate_limit_tag) . 25 | 26 | nginx_no_rate_limit.conf: export PYTHONPATH := ../.. 27 | nginx_no_rate_limit.conf: 28 | @python -c "import os; import hathor; print('Using hathor-core from:', os.path.dirname(hathor.__file__))" 29 | python -m hathor generate_nginx_config --disable-rate-limits - > $@ 30 | 31 | set_real_ip_from_cloudfront: 32 | curl https://ip-ranges.amazonaws.com/ip-ranges.json -s \ 33 | | jq '.prefixes|map(select(.service=="CLOUDFRONT"))[]|.ip_prefix' -r \ 34 | | sort -h \ 35 | | xargs -n 1 printf "set_real_ip_from %s;\n" \ 36 | > $@ 37 | 38 | .PHONY: clean 39 | clean: 40 | rm -f nginx.conf set_real_ip_from_cloudfront 41 | -------------------------------------------------------------------------------- /extras/nginx_docker/cors_params: -------------------------------------------------------------------------------- 1 | if ($request_method = 'OPTIONS') { 2 | add_header 'Access-Control-Allow-Origin' '*' always; 3 | add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; 4 | # 5 | # Custom headers and headers various browsers *should* be OK with but aren't 6 | # 7 | add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; 8 | # 9 | # Tell client that this pre-flight info is valid for 20 days 10 | # 11 | add_header 'Access-Control-Max-Age' 1728000 always; 12 | add_header 'Content-Type' 'text/plain; charset=utf-8' always; 13 | add_header 'Content-Length' 0 always; 14 | return 204; 15 | } 16 | add_header 'Access-Control-Allow-Origin' '*' always; 17 | add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; 18 | add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; 19 | add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; 20 | -------------------------------------------------------------------------------- /extras/nginx_docker/proxy_params: -------------------------------------------------------------------------------- 1 | proxy_intercept_errors on; 2 | proxy_set_header Host $http_host; 3 | proxy_set_header X-Real-IP $realip_remote_addr; 4 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 5 | proxy_set_header X-Forwarded-Proto $scheme; 6 | proxy_set_header Cookie ""; 7 | proxy_hide_header Access-Control-Allow-Origin; 8 | proxy_hide_header Access-Control-Allow-Methods; 9 | proxy_hide_header Access-Control-Allow-Headers; 10 | proxy_hide_header Access-Control-Max-Age; 11 | proxy_hide_header Set-Cookie; 12 | proxy_ignore_headers Set-Cookie; 13 | -------------------------------------------------------------------------------- /extras/node_exporter.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Node Exporter 3 | Wants=network-online.target 4 | After=network-online.target 5 | 6 | [Service] 7 | User=node_exporter 8 | Group=node_exporter 9 | Type=simple 10 | ExecStart=/usr/local/bin/node_exporter 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /extras/run_hathord.template: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd ${INSTALL_DIR}/hathor-python/ 3 | source ./venv/bin/activate 4 | 5 | WORDS=${WALLET_WORDS} 6 | 7 | exec ./hathor-cli run_node --hostname ${NODE_HOST} --listen tcp:40403 --status 8001 --testnet --peer peer_id.json --data ${INSTALL_DIR}/data --words "$${EMPTY}WORDS" 8 | -------------------------------------------------------------------------------- /extras/run_miner.template: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source ./venv/bin/activate 3 | exec ./hathor-cli run_miner http://localhost:8001/mining --sleep 0.0005 4 | -------------------------------------------------------------------------------- /extras/supervisor.conf.template: -------------------------------------------------------------------------------- 1 | [program:hathord] 2 | command=${INSTALL_DIR}/hathor-python/run_hathord 3 | user=ubuntu 4 | directory=${INSTALL_DIR}/hathor-python/ 5 | stdout_logfile=${INSTALL_DIR}/logs/hathord.log 6 | stderr_logfile=${INSTALL_DIR}/logs/hathord.err 7 | 8 | [program:hathor-miner] 9 | command=${INSTALL_DIR}/hathor-python/run_miner 10 | user=ubuntu 11 | directory=${INSTALL_DIR}/hathor-python/ 12 | stdout_logfile=${INSTALL_DIR}/logs/hathor-miner.log 13 | stderr_logfile=${INSTALL_DIR}/logs/hathor-miner.err 14 | 15 | [inet_http_server] 16 | port = 127.0.0.1:9001 17 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "virtual environments"; 3 | 4 | inputs.devshell.url = "github:numtide/devshell"; 5 | inputs.flake-utils.url = "github:numtide/flake-utils"; 6 | inputs.nixpkgs.url = "github:NixOS/nixpkgs/master"; 7 | 8 | outputs = { self, flake-utils, devshell, nixpkgs }: 9 | 10 | flake-utils.lib.eachDefaultSystem (system: { 11 | devShells.default = 12 | let 13 | pkgs = import nixpkgs { 14 | inherit system; 15 | overlays = [ devshell.overlays.default ]; 16 | }; 17 | in 18 | pkgs.mkShell { 19 | buildInputs = [ 20 | pkgs.python310 21 | pkgs.poetry 22 | pkgs.rocksdb 23 | pkgs.snappy 24 | pkgs.openssl 25 | pkgs.readline 26 | pkgs.zlib 27 | pkgs.xz 28 | pkgs.bzip2 29 | pkgs.lz4 30 | pkgs.cmake 31 | ]; 32 | 33 | shellHook = '' 34 | export CFLAGS="-I${pkgs.rocksdb}/include" 35 | export LDFLAGS="-L${pkgs.rocksdb}/lib" 36 | poetry env use python3.11 37 | ''; 38 | }; 39 | }); 40 | } 41 | -------------------------------------------------------------------------------- /hathor-cli: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec python -m hathor "$@" 4 | -------------------------------------------------------------------------------- /hathor/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.version import __version__ 16 | 17 | __all__ = ['__version__'] 18 | -------------------------------------------------------------------------------- /hathor/__main__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | if __name__ == '__main__': 16 | from .cli import main 17 | main.main() 18 | -------------------------------------------------------------------------------- /hathor/builder/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.builder.builder import BuildArtifacts, Builder, SyncSupportLevel 16 | from hathor.builder.cli_builder import CliBuilder 17 | from hathor.builder.resources_builder import ResourcesBuilder 18 | 19 | __all__ = [ 20 | 'BuildArtifacts', 21 | 'Builder', 22 | 'CliBuilder', 23 | 'ResourcesBuilder', 24 | 'SyncSupportLevel', 25 | ] 26 | -------------------------------------------------------------------------------- /hathor/builder/sysctl_builder.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.builder import BuildArtifacts 16 | from hathor.sysctl import ( 17 | ConnectionsManagerSysctl, 18 | FeatureActivationSysctl, 19 | HathorManagerSysctl, 20 | Sysctl, 21 | WebsocketManagerSysctl, 22 | ) 23 | 24 | 25 | class SysctlBuilder: 26 | """Builder for the sysctl tree.""" 27 | 28 | def __init__(self, artifacts: BuildArtifacts) -> None: 29 | self.artifacts = artifacts 30 | 31 | def build(self) -> Sysctl: 32 | """Build the sysctl tree.""" 33 | root = Sysctl() 34 | 35 | core = HathorManagerSysctl(self.artifacts.manager) 36 | core.put_child('features', FeatureActivationSysctl(self.artifacts.bit_signaling_service)) 37 | 38 | root.put_child('core', core) 39 | root.put_child('p2p', ConnectionsManagerSysctl(self.artifacts.p2p_manager)) 40 | 41 | ws_factory = self.artifacts.manager.websocket_factory 42 | if ws_factory is not None: 43 | root.put_child('ws', WebsocketManagerSysctl(ws_factory)) 44 | 45 | return root 46 | -------------------------------------------------------------------------------- /hathor/checkpoint.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import NamedTuple 16 | 17 | 18 | class Checkpoint(NamedTuple): 19 | height: int 20 | hash: bytes 21 | -------------------------------------------------------------------------------- /hathor/cli/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/cli/__init__.py -------------------------------------------------------------------------------- /hathor/cli/events_simulator/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/cli/events_simulator/__init__.py -------------------------------------------------------------------------------- /hathor/cli/events_simulator/event_forwarding_websocket_factory.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import TYPE_CHECKING, Any 16 | 17 | from twisted.internet.interfaces import IAddress 18 | 19 | from hathor.event.websocket import EventWebsocketFactory # skip-cli-import-custom-check 20 | 21 | if TYPE_CHECKING: 22 | from hathor.cli.events_simulator.event_forwarding_websocket_protocol import EventForwardingWebsocketProtocol 23 | from hathor.simulator import Simulator 24 | 25 | 26 | class EventForwardingWebsocketFactory(EventWebsocketFactory): 27 | def __init__(self, simulator: 'Simulator', *args: Any, **kwargs: Any) -> None: 28 | self._simulator = simulator 29 | super().__init__(*args, **kwargs) 30 | 31 | def buildProtocol(self, _: IAddress) -> 'EventForwardingWebsocketProtocol': 32 | from hathor.cli.events_simulator.event_forwarding_websocket_protocol import EventForwardingWebsocketProtocol 33 | protocol = EventForwardingWebsocketProtocol(self._simulator) 34 | protocol.factory = self 35 | return protocol 36 | -------------------------------------------------------------------------------- /hathor/cli/generate_valid_words.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from argparse import ArgumentParser, Namespace 16 | 17 | 18 | def generate_words(language: str = 'english', count: int = 24) -> str: 19 | from mnemonic import Mnemonic 20 | mnemonic = Mnemonic(language) 21 | return mnemonic.generate(strength=int(count * 10.67)) 22 | 23 | 24 | def create_parser() -> ArgumentParser: 25 | from hathor.cli.util import create_parser 26 | parser = create_parser() 27 | parser.add_argument('--language', help='Words language') 28 | parser.add_argument('--count', type=int, help='Word count') 29 | return parser 30 | 31 | 32 | def execute(args: Namespace) -> None: 33 | kwargs = {} 34 | 35 | if args.language: 36 | kwargs['language'] = args.language 37 | if args.count: 38 | kwargs['count'] = args.count 39 | 40 | print(generate_words(**kwargs)) 41 | 42 | 43 | def main(): 44 | parser = create_parser() 45 | args = parser.parse_args() 46 | execute(args) 47 | -------------------------------------------------------------------------------- /hathor/cli/openapi_files/.gitignore: -------------------------------------------------------------------------------- 1 | openapi.json 2 | -------------------------------------------------------------------------------- /hathor/cli/openapi_files/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/cli/openapi_files/__init__.py -------------------------------------------------------------------------------- /hathor/cli/openapi_files/openapi_base.json: -------------------------------------------------------------------------------- 1 | { 2 | "openapi": "3.0.0", 3 | "servers": [ 4 | { 5 | "url": "http://localhost:8080" 6 | } 7 | ], 8 | "info": { 9 | "title": "Hathor API", 10 | "version": "0.63.1" 11 | }, 12 | "consumes": [ 13 | "application/json" 14 | ], 15 | "produces": [ 16 | "application/json" 17 | ], 18 | "paths": {} 19 | } 20 | -------------------------------------------------------------------------------- /hathor/cli/oracle_create_key.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import base64 16 | 17 | from cryptography.hazmat.backends import default_backend 18 | from cryptography.hazmat.primitives.asymmetric import ec 19 | 20 | 21 | def main(): 22 | from hathor.cli.util import create_parser 23 | from hathor.crypto.util import get_hash160, get_private_key_bytes, get_public_key_bytes_compressed 24 | 25 | parser = create_parser() 26 | 27 | parser.add_argument('filepath', help='Create a new private key in the given file') 28 | args = parser.parse_args() 29 | 30 | new_key = ec.generate_private_key(ec.SECP256K1(), default_backend()) 31 | private_key_bytes = get_private_key_bytes(new_key) 32 | with open(args.filepath, 'w') as key_file: 33 | key_file.write(base64.b64encode(private_key_bytes).decode('utf-8')) 34 | print('key created!') 35 | public_key_bytes = get_public_key_bytes_compressed(new_key.public_key()) 36 | print('base64 pubkey hash:', base64.b64encode(get_hash160(public_key_bytes)).decode('utf-8')) 37 | -------------------------------------------------------------------------------- /hathor/cli/oracle_get_pubkey.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import base64 16 | 17 | 18 | def main(): 19 | from hathor.cli.util import create_parser 20 | from hathor.crypto.util import get_hash160, get_private_key_from_bytes, get_public_key_bytes_compressed 21 | 22 | parser = create_parser() 23 | 24 | parser.add_argument('filepath', help='Get public key hash given the private key file') 25 | args = parser.parse_args() 26 | 27 | with open(args.filepath, 'r') as key_file: 28 | private_key_bytes = base64.b64decode(key_file.read()) 29 | private_key = get_private_key_from_bytes(private_key_bytes) 30 | public_key_bytes = get_public_key_bytes_compressed(private_key.public_key()) 31 | print('base64:', base64.b64encode(public_key_bytes).decode('utf-8')) 32 | print('hash base64:', base64.b64encode(get_hash160(public_key_bytes)).decode('utf-8')) 33 | -------------------------------------------------------------------------------- /hathor/cli/peer_id.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ Generates a random Peer and print it to stdout. 16 | It may be used to testing purposes. 17 | """ 18 | 19 | import json 20 | 21 | 22 | def main() -> None: 23 | from hathor.p2p.peer import PrivatePeer 24 | 25 | peer = PrivatePeer.auto_generated() 26 | data = peer.to_json_private() 27 | txt = json.dumps(data, indent=4) 28 | print(txt) 29 | -------------------------------------------------------------------------------- /hathor/cli/reset_event_queue.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from argparse import ArgumentParser, Namespace 16 | 17 | from structlog import get_logger 18 | 19 | logger = get_logger() 20 | 21 | 22 | def create_parser() -> ArgumentParser: 23 | from hathor.cli.util import create_parser 24 | 25 | parser = create_parser() 26 | parser.add_argument('--data', help='Data directory') 27 | 28 | return parser 29 | 30 | 31 | def execute(args: Namespace) -> None: 32 | from hathor.event.storage import EventRocksDBStorage 33 | from hathor.storage import RocksDBStorage 34 | 35 | assert args.data is not None, '--data is required' 36 | 37 | rocksdb_storage = RocksDBStorage(path=args.data) 38 | event_storage = EventRocksDBStorage(rocksdb_storage) 39 | 40 | logger.info('removing all events and related data...') 41 | event_storage.reset_all() 42 | logger.info('reset complete') 43 | 44 | 45 | def main(): 46 | parser = create_parser() 47 | args = parser.parse_args() 48 | execute(args) 49 | -------------------------------------------------------------------------------- /hathor/conf/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from pathlib import Path 16 | 17 | from hathor.conf.get_settings import HathorSettings 18 | 19 | parent_dir = Path(__file__).parent 20 | 21 | MAINNET_SETTINGS_FILEPATH = str(parent_dir / 'mainnet.yml') 22 | TESTNET_SETTINGS_FILEPATH = str(parent_dir / 'testnet.yml') 23 | NANO_TESTNET_SETTINGS_FILEPATH = str(parent_dir / 'nano_testnet.yml') 24 | LOCALNET_SETTINGS_FILEPATH = str(parent_dir / 'localnet.yml') 25 | UNITTESTS_SETTINGS_FILEPATH = str(parent_dir / 'unittests.yml') 26 | 27 | __all__ = [ 28 | 'MAINNET_SETTINGS_FILEPATH', 29 | 'TESTNET_SETTINGS_FILEPATH', 30 | 'NANO_TESTNET_SETTINGS_FILEPATH', 31 | 'LOCALNET_SETTINGS_FILEPATH', 32 | 'UNITTESTS_SETTINGS_FILEPATH', 33 | 'HathorSettings', 34 | ] 35 | -------------------------------------------------------------------------------- /hathor/conf/localnet.yml: -------------------------------------------------------------------------------- 1 | P2PKH_VERSION_BYTE: x49 2 | MULTISIG_VERSION_BYTE: x87 3 | NETWORK_NAME: local-privatenet 4 | BOOTSTRAP_DNS: [] 5 | 6 | # Ledger genesis 7 | GENESIS_OUTPUT_SCRIPT: 76a91466665b27f7dbc4c8c089d2f686c170c74d66f0b588ac 8 | GENESIS_BLOCK_TIMESTAMP: 1643902665 9 | GENESIS_BLOCK_NONCE: 4784939 10 | GENESIS_BLOCK_HASH: 00000334a21fbb58b4db8d7ff282d018e03e2977abd3004cf378fb1d677c3967 11 | GENESIS_TX1_NONCE: 0 12 | GENESIS_TX1_HASH: 54165cef1fd4cf2240d702b8383c307c822c16ca407f78014bdefa189a7571c2 13 | GENESIS_TX2_NONCE: 0 14 | GENESIS_TX2_HASH: 039906854ce6309b3180945f2a23deb9edff369753f7082e19053f5ac11bfbae 15 | 16 | # Genesis wallet: 17 | # avocado spot town typical traffic vault danger century property shallow divorce festival 18 | # spend attack anchor afford rotate green audit adjust fade wagon depart level 19 | 20 | MIN_TX_WEIGHT_K: 0 21 | MIN_TX_WEIGHT_COEFFICIENT: 0 22 | MIN_TX_WEIGHT: 1 23 | REWARD_SPEND_MIN_BLOCKS: 1 24 | 25 | CHECKPOINTS: [] 26 | 27 | extends: testnet.yml 28 | -------------------------------------------------------------------------------- /hathor/conf/nano_testnet.yml: -------------------------------------------------------------------------------- 1 | P2PKH_VERSION_BYTE: x49 2 | MULTISIG_VERSION_BYTE: x87 3 | NETWORK_NAME: nano-testnet-alpha 4 | BOOTSTRAP_DNS: 5 | - alpha.nano-testnet.hathor.network 6 | 7 | # Genesis stuff 8 | GENESIS_OUTPUT_SCRIPT: 76a91478e804bf8aa68332c6c1ada274ac598178b972bf88ac 9 | GENESIS_BLOCK_TIMESTAMP: 1677601898 10 | GENESIS_BLOCK_NONCE: 7881594 11 | GENESIS_BLOCK_HASH: 000003472f6a17c2199e24c481a4326c217d07376acd9598651f8413c008554d 12 | GENESIS_TX1_NONCE: 110 13 | GENESIS_TX1_HASH: 0008f0e9dbe6e4bbc3a85fce7494fee70011b9c7e72f5276daa2a235355ac013 14 | GENESIS_TX2_NONCE: 180 15 | GENESIS_TX2_HASH: 008d81d9d58a43fd9649f33483d804a4417247b4d4e4e01d64406c4177fee0c2 16 | 17 | # tx weight parameters. With these settings tx weight is always 8 18 | MIN_TX_WEIGHT_K: 0 19 | MIN_TX_WEIGHT_COEFFICIENT: 0 20 | MIN_TX_WEIGHT: 8 21 | ENABLE_NANO_CONTRACTS: true 22 | ENABLE_ON_CHAIN_BLUEPRINTS: true 23 | NC_ON_CHAIN_BLUEPRINT_ALLOWED_ADDRESSES: 24 | - WWFiNeWAFSmgtjm4ht2MydwS5GY3kMJsEK 25 | BLUEPRINTS: 26 | 3cb032600bdf7db784800e4ea911b10676fa2f67591f82bb62628c234e771595: Bet 27 | 28 | SOFT_VOIDED_TX_IDS: 29 | - 0000003dd5802b05f430a1f54304879173550c0944b49d74321bb9125ee727cb 30 | -------------------------------------------------------------------------------- /hathor/conf/unittests.yml: -------------------------------------------------------------------------------- 1 | P2PKH_VERSION_BYTE: x28 2 | MULTISIG_VERSION_BYTE: x64 3 | NETWORK_NAME: unittests 4 | BLOCKS_PER_HALVING: 120 5 | MIN_BLOCK_WEIGHT: 2 6 | MIN_TX_WEIGHT: 2 7 | MIN_SHARE_WEIGHT: 2 8 | MAX_TX_WEIGHT_DIFF: 25.0 9 | BLOCK_DIFFICULTY_N_BLOCKS: 20 10 | GENESIS_OUTPUT_SCRIPT: 76a914d07bc82d6e0d1bb116614076645e9b87c8c83b4188ac 11 | GENESIS_BLOCK_NONCE: 5 12 | GENESIS_BLOCK_HASH: 2ebb3b8edcb72a7e46cc0efacfe1b109e2e9dd868a90fe0906968dc8fbbf6488 13 | GENESIS_TX1_NONCE: 6 14 | GENESIS_TX1_HASH: 16ba3dbe424c443e571b00840ca54b9ff4cff467e10b6a15536e718e2008f952 15 | GENESIS_TX2_NONCE: 2 16 | GENESIS_TX2_HASH: 33e14cb555a96967841dcbe0f95e9eab5810481d01de8f4f73afb8cce365e869 17 | REWARD_SPEND_MIN_BLOCKS: 10 18 | SLOW_ASSERTS: true 19 | MAX_TX_WEIGHT_DIFF_ACTIVATION: 0.0 20 | 21 | FEATURE_ACTIVATION: 22 | evaluation_interval: 4 23 | max_signal_bits: 4 24 | default_threshold: 3 25 | 26 | ENABLE_NANO_CONTRACTS: true 27 | ENABLE_ON_CHAIN_BLUEPRINTS: true 28 | 29 | NC_ON_CHAIN_BLUEPRINT_ALLOWED_ADDRESSES: 30 | # keypair wallet: 31 | # - privkey: 32 | # MIH0MF8GCSqGSIb3DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBCIdovnmKjK3KUc61YGgja0AgIIAD 33 | # AMBggqhkiG9w0CCQUAMB0GCWCGSAFlAwQBKgQQl2CJT4I2IUzRNoU9hyOWEwSBkLznN9Nunel+ 34 | # kK0FXpk//z0ZAnIyVacfHklCxFGyOj1VSjor0CHzH2Gmblvr+m7lCmRmqSVAwJpplqQYdBUF6s 35 | # R9djHLY6svPY0o//dqQ/xM7QiY2FHlb3JQCTu7DaMflqPcJXlRXAFyoACnmj4/lUJWgrcWalar 36 | # CSI+8rIillg3AU8/2gfoB1BxulVIIG35SQ== 37 | # - password: 38 | # OCBtestPW 39 | - HFwHrQHUftQ7obLj7xbQjG4ZEwvyVXeyoE 40 | -------------------------------------------------------------------------------- /hathor/consensus/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.consensus.consensus import ConsensusAlgorithm 16 | 17 | __all__ = [ 18 | 'ConsensusAlgorithm', 19 | ] 20 | -------------------------------------------------------------------------------- /hathor/consensus/poa/__init__.py: -------------------------------------------------------------------------------- 1 | from .poa import ( 2 | BLOCK_WEIGHT_IN_TURN, 3 | BLOCK_WEIGHT_OUT_OF_TURN, 4 | SIGNER_ID_LEN, 5 | InvalidSignature, 6 | ValidSignature, 7 | calculate_weight, 8 | get_active_signers, 9 | get_hashed_poa_data, 10 | get_signer_index_distance, 11 | verify_poa_signature, 12 | ) 13 | from .poa_block_producer import PoaBlockProducer 14 | from .poa_signer import PoaSigner, PoaSignerFile 15 | 16 | __all__ = [ 17 | 'BLOCK_WEIGHT_IN_TURN', 18 | 'BLOCK_WEIGHT_OUT_OF_TURN', 19 | 'SIGNER_ID_LEN', 20 | 'get_hashed_poa_data', 21 | 'calculate_weight', 22 | 'PoaBlockProducer', 23 | 'PoaSigner', 24 | 'PoaSignerFile', 25 | 'verify_poa_signature', 26 | 'InvalidSignature', 27 | 'ValidSignature', 28 | 'get_active_signers', 29 | 'get_signer_index_distance', 30 | ] 31 | -------------------------------------------------------------------------------- /hathor/crypto/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/crypto/__init__.py -------------------------------------------------------------------------------- /hathor/dag_builder/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.dag_builder.builder import DAGBuilder 16 | 17 | __all__ = ['DAGBuilder'] 18 | -------------------------------------------------------------------------------- /hathor/event/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.event.event_manager import EventManager 16 | 17 | __all__ = ['EventManager'] 18 | -------------------------------------------------------------------------------- /hathor/event/model/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/event/model/__init__.py -------------------------------------------------------------------------------- /hathor/event/model/node_state.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from enum import Enum 16 | 17 | 18 | class NodeState(Enum): 19 | LOAD = 0 20 | SYNC = 1 21 | -------------------------------------------------------------------------------- /hathor/event/resources/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /hathor/event/storage/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.event.storage.event_storage import EventStorage 16 | from hathor.event.storage.rocksdb_storage import EventRocksDBStorage 17 | 18 | __all__ = ['EventStorage', 'EventRocksDBStorage'] 19 | -------------------------------------------------------------------------------- /hathor/event/websocket/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.event.websocket.factory import EventWebsocketFactory 16 | from hathor.event.websocket.protocol import EventWebsocketProtocol 17 | 18 | __all__ = ['EventWebsocketFactory', 'EventWebsocketProtocol'] 19 | -------------------------------------------------------------------------------- /hathor/feature_activation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/feature_activation/__init__.py -------------------------------------------------------------------------------- /hathor/feature_activation/feature.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from enum import Enum, unique 16 | 17 | 18 | @unique 19 | class Feature(str, Enum): 20 | """ 21 | An enum containing all features that participate in the feature activation process, past or future, activated 22 | or not, for all networks. Features should NOT be removed from this enum, to preserve history. Their values 23 | should NOT be changed either, as configuration uses them for setting feature activation criteria. 24 | """ 25 | 26 | # These NOP features are used in tests 27 | NOP_FEATURE_1 = 'NOP_FEATURE_1' 28 | NOP_FEATURE_2 = 'NOP_FEATURE_2' 29 | NOP_FEATURE_3 = 'NOP_FEATURE_3' 30 | 31 | INCREASE_MAX_MERKLE_PATH_LENGTH = 'INCREASE_MAX_MERKLE_PATH_LENGTH' 32 | -------------------------------------------------------------------------------- /hathor/feature_activation/model/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/feature_activation/model/__init__.py -------------------------------------------------------------------------------- /hathor/feature_activation/model/feature_info.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import NamedTuple 16 | 17 | from hathor.feature_activation.model.criteria import Criteria 18 | from hathor.feature_activation.model.feature_state import FeatureState 19 | 20 | 21 | class FeatureInfo(NamedTuple): 22 | """Represents all information related to one feature, that is, its criteria and state.""" 23 | criteria: Criteria 24 | state: FeatureState 25 | -------------------------------------------------------------------------------- /hathor/feature_activation/resources/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/feature_activation/resources/__init__.py -------------------------------------------------------------------------------- /hathor/feature_activation/storage/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/feature_activation/storage/__init__.py -------------------------------------------------------------------------------- /hathor/healthcheck/resources/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.healthcheck.resources.healthcheck import HealthcheckResource 16 | 17 | __all__ = [ 18 | 'HealthcheckResource', 19 | ] 20 | -------------------------------------------------------------------------------- /hathor/indexes/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.indexes.address_index import AddressIndex 16 | from hathor.indexes.manager import IndexesManager, RocksDBIndexesManager 17 | from hathor.indexes.timestamp_index import TimestampIndex 18 | 19 | __all__ = [ 20 | 'IndexesManager', 21 | 'RocksDBIndexesManager', 22 | 'AddressIndex', 23 | 'TimestampIndex', 24 | ] 25 | -------------------------------------------------------------------------------- /hathor/indexes/blueprint_timestamp_index.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import final 16 | 17 | from hathor.indexes.rocksdb_vertex_timestamp_index import RocksDBVertexTimestampIndex 18 | from hathor.indexes.scope import Scope 19 | from hathor.transaction import BaseTransaction 20 | 21 | SCOPE = Scope( 22 | include_blocks=False, 23 | include_txs=True, 24 | include_voided=True, 25 | ) 26 | 27 | 28 | class BlueprintTimestampIndex(RocksDBVertexTimestampIndex): 29 | """Index of on-chain Blueprints sorted by their timestamps.""" 30 | cf_name = b'blueprint-index' 31 | db_name = 'on-chain-blueprints' 32 | 33 | def get_scope(self) -> Scope: 34 | return SCOPE 35 | 36 | @final 37 | def _should_add(self, tx: BaseTransaction) -> bool: 38 | from hathor.nanocontracts import OnChainBlueprint 39 | return isinstance(tx, OnChainBlueprint) 40 | -------------------------------------------------------------------------------- /hathor/indexes/memory_mempool_tips_index.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import Iterable, Optional 16 | 17 | from structlog import get_logger 18 | 19 | from hathor.conf.settings import HathorSettings 20 | from hathor.indexes.mempool_tips_index import ByteCollectionMempoolTipsIndex 21 | 22 | logger = get_logger() 23 | 24 | 25 | class MemoryMempoolTipsIndex(ByteCollectionMempoolTipsIndex): 26 | _index: set[bytes] 27 | 28 | def __init__(self, *, settings: HathorSettings) -> None: 29 | super().__init__(settings=settings) 30 | self.log = logger.new() 31 | self.force_clear() 32 | 33 | def get_db_name(self) -> Optional[str]: 34 | return None 35 | 36 | def force_clear(self) -> None: 37 | self._index = set() 38 | 39 | def _discard(self, tx: bytes) -> None: 40 | self._index.discard(tx) 41 | 42 | def _add(self, tx: bytes) -> None: 43 | self._index.add(tx) 44 | 45 | def _add_many(self, txs: Iterable[bytes]) -> None: 46 | self._index.update(txs) 47 | -------------------------------------------------------------------------------- /hathor/indexes/nc_creation_index.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.indexes.rocksdb_vertex_timestamp_index import RocksDBVertexTimestampIndex 16 | from hathor.indexes.scope import Scope 17 | from hathor.transaction import BaseTransaction, Transaction 18 | 19 | SCOPE = Scope( 20 | include_blocks=False, 21 | include_txs=True, 22 | include_voided=True, 23 | ) 24 | 25 | 26 | class NCCreationIndex(RocksDBVertexTimestampIndex): 27 | """Index of Nano Contract creation txs sorted by their timestamps.""" 28 | cf_name = b'nc-creation-index' 29 | db_name = 'nc-creation' 30 | 31 | def get_scope(self) -> Scope: 32 | return SCOPE 33 | 34 | def _should_add(self, tx: BaseTransaction) -> bool: 35 | if not tx.is_nano_contract(): 36 | return False 37 | assert isinstance(tx, Transaction) 38 | nano_header = tx.get_nano_header() 39 | return nano_header.is_creating_a_new_contract() 40 | -------------------------------------------------------------------------------- /hathor/indexes/rocksdb_blueprint_history_index.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import rocksdb 16 | from typing_extensions import override 17 | 18 | from hathor.indexes.blueprint_history_index import BlueprintHistoryIndex 19 | from hathor.indexes.rocksdb_tx_group_index import RocksDBTxGroupIndex 20 | from hathor.indexes.rocksdb_utils import RocksDBIndexUtils 21 | 22 | _CF_NAME_BLUEPRINT_HISTORY_INDEX = b'blueprint-history-index' 23 | _DB_NAME: str = 'blueprint-history' 24 | 25 | 26 | class RocksDBBlueprintHistoryIndex(RocksDBTxGroupIndex[bytes], BlueprintHistoryIndex, RocksDBIndexUtils): 27 | _KEY_SIZE = 32 28 | 29 | def __init__(self, db: rocksdb.DB) -> None: 30 | RocksDBTxGroupIndex.__init__(self, db, _CF_NAME_BLUEPRINT_HISTORY_INDEX) 31 | 32 | @override 33 | def _serialize_key(self, key: bytes) -> bytes: 34 | return key 35 | 36 | @override 37 | def _deserialize_key(self, key_bytes: bytes) -> bytes: 38 | return key_bytes 39 | 40 | @override 41 | def get_db_name(self) -> str | None: 42 | return _DB_NAME 43 | -------------------------------------------------------------------------------- /hathor/merged_mining/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.merged_mining.coordinator import MAGIC_NUMBER, MergedMiningCoordinator 16 | 17 | __all__ = [ 18 | 'MAGIC_NUMBER', 19 | 'MergedMiningCoordinator' 20 | ] 21 | -------------------------------------------------------------------------------- /hathor/mining/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.mining.block_template import BlockTemplate, BlockTemplates 16 | 17 | __all__ = [ 18 | 'BlockTemplate', 19 | 'BlockTemplates', 20 | ] 21 | -------------------------------------------------------------------------------- /hathor/nanocontracts/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.nanocontracts.blueprint import Blueprint 16 | from hathor.nanocontracts.context import Context 17 | from hathor.nanocontracts.exception import NCFail 18 | from hathor.nanocontracts.on_chain_blueprint import OnChainBlueprint 19 | from hathor.nanocontracts.runner import Runner 20 | from hathor.nanocontracts.storage import NCMemoryStorageFactory, NCRocksDBStorageFactory, NCStorageFactory 21 | from hathor.nanocontracts.types import public, view 22 | 23 | __all__ = [ 24 | 'Blueprint', 25 | 'Context', 26 | 'Runner', 27 | 'OnChainBlueprint', 28 | 'NCFail', 29 | 'NCMemoryStorageFactory', 30 | 'NCRocksDBStorageFactory', 31 | 'NCStorageFactory', 32 | 'public', 33 | 'view', 34 | ] 35 | -------------------------------------------------------------------------------- /hathor/nanocontracts/blueprints/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import TYPE_CHECKING, Type 16 | 17 | if TYPE_CHECKING: 18 | from hathor.nanocontracts.blueprint import Blueprint 19 | 20 | 21 | _blueprints_mapper: dict[str, Type['Blueprint']] = { 22 | } 23 | -------------------------------------------------------------------------------- /hathor/nanocontracts/fields/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from collections.abc import Mapping 16 | from typing import TYPE_CHECKING, TypeAlias 17 | 18 | if TYPE_CHECKING: 19 | from hathor.nanocontracts.fields import Field 20 | 21 | 22 | TypeToFieldMap: TypeAlias = Mapping[type, type['Field']] 23 | -------------------------------------------------------------------------------- /hathor/nanocontracts/resources/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.nanocontracts.resources.blueprint import BlueprintInfoResource 16 | from hathor.nanocontracts.resources.blueprint_source_code import BlueprintSourceCodeResource 17 | from hathor.nanocontracts.resources.builtin import BlueprintBuiltinResource 18 | from hathor.nanocontracts.resources.history import NanoContractHistoryResource 19 | from hathor.nanocontracts.resources.nc_creation import NCCreationResource 20 | from hathor.nanocontracts.resources.on_chain import BlueprintOnChainResource 21 | from hathor.nanocontracts.resources.state import NanoContractStateResource 22 | 23 | __all__ = [ 24 | 'BlueprintBuiltinResource', 25 | 'BlueprintInfoResource', 26 | 'BlueprintOnChainResource', 27 | 'BlueprintSourceCodeResource', 28 | 'NanoContractStateResource', 29 | 'NanoContractHistoryResource', 30 | 'NCCreationResource', 31 | ] 32 | -------------------------------------------------------------------------------- /hathor/nanocontracts/runner/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.nanocontracts.runner.runner import Runner 16 | from hathor.nanocontracts.runner.types import CallInfo, CallRecord, CallType 17 | 18 | __all__ = [ 19 | 'CallType', 20 | 'CallRecord', 21 | 'CallInfo', 22 | 'Runner', 23 | ] 24 | -------------------------------------------------------------------------------- /hathor/nanocontracts/sorter/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/nanocontracts/sorter/__init__.py -------------------------------------------------------------------------------- /hathor/nanocontracts/sorter/timestamp_sorter.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.transaction import Block, Transaction 16 | 17 | 18 | def timestamp_nc_calls_sorter(block: Block, nc_calls: list[Transaction]) -> list[Transaction]: 19 | """Return the nc_calls sorted by (timestamp, hash). 20 | 21 | DEPRECATED: This is used only to keep compatibility with the alpha nano-testnet. 22 | """ 23 | return sorted(nc_calls, key=lambda tx: (tx.timestamp, tx.hash)) 24 | -------------------------------------------------------------------------------- /hathor/nanocontracts/sorter/types.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import Callable 16 | 17 | from hathor.transaction import Block, Transaction 18 | 19 | NCSorterCallable = Callable[[Block, list[Transaction]], list[Transaction]] 20 | -------------------------------------------------------------------------------- /hathor/nanocontracts/storage/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.nanocontracts.storage.block_storage import NCBlockStorage 16 | from hathor.nanocontracts.storage.changes_tracker import NCChangesTracker 17 | from hathor.nanocontracts.storage.contract_storage import NCContractStorage 18 | from hathor.nanocontracts.storage.factory import NCMemoryStorageFactory, NCRocksDBStorageFactory, NCStorageFactory 19 | from hathor.nanocontracts.storage.types import DeletedKey 20 | 21 | __all__ = [ 22 | 'NCBlockStorage', 23 | 'NCContractStorage', 24 | 'NCChangesTracker', 25 | 'NCMemoryStorageFactory', 26 | 'NCRocksDBStorageFactory', 27 | 'NCStorageFactory', 28 | 'DeletedKey', 29 | ] 30 | -------------------------------------------------------------------------------- /hathor/nanocontracts/storage/token_proxy.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from __future__ import annotations 16 | 17 | from typing import TYPE_CHECKING 18 | 19 | if TYPE_CHECKING: 20 | from hathor.nanocontracts.storage.block_storage import NCBlockStorage 21 | from hathor.nanocontracts.types import TokenUid 22 | 23 | 24 | class TokenProxy: 25 | """A proxy used to limit access to only the tokens method of a block storage. 26 | """ 27 | def __init__(self, block_storage: NCBlockStorage) -> None: 28 | self.__block_storage = block_storage 29 | 30 | def has_token(self, token_id: TokenUid) -> bool: 31 | """Proxy to block_storage.has_token().""" 32 | return self.__block_storage.has_token(token_id) 33 | 34 | def create_token(self, token_id: TokenUid, token_name: str, token_symbol: str) -> None: 35 | """Proxy to block_storage.create_token().""" 36 | self.__block_storage.create_token(token_id, token_name, token_symbol) 37 | -------------------------------------------------------------------------------- /hathor/nanocontracts/storage/types.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import Any 16 | 17 | 18 | class DeletedKeyType: 19 | pass 20 | 21 | 22 | # Placeholder to mark a key as deleted in a dict. 23 | DeletedKey = DeletedKeyType() 24 | 25 | # Sentinel value to differentiate where a user has provided a default value or not. 26 | # Since _NOT_PROVIDED is a unique object, it is guaranteed not to be equal to any other value. 27 | _NOT_PROVIDED: Any = object() 28 | -------------------------------------------------------------------------------- /hathor/p2p/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/p2p/__init__.py -------------------------------------------------------------------------------- /hathor/p2p/ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC0jCCAbqgAwIBAgIUOIpniBA41tlMrIHZ0mXk+F2N5RAwDQYJKoZIhvcNAQEL 3 | BQAwFjEUMBIGA1UEAwwLSGF0aG9yIExhYnMwIBcNMTkwODI3MTE0NzA4WhgPMjEx 4 | OTA4MDMxMjQ3MDhaMBYxFDASBgNVBAMMC0hhdGhvciBMYWJzMIIBIjANBgkqhkiG 5 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxpHLIS0htvkfMmO05fJUE04f+i+zOfrbNBz/ 6 | uNRPOJyaiICLWpr/xFpQX7cqHbgEMu7plfaN96SX1o/S/frwkW0vaqqOqwVmZ6T1 7 | 8ASxlkwhBIp964D3mCsmUFLILDwYaHmJlRWo19lIJEQ+NfH6wWgpQ8e8ij1DsPw+ 8 | wXpmSTVdQFDa5nN+roxaRfgVx2hI3j0Uyh3JjNCQJNTfINmEPLBmHEjiBXvLsP67 9 | XATKBYy5bFVIxGJsHYM3HSKbmjAL9vuG2ELOnAQTJYyB9RmTIHGIFIPN+595j9Z7 10 | nBdqMAxEmYLufoK1gldIqFrYjbJixRX1HE1FZ06L27atmEiPswIDAQABoxYwFDAS 11 | BgNVHRMBAf8ECDAGAQH/AgEBMA0GCSqGSIb3DQEBCwUAA4IBAQBIXdEo9Fpb/YSL 12 | rLUePY2cBeV+hgK2U4hKojdBEqnl5se2R4pQq1Jk4MO9YTReDw0WVb12mJZyXF+/ 13 | LFpm9hOGe7tF6jdNtvo9//CZ15DzFZb/mep/ojcdhRy0YxXz5GbfMrnDF+Cdipx5 14 | /CWBG8oo3LuOWY5uDl4ux0pyDSTAOChzsxxRwGjTAZuHUJc0iZLgQvkfhJwT7F7u 15 | 5Xi+zxT5P5v69f+cIXCoLeW2tQS5THezzGTvMNDGF9sJU+ntHM4rGnAbXdzCwzLq 16 | ZacY8pW3SFDTzT+rwHw6+cpHJMeuM0Hl2W4m/pxqXa7xJbForF+3VQ6j51c/tikM 17 | Sp7xAXG8 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /hathor/p2p/netfilter/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.p2p.netfilter.instances import get_table 16 | 17 | __all__ = [ 18 | 'get_table', 19 | ] 20 | -------------------------------------------------------------------------------- /hathor/p2p/netfilter/context.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import TYPE_CHECKING, Optional 16 | 17 | if TYPE_CHECKING: 18 | from twisted.internet.interfaces import IAddress 19 | 20 | from hathor.p2p.manager import ConnectionsManager 21 | from hathor.p2p.protocol import HathorProtocol 22 | 23 | 24 | class NetfilterContext: 25 | """Context sent to the targets when a match occurs.""" 26 | def __init__(self, *, connections: Optional['ConnectionsManager'] = None, addr: Optional['IAddress'] = None, 27 | protocol: Optional['HathorProtocol'] = None): 28 | """Initialize the context.""" 29 | self.addr = addr 30 | self.protocol = protocol 31 | self.connections = connections 32 | -------------------------------------------------------------------------------- /hathor/p2p/netfilter/instances.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.p2p.netfilter.chain import NetfilterChain 16 | from hathor.p2p.netfilter.table import NetfilterTable 17 | from hathor.p2p.netfilter.targets import NetfilterAccept 18 | 19 | filter_table = NetfilterTable('filter') 20 | filter_table.add_chain(NetfilterChain('pre_conn', policy=NetfilterAccept())) 21 | filter_table.add_chain(NetfilterChain('post_hello', policy=NetfilterAccept())) 22 | filter_table.add_chain(NetfilterChain('post_peerid', policy=NetfilterAccept())) 23 | 24 | tables = { 25 | 'filter': filter_table, 26 | } 27 | 28 | 29 | def get_table(name): 30 | """Get table `name` of the netfilter.""" 31 | if name not in tables: 32 | raise KeyError('Table {} does not exists'.format(name)) 33 | return tables[name] 34 | -------------------------------------------------------------------------------- /hathor/p2p/netfilter/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.p2p.netfilter import get_table 16 | from hathor.p2p.netfilter.matches import NetfilterMatchPeerId 17 | from hathor.p2p.netfilter.rule import NetfilterRule 18 | from hathor.p2p.netfilter.targets import NetfilterReject 19 | 20 | 21 | def add_peer_id_blacklist(peer_id_blacklist: list[str]) -> None: 22 | """ Add a list of peer ids to a blacklist using netfilter reject 23 | """ 24 | post_peerid = get_table('filter').get_chain('post_peerid') 25 | 26 | for peer_id in peer_id_blacklist: 27 | if not peer_id: 28 | continue 29 | match = NetfilterMatchPeerId(peer_id) 30 | rule = NetfilterRule(match, NetfilterReject()) 31 | post_peerid.add_rule(rule) 32 | -------------------------------------------------------------------------------- /hathor/p2p/peer_discovery/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from .bootstrap import BootstrapPeerDiscovery 16 | from .dns import DNSPeerDiscovery 17 | from .peer_discovery import PeerDiscovery 18 | 19 | __all__ = [ 20 | 'PeerDiscovery', 21 | 'BootstrapPeerDiscovery', 22 | 'DNSPeerDiscovery', 23 | ] 24 | -------------------------------------------------------------------------------- /hathor/p2p/peer_discovery/bootstrap.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import Callable 16 | 17 | from structlog import get_logger 18 | from typing_extensions import override 19 | 20 | from hathor.p2p.peer_endpoint import PeerEndpoint 21 | 22 | from .peer_discovery import PeerDiscovery 23 | 24 | logger = get_logger() 25 | 26 | 27 | class BootstrapPeerDiscovery(PeerDiscovery): 28 | """ It implements a bootstrap peer discovery, which receives a static list of peers. 29 | """ 30 | 31 | def __init__(self, entrypoints: list[PeerEndpoint]): 32 | """ 33 | :param entrypoints: Addresses of peers to connect to. 34 | """ 35 | super().__init__() 36 | self.log = logger.new() 37 | self.entrypoints = entrypoints 38 | 39 | @override 40 | async def discover_and_connect(self, connect_to_endpoint: Callable[[PeerEndpoint], None]) -> None: 41 | for entrypoint in self.entrypoints: 42 | connect_to_endpoint(entrypoint) 43 | -------------------------------------------------------------------------------- /hathor/p2p/peer_discovery/peer_discovery.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from abc import ABC, abstractmethod 16 | from typing import Callable 17 | 18 | from hathor.p2p.peer_endpoint import PeerEndpoint 19 | 20 | 21 | class PeerDiscovery(ABC): 22 | """ Base class to implement peer discovery strategies. 23 | """ 24 | 25 | @abstractmethod 26 | async def discover_and_connect(self, connect_to_endpoint: Callable[[PeerEndpoint], None]) -> None: 27 | """ This method must discover the peers and call `connect_to_endpoint` for each of them. 28 | 29 | :param connect_to_endpoint: Function which will be called for each discovered peer. 30 | :type connect_to_endpoint: function 31 | """ 32 | raise NotImplementedError 33 | -------------------------------------------------------------------------------- /hathor/p2p/peer_id.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.types import Hash 16 | 17 | 18 | class PeerId(Hash): 19 | pass 20 | -------------------------------------------------------------------------------- /hathor/p2p/resources/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.p2p.resources.add_peers import AddPeersResource 16 | from hathor.p2p.resources.healthcheck import HealthcheckReadinessResource 17 | from hathor.p2p.resources.mining import MiningResource 18 | from hathor.p2p.resources.mining_info import MiningInfoResource 19 | from hathor.p2p.resources.netfilter import NetfilterRuleResource 20 | from hathor.p2p.resources.status import StatusResource 21 | 22 | __all__ = [ 23 | 'AddPeersResource', 24 | 'StatusResource', 25 | 'MiningResource', 26 | 'MiningInfoResource', 27 | 'HealthcheckReadinessResource', 28 | 'NetfilterRuleResource' 29 | ] 30 | -------------------------------------------------------------------------------- /hathor/p2p/states/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from .base import BaseState 16 | from .hello import HelloState 17 | from .peer_id import PeerIdState 18 | from .ready import ReadyState 19 | 20 | __all__ = ['BaseState', 'HelloState', 'PeerIdState', 'ReadyState'] 21 | -------------------------------------------------------------------------------- /hathor/p2p/sync_factory.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from abc import ABC, abstractmethod 16 | from typing import TYPE_CHECKING 17 | 18 | from hathor.p2p.sync_agent import SyncAgent 19 | from hathor.reactor import ReactorProtocol as Reactor 20 | 21 | if TYPE_CHECKING: 22 | from hathor.p2p.protocol import HathorProtocol 23 | 24 | 25 | class SyncAgentFactory(ABC): 26 | @abstractmethod 27 | def create_sync_agent(self, protocol: 'HathorProtocol', reactor: Reactor) -> SyncAgent: 28 | pass 29 | -------------------------------------------------------------------------------- /hathor/p2p/sync_v2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/p2p/sync_v2/__init__.py -------------------------------------------------------------------------------- /hathor/p2p/sync_v2/exception.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | class StreamingError(Exception): 16 | """Base error for sync-v2 streaming.""" 17 | pass 18 | 19 | 20 | class TooManyVerticesReceivedError(StreamingError): 21 | """Raised when the other peer has sent too many vertices.""" 22 | pass 23 | 24 | 25 | class TooManyRepeatedVerticesError(StreamingError): 26 | """Raised when the other peer has sent too many repeated vertices.""" 27 | pass 28 | 29 | 30 | class BlockNotConnectedToPreviousBlock(StreamingError): 31 | """Raised when the received block is not connected to the previous one.""" 32 | pass 33 | 34 | 35 | class InvalidVertexError(StreamingError): 36 | """Raised when the received vertex fails validation.""" 37 | pass 38 | 39 | 40 | class UnexpectedVertex(StreamingError): 41 | """Raised when we are not expecting the received vertex.""" 42 | pass 43 | -------------------------------------------------------------------------------- /hathor/profiler/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.profiler.cpu import SimpleCPUProfiler 16 | 17 | # Create a singleton to be used in the other modules. 18 | # When using, call `get_cpu_profiler()` to get the singleton. 19 | # You should NEVER access `_cpu_instance` directly. 20 | _cpu_instance = SimpleCPUProfiler() 21 | 22 | 23 | def get_cpu_profiler() -> SimpleCPUProfiler: 24 | """Return the singleton CPU profiler.""" 25 | return _cpu_instance 26 | 27 | 28 | __all__ = [ 29 | 'get_cpu_profiler', 30 | ] 31 | -------------------------------------------------------------------------------- /hathor/profiler/resources/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.profiler.resources.cpu_profiler import CPUProfilerResource 16 | from hathor.profiler.resources.profiler import ProfilerResource 17 | 18 | __all__ = [ 19 | 'ProfilerResource', 20 | 'CPUProfilerResource', 21 | ] 22 | -------------------------------------------------------------------------------- /hathor/pycoin/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/pycoin/__init__.py -------------------------------------------------------------------------------- /hathor/pycoin/htr.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from pycoin.networks.bitcoinish import create_bitcoinish_network 16 | 17 | from hathor.conf import HathorSettings 18 | 19 | settings = HathorSettings() 20 | 21 | network = create_bitcoinish_network( 22 | symbol='HTR', network_name='Hathor', subnet_name='mainnet', 23 | wif_prefix_hex='80', 24 | address_prefix_hex=settings.P2PKH_VERSION_BYTE.hex(), 25 | pay_to_script_prefix_hex=settings.MULTISIG_VERSION_BYTE.hex(), 26 | bip32_prv_prefix_hex='0488ade4', bip32_pub_prefix_hex='0488B21E', 27 | ) 28 | -------------------------------------------------------------------------------- /hathor/reactor/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.reactor.reactor import get_global_reactor, initialize_global_reactor 16 | from hathor.reactor.reactor_protocol import ReactorProtocol 17 | 18 | __all__ = [ 19 | 'initialize_global_reactor', 20 | 'get_global_reactor', 21 | 'ReactorProtocol', 22 | ] 23 | -------------------------------------------------------------------------------- /hathor/reactor/reactor_protocol.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import Protocol 16 | 17 | from hathor.reactor.reactor_core_protocol import ReactorCoreProtocol 18 | from hathor.reactor.reactor_tcp_protocol import ReactorTCPProtocol 19 | from hathor.reactor.reactor_time_protocol import ReactorTimeProtocol 20 | 21 | 22 | class ReactorProtocol( 23 | ReactorCoreProtocol, 24 | ReactorTimeProtocol, 25 | ReactorTCPProtocol, 26 | Protocol, 27 | ): 28 | """ 29 | A Python protocol that represents the intersection of Twisted's IReactorCore+IReactorTime+IReactorTCP interfaces. 30 | """ 31 | pass 32 | -------------------------------------------------------------------------------- /hathor/reactor/reactor_time_protocol.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from abc import abstractmethod 16 | from typing import TYPE_CHECKING, Any, Callable, Protocol, Sequence 17 | 18 | from twisted.internet.interfaces import IReactorTime 19 | from zope.interface import implementer 20 | 21 | if TYPE_CHECKING: 22 | from twisted.internet.interfaces import IDelayedCall 23 | 24 | 25 | @implementer(IReactorTime) 26 | class ReactorTimeProtocol(Protocol): 27 | """ 28 | A Python protocol that stubs Twisted's IReactorTime interface. 29 | """ 30 | 31 | @abstractmethod 32 | def seconds(self) -> float: 33 | raise NotImplementedError 34 | 35 | @abstractmethod 36 | def callLater(self, delay: float, callable: Callable[..., Any], *args: object, **kwargs: object) -> 'IDelayedCall': 37 | raise NotImplementedError 38 | 39 | @abstractmethod 40 | def getDelayedCalls(self) -> Sequence['IDelayedCall']: 41 | raise NotImplementedError 42 | -------------------------------------------------------------------------------- /hathor/reward_lock/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.reward_lock.reward_lock import get_spent_reward_locked_info, is_spent_reward_locked, iter_spent_rewards 16 | 17 | __all__ = [ 18 | 'iter_spent_rewards', 19 | 'is_spent_reward_locked', 20 | 'get_spent_reward_locked_info', 21 | ] 22 | -------------------------------------------------------------------------------- /hathor/serialization/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from .deserializer import Deserializer 16 | from .exceptions import BadDataError, OutOfDataError, SerializationError, TooLongError, UnsupportedTypeError 17 | from .serializer import Serializer 18 | 19 | __all__ = [ 20 | 'Serializer', 21 | 'Deserializer', 22 | 'SerializationError', 23 | 'UnsupportedTypeError', 24 | 'TooLongError', 25 | 'OutOfDataError', 26 | 'BadDataError', 27 | ] 28 | -------------------------------------------------------------------------------- /hathor/serialization/adapters/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from .generic_adapter import GenericDeserializerAdapter, GenericSerializerAdapter 16 | from .max_bytes import MaxBytesDeserializer, MaxBytesExceededError, MaxBytesSerializer 17 | 18 | __all__ = [ 19 | 'GenericDeserializerAdapter', 20 | 'GenericSerializerAdapter', 21 | 'MaxBytesDeserializer', 22 | 'MaxBytesExceededError', 23 | 'MaxBytesSerializer', 24 | ] 25 | -------------------------------------------------------------------------------- /hathor/serialization/consts.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | DEFAULT_LEB128_MAX_BYTES: int = 4 16 | DEFAULT_BYTES_MAX_LENGTH: int = 2**16 # 64KiB 17 | -------------------------------------------------------------------------------- /hathor/serialization/encoding/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """ 16 | This module was made to hold simple encoding implementations. 17 | 18 | Simple in this context means "not compound". For example a fixed-size int encoding can have sized/signed parameters, 19 | but not a have a generic function or type as a parameter. For compound types (optionals, lists, dicts, ...) the encoder 20 | should be in the `encoding_compound` module. 21 | 22 | The general organization should be that each submodule `x` deals with a single type and look like this: 23 | 24 | def encode_x(serializer: Serializer, value: ValueType, ...config params...) -> None: 25 | ... 26 | 27 | def decode_x(deserializer: Deserializer, ...config params...) -> ValueType: 28 | ... 29 | 30 | The "config params" are optional and specific to each encoder. Submodules should not have to take into consideration 31 | how types are mapped to encoders. 32 | """ 33 | -------------------------------------------------------------------------------- /hathor/serialization/exceptions.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import struct 16 | 17 | from hathor.exception import HathorError 18 | 19 | 20 | class SerializationError(HathorError): 21 | pass 22 | 23 | 24 | class UnsupportedTypeError(SerializationError): 25 | pass 26 | 27 | 28 | class TooLongError(SerializationError): 29 | pass 30 | 31 | 32 | class OutOfDataError(SerializationError, struct.error): 33 | pass 34 | 35 | 36 | class BadDataError(SerializationError): 37 | pass 38 | -------------------------------------------------------------------------------- /hathor/serialization/types.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import TypeAlias 16 | 17 | Buffer: TypeAlias = bytes | memoryview 18 | -------------------------------------------------------------------------------- /hathor/simulator/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | from hathor.simulator.fake_connection import FakeConnection 17 | from hathor.simulator.simulator import Simulator 18 | from hathor.simulator.tx_generator import RandomTransactionGenerator 19 | 20 | __all__ = [ 21 | 'FakeConnection', 22 | 'RandomTransactionGenerator', 23 | 'Simulator', 24 | ] 25 | -------------------------------------------------------------------------------- /hathor/simulator/miner/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.simulator.miner.abstract_miner import AbstractMiner 16 | from hathor.simulator.miner.geometric_miner import GeometricMiner 17 | 18 | __all__ = [ 19 | 'AbstractMiner', 20 | 'GeometricMiner', 21 | ] 22 | -------------------------------------------------------------------------------- /hathor/simulator/patches.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import Optional 16 | 17 | from structlog import get_logger 18 | 19 | from hathor.mining.cpu_mining_service import CpuMiningService 20 | from hathor.transaction import BaseTransaction 21 | from hathor.verification.vertex_verifier import VertexVerifier 22 | 23 | logger = get_logger() 24 | 25 | 26 | class SimulatorVertexVerifier(VertexVerifier): 27 | @classmethod 28 | def verify_pow(cls, vertex: BaseTransaction, *, override_weight: Optional[float] = None) -> None: 29 | logger.new().debug('Skipping VertexVerifier.verify_pow() for simulator') 30 | 31 | 32 | class SimulatorCpuMiningService(CpuMiningService): 33 | def resolve(self, vertex: BaseTransaction, *, update_time: bool = False) -> bool: 34 | vertex.update_hash() 35 | logger.new().debug('Skipping CpuMiningService.resolve() for simulator') 36 | return True 37 | -------------------------------------------------------------------------------- /hathor/storage/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.storage.rocksdb_storage import RocksDBStorage 16 | 17 | __all__ = ['RocksDBStorage'] 18 | -------------------------------------------------------------------------------- /hathor/stratum/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.stratum.stratum import ( 16 | INVALID_ADDRESS, 17 | INVALID_PARAMS, 18 | INVALID_REQUEST, 19 | INVALID_SOLUTION, 20 | JOB_NOT_FOUND, 21 | JSONRPC, 22 | METHOD_NOT_FOUND, 23 | PARSE_ERROR, 24 | STALE_JOB, 25 | StratumClient, 26 | StratumFactory, 27 | ) 28 | 29 | __all__ = [ 30 | 'INVALID_ADDRESS', 31 | 'INVALID_PARAMS', 32 | 'INVALID_REQUEST', 33 | 'INVALID_SOLUTION', 34 | 'JOB_NOT_FOUND', 35 | 'JSONRPC', 36 | 'METHOD_NOT_FOUND', 37 | 'PARSE_ERROR', 38 | 'STALE_JOB', 39 | 'StratumClient', 40 | 'StratumFactory', 41 | ] 42 | -------------------------------------------------------------------------------- /hathor/sysctl/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.sysctl.core.manager import HathorManagerSysctl 16 | from hathor.sysctl.feature_activation.manager import FeatureActivationSysctl 17 | from hathor.sysctl.p2p.manager import ConnectionsManagerSysctl 18 | from hathor.sysctl.sysctl import Sysctl 19 | from hathor.sysctl.websocket.manager import WebsocketManagerSysctl 20 | 21 | __all__ = [ 22 | 'Sysctl', 23 | 'ConnectionsManagerSysctl', 24 | 'HathorManagerSysctl', 25 | 'WebsocketManagerSysctl', 26 | 'FeatureActivationSysctl', 27 | ] 28 | -------------------------------------------------------------------------------- /hathor/sysctl/core/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /hathor/sysctl/exception.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | class SysctlException(Exception): 16 | pass 17 | 18 | 19 | class SysctlEntryNotFound(SysctlException): 20 | pass 21 | 22 | 23 | class SysctlReadOnlyEntry(SysctlException): 24 | pass 25 | 26 | 27 | class SysctlWriteOnlyEntry(SysctlException): 28 | pass 29 | 30 | 31 | class SysctlRunnerException(SysctlException): 32 | pass 33 | -------------------------------------------------------------------------------- /hathor/sysctl/factory.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from twisted.internet.protocol import Factory 16 | 17 | from hathor.sysctl.protocol import SysctlProtocol 18 | from hathor.sysctl.runner import SysctlRunner 19 | 20 | 21 | class SysctlFactory(Factory): 22 | def __init__(self, runner: SysctlRunner) -> None: 23 | self.runner = runner 24 | 25 | def buildProtocol(self, addr): 26 | return SysctlProtocol(self.runner) 27 | -------------------------------------------------------------------------------- /hathor/sysctl/feature_activation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/sysctl/feature_activation/__init__.py -------------------------------------------------------------------------------- /hathor/sysctl/init_file_loader.py: -------------------------------------------------------------------------------- 1 | from hathor.sysctl.runner import SysctlRunner 2 | 3 | 4 | class SysctlInitFileLoader: 5 | def __init__(self, runner: SysctlRunner, init_file: str) -> None: 6 | assert runner 7 | assert init_file 8 | 9 | self.runner = runner 10 | self.init_file = init_file 11 | 12 | def load(self) -> None: 13 | """Read the init_file and execute each line as a syctl command in the runner.""" 14 | with open(self.init_file, 'r', encoding='utf-8') as file: 15 | lines = file.readlines() 16 | 17 | for line in lines: 18 | self.runner.run(line.strip()) 19 | -------------------------------------------------------------------------------- /hathor/sysctl/p2p/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /hathor/sysctl/websocket/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /hathor/transaction/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.transaction.aux_pow import BitcoinAuxPow 16 | from hathor.transaction.base_transaction import ( 17 | MAX_OUTPUT_VALUE, 18 | BaseTransaction, 19 | TxInput, 20 | TxOutput, 21 | TxVersion, 22 | Vertex, 23 | sum_weights, 24 | ) 25 | from hathor.transaction.block import Block 26 | from hathor.transaction.merge_mined_block import MergeMinedBlock 27 | from hathor.transaction.transaction import Transaction 28 | from hathor.transaction.transaction_metadata import TransactionMetadata 29 | 30 | __all__ = [ 31 | 'Transaction', 32 | 'BitcoinAuxPow', 33 | 'Vertex', 34 | 'BaseTransaction', 35 | 'Block', 36 | 'MergeMinedBlock', 37 | 'TransactionMetadata', 38 | 'TxInput', 39 | 'TxOutput', 40 | 'TxVersion', 41 | 'MAX_OUTPUT_VALUE', 42 | 'sum_weights', 43 | ] 44 | -------------------------------------------------------------------------------- /hathor/transaction/headers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.transaction.headers.base import VertexBaseHeader 16 | from hathor.transaction.headers.nano_header import NanoHeader 17 | from hathor.transaction.headers.types import VertexHeaderId 18 | 19 | __all__ = [ 20 | 'VertexBaseHeader', 21 | 'VertexHeaderId', 22 | 'NanoHeader', 23 | ] 24 | -------------------------------------------------------------------------------- /hathor/transaction/headers/types.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from enum import Enum, unique 16 | 17 | 18 | @unique 19 | class VertexHeaderId(Enum): 20 | NANO_HEADER = b'\x10' 21 | -------------------------------------------------------------------------------- /hathor/transaction/nc_execution_state.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from enum import Enum, unique 16 | 17 | 18 | @unique 19 | class NCExecutionState(str, Enum): 20 | PENDING = 'pending' # aka, not even tried to execute it 21 | SUCCESS = 'success' # execution was sucessful 22 | FAILURE = 'failure' # execution failed and the transaction is voided 23 | SKIPPED = 'skipped' # execution was skipped, usually because the transaction was voided 24 | -------------------------------------------------------------------------------- /hathor/transaction/poa/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.transaction.poa.poa_block import PoaBlock 16 | 17 | __all__ = [ 18 | 'PoaBlock', 19 | ] 20 | -------------------------------------------------------------------------------- /hathor/transaction/scripts/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.transaction.scripts.construct import ( 16 | create_base_script, 17 | create_output_script, 18 | get_sigops_count, 19 | parse_address_script, 20 | ) 21 | from hathor.transaction.scripts.execute import ScriptExtras, script_eval 22 | from hathor.transaction.scripts.hathor_script import HathorScript 23 | from hathor.transaction.scripts.multi_sig import MultiSig 24 | from hathor.transaction.scripts.nano_contract_match_values import NanoContractMatchValues 25 | from hathor.transaction.scripts.opcode import Opcode 26 | from hathor.transaction.scripts.p2pkh import P2PKH 27 | 28 | __all__ = [ 29 | 'Opcode', 30 | 'P2PKH', 31 | 'MultiSig', 32 | 'NanoContractMatchValues', 33 | 'HathorScript', 34 | 'ScriptExtras', 35 | 'parse_address_script', 36 | 'create_base_script', 37 | 'create_output_script', 38 | 'script_eval', 39 | 'get_sigops_count', 40 | ] 41 | -------------------------------------------------------------------------------- /hathor/transaction/scripts/script_context.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.transaction.scripts.execute import ScriptExtras, Stack 16 | 17 | 18 | class ScriptContext: 19 | """A context to be manipulated during script execution. A separate instance must be used for each script.""" 20 | __slots__ = ('stack', 'logs', 'extras') 21 | 22 | def __init__(self, *, stack: Stack, logs: list[str], extras: ScriptExtras) -> None: 23 | self.stack = stack 24 | self.logs = logs 25 | self.extras = extras 26 | -------------------------------------------------------------------------------- /hathor/transaction/storage/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.transaction.storage.cache_storage import TransactionCacheStorage 16 | from hathor.transaction.storage.rocksdb_storage import TransactionRocksDBStorage 17 | from hathor.transaction.storage.transaction_storage import TransactionStorage 18 | from hathor.transaction.storage.vertex_storage_protocol import VertexStorageProtocol 19 | 20 | __all__ = [ 21 | 'TransactionStorage', 22 | 'TransactionCacheStorage', 23 | 'TransactionRocksDBStorage', 24 | 'VertexStorageProtocol' 25 | ] 26 | -------------------------------------------------------------------------------- /hathor/transaction/storage/memory_storage.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/transaction/storage/memory_storage.py -------------------------------------------------------------------------------- /hathor/transaction/storage/migrations/add_closest_ancestor_block.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import TYPE_CHECKING 16 | 17 | from structlog import get_logger 18 | 19 | from hathor.transaction.storage.migrations import BaseMigration 20 | 21 | if TYPE_CHECKING: 22 | from hathor.transaction.storage import TransactionStorage 23 | 24 | logger = get_logger() 25 | 26 | 27 | class Migration(BaseMigration): 28 | def skip_empty_db(self) -> bool: 29 | return True 30 | 31 | def get_db_name(self) -> str: 32 | return 'add_closest_ancestor_block' 33 | 34 | def run(self, storage: 'TransactionStorage') -> None: 35 | raise Exception('Cannot migrate your database due to an incompatible change in the metadata. ' 36 | 'Please, delete your data folder and use the latest available snapshot or sync ' 37 | 'from beginning.') 38 | -------------------------------------------------------------------------------- /hathor/transaction/storage/migrations/change_score_acc_weight_metadata.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import TYPE_CHECKING 16 | 17 | from hathor.transaction.storage.migrations import BaseMigration 18 | 19 | if TYPE_CHECKING: 20 | from hathor.transaction.storage import TransactionStorage 21 | 22 | 23 | class Migration(BaseMigration): 24 | def skip_empty_db(self) -> bool: 25 | return True 26 | 27 | def get_db_name(self) -> str: 28 | return 'change_score_acc_weight_metadata' 29 | 30 | def run(self, storage: 'TransactionStorage') -> None: 31 | raise Exception('Cannot migrate your database due to an incompatible change in the metadata. ' 32 | 'Please, delete your data folder and use the latest available snapshot or sync ' 33 | 'from beginning.') 34 | -------------------------------------------------------------------------------- /hathor/transaction/storage/migrations/include_funds_for_first_block.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import TYPE_CHECKING 16 | 17 | from structlog import get_logger 18 | 19 | from hathor.transaction.storage.migrations import BaseMigration 20 | 21 | if TYPE_CHECKING: 22 | from hathor.transaction.storage import TransactionStorage 23 | 24 | logger = get_logger() 25 | 26 | 27 | class Migration(BaseMigration): 28 | def skip_empty_db(self) -> bool: 29 | return True 30 | 31 | def get_db_name(self) -> str: 32 | return 'include_funds_for_first_block' 33 | 34 | def run(self, storage: 'TransactionStorage') -> None: 35 | raise Exception('Cannot migrate your database due to an incompatible change in the metadata. ' 36 | 'Please, delete your data folder and use the latest available snapshot or sync ' 37 | 'from beginning.') 38 | -------------------------------------------------------------------------------- /hathor/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/utils/__init__.py -------------------------------------------------------------------------------- /hathor/utils/iter.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import Iterable, TypeVar 16 | 17 | T = TypeVar('T') 18 | 19 | 20 | def batch_iterator(iterator: Iterable[T], batch_size: int) -> Iterable[list[T]]: 21 | """ 22 | Yield batches of up to batch_size items from iterator. 23 | 24 | >>> list(batch_iterator([], 10)) 25 | [] 26 | >>> list(batch_iterator([1, 2, 3, 4], 1)) 27 | [[1], [2], [3], [4]] 28 | >>> list(batch_iterator([1, 2, 3, 4], 2)) 29 | [[1, 2], [3, 4]] 30 | >>> list(batch_iterator([1, 2, 3, 4], 3)) 31 | [[1, 2, 3], [4]] 32 | >>> list(batch_iterator([1, 2, 3, 4], 4)) 33 | [[1, 2, 3, 4]] 34 | """ 35 | assert batch_size >= 1 36 | batch = [] 37 | for item in iterator: 38 | batch.append(item) 39 | if len(batch) >= batch_size: 40 | yield batch 41 | batch = [] 42 | 43 | if batch: 44 | yield batch 45 | -------------------------------------------------------------------------------- /hathor/utils/list.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import Optional, TypeVar 16 | 17 | T = TypeVar('T') 18 | 19 | 20 | def single_or_none(_list: list[T]) -> Optional[T]: 21 | """Function to convert a list with at most one element to the given element or None. 22 | >>> single_or_none([]) is None 23 | True 24 | >>> single_or_none([1]) 25 | 1 26 | >>> single_or_none([1, 2]) 27 | Traceback (most recent call last): 28 | ... 29 | AssertionError: expected one value at most 30 | """ 31 | assert len(_list) <= 1, 'expected one value at most' 32 | 33 | return None if not len(_list) else _list[0] 34 | -------------------------------------------------------------------------------- /hathor/utils/weight.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import math 16 | 17 | 18 | def weight_to_work(weight: float) -> int: 19 | """Convert weight to work rounding up to the nearest integer.""" 20 | return math.floor(0.5 + 2**weight) 21 | 22 | 23 | def work_to_weight(work: int) -> float: 24 | """Convert work to weight.""" 25 | if work <= 1: 26 | return 0.0 27 | return math.log2(work) 28 | 29 | 30 | def calculate_min_significant_weight(score: int, tol: float) -> float: 31 | """ This function will return the min significant weight to increase score by tol. 32 | 33 | When most peers are updated to store work as integers for their internal score and accumulated weight metadata, 34 | this function will not be needed anymore. It's only use currently is to make sure miner nodes will produce blocks 35 | with weight that are high enough for outdated nodes to be able to observe the score increasing. 36 | """ 37 | return work_to_weight(score) + math.log2(2 ** tol - 1) 38 | -------------------------------------------------------------------------------- /hathor/utils/zope.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import Any, Optional, TypeVar, cast 16 | 17 | from zope.interface import Interface 18 | from zope.interface.exceptions import Invalid 19 | from zope.interface.verify import verifyObject 20 | 21 | T = TypeVar('T', bound=Interface) 22 | 23 | 24 | def verified_cast(interface_class: type[T], obj: Any) -> Optional[T]: 25 | """ 26 | Receive a zope interface and an object, and return a cast to this interface if the object implements it. 27 | Return None otherwise. 28 | """ 29 | try: 30 | if verifyObject(interface_class, obj): 31 | return cast(T, obj) 32 | except Invalid: 33 | pass 34 | 35 | return None 36 | 37 | 38 | def asserted_cast(interface_class: type[T], obj: Any) -> T: 39 | """ 40 | Receive a zope interface and an object, and return a cast to this interface if the object implements it. 41 | Raise and AssertionError otherwise. 42 | """ 43 | result = verified_cast(interface_class, obj) 44 | assert result is not None 45 | return result 46 | -------------------------------------------------------------------------------- /hathor/verification/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/hathor/verification/__init__.py -------------------------------------------------------------------------------- /hathor/vertex_handler/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.vertex_handler.vertex_handler import VertexHandler 16 | 17 | __all__ = [ 18 | 'VertexHandler' 19 | ] 20 | -------------------------------------------------------------------------------- /hathor/wallet/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.wallet.base_wallet import BaseWallet 16 | from hathor.wallet.hd_wallet import HDWallet 17 | from hathor.wallet.keypair import KeyPair 18 | from hathor.wallet.wallet import Wallet 19 | 20 | __all__ = ['Wallet', 'KeyPair', 'BaseWallet', 'HDWallet'] 21 | -------------------------------------------------------------------------------- /hathor/wallet/resources/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.wallet.resources.address import AddressResource 16 | from hathor.wallet.resources.balance import BalanceResource 17 | from hathor.wallet.resources.history import HistoryResource 18 | from hathor.wallet.resources.lock import LockWalletResource 19 | from hathor.wallet.resources.send_tokens import SendTokensResource 20 | from hathor.wallet.resources.sign_tx import SignTxResource 21 | from hathor.wallet.resources.state import StateWalletResource 22 | from hathor.wallet.resources.unlock import UnlockWalletResource 23 | 24 | __all__ = [ 25 | 'BalanceResource', 26 | 'HistoryResource', 27 | 'AddressResource', 28 | 'SendTokensResource', 29 | 'UnlockWalletResource', 30 | 'LockWalletResource', 31 | 'StateWalletResource', 32 | 'SignTxResource', 33 | ] 34 | -------------------------------------------------------------------------------- /hathor/wallet/resources/nano_contracts/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.wallet.resources.nano_contracts.decode import NanoContractDecodeResource 16 | from hathor.wallet.resources.nano_contracts.execute import NanoContractExecuteResource 17 | from hathor.wallet.resources.nano_contracts.match_value import NanoContractMatchValueResource 18 | 19 | __all__ = [ 20 | 'NanoContractMatchValueResource', 21 | 'NanoContractDecodeResource', 22 | 'NanoContractExecuteResource', 23 | ] 24 | -------------------------------------------------------------------------------- /hathor/wallet/resources/thin_wallet/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.wallet.resources.thin_wallet.address_balance import AddressBalanceResource 16 | from hathor.wallet.resources.thin_wallet.address_history import AddressHistoryResource 17 | from hathor.wallet.resources.thin_wallet.address_search import AddressSearchResource 18 | from hathor.wallet.resources.thin_wallet.send_tokens import SendTokensResource 19 | from hathor.wallet.resources.thin_wallet.token_history import TokenHistoryResource 20 | from hathor.wallet.resources.thin_wallet.tokens import TokenResource 21 | 22 | __all__ = [ 23 | 'AddressBalanceResource', 24 | 'AddressHistoryResource', 25 | 'AddressSearchResource', 26 | 'SendTokensResource', 27 | 'TokenResource', 28 | 'TokenHistoryResource', 29 | ] 30 | -------------------------------------------------------------------------------- /hathor/websocket/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.websocket.factory import HathorAdminWebsocketFactory 16 | from hathor.websocket.protocol import HathorAdminWebsocketProtocol 17 | from hathor.websocket.resource import WebsocketStatsResource 18 | 19 | __all__ = ['HathorAdminWebsocketFactory', 'HathorAdminWebsocketProtocol', 'WebsocketStatsResource'] 20 | -------------------------------------------------------------------------------- /hathor/websocket/exception.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from hathor.exception import HathorError 16 | 17 | 18 | class InvalidXPub(HathorError): 19 | """Raised when an invalid xpub is provided.""" 20 | 21 | 22 | class LimitExceeded(HathorError): 23 | """Raised when a limit is exceeded.""" 24 | 25 | 26 | class InvalidAddress(HathorError): 27 | """Raised when an invalid address is provided.""" 28 | -------------------------------------------------------------------------------- /profiles/cprof2pdf: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASENAME=`basename $0` 4 | 5 | if [ $# -ne 1 ]; then 6 | echo "usage: ${BASENAME} " 7 | exit 1 8 | fi 9 | 10 | PROF=$1 11 | 12 | gprof2dot -f pstats $PROF -o $PROF.dot 13 | dot -O -Tpdf $PROF.dot 14 | -------------------------------------------------------------------------------- /profiles/pstats_console: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASENAME=`basename $0` 4 | 5 | if [ $# -ne 1 ]; then 6 | echo "usage: ${BASENAME} " 7 | exit 1 8 | fi 9 | 10 | FILE=$1 11 | 12 | exec python -m pstats $FILE 13 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [coverage:run] 2 | branch = True 3 | omit = 4 | # Cli files have a different test coverage target 5 | hathor/cli/* 6 | 7 | # Subprocess storage will be revisited later 8 | hathor/transaction/storage/subprocess_storage.py 9 | 10 | [coverage:report] 11 | ignore_errors = True 12 | exclude_lines = 13 | # Have to re-enable the standard pragma 14 | pragma: no cover 15 | 16 | # Don't complain about TYPE_CHECKING: 17 | if TYPE_CHECKING: 18 | 19 | # Don't complain about missing debug-only code: 20 | def __repr__ 21 | if self\.debug 22 | 23 | # Don't complain if tests don't hit defensive assertion code: 24 | raise AssertionError 25 | raise NotImplementedError 26 | 27 | # Don't complain if non-runnable code isn't run: 28 | if 0: 29 | if __name__ == .__main__.: 30 | 31 | [coverage:html] 32 | directory = coverage_html_report 33 | 34 | [flake8] 35 | max-line-length = 119 36 | 37 | [mypy] 38 | ignore_missing_imports = True 39 | strict_optional = True 40 | -------------------------------------------------------------------------------- /slow_tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/slow_tests/__init__.py -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/__init__.py -------------------------------------------------------------------------------- /tests/cli/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/cli/__init__.py -------------------------------------------------------------------------------- /tests/cli/test_db_export.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from hathor.cli.db_export import DbExport 4 | from tests import unittest 5 | 6 | 7 | class TestDbExport(unittest.TestCase): 8 | def test_db_export(self): 9 | tmp_dir = self.mkdtemp() 10 | tmp_file = os.path.join(tmp_dir, 'test_file') 11 | db_export = DbExport(argv=['--temp-data', '--export-file', tmp_file]) 12 | assert db_export is not None 13 | -------------------------------------------------------------------------------- /tests/cli/test_db_import.py: -------------------------------------------------------------------------------- 1 | import tempfile 2 | 3 | from hathor.cli.db_import import DbImport 4 | from tests import unittest 5 | 6 | 7 | class TestDbImport(unittest.TestCase): 8 | def test_db_import(self): 9 | _, tmp_file = tempfile.mkstemp() 10 | db_import = DbImport(argv=['--temp-data', '--import-file', tmp_file]) 11 | assert db_import is not None 12 | -------------------------------------------------------------------------------- /tests/cli/test_events_simulator.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from unittest.mock import Mock 16 | 17 | from hathor.cli.events_simulator.event_forwarding_websocket_factory import EventForwardingWebsocketFactory 18 | from hathor.cli.events_simulator.events_simulator import create_parser, execute 19 | from hathor.conf.get_settings import get_global_settings 20 | from tests.test_memory_reactor_clock import TestMemoryReactorClock 21 | 22 | 23 | def test_events_simulator() -> None: 24 | parser = create_parser() 25 | args = parser.parse_args(['--scenario', 'ONLY_LOAD']) 26 | reactor = TestMemoryReactorClock() 27 | 28 | execute(args, reactor) 29 | reactor.advance(1) 30 | 31 | factory = EventForwardingWebsocketFactory( 32 | simulator=Mock(), 33 | peer_id='test_peer_id', 34 | settings=get_global_settings(), 35 | reactor=reactor, 36 | event_storage=Mock() 37 | ) 38 | protocol = factory.buildProtocol(Mock()) 39 | 40 | assert protocol is not None 41 | -------------------------------------------------------------------------------- /tests/cli/test_peer_id.py: -------------------------------------------------------------------------------- 1 | from contextlib import redirect_stdout 2 | from io import StringIO 3 | 4 | from structlog.testing import capture_logs 5 | 6 | from hathor.cli.peer_id import main 7 | from hathor.util import json_loadb 8 | from tests import unittest 9 | 10 | 11 | class PeerIdTest(unittest.TestCase): 12 | def test_peer_id(self): 13 | f = StringIO() 14 | with capture_logs(): 15 | with redirect_stdout(f): 16 | main() 17 | # Transforming prints str in array 18 | output = f.getvalue().strip().splitlines() 19 | 20 | peer_id = json_loadb(''.join(output)) 21 | self.assertTrue('id' in peer_id) 22 | self.assertTrue('pubKey' in peer_id) 23 | self.assertTrue('entrypoints' in peer_id) 24 | self.assertTrue('privKey' in peer_id) 25 | -------------------------------------------------------------------------------- /tests/cli/test_quick_test.py: -------------------------------------------------------------------------------- 1 | from hathor.cli.quick_test import QuickTest 2 | from tests import unittest 3 | 4 | 5 | class TestQuickTest(unittest.TestCase): 6 | def test_quick_test(self): 7 | class CustomQuickTest(QuickTest): 8 | def start_manager(self) -> None: 9 | pass 10 | 11 | def register_signal_handlers(self) -> None: 12 | pass 13 | 14 | quick_test = CustomQuickTest(argv=['--temp-data', '--no-wait']) 15 | assert quick_test is not None 16 | 17 | self.clean_pending(required_to_quiesce=False) 18 | -------------------------------------------------------------------------------- /tests/cli/test_shell.py: -------------------------------------------------------------------------------- 1 | import tempfile 2 | 3 | from hathor.cli.shell import Shell 4 | from tests import unittest 5 | 6 | 7 | class ShellTest(unittest.TestCase): 8 | # In this case we just want to go through the code to see if it's okay 9 | 10 | def test_shell_execution_temp_data(self): 11 | shell = Shell(argv=['--temp-data', '--', '--extra-arg']) 12 | self.assertTrue(shell is not None) 13 | 14 | def test_shell_execution_default_storage(self): 15 | temp_data = tempfile.TemporaryDirectory() 16 | shell = Shell(argv=['--data', temp_data.name]) 17 | self.assertTrue(shell is not None) 18 | -------------------------------------------------------------------------------- /tests/cli/test_wallet.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | import tempfile 3 | 4 | from hathor.cli.wallet import create_parser, execute 5 | from hathor.util import json_loadb 6 | from tests import unittest 7 | 8 | 9 | class WalletTest(unittest.TestCase): 10 | def test_wallet(self): 11 | parser = create_parser() 12 | 13 | tmpdir = tempfile.mkdtemp() 14 | 15 | count = 5 16 | args = parser.parse_args(['--count', '{}'.format(count), '--directory', tmpdir]) 17 | execute(args, '1234') 18 | 19 | with open('{}/keys.json'.format(tmpdir), 'rb') as f: 20 | data = json_loadb(f.read()) 21 | 22 | self.assertEqual(len(data), 5) 23 | 24 | # Removing tmpdir 25 | shutil.rmtree(tmpdir) 26 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from hathor.conf import UNITTESTS_SETTINGS_FILEPATH 4 | from hathor.reactor import initialize_global_reactor 5 | 6 | os.environ['HATHOR_CONFIG_YAML'] = os.environ.get('HATHOR_TEST_CONFIG_YAML', UNITTESTS_SETTINGS_FILEPATH) 7 | 8 | # TODO: We should remove this call from the module level. 9 | initialize_global_reactor(use_asyncio_reactor=True) 10 | -------------------------------------------------------------------------------- /tests/consensus/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/consensus/__init__.py -------------------------------------------------------------------------------- /tests/crypto/test_util.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from cryptography.hazmat.backends import default_backend 4 | from cryptography.hazmat.primitives.asymmetric import ec 5 | 6 | from hathor.crypto.util import ( 7 | decode_address, 8 | get_address_b58_from_public_key, 9 | get_address_from_public_key, 10 | get_private_key_bytes, 11 | get_private_key_from_bytes, 12 | ) 13 | 14 | 15 | class CryptoUtilTestCase(unittest.TestCase): 16 | def setUp(self) -> None: 17 | super().setUp() 18 | key = ec.generate_private_key(ec.SECP256K1(), default_backend()) 19 | assert isinstance(key, ec.EllipticCurvePrivateKeyWithSerialization) 20 | self.private_key = key 21 | self.public_key = self.private_key.public_key() 22 | 23 | def test_privkey_serialization(self) -> None: 24 | private_key_bytes = get_private_key_bytes(self.private_key) 25 | self.assertEqual(self.private_key.private_numbers(), 26 | get_private_key_from_bytes(private_key_bytes).private_numbers()) 27 | 28 | def test_address(self) -> None: 29 | address = get_address_from_public_key(self.public_key) 30 | address_b58 = get_address_b58_from_public_key(self.public_key) 31 | self.assertEqual(address, decode_address(address_b58)) 32 | 33 | def test_invalid_address(self) -> None: 34 | from hathor.wallet.exceptions import InvalidAddress 35 | address_b58 = get_address_b58_from_public_key(self.public_key) 36 | address_b58 += '0' # 0 is invalid in base58 37 | with self.assertRaises(InvalidAddress): 38 | decode_address(address_b58) 39 | -------------------------------------------------------------------------------- /tests/dag_builder/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/dag_builder/__init__.py -------------------------------------------------------------------------------- /tests/event/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/event/__init__.py -------------------------------------------------------------------------------- /tests/event/websocket/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/event/websocket/__init__.py -------------------------------------------------------------------------------- /tests/execution_manager/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/execution_manager/__init__.py -------------------------------------------------------------------------------- /tests/feature_activation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/feature_activation/__init__.py -------------------------------------------------------------------------------- /tests/others/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/others/__init__.py -------------------------------------------------------------------------------- /tests/others/fixtures/invalid_byte_hathor_settings_fixture.yml: -------------------------------------------------------------------------------- 1 | P2PKH_VERSION_BYTE: x28 2 | MULTISIG_VERSION_BYTE: 64 3 | NETWORK_NAME: testing 4 | BOOTSTRAP_DNS: 5 | - mainnet.hathor.network 6 | ENABLE_PEER_WHITELIST: true 7 | WHITELIST_URL: https://hathor-public-files.s3.amazonaws.com/whitelist_peer_ids 8 | 9 | GENESIS_OUTPUT_SCRIPT: 76a9147fd4ae0e4fb2d2854e76d359029d8078bb99649e88ac 10 | GENESIS_BLOCK_TIMESTAMP: 1578075305 11 | GENESIS_BLOCK_NONCE: 2591358 12 | GENESIS_BLOCK_HASH: 000006cb93385b8b87a545a1cbb6197e6caff600c12cc12fc54250d39c8088fc 13 | GENESIS_TX1_NONCE: 7715 14 | GENESIS_TX1_HASH: 0002d4d2a15def7604688e1878ab681142a7b155cbe52a6b4e031250ae96db0a 15 | GENESIS_TX2_NONCE: 3769 16 | GENESIS_TX2_HASH: 0002ad8d1519daaddc8e1a37b14aac0b045129c01832281fb1c02d873c7abbf9 17 | 18 | MIN_TX_WEIGHT_K: 0 19 | MIN_TX_WEIGHT_COEFFICIENT: 0 20 | MIN_TX_WEIGHT: 8 21 | 22 | BLOCKS_PER_HALVING: 120 23 | MIN_BLOCK_WEIGHT: 2 24 | MIN_SHARE_WEIGHT: 2 25 | MAX_TX_WEIGHT_DIFF: 25.0 26 | BLOCK_DIFFICULTY_N_BLOCKS: 20 27 | 28 | REWARD_SPEND_MIN_BLOCKS: 10 29 | SLOW_ASSERTS: true 30 | MAX_TX_WEIGHT_DIFF_ACTIVATION: 0.0 31 | 32 | CHECKPOINTS: 33 | - 0000000000001247073138556b4f60fff3ff6eec6521373ccee5a6526a7c10af 34 | - 00000000000001bf13197340ae0807df2c16f4959da6054af822550d7b20e19e 35 | 36 | 37 | SOFT_VOIDED_TX_IDS: 38 | - gggggggggg 39 | - 000000001980b413ad5b5c5152338093aecfb1f5a7563d4e7fef8fb240a50bb9 40 | -------------------------------------------------------------------------------- /tests/others/fixtures/missing_hathor_settings_fixture.yml: -------------------------------------------------------------------------------- 1 | P2PKH_VERSION_BYTE: x28 2 | MULTISIG_VERSION_BYTE: '64' 3 | BOOTSTRAP_DNS: 4 | - mainnet.hathor.network 5 | ENABLE_PEER_WHITELIST: true 6 | WHITELIST_URL: https://hathor-public-files.s3.amazonaws.com/whitelist_peer_ids 7 | 8 | GENESIS_OUTPUT_SCRIPT: 76a9147fd4ae0e4fb2d2854e76d359029d8078bb99649e88ac 9 | GENESIS_BLOCK_TIMESTAMP: 1578075305 10 | GENESIS_BLOCK_NONCE: 2591358 11 | GENESIS_BLOCK_HASH: 000006cb93385b8b87a545a1cbb6197e6caff600c12cc12fc54250d39c8088fc 12 | GENESIS_TX1_NONCE: 7715 13 | GENESIS_TX1_HASH: 0002d4d2a15def7604688e1878ab681142a7b155cbe52a6b4e031250ae96db0a 14 | GENESIS_TX2_NONCE: 3769 15 | GENESIS_TX2_HASH: 0002ad8d1519daaddc8e1a37b14aac0b045129c01832281fb1c02d873c7abbf9 16 | 17 | MIN_TX_WEIGHT_K: 0 18 | MIN_TX_WEIGHT_COEFFICIENT: 0 19 | MIN_TX_WEIGHT: 8 20 | 21 | BLOCKS_PER_HALVING: 120 22 | MIN_BLOCK_WEIGHT: 2 23 | MIN_SHARE_WEIGHT: 2 24 | MAX_TX_WEIGHT_DIFF: 25.0 25 | BLOCK_DIFFICULTY_N_BLOCKS: 20 26 | 27 | REWARD_SPEND_MIN_BLOCKS: 10 28 | SLOW_ASSERTS: true 29 | MAX_TX_WEIGHT_DIFF_ACTIVATION: 0.0 30 | 31 | CHECKPOINTS: 32 | 100_000: 0000000000001247073138556b4f60fff3ff6eec6521373ccee5a6526a7c10af 33 | 200_000: 00000000000001bf13197340ae0807df2c16f4959da6054af822550d7b20e19e 34 | 35 | 36 | SOFT_VOIDED_TX_IDS: 37 | - 0000000012a922a6887497bed9c41e5ed7dc7213cae107db295602168266cd02 38 | - 000000001980b413ad5b5c5152338093aecfb1f5a7563d4e7fef8fb240a50bb9 39 | -------------------------------------------------------------------------------- /tests/others/fixtures/valid_hathor_settings_fixture.yml: -------------------------------------------------------------------------------- 1 | P2PKH_VERSION_BYTE: x28 2 | MULTISIG_VERSION_BYTE: '64' 3 | NETWORK_NAME: testing 4 | BOOTSTRAP_DNS: 5 | - mainnet.hathor.network 6 | ENABLE_PEER_WHITELIST: true 7 | WHITELIST_URL: https://hathor-public-files.s3.amazonaws.com/whitelist_peer_ids 8 | 9 | GENESIS_OUTPUT_SCRIPT: 76a9147fd4ae0e4fb2d2854e76d359029d8078bb99649e88ac 10 | GENESIS_BLOCK_TIMESTAMP: 1578075305 11 | GENESIS_BLOCK_NONCE: 2591358 12 | GENESIS_BLOCK_HASH: 000006cb93385b8b87a545a1cbb6197e6caff600c12cc12fc54250d39c8088fc 13 | GENESIS_TX1_NONCE: 7715 14 | GENESIS_TX1_HASH: 0002d4d2a15def7604688e1878ab681142a7b155cbe52a6b4e031250ae96db0a 15 | GENESIS_TX2_NONCE: 3769 16 | GENESIS_TX2_HASH: 0002ad8d1519daaddc8e1a37b14aac0b045129c01832281fb1c02d873c7abbf9 17 | 18 | MIN_TX_WEIGHT_K: 0 19 | MIN_TX_WEIGHT_COEFFICIENT: 0 20 | MIN_TX_WEIGHT: 8 21 | 22 | BLOCKS_PER_HALVING: 120 23 | MIN_BLOCK_WEIGHT: 2 24 | MIN_SHARE_WEIGHT: 2 25 | MAX_TX_WEIGHT_DIFF: 25.0 26 | BLOCK_DIFFICULTY_N_BLOCKS: 20 27 | 28 | REWARD_SPEND_MIN_BLOCKS: 10 29 | SLOW_ASSERTS: true 30 | MAX_TX_WEIGHT_DIFF_ACTIVATION: 0.0 31 | 32 | CHECKPOINTS: 33 | 100_000: 0000000000001247073138556b4f60fff3ff6eec6521373ccee5a6526a7c10af 34 | 200_000: 00000000000001bf13197340ae0807df2c16f4959da6054af822550d7b20e19e 35 | 36 | 37 | SOFT_VOIDED_TX_IDS: 38 | - 0000000012a922a6887497bed9c41e5ed7dc7213cae107db295602168266cd02 39 | - 000000001980b413ad5b5c5152338093aecfb1f5a7563d4e7fef8fb240a50bb9 40 | -------------------------------------------------------------------------------- /tests/others/test_api_utils.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from hathor.api_util import parse_args 4 | 5 | 6 | class ApiUtilsTestCase(unittest.TestCase): 7 | def test_parse_get_arguments(self): 8 | params = { 9 | b'arg1': [b'value1'], 10 | b'arg2': [b'value2'], 11 | b'arg3': [b'value3'], 12 | } 13 | 14 | # missing param 15 | expected = ['arg1', 'arg2', 'arg3', 'arg4'] 16 | self.assertFalse(parse_args(params, expected)['success']) 17 | 18 | # we can have more params than expected; that's ok 19 | expected = ['arg1', 'arg2'] 20 | self.assertTrue(parse_args(params, expected)['success']) 21 | 22 | # check return dict 23 | expected = ['arg1', 'arg2', 'arg3'] 24 | ret = parse_args(params, expected) 25 | self.assertTrue(ret['success']) 26 | args = ret['args'] 27 | for arg in expected: 28 | returned_value = args.get(arg) 29 | expected_value = (params.get(arg.encode('utf-8'))[0]).decode('utf-8') 30 | self.assertEqual(returned_value, expected_value) 31 | -------------------------------------------------------------------------------- /tests/others/test_builder.py: -------------------------------------------------------------------------------- 1 | from tests import unittest 2 | from tests.unittest import TestBuilder 3 | 4 | 5 | class BuilderTestCase(unittest.TestCase): 6 | def setUp(self): 7 | super().setUp() 8 | self.reactor = self.clock 9 | self.builder = TestBuilder() 10 | 11 | def test_multiple_calls_to_build(self): 12 | self.builder.build() 13 | 14 | with self.assertRaises(ValueError): 15 | self.builder.build() 16 | 17 | def test_check_if_can_modify(self): 18 | self.builder.build() 19 | 20 | with self.assertRaises(ValueError): 21 | self.builder.set_reactor(self.reactor) 22 | -------------------------------------------------------------------------------- /tests/others/test_util.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from json import JSONDecodeError 3 | 4 | from hathor.util import json_loadb 5 | 6 | 7 | class UtilsTest(unittest.TestCase): 8 | def test_invalid_json_valid_utf8(self): 9 | message = b'a' 10 | message.decode('utf-8') 11 | self.assertRaises(JSONDecodeError, json_loadb, message) 12 | 13 | def test_valid_json_invalid_utf8(self): 14 | message = b'\xc3\x28' 15 | self.assertRaises(UnicodeDecodeError, message.decode, 'utf-8') 16 | self.assertRaises(JSONDecodeError, json_loadb, message) 17 | 18 | def test_valid_json_valid_utf8(self): 19 | message = b'{}' 20 | message.decode('utf-8') 21 | self.assertEqual({}, json_loadb(message)) 22 | -------------------------------------------------------------------------------- /tests/p2p/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/p2p/__init__.py -------------------------------------------------------------------------------- /tests/p2p/netfilter/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/p2p/netfilter/__init__.py -------------------------------------------------------------------------------- /tests/p2p/netfilter/test_factory.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import Mock 2 | 3 | from twisted.internet.address import IPv4Address 4 | 5 | from hathor.p2p.netfilter import get_table 6 | from hathor.p2p.netfilter.factory import NetfilterFactory 7 | from hathor.p2p.netfilter.matches import NetfilterMatchIPAddress 8 | from hathor.p2p.netfilter.rule import NetfilterRule 9 | from hathor.p2p.netfilter.targets import NetfilterReject 10 | from tests import unittest 11 | from tests.unittest import TestBuilder 12 | 13 | 14 | class NetfilterFactoryTest(unittest.TestCase): 15 | def test_factory(self) -> None: 16 | pre_conn = get_table('filter').get_chain('pre_conn') 17 | 18 | match = NetfilterMatchIPAddress('192.168.0.1/32') 19 | rule = NetfilterRule(match, NetfilterReject()) 20 | pre_conn.add_rule(rule) 21 | 22 | builder = TestBuilder() 23 | artifacts = builder.build() 24 | wrapped_factory = artifacts.p2p_manager.server_factory 25 | factory = NetfilterFactory(connections=Mock(), wrappedFactory=wrapped_factory) 26 | 27 | ret = factory.buildProtocol(IPv4Address('TCP', '192.168.0.1', 1234)) 28 | self.assertIsNone(ret) 29 | 30 | ret = factory.buildProtocol(IPv4Address('TCP', '192.168.0.2', 1234)) 31 | self.assertIsNotNone(ret) 32 | 33 | pre_conn.delete_rule(rule.uuid) 34 | ret = factory.buildProtocol(IPv4Address('TCP', '192.168.0.1', 1234)) 35 | self.assertIsNotNone(ret) 36 | -------------------------------------------------------------------------------- /tests/p2p/netfilter/test_match_remote.py: -------------------------------------------------------------------------------- 1 | from twisted.internet.address import IPv4Address 2 | 3 | from hathor.p2p.netfilter.context import NetfilterContext 4 | from hathor.p2p.netfilter.matches_remote import NetfilterMatchIPAddressRemoteURL 5 | from tests import unittest 6 | 7 | 8 | class NetfilterMatchRemoteTest(unittest.TestCase): 9 | def test_match_ip(self) -> None: 10 | matcher = NetfilterMatchIPAddressRemoteURL('test', self.clock, 'http://localhost:8080') 11 | context = NetfilterContext(addr=IPv4Address('TCP', '192.168.0.1', 1234)) 12 | self.assertFalse(matcher.match(context)) 13 | 14 | matcher._update_cb(b'hathor-ip-list\n192.168.0.1') 15 | self.assertTrue(matcher.match(context)) 16 | 17 | matcher._update_cb(b'hathor-ip-list\n192.168.0.2') 18 | self.assertFalse(matcher.match(context)) 19 | 20 | # Guarantee the to_json is working fine 21 | json = matcher.to_json() 22 | self.assertEqual(json['match_params']['name'], 'test') 23 | self.assertEqual(json['match_params']['url'], 'http://localhost:8080') 24 | -------------------------------------------------------------------------------- /tests/p2p/netfilter/test_tables.py: -------------------------------------------------------------------------------- 1 | from hathor.p2p.netfilter import get_table 2 | from hathor.p2p.netfilter.chain import NetfilterChain 3 | from hathor.p2p.netfilter.table import NetfilterTable 4 | from hathor.p2p.netfilter.targets import NetfilterAccept 5 | from tests import unittest 6 | 7 | 8 | class NetfilterTableTest(unittest.TestCase): 9 | def test_default_table_filter(self) -> None: 10 | tb_filter = get_table('filter') 11 | tb_filter.get_chain('pre_conn') 12 | tb_filter.get_chain('post_hello') 13 | tb_filter.get_chain('post_peerid') 14 | 15 | def test_default_table_not_exists(self) -> None: 16 | with self.assertRaises(KeyError): 17 | get_table('do-not-exists') 18 | 19 | def test_add_get_chain(self) -> None: 20 | mytable = NetfilterTable('mytable') 21 | mychain = NetfilterChain('mychain', NetfilterAccept()) 22 | mytable.add_chain(mychain) 23 | ret = mytable.get_chain('mychain') 24 | self.assertEqual(mychain, ret) 25 | 26 | with self.assertRaises(ValueError): 27 | mytable.add_chain(mychain) 28 | 29 | with self.assertRaises(KeyError): 30 | mytable.get_chain('do-not-exists') 31 | -------------------------------------------------------------------------------- /tests/p2p/netfilter/test_utils.py: -------------------------------------------------------------------------------- 1 | from hathor.p2p.netfilter import get_table 2 | from hathor.p2p.netfilter.utils import add_peer_id_blacklist 3 | from tests import unittest 4 | 5 | 6 | class NetfilterUtilsTest(unittest.TestCase): 7 | def test_peer_id_blacklist(self) -> None: 8 | post_peerid = get_table('filter').get_chain('post_peerid') 9 | 10 | # Chain starts empty 11 | self.assertEqual(len(post_peerid.rules), 0) 12 | 13 | # Add two rules to reject peer ids 14 | blacklist = ['123', '456'] 15 | add_peer_id_blacklist(blacklist) 16 | 17 | # Chain has two rules now 18 | self.assertEqual(len(post_peerid.rules), 2) 19 | 20 | # Check that the rules are what we expect 21 | for rule in post_peerid.rules: 22 | data = rule.to_json() 23 | self.assertEqual(data['chain']['name'], 'post_peerid') 24 | self.assertEqual(data['match']['type'], 'NetfilterMatchPeerId') 25 | self.assertIn(data['match']['match_params']['peer_id'], blacklist) 26 | self.assertEqual(data['target']['type'], 'NetfilterReject') 27 | -------------------------------------------------------------------------------- /tests/p2p/test_entrypoint.py: -------------------------------------------------------------------------------- 1 | from hathor.p2p.peer_endpoint import PeerAddress, PeerEndpoint, Protocol 2 | from tests import unittest 3 | 4 | 5 | class EntrypointTestCase(unittest.TestCase): 6 | def test_is_ipv6(self) -> None: 7 | valid_addresses = [ 8 | '::', 9 | '::1', 10 | '2001:0db8:85a3:0000:0000:8a2e:0370:7334', 11 | '2001:db8:85a3:0:0:8a2e:370:7334', 12 | '2001:db8::8a2e:370:7334', 13 | '2001:db8:0:0:0:0:2:1', 14 | '1234::5678', 15 | 'fe80::', 16 | '::abcd:abcd:abcd:abcd:abcd:abcd', 17 | '0:0:0:0:0:0:0:1', 18 | '0:0:0:0:0:0:0:0' 19 | ] 20 | 21 | invalid_addresses = [ 22 | '127.0.0.1', 23 | '1200::AB00:1234::2552:7777:1313', 24 | '2001:db8::g123', 25 | '2001:db8::85a3::7334', 26 | '2001:db8:85a3:0000:0000:8a2e:0370:7334:1234', 27 | '12345::abcd', 28 | '2001:db8:85a3:8a2e:0370', 29 | '2001:db8:85a3::8a2e:3707334', 30 | '1234:56789::abcd', 31 | ':2001:db8::1', 32 | '2001:db8::1:', 33 | '2001::85a3::8a2e:370:7334' 34 | ] 35 | 36 | for address in valid_addresses: 37 | peer_address = PeerAddress(Protocol.TCP, address, 40403) 38 | self.assertTrue(PeerEndpoint(peer_address).addr.is_ipv6()) 39 | 40 | for address in invalid_addresses: 41 | peer_address = PeerAddress(Protocol.TCP, address, 40403) 42 | self.assertFalse(PeerEndpoint(peer_address).addr.is_ipv6()) 43 | -------------------------------------------------------------------------------- /tests/p2p/test_peer_storage.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from hathor.p2p.peer_storage import UnverifiedPeerStorage, VerifiedPeerStorage 4 | from hathor.util import Random 5 | from tests.unittest import PEER_ID_POOL 6 | 7 | 8 | @pytest.fixture 9 | def rng() -> Random: 10 | import secrets 11 | seed = secrets.randbits(64) 12 | return Random(seed) 13 | 14 | 15 | def test_unverified_peer_storage_max_size(rng: Random) -> None: 16 | max_size = 5 17 | peer_storage = UnverifiedPeerStorage(rng=rng, max_size=max_size) 18 | for i in range(2 * max_size): 19 | peer = PEER_ID_POOL[i].to_unverified_peer() 20 | peer_storage.add(peer) 21 | assert len(peer_storage) == max_size 22 | 23 | 24 | def test_verified_peer_storage_max_size(rng: Random) -> None: 25 | max_size = 5 26 | peer_storage = VerifiedPeerStorage(rng=rng, max_size=max_size) 27 | for i in range(2 * max_size): 28 | peer = PEER_ID_POOL[i].to_public_peer() 29 | peer_storage.add(peer) 30 | assert len(peer_storage) == max_size 31 | -------------------------------------------------------------------------------- /tests/p2p/test_rate_limiter.py: -------------------------------------------------------------------------------- 1 | from hathor.p2p.rate_limiter import RateLimiter 2 | from hathor.util import not_none 3 | from tests import unittest 4 | 5 | 6 | class RateLimiterTestCase(unittest.TestCase): 7 | def setUp(self) -> None: 8 | super().setUp() 9 | self.rate_limiter = RateLimiter(reactor=self.clock) 10 | 11 | def test_limiter(self) -> None: 12 | key = 'test' 13 | self.rate_limiter.set_limit(key, 2, 2) 14 | 15 | # Hits limit 16 | self.assertTrue(self.rate_limiter.add_hit(key)) 17 | self.assertTrue(self.rate_limiter.add_hit(key)) 18 | self.assertFalse(self.rate_limiter.add_hit(key)) 19 | 20 | # Advance 3 seconds to release limit 21 | self.clock.advance(3) 22 | 23 | # Add hits until limit again 24 | self.assertTrue(self.rate_limiter.add_hit(key)) 25 | self.assertTrue(self.rate_limiter.add_hit(key)) 26 | self.assertFalse(self.rate_limiter.add_hit(key)) 27 | 28 | # Reset hits 29 | self.rate_limiter.reset(key) 30 | 31 | # Limit is free again 32 | self.assertTrue(self.rate_limiter.add_hit(key)) 33 | 34 | # Get limit 35 | self.assertEqual(not_none(self.rate_limiter.get_limit(key)).max_hits, 2) 36 | 37 | # Unset limit 38 | self.rate_limiter.unset_limit(key) 39 | self.assertIsNone(self.rate_limiter.get_limit(key)) 40 | -------------------------------------------------------------------------------- /tests/poa/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/poa/__init__.py -------------------------------------------------------------------------------- /tests/pubsub/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/pubsub/__init__.py -------------------------------------------------------------------------------- /tests/pubsub/test_pubsub.py: -------------------------------------------------------------------------------- 1 | from hathor.pubsub import EventArguments, HathorEvents, PubSubManager 2 | from tests.unittest import TestCase 3 | 4 | 5 | class PubSubTestCase(TestCase): 6 | def test_duplicate_subscribe(self) -> None: 7 | def noop(event: HathorEvents, args: EventArguments) -> None: 8 | pass 9 | pubsub = PubSubManager(self.clock) 10 | pubsub.subscribe(HathorEvents.NETWORK_NEW_TX_ACCEPTED, noop) 11 | pubsub.subscribe(HathorEvents.NETWORK_NEW_TX_ACCEPTED, noop) 12 | self.assertEqual(1, len(pubsub._subscribers[HathorEvents.NETWORK_NEW_TX_ACCEPTED])) 13 | -------------------------------------------------------------------------------- /tests/resources/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/resources/__init__.py -------------------------------------------------------------------------------- /tests/resources/event/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/resources/event/__init__.py -------------------------------------------------------------------------------- /tests/resources/feature/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/resources/feature/__init__.py -------------------------------------------------------------------------------- /tests/resources/nanocontracts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/resources/nanocontracts/__init__.py -------------------------------------------------------------------------------- /tests/resources/p2p/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/resources/p2p/__init__.py -------------------------------------------------------------------------------- /tests/resources/transaction/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/resources/transaction/__init__.py -------------------------------------------------------------------------------- /tests/resources/transaction/test_get_tx_parents.py: -------------------------------------------------------------------------------- 1 | from twisted.internet.defer import inlineCallbacks 2 | 3 | from hathor.transaction.resources import TxParentsResource 4 | from tests.resources.base_resource import StubSite, _BaseResourceTest 5 | 6 | 7 | class DecodeTxTest(_BaseResourceTest._ResourceTest): 8 | def setUp(self): 9 | super().setUp() 10 | self.web = StubSite(TxParentsResource(self.manager)) 11 | 12 | @inlineCallbacks 13 | def test_get_success(self): 14 | resp = yield self.web.get('tx_parents') 15 | data = resp.json_value() 16 | 17 | self.assertTrue(data['success']) 18 | self.assertEqual(2, len(data['tx_parents'])) 19 | 20 | @inlineCallbacks 21 | def test_get_syncing(self): 22 | self.manager._allow_mining_without_peers = False 23 | 24 | resp = yield self.web.get('tx_parents') 25 | data = resp.json_value() 26 | 27 | self.assertFalse(data['success']) 28 | -------------------------------------------------------------------------------- /tests/resources/wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/resources/wallet/__init__.py -------------------------------------------------------------------------------- /tests/resources/wallet/test_address.py: -------------------------------------------------------------------------------- 1 | from twisted.internet.defer import inlineCallbacks 2 | 3 | from hathor.wallet.resources import AddressResource 4 | from tests.resources.base_resource import StubSite, _BaseResourceTest 5 | 6 | 7 | class AddressTest(_BaseResourceTest._ResourceTest): 8 | def setUp(self): 9 | super().setUp() 10 | self.web = StubSite(AddressResource(self.manager)) 11 | 12 | @inlineCallbacks 13 | def test_get(self): 14 | response = yield self.web.get("wallet/address", {b'new': b'true'}) 15 | data = response.json_value() 16 | new_address1 = data['address'] 17 | 18 | response_same = yield self.web.get("wallet/address", {b'new': b'false'}) 19 | data_same = response_same.json_value() 20 | same_address = data_same['address'] 21 | 22 | # Default has to be new: false 23 | response_same2 = yield self.web.get("wallet/address") 24 | data_same2 = response_same2.json_value() 25 | same_address2 = data_same2['address'] 26 | 27 | response_new = yield self.web.get("wallet/address", {b'new': b'true'}) 28 | data_new = response_new.json_value() 29 | new_address2 = data_new['address'] 30 | 31 | self.assertEqual(new_address1, same_address) 32 | self.assertEqual(same_address, same_address2) 33 | self.assertNotEqual(new_address1, new_address2) 34 | -------------------------------------------------------------------------------- /tests/resources/wallet/test_history.py: -------------------------------------------------------------------------------- 1 | import base64 2 | 3 | from twisted.internet.defer import inlineCallbacks 4 | 5 | from hathor.mining.cpu_mining_service import CpuMiningService 6 | from hathor.p2p.resources import MiningResource 7 | from hathor.wallet.resources import HistoryResource 8 | from tests.resources.base_resource import StubSite, _BaseResourceTest 9 | from tests.utils import resolve_block_bytes 10 | 11 | 12 | class HistoryTest(_BaseResourceTest._ResourceTest): 13 | def setUp(self): 14 | super().setUp() 15 | self.web = StubSite(HistoryResource(self.manager)) 16 | self.web_mining = StubSite(MiningResource(self.manager)) 17 | 18 | @inlineCallbacks 19 | def test_get(self): 20 | # Mining new block 21 | response_mining = yield self.web_mining.get("mining") 22 | data_mining = response_mining.json_value() 23 | block_bytes = resolve_block_bytes( 24 | block_bytes=data_mining['block_bytes'], 25 | cpu_mining_service=CpuMiningService() 26 | ) 27 | yield self.web_mining.post("mining", {'block_bytes': base64.b64encode(block_bytes).decode('utf-8')}) 28 | 29 | # Getting wallet history 30 | response = yield self.web.get("wallet/history", {b'page': 1, b'count': 10}) 31 | data = response.json_value() 32 | self.assertEqual(len(data['history']), 1) 33 | self.assertEqual(data['total_pages'], 1) 34 | -------------------------------------------------------------------------------- /tests/simulation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/simulation/__init__.py -------------------------------------------------------------------------------- /tests/simulation/base.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from hathor.manager import HathorManager 4 | from hathor.simulator import Simulator 5 | from hathor.types import VertexId 6 | from tests import unittest 7 | 8 | 9 | class SimulatorTestCase(unittest.TestCase): 10 | seed_config: Optional[int] = None 11 | 12 | def setUp(self) -> None: 13 | super().setUp() 14 | 15 | self.simulator = Simulator(self.seed_config) 16 | self.simulator.start() 17 | 18 | print('-'*30) 19 | print('Simulation seed config:', self.simulator.seed) 20 | print('-'*30) 21 | 22 | def tearDown(self) -> None: 23 | self.simulator.stop() 24 | super().tearDown() 25 | 26 | def create_peer( # type: ignore[override] 27 | self, 28 | soft_voided_tx_ids: set[VertexId] = set(), 29 | simulator: Simulator | None = None 30 | ) -> HathorManager: 31 | if simulator is None: 32 | simulator = self.simulator 33 | 34 | builder = simulator.get_default_builder() \ 35 | .set_peer(self.get_random_peer_from_pool(rng=simulator.rng)) \ 36 | .set_soft_voided_tx_ids(soft_voided_tx_ids) 37 | 38 | return simulator.create_peer(builder) 39 | -------------------------------------------------------------------------------- /tests/sysctl/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/sysctl/__init__.py -------------------------------------------------------------------------------- /tests/sysctl/test_core.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock, Mock, call 2 | 3 | from hathor.sysctl import HathorManagerSysctl 4 | from tests.simulation.base import SimulatorTestCase 5 | 6 | 7 | class HathorManagerSysctlTestCase(SimulatorTestCase): 8 | __test__ = True 9 | 10 | def test_profiler(self): 11 | manager = self.create_peer() 12 | sysctl = HathorManagerSysctl(manager) 13 | 14 | status = sysctl.get('profiler.status') 15 | self.assertEqual(status, (0, 0)) 16 | 17 | manager.start_profiler = Mock(wraps=manager.start_profiler) 18 | self.assertEqual(manager.start_profiler.call_count, 0) 19 | sysctl.unsafe_set('profiler.start', False) 20 | self.assertEqual(manager.start_profiler.call_count, 1) 21 | 22 | manager.reactor.advance(100) 23 | status = sysctl.get('profiler.status') 24 | self.assertEqual(status, (1, 100)) 25 | 26 | manager.stop_profiler = Mock(wraps=manager.stop_profiler) 27 | manager.profiler = MagicMock() # prevents a call to profiler.dump_stats() 28 | self.assertEqual(manager.stop_profiler.call_count, 0) 29 | sysctl.unsafe_set('profiler.stop', '/path/to/dump') 30 | self.assertEqual(manager.stop_profiler.call_count, 1) 31 | self.assertEqual(manager.stop_profiler.call_args, call(save_to='/path/to/dump',)) 32 | 33 | status = sysctl.get('profiler.status') 34 | self.assertEqual(status, (0, 0)) 35 | -------------------------------------------------------------------------------- /tests/sysctl/test_runner.py: -------------------------------------------------------------------------------- 1 | 2 | import pytest 3 | 4 | from hathor.sysctl import Sysctl 5 | from hathor.sysctl.runner import SysctlRunner 6 | 7 | 8 | @pytest.mark.parametrize( 9 | 'args', 10 | [ 11 | 'string', 12 | "\"", 13 | 1, 14 | True, 15 | False, 16 | 'a,b', 17 | (1, 2, 3), 18 | (1, 'string', True), 19 | [1, 2, 3], 20 | (1, [1, 2, 3]), 21 | (1, ["a,a,a", "b", "c"]), 22 | ] 23 | ) 24 | def test_deserialize(args): 25 | root = Sysctl() 26 | runner = SysctlRunner(root) 27 | 28 | args_serialized = runner.serialize(args) 29 | args_deserialized = runner.deserialize(args_serialized) 30 | 31 | assert args == args_deserialized 32 | -------------------------------------------------------------------------------- /tests/test_memory_reactor_clock.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from twisted.internet.testing import MemoryReactorClock 16 | 17 | 18 | class TestMemoryReactorClock(MemoryReactorClock): 19 | __test__ = False 20 | 21 | def run(self): 22 | """ 23 | We have to override MemoryReactor.run() because the original Twisted implementation weirdly calls stop() inside 24 | run(), and we need the reactor running during our tests. 25 | """ 26 | self.running = True 27 | -------------------------------------------------------------------------------- /tests/test_utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/test_utils/__init__.py -------------------------------------------------------------------------------- /tests/test_utils/test_list.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Hathor Labs 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import pytest 15 | 16 | from hathor.utils.list import single_or_none 17 | 18 | 19 | def test_single_or_none_empty(): 20 | result = single_or_none([]) 21 | 22 | assert result is None 23 | 24 | 25 | @pytest.mark.parametrize('value', [None, 1, 10.4, 'test', b'test']) 26 | def test_single_or_none_one(value): 27 | result = single_or_none([value]) 28 | 29 | assert result == value 30 | 31 | 32 | def test_single_or_none_more_than_one(): 33 | with pytest.raises(AssertionError) as exc_info: 34 | single_or_none([1, 2, 3]) 35 | 36 | assert exc_info.value.args[0] == 'expected one value at most' 37 | -------------------------------------------------------------------------------- /tests/tx/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/tx/__init__.py -------------------------------------------------------------------------------- /tests/utils_modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/utils_modules/__init__.py -------------------------------------------------------------------------------- /tests/utils_modules/fixtures/empty.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/utils_modules/fixtures/empty.yml -------------------------------------------------------------------------------- /tests/utils_modules/fixtures/empty_extends.yml: -------------------------------------------------------------------------------- 1 | extends: 2 | 3 | a: aa 4 | b: 5 | d: dd 6 | e: ee 7 | -------------------------------------------------------------------------------- /tests/utils_modules/fixtures/invalid_extends.yml: -------------------------------------------------------------------------------- 1 | extends: ./unknown_file.yml 2 | 3 | a: aa 4 | b: 5 | d: dd 6 | e: ee 7 | -------------------------------------------------------------------------------- /tests/utils_modules/fixtures/mainnet_extends.yml: -------------------------------------------------------------------------------- 1 | extends: mainnet.yml 2 | 3 | a: aa 4 | b: 5 | d: dd 6 | e: ee 7 | -------------------------------------------------------------------------------- /tests/utils_modules/fixtures/number.yml: -------------------------------------------------------------------------------- 1 | 123 2 | -------------------------------------------------------------------------------- /tests/utils_modules/fixtures/self_extends.yml: -------------------------------------------------------------------------------- 1 | extends: self_extends.yml 2 | 3 | a: aa 4 | b: 5 | d: dd 6 | e: ee 7 | -------------------------------------------------------------------------------- /tests/utils_modules/fixtures/valid.yml: -------------------------------------------------------------------------------- 1 | a: 1 2 | b: 3 | c: 2 4 | d: 3 5 | -------------------------------------------------------------------------------- /tests/utils_modules/fixtures/valid_extends.yml: -------------------------------------------------------------------------------- 1 | extends: valid.yml 2 | 3 | a: aa 4 | b: 5 | d: dd 6 | e: ee 7 | -------------------------------------------------------------------------------- /tests/wallet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/wallet/__init__.py -------------------------------------------------------------------------------- /tests/websocket/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HathorNetwork/hathor-core/ad4613134f3646f2ef74c3f43357fc6df00ad6de/tests/websocket/__init__.py -------------------------------------------------------------------------------- /tools/run_local_measure_tx: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd ../ 4 | exec ./hathor-cli gen_rand_tx http://localhost:8080 $@ 5 | -------------------------------------------------------------------------------- /tools/run_local_mining: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd ../ 4 | exec ./hathor-cli run_miner http://localhost:8080/mining 5 | -------------------------------------------------------------------------------- /tools/speed-check.py: -------------------------------------------------------------------------------- 1 | """ It measures the number of operations per second involving digital signatures. 2 | """ 3 | 4 | import timeit 5 | 6 | from cryptography.hazmat.backends import default_backend 7 | from cryptography.hazmat.primitives import hashes 8 | from cryptography.hazmat.primitives.asymmetric import ec 9 | 10 | number = 20000 11 | 12 | dt = timeit.timeit('ec.generate_private_key(ec.SECP256K1(), default_backend())', number=number, globals=globals()) 13 | print('Private key generations per second: {:.1f}'.format(number / dt)) 14 | 15 | data = bytes(32) 16 | priv_key = ec.generate_private_key(ec.SECP256K1(), default_backend()) 17 | priv_key.sign(data, ec.ECDSA(hashes.SHA256())) 18 | dt = timeit.timeit('priv_key.sign(data, ec.ECDSA(hashes.SHA256()))', number=number, globals=globals()) 19 | print('Generation of digital signatures per second: {:.1f}'.format(number / dt)) 20 | 21 | pub_key = priv_key.public_key() 22 | signature = priv_key.sign(data, ec.ECDSA(hashes.SHA256())) 23 | dt = timeit.timeit('pub_key.verify(signature, data, ec.ECDSA(hashes.SHA256()))', number=number, globals=globals()) 24 | print('Verification of digital signatures per second: {:.1f}'.format(number / dt)) 25 | --------------------------------------------------------------------------------