├── .circleci └── config.yml ├── .editorconfig ├── .envrc ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── ip.md │ └── jip.md ├── actions │ └── nix-common-setup │ │ └── action.yml ├── dependabot.yml └── workflows │ ├── api.yml │ ├── audit.yml │ ├── changelog.yml │ ├── docker.yml │ ├── docs.yml │ ├── editorconfig.yml │ ├── nix.yml │ ├── python-scripts.yml │ ├── release.yml │ ├── test.yml │ ├── test_evm.yml │ ├── test_networking.yml │ └── update-flake-lock.yml ├── .github_changelog_generator ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── RELEASE.md ├── ROADMAP.md ├── book.toml ├── ci ├── docker │ └── Dockerfile ├── pack-assets.py ├── release-info.py └── strip-own-version-from-cargo-lock.pl ├── default.nix ├── doc ├── SUMMARY.md ├── advanced │ ├── 01_the_genesis_block.md │ ├── 02_starting_bft_blockchain.md │ ├── 03_starting_genesis_praos_blockchain.md │ └── introduction.md ├── api │ ├── v0.yaml │ └── v1.yaml ├── concepts │ ├── blockchain.md │ ├── introduction.md │ ├── network.md │ ├── node.md │ └── stake.md ├── configuration │ ├── introduction.md │ ├── leadership.md │ ├── logging.md │ ├── mempool.md │ ├── network.md │ └── prometheus.md ├── internal_design.md ├── internal_design │ ├── architecture-1.png │ ├── blockchain_structure.dot │ ├── blockchain_structure.png │ ├── blockchain_structure_block0.dot │ ├── blockchain_structure_block0.png │ ├── blockchain_structure_blockk.dot │ ├── blockchain_structure_blockk.png │ ├── blockchain_structure_transition.dot │ ├── blockchain_structure_transition.png │ ├── network_nano_protocol_simple.dot │ └── network_nano_protocol_simple.png ├── introduction.md ├── jcli │ ├── address.md │ ├── certificate.md │ ├── genesis.md │ ├── introduction.md │ ├── key.md │ ├── rest.md │ ├── transaction.md │ └── vote.md ├── quickstart │ ├── 01_command_line.md │ ├── 02_passive_node.md │ ├── 03_rest_api.md │ ├── 04_explorer.md │ ├── 05_leader_candidate.md │ └── introduction.md ├── specs │ ├── introduction.md │ ├── migration.md │ ├── network.md │ └── quarantine.png ├── stake_pool │ ├── delegating_stake.md │ ├── introduction.md │ ├── registering_stake_pool.md │ └── retiring_stake_pool.md └── testing │ ├── automation.md │ ├── graphs │ ├── jormungandr-simplified-arch.svg │ ├── jormungandr-test-categories.svg │ └── testing-architecture.svg │ ├── hersir.md │ ├── integration_tests.md │ ├── introduction.md │ ├── loki.md │ ├── mjolnir.md │ └── thor.md ├── docker ├── Dockerfile ├── README.md └── alpine │ └── Dockerfile ├── explorer ├── Cargo.toml └── src │ ├── api │ ├── graphql │ │ ├── certificates.rs │ │ ├── config_param.rs │ │ ├── connections.rs │ │ ├── error.rs │ │ ├── mod.rs │ │ └── scalars.rs │ └── mod.rs │ ├── db │ ├── error.rs │ ├── indexing.rs │ ├── mod.rs │ ├── multiverse.rs │ ├── persistent_sequence.rs │ ├── set.rs │ └── tally.rs │ ├── indexer.rs │ ├── logging.rs │ ├── main.rs │ ├── settings.rs │ └── tests.rs ├── flake.lock ├── flake.nix ├── jcli ├── Cargo.toml ├── build.rs └── src │ ├── jcli_lib │ ├── address.rs │ ├── auto_completion.rs │ ├── block │ │ └── mod.rs │ ├── certificate │ │ ├── mod.rs │ │ ├── new_evm_mapping.rs │ │ ├── new_owner_stake_delegation.rs │ │ ├── new_stake_delegation.rs │ │ ├── new_stake_pool_registration.rs │ │ ├── new_stake_pool_retirement.rs │ │ ├── new_update_proposal.rs │ │ ├── new_update_vote.rs │ │ ├── new_vote_cast.rs │ │ ├── new_vote_plan.rs │ │ ├── new_vote_tally.rs │ │ ├── show.rs │ │ ├── show │ │ │ ├── stake_pool_id.rs │ │ │ └── vote_plan_id.rs │ │ ├── sign.rs │ │ └── weighted_pool_ids.rs │ ├── debug │ │ ├── block.rs │ │ ├── message.rs │ │ └── mod.rs │ ├── key.rs │ ├── mod.rs │ ├── rest │ │ ├── config.rs │ │ ├── mod.rs │ │ ├── v0 │ │ │ ├── account │ │ │ │ └── mod.rs │ │ │ ├── block │ │ │ │ ├── mod.rs │ │ │ │ ├── next_id.rs │ │ │ │ └── subcommand.rs │ │ │ ├── diagnostic │ │ │ │ └── mod.rs │ │ │ ├── leaders │ │ │ │ └── mod.rs │ │ │ ├── message │ │ │ │ └── mod.rs │ │ │ ├── mod.rs │ │ │ ├── network │ │ │ │ ├── mod.rs │ │ │ │ └── stats.rs │ │ │ ├── node │ │ │ │ ├── mod.rs │ │ │ │ └── stats.rs │ │ │ ├── rewards │ │ │ │ ├── epoch.rs │ │ │ │ ├── history.rs │ │ │ │ └── mod.rs │ │ │ ├── settings │ │ │ │ └── mod.rs │ │ │ ├── shutdown │ │ │ │ └── mod.rs │ │ │ ├── stake │ │ │ │ └── mod.rs │ │ │ ├── stake_pool │ │ │ │ └── mod.rs │ │ │ ├── stake_pools │ │ │ │ └── mod.rs │ │ │ ├── tip │ │ │ │ └── mod.rs │ │ │ ├── utxo │ │ │ │ └── mod.rs │ │ │ └── vote │ │ │ │ ├── active.rs │ │ │ │ ├── committees.rs │ │ │ │ ├── mod.rs │ │ │ │ └── plans.rs │ │ └── v1 │ │ │ ├── mod.rs │ │ │ └── vote │ │ │ └── mod.rs │ ├── transaction │ │ ├── add_account.rs │ │ ├── add_certificate.rs │ │ ├── add_evm_transaction.rs │ │ ├── add_input.rs │ │ ├── add_output.rs │ │ ├── add_witness.rs │ │ ├── auth.rs │ │ ├── common.rs │ │ ├── finalize.rs │ │ ├── info.rs │ │ ├── mk_witness.rs │ │ ├── mod.rs │ │ ├── new.rs │ │ ├── seal.rs │ │ ├── set_expiry_date.rs │ │ ├── simplified.rs │ │ └── staging.rs │ ├── utils │ │ ├── account_id.rs │ │ ├── io.rs │ │ ├── key_parser.rs │ │ ├── mod.rs │ │ ├── output_file.rs │ │ ├── output_format.rs │ │ └── vote.rs │ └── vote │ │ ├── committee │ │ ├── communication_key.rs │ │ ├── member_key.rs │ │ └── mod.rs │ │ ├── election_public_key.rs │ │ ├── mod.rs │ │ └── tally │ │ ├── decrypt_tally.rs │ │ ├── decryption_shares.rs │ │ ├── merge_results.rs │ │ └── mod.rs │ ├── lib.rs │ └── main.rs ├── jormungandr-lib ├── Cargo.toml └── src │ ├── crypto │ ├── account.rs │ ├── hash.rs │ ├── key.rs │ ├── mod.rs │ └── serde.rs │ ├── interfaces │ ├── CONFIG_PARAMS_DOCUMENTED_EXAMPLE.yaml │ ├── account_identifier.rs │ ├── account_state.rs │ ├── address.rs │ ├── block0_configuration │ │ ├── BLOCKCHAIN_CONFIGURATION_DOCUMENTED_EXAMPLE.yaml │ │ ├── active_slot_coefficient.rs │ │ ├── block_content_max_size.rs │ │ ├── default_values.rs │ │ ├── epoch_stability_depth.rs │ │ ├── fees_go_to.rs │ │ ├── initial_config.rs │ │ ├── initial_fragment.rs │ │ ├── kes_update_speed.rs │ │ ├── leader_id.rs │ │ ├── mod.rs │ │ ├── number_of_slots_per_epoch.rs │ │ ├── proposal_expiration.rs │ │ ├── reward_constraint.rs │ │ └── slots_duration.rs │ ├── blockdate.rs │ ├── certificate.rs │ ├── committee.rs │ ├── config │ │ ├── log.rs │ │ ├── mempool.rs │ │ ├── mod.rs │ │ ├── node.rs │ │ └── secret.rs │ ├── config_params.rs │ ├── evm_params.rs │ ├── evm_transaction.rs │ ├── fragment.rs │ ├── fragment_log.rs │ ├── fragment_log_persistent.rs │ ├── fragments_batch.rs │ ├── fragments_processing_summary.rs │ ├── leadership_log.rs │ ├── linear_fee.rs │ ├── mint_token.rs │ ├── mod.rs │ ├── old_address.rs │ ├── peer_stats.rs │ ├── ratio.rs │ ├── reward_parameters.rs │ ├── rewards_info.rs │ ├── settings.rs │ ├── stake.rs │ ├── stake_distribution.rs │ ├── stake_pool_stats.rs │ ├── stats.rs │ ├── tax_type.rs │ ├── transaction_input.rs │ ├── transaction_output.rs │ ├── transaction_witness.rs │ ├── utxo_info.rs │ ├── value.rs │ └── vote.rs │ ├── lib.rs │ ├── multiaddr.rs │ └── time.rs ├── jormungandr ├── Cargo.toml ├── benches │ └── rest_v0.rs ├── build.rs └── src │ ├── bin │ └── jormungandr.rs │ ├── blockcfg │ └── mod.rs │ ├── blockchain │ ├── bootstrap.rs │ ├── branch.rs │ ├── candidate.rs │ ├── chain.rs │ ├── chain_selection.rs │ ├── checkpoints.rs │ ├── mod.rs │ ├── multiverse.rs │ ├── process.rs │ ├── reference.rs │ ├── reference_cache.rs │ ├── storage.rs │ └── tip.rs │ ├── client.rs │ ├── context │ └── mod.rs │ ├── diagnostic.rs │ ├── fragment │ ├── entry.rs │ ├── logs.rs │ ├── mod.rs │ ├── pool.rs │ ├── process.rs │ └── selection.rs │ ├── intercom.rs │ ├── jrpc │ ├── eth_account │ │ ├── logic.rs │ │ └── mod.rs │ ├── eth_block_info │ │ ├── logic.rs │ │ └── mod.rs │ ├── eth_chain_info │ │ ├── logic.rs │ │ └── mod.rs │ ├── eth_filter │ │ ├── filters.rs │ │ ├── logic.rs │ │ └── mod.rs │ ├── eth_miner │ │ ├── logic.rs │ │ └── mod.rs │ ├── eth_transaction │ │ ├── logic.rs │ │ └── mod.rs │ ├── eth_types │ │ ├── block.rs │ │ ├── block_number.rs │ │ ├── bytes.rs │ │ ├── fee.rs │ │ ├── filter.rs │ │ ├── log.rs │ │ ├── mod.rs │ │ ├── number.rs │ │ ├── receipt.rs │ │ ├── sync.rs │ │ ├── transaction.rs │ │ └── work.rs │ └── mod.rs │ ├── leadership │ ├── enclave.rs │ ├── logs.rs │ ├── mod.rs │ └── process.rs │ ├── lib.rs │ ├── log │ └── mod.rs │ ├── metrics │ ├── backends │ │ ├── mod.rs │ │ ├── prometheus_exporter.rs │ │ └── simple_counter.rs │ └── mod.rs │ ├── network │ ├── bootstrap.rs │ ├── client │ │ ├── connect.rs │ │ └── mod.rs │ ├── convert.rs │ ├── grpc │ │ ├── client.rs │ │ ├── mod.rs │ │ └── server.rs │ ├── mod.rs │ ├── p2p │ │ ├── comm.rs │ │ ├── comm │ │ │ └── peer_map.rs │ │ └── mod.rs │ ├── service.rs │ └── subscription.rs │ ├── rest │ ├── mod.rs │ ├── prometheus.rs │ ├── v0 │ │ ├── handlers.rs │ │ ├── logic.rs │ │ └── mod.rs │ └── v1 │ │ ├── handlers.rs │ │ ├── logic.rs │ │ └── mod.rs │ ├── secure │ ├── enclave.rs │ └── mod.rs │ ├── settings │ ├── command_arguments.rs │ ├── logging.rs │ ├── mod.rs │ └── start │ │ ├── config.rs │ │ ├── mod.rs │ │ └── network.rs │ ├── start_up │ ├── error.rs │ └── mod.rs │ ├── state.rs │ ├── stuck_notifier.rs │ ├── topology │ ├── gossip.rs │ ├── layers │ │ ├── mod.rs │ │ ├── preferred_list.rs │ │ └── rings.rs │ ├── mod.rs │ ├── process.rs │ ├── quarantine.rs │ └── topology.rs │ ├── utils │ ├── async_msg.rs │ ├── fire_forget_scheduler.rs │ ├── mod.rs │ └── task.rs │ └── watch_client.rs ├── modules ├── blockchain │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── block0.rs │ │ ├── blockchain.rs │ │ ├── checkpoints.rs │ │ ├── epoch_info.rs │ │ ├── lib.rs │ │ └── reference.rs └── settings │ ├── Cargo.toml │ ├── README.md │ └── src │ └── lib.rs ├── rustfmt.toml ├── scripts ├── .gitignore ├── bootstrap.py └── jcli-helpers ├── shell.nix ├── testing ├── hersir │ ├── Cargo.toml │ ├── res │ │ └── example.yaml │ └── src │ │ ├── args.rs │ │ ├── builder │ │ ├── committee.rs │ │ ├── explorer.rs │ │ ├── mod.rs │ │ ├── rng.rs │ │ ├── settings │ │ │ ├── mod.rs │ │ │ ├── node.rs │ │ │ ├── vote_plan.rs │ │ │ └── wallet.rs │ │ ├── stake_pool.rs │ │ ├── topology.rs │ │ ├── vote.rs │ │ └── wallet.rs │ │ ├── cli.rs │ │ ├── config │ │ ├── blockchain.rs │ │ ├── committee.rs │ │ ├── mod.rs │ │ ├── spawn_params.rs │ │ ├── vote_plan.rs │ │ └── wallet │ │ │ ├── builder.rs │ │ │ └── mod.rs │ │ ├── controller │ │ ├── error.rs │ │ ├── interactive │ │ │ ├── args │ │ │ │ ├── describe.rs │ │ │ │ ├── explorer.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── send │ │ │ │ │ ├── cast.rs │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── tally.rs │ │ │ │ │ └── tx.rs │ │ │ │ ├── show.rs │ │ │ │ └── spawn.rs │ │ │ ├── command.rs │ │ │ ├── controller.rs │ │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── monitor │ │ │ ├── mod.rs │ │ │ └── node │ │ │ │ ├── legacy.rs │ │ │ │ └── mod.rs │ │ └── scenario │ │ │ └── dotifier.rs │ │ ├── error.rs │ │ ├── lib.rs │ │ ├── main.rs │ │ ├── spawn │ │ ├── interactive.rs │ │ ├── mod.rs │ │ ├── monitor.rs │ │ └── standard.rs │ │ └── utils │ │ ├── dotifier.rs │ │ ├── introduction.rs │ │ └── mod.rs ├── jormungandr-automation │ ├── Cargo.toml │ ├── build.rs │ ├── proto │ │ ├── node.proto │ │ ├── types.proto │ │ └── watch.proto │ ├── resources │ │ ├── explorer │ │ │ └── graphql │ │ │ │ ├── address.graphql │ │ │ │ ├── allblocks.graphql │ │ │ │ ├── allstakepools.graphql │ │ │ │ ├── block.graphql │ │ │ │ ├── block_by_id.graphql │ │ │ │ ├── blocksbychainlength.graphql │ │ │ │ ├── epoch.graphql │ │ │ │ ├── generate_schema.sh │ │ │ │ ├── lastblock.graphql │ │ │ │ ├── schema.graphql │ │ │ │ ├── settings.graphql │ │ │ │ ├── stakepool.graphql │ │ │ │ ├── transaction_by_id.graphql │ │ │ │ ├── transaction_by_id_certificates.graphql │ │ │ │ ├── transactions_by_address.graphql │ │ │ │ ├── voteplan_by_id.graphql │ │ │ │ └── voteplans.graphql │ │ └── tls │ │ │ ├── ca.crt │ │ │ ├── server.crt │ │ │ └── server.key │ └── src │ │ ├── bin │ │ ├── explorer-client.rs │ │ ├── grpc_client_app.rs │ │ └── grpc_server_app.rs │ │ ├── jcli │ │ ├── api │ │ │ ├── address.rs │ │ │ ├── certificate.rs │ │ │ ├── genesis.rs │ │ │ ├── key.rs │ │ │ ├── mod.rs │ │ │ ├── rest │ │ │ │ ├── mod.rs │ │ │ │ ├── v0 │ │ │ │ │ ├── block.rs │ │ │ │ │ ├── message.rs │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── node.rs │ │ │ │ │ ├── utxo.rs │ │ │ │ │ └── vote.rs │ │ │ │ └── v1 │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── vote.rs │ │ │ ├── transaction.rs │ │ │ └── votes │ │ │ │ ├── committee │ │ │ │ ├── communication_key.rs │ │ │ │ ├── member_key.rs │ │ │ │ └── mod.rs │ │ │ │ ├── crs.rs │ │ │ │ ├── mod.rs │ │ │ │ └── tally.rs │ │ ├── command │ │ │ ├── address │ │ │ │ ├── account.rs │ │ │ │ ├── info.rs │ │ │ │ ├── mod.rs │ │ │ │ └── single.rs │ │ │ ├── certificate.rs │ │ │ ├── genesis │ │ │ │ ├── decode.rs │ │ │ │ ├── encode.rs │ │ │ │ ├── hash.rs │ │ │ │ └── mod.rs │ │ │ ├── key │ │ │ │ ├── from_bytes.rs │ │ │ │ ├── generate.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── to_bytes.rs │ │ │ │ └── to_public.rs │ │ │ ├── mod.rs │ │ │ ├── rest │ │ │ │ ├── mod.rs │ │ │ │ ├── v0 │ │ │ │ │ ├── block.rs │ │ │ │ │ ├── message.rs │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── node.rs │ │ │ │ │ ├── utxo.rs │ │ │ │ │ └── vote.rs │ │ │ │ └── v1 │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── vote.rs │ │ │ ├── transaction.rs │ │ │ └── votes │ │ │ │ ├── committee │ │ │ │ ├── communication_key.rs │ │ │ │ ├── member_key.rs │ │ │ │ └── mod.rs │ │ │ │ ├── crs.rs │ │ │ │ ├── election_public_key.rs │ │ │ │ ├── mod.rs │ │ │ │ └── tally.rs │ │ ├── data │ │ │ ├── mod.rs │ │ │ └── witness.rs │ │ ├── mod.rs │ │ ├── services │ │ │ ├── certificate_builder.rs │ │ │ ├── fragment_check.rs │ │ │ ├── fragment_sender.rs │ │ │ ├── fragments_check.rs │ │ │ ├── mod.rs │ │ │ └── transaction_builder.rs │ │ └── utxo.rs │ │ ├── jormungandr │ │ ├── configuration │ │ │ ├── block0_config_builder.rs │ │ │ ├── configuration_builder.rs │ │ │ ├── jormungandr_config.rs │ │ │ ├── mod.rs │ │ │ ├── node_config.rs │ │ │ ├── node_config_builder.rs │ │ │ └── secret_model_factory.rs │ │ ├── explorer │ │ │ ├── client.rs │ │ │ ├── configuration.rs │ │ │ ├── data.rs │ │ │ ├── mod.rs │ │ │ ├── verifiers │ │ │ │ ├── block_by_id_verifier.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── transaction_by_id_verifier.rs │ │ │ │ └── vote_plan_verifier.rs │ │ │ └── wrappers.rs │ │ ├── fragment_node.rs │ │ ├── grpc │ │ │ ├── client.rs │ │ │ ├── convert.rs │ │ │ ├── mod.rs │ │ │ └── server │ │ │ │ ├── builder.rs │ │ │ │ ├── controller.rs │ │ │ │ ├── data.rs │ │ │ │ ├── logger.rs │ │ │ │ ├── mod.rs │ │ │ │ └── verifier.rs │ │ ├── legacy │ │ │ ├── config │ │ │ │ ├── configuration_builder.rs │ │ │ │ ├── mod.rs │ │ │ │ └── node.rs │ │ │ ├── mod.rs │ │ │ ├── rest.rs │ │ │ └── version.rs │ │ ├── logger.rs │ │ ├── mod.rs │ │ ├── process.rs │ │ ├── remote.rs │ │ ├── rest │ │ │ ├── mod.rs │ │ │ ├── raw.rs │ │ │ └── settings.rs │ │ ├── starter │ │ │ ├── commands.rs │ │ │ ├── mod.rs │ │ │ └── testing_directory.rs │ │ └── verifier │ │ │ ├── fragment_log.rs │ │ │ └── mod.rs │ │ ├── lib.rs │ │ ├── testing │ │ ├── asserts.rs │ │ ├── benchmark │ │ │ ├── mod.rs │ │ │ ├── node.rs │ │ │ └── sync │ │ │ │ ├── measure.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── node.rs │ │ │ │ ├── report.rs │ │ │ │ └── wait.rs │ │ ├── block0.rs │ │ ├── blockchain_config.rs │ │ ├── collector.rs │ │ ├── configuration.rs │ │ ├── keys.rs │ │ ├── mod.rs │ │ ├── observer.rs │ │ ├── panic.rs │ │ ├── process.rs │ │ ├── resources.rs │ │ ├── storage.rs │ │ ├── time.rs │ │ ├── verify.rs │ │ └── vit │ │ │ ├── builder.rs │ │ │ ├── mod.rs │ │ │ └── vote_cast_register.rs │ │ └── utils │ │ ├── mod.rs │ │ ├── multiaddr.rs │ │ └── observer.rs ├── jormungandr-integration-tests │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── jcli │ │ ├── address │ │ │ ├── account.rs │ │ │ ├── info.rs │ │ │ ├── mod.rs │ │ │ └── single.rs │ │ ├── certificate │ │ │ ├── e2e.rs │ │ │ ├── mod.rs │ │ │ └── retirement.rs │ │ ├── genesis │ │ │ ├── encode.rs │ │ │ ├── hash.rs │ │ │ ├── init.rs │ │ │ └── mod.rs │ │ ├── key │ │ │ ├── from_bytes.rs │ │ │ ├── generate.rs │ │ │ ├── mod.rs │ │ │ ├── to_bytes.rs │ │ │ └── to_public.rs │ │ ├── mod.rs │ │ ├── rest │ │ │ ├── block.rs │ │ │ ├── host.rs │ │ │ ├── mod.rs │ │ │ ├── tip.rs │ │ │ ├── utxo.rs │ │ │ └── vote.rs │ │ ├── tally │ │ │ ├── merge_results.rs │ │ │ └── mod.rs │ │ ├── transaction │ │ │ ├── add_account.rs │ │ │ ├── e2e.rs │ │ │ ├── finalize.rs │ │ │ ├── input.rs │ │ │ ├── mod.rs │ │ │ ├── new.rs │ │ │ ├── simplified.rs │ │ │ └── witness.rs │ │ └── update_proposal │ │ │ ├── e2e.rs │ │ │ └── mod.rs │ │ ├── jormungandr │ │ ├── bft │ │ │ ├── block.rs │ │ │ ├── counter.rs │ │ │ ├── mempool │ │ │ │ ├── mod.rs │ │ │ │ ├── v0.rs │ │ │ │ └── v1.rs │ │ │ ├── mod.rs │ │ │ ├── start_node.rs │ │ │ └── update_proposal.rs │ │ ├── block.rs │ │ ├── cors.rs │ │ ├── evm_mapping.rs │ │ ├── evm_transaction.rs │ │ ├── explorer │ │ │ ├── address.rs │ │ │ ├── block.rs │ │ │ ├── certificates.rs │ │ │ ├── explorer_sanity.rs │ │ │ ├── mod.rs │ │ │ ├── settings.rs │ │ │ ├── transaction.rs │ │ │ └── vote_plan.rs │ │ ├── fragments.rs │ │ ├── genesis │ │ │ ├── fragments.rs │ │ │ ├── mod.rs │ │ │ ├── pool_update.rs │ │ │ ├── rewards.rs │ │ │ ├── stake_distribution.rs │ │ │ ├── stake_pool.rs │ │ │ └── start_node.rs │ │ ├── grpc │ │ │ ├── client_tests.rs │ │ │ ├── mod.rs │ │ │ ├── server_tests.rs │ │ │ └── setup.rs │ │ ├── leadership.rs │ │ ├── legacy.rs │ │ ├── mempool.rs │ │ ├── mod.rs │ │ ├── persistent_log.rs │ │ ├── recovery.rs │ │ ├── rest │ │ │ ├── mod.rs │ │ │ ├── v0 │ │ │ │ ├── errors.rs │ │ │ │ └── mod.rs │ │ │ └── v1 │ │ │ │ ├── fragments │ │ │ │ ├── fail_fast.rs │ │ │ │ ├── mod.rs │ │ │ │ └── statuses.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── utils │ │ │ │ ├── mod.rs │ │ │ │ └── settings.rs │ │ │ │ └── votes.rs │ │ ├── tls.rs │ │ ├── tokens.rs │ │ ├── transactions.rs │ │ └── vit │ │ │ ├── mod.rs │ │ │ ├── private.rs │ │ │ └── public.rs │ │ ├── lib.rs │ │ ├── networking │ │ ├── bft.rs │ │ ├── communication │ │ │ ├── leader_leader.rs │ │ │ ├── mod.rs │ │ │ ├── parallel_spending_counter.rs │ │ │ └── passive_leader.rs │ │ ├── cross_version │ │ │ ├── disruption.rs │ │ │ ├── fragment_propagation.rs │ │ │ └── mod.rs │ │ ├── explorer.rs │ │ ├── leadership_log.rs │ │ ├── mod.rs │ │ ├── p2p │ │ │ ├── connections.rs │ │ │ ├── mod.rs │ │ │ ├── quarantine.rs │ │ │ └── stats.rs │ │ ├── stake_pool │ │ │ ├── mod.rs │ │ │ └── retire.rs │ │ ├── testnet.rs │ │ ├── topology.rs │ │ └── utils │ │ │ └── mod.rs │ │ ├── non_functional │ │ ├── bootstrap.rs │ │ ├── compatibility.rs │ │ ├── explorer.rs │ │ ├── fragment.rs │ │ ├── mod.rs │ │ ├── network │ │ │ ├── big.rs │ │ │ ├── desync.rs │ │ │ ├── disruption.rs │ │ │ ├── mod.rs │ │ │ └── soak.rs │ │ ├── persistent_log.rs │ │ ├── rest.rs │ │ ├── rewards.rs │ │ ├── soak.rs │ │ ├── transaction.rs │ │ └── voting │ │ │ ├── config.rs │ │ │ ├── mod.rs │ │ │ ├── private │ │ │ ├── load.rs │ │ │ ├── mod.rs │ │ │ ├── noise.rs │ │ │ └── soak.rs │ │ │ └── public │ │ │ ├── load.rs │ │ │ ├── mod.rs │ │ │ ├── noise.rs │ │ │ └── soak.rs │ │ └── startup.rs ├── loki │ ├── Cargo.toml │ └── src │ │ ├── args.rs │ │ ├── block.rs │ │ ├── error.rs │ │ ├── lib.rs │ │ ├── main.rs │ │ ├── process.rs │ │ ├── rest │ │ ├── handlers.rs │ │ └── mod.rs │ │ └── sender.rs ├── mjolnir │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ ├── main.rs │ │ └── mjolnir_lib │ │ ├── args.rs │ │ ├── bootstrap │ │ ├── config.rs │ │ ├── mod.rs │ │ └── scenario │ │ │ ├── duration.rs │ │ │ ├── iteration.rs │ │ │ └── mod.rs │ │ ├── error.rs │ │ ├── explorer.rs │ │ ├── fragment │ │ ├── batch │ │ │ ├── adversary │ │ │ │ ├── all.rs │ │ │ │ ├── mod.rs │ │ │ │ └── votes_only.rs │ │ │ ├── mod.rs │ │ │ └── tx_only.rs │ │ ├── mod.rs │ │ └── standard │ │ │ ├── adversary │ │ │ ├── all.rs │ │ │ ├── mod.rs │ │ │ └── votes_only.rs │ │ │ ├── all.rs │ │ │ ├── mod.rs │ │ │ └── tx_only.rs │ │ ├── generators │ │ ├── adversary_generator.rs │ │ ├── adversary_vote_casts_generator.rs │ │ ├── batch_generator.rs │ │ ├── explorer.rs │ │ ├── fragment_generator.rs │ │ ├── mod.rs │ │ ├── rest.rs │ │ ├── status_provider.rs │ │ ├── transaction_generator.rs │ │ ├── vote_casts_generator.rs │ │ └── wallet_lane_iter.rs │ │ ├── mod.rs │ │ └── rest.rs └── thor │ ├── Cargo.toml │ ├── README.md │ └── src │ ├── bin │ ├── cli │ │ ├── command.rs │ │ ├── mod.rs │ │ ├── send.rs │ │ └── wallet.rs │ └── thor.rs │ ├── cli │ ├── config.rs │ ├── controller.rs │ ├── error.rs │ ├── mod.rs │ └── wallet_controller.rs │ ├── fragment │ ├── chain_sender.rs │ ├── export.rs │ ├── initial_certificates.rs │ ├── mod.rs │ ├── persistent_log.rs │ ├── sender.rs │ ├── setup.rs │ ├── transaction.rs │ ├── transaction_utils.rs │ └── verifier.rs │ ├── lib.rs │ ├── stake_pool.rs │ └── wallet │ ├── account.rs │ ├── committee │ ├── mod.rs │ └── single.rs │ ├── delegation.rs │ ├── discrimination.rs │ ├── mod.rs │ └── utxo.rs └── tools ├── prepare-changelog.sh └── update-version.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # DEVOPS 2 | 3 | /.github/action/nix-common-setup* @input-output-hk/jormungandr-devops 4 | /.github/workflows/nix.yml @input-output-hk/jormungandr-devops 5 | /.github/workflows/update-flake-lock.yml @input-output-hk/jormungandr-devops 6 | /default.nix @input-output-hk/jormungandr-devops 7 | /flake.lock @input-output-hk/jormungandr-devops 8 | /flake.nix @input-output-hk/jormungandr-devops 9 | /shell.nix @input-output-hk/jormungandr-devops 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **Mandatory Information** 11 | 1. `jcli --full-version` output; 12 | 2. `jormungandr --full-version` output; 13 | 14 | **To Reproduce** 15 | Steps to reproduce the behavior: 16 | 1. Go to '...' 17 | 2. Click on '....' 18 | 3. Scroll down to '....' 19 | 4. See error 20 | 21 | **Expected behavior** 22 | A clear and concise description of what you expected to happen. 23 | 24 | **Additional context** 25 | Add any other context about the problem here. 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ip.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: IP 3 | about: Improvement Proposal 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem/context ? Please describe if applicable.** 8 | A clear and concise description of what the problem and/or context is. 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. possible alternative solutions 12 | 13 | **Additional context** 14 | Add any other context about the feature request here. 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/jip.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: JIP 3 | about: Node Improvement Proposal 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem/context ? Please describe if applicable.** 8 | A clear and concise description of what the problem and/or context is. 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. possible alternative solutions 12 | 13 | **Additional context** 14 | Add any other context about the feature request here. 15 | -------------------------------------------------------------------------------- /.github/actions/nix-common-setup/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup Nix Environment 2 | inputs: 3 | CACHIX_AUTH_TOKEN: 4 | required: true 5 | description: 'Cachix Auth Token' 6 | runs: 7 | using: "composite" 8 | steps: 9 | 10 | - name: Installing Nix 11 | uses: cachix/install-nix-action@v16 12 | with: 13 | nix_path: nixpkgs=channel:nixpkgs-unstable 14 | extra_nix_config: | 15 | accept-flake-config = true 16 | trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= 17 | substituters = https://hydra.iohk.io https://cache.nixos.org/ 18 | 19 | - uses: cachix/cachix-action@v10 20 | with: 21 | name: iog 22 | authToken: '${{ inputs.CACHIX_AUTH_TOKEN }}' 23 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | 4 | - package-ecosystem: github-actions 5 | directory: "/" 6 | schedule: 7 | interval: daily 8 | time: '00:00' 9 | timezone: UTC 10 | open-pull-requests-limit: 10 11 | commit-message: 12 | prefix: "chore" 13 | include: "scope" 14 | 15 | - package-ecosystem: cargo 16 | directory: '/' 17 | schedule: 18 | interval: daily 19 | open-pull-requests-limit: 10 20 | 21 | ignore: 22 | # Ignore crates from chain-libs. chain-impl-mockchain is not ignored to be kept as a watchdog. 23 | # Due to how `cargo update` works, updating a single chain-libs crate causes all other crates 24 | # from that repo to update. Thus, pull requests for each single dependency from chain-libs are 25 | # basically all the same and are not needed. 26 | - dependency-name: cardano-legacy-address 27 | - dependency-name: chain-addr 28 | - dependency-name: chain-core 29 | - dependency-name: chain-crypto 30 | - dependency-name: chain-evm 31 | - dependency-name: chain-network 32 | - dependency-name: chain-ser 33 | - dependency-name: chain-storage 34 | - dependency-name: chain-time 35 | - dependency-name: chain-vote 36 | - dependency-name: imhamt 37 | - dependency-name: sparse-array 38 | - dependency-name: typed-bytes 39 | -------------------------------------------------------------------------------- /.github/workflows/api.yml: -------------------------------------------------------------------------------- 1 | name: API Check 2 | on: 3 | push: 4 | branches: 5 | - master 6 | paths: 7 | - 'doc/api/*.yaml' 8 | pull_request: 9 | paths: 10 | - 'doc/api/*.yaml' 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: stoplightio/spectral-action@v0.8.8 17 | with: 18 | file_glob: doc/api/*.yaml 19 | repo_token: ${{ secrets.GITHUB_TOKEN }} 20 | -------------------------------------------------------------------------------- /.github/workflows/audit.yml: -------------------------------------------------------------------------------- 1 | name: Security audit 2 | on: 3 | push: 4 | branches: 5 | - master 6 | paths: 7 | - Cargo.lock 8 | pull_request: 9 | paths: 10 | - Cargo.lock 11 | schedule: 12 | - cron: '0 5 * * 0' # Weekly every Sunday 05:00 UTC 13 | 14 | jobs: 15 | security_audit: 16 | runs-on: ubuntu-latest 17 | container: 18 | image: ghcr.io/${{ github.repository_owner }}/jormungandr-rust-ci:latest 19 | credentials: 20 | username: ${{ github.actor }} 21 | password: ${{ secrets.GITHUB_TOKEN }} 22 | volumes: 23 | - cargo-registry-index:/usr/local/cargo/registry/index 24 | steps: 25 | - uses: actions/checkout@v3 26 | 27 | - id: ls-crates-io-index 28 | name: Get head commit hash of crates.io registry index 29 | run: | 30 | commit=$( 31 | git ls-remote --heads https://github.com/rust-lang/crates.io-index.git master | 32 | cut -f 1 33 | ) 34 | echo "::set-output name=head::$commit" 35 | 36 | - name: Cache cargo registry index 37 | uses: actions/cache@v3 38 | with: 39 | path: /usr/local/cargo/registry/index 40 | key: cargo-index-${{ steps.ls-crates-io-index.outputs.head }} 41 | restore-keys: | 42 | cargo-index- 43 | 44 | - run: cargo audit 45 | -------------------------------------------------------------------------------- /.github/workflows/changelog.yml: -------------------------------------------------------------------------------- 1 | name: CHANGELOG 2 | 3 | on: 4 | pull_request: 5 | 6 | jobs: 7 | diff_changelog: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - run: git fetch origin master 12 | - run: | 13 | if [[ ! `git diff --exit-code origin/master -- CHANGELOG.md` ]] 14 | then 15 | echo "::warning file=CHANGELOG.md::CHANGELOG.md was not updated" 16 | fi 17 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Build Docker images for CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - 'ci/docker/Dockerfile' 9 | workflow_dispatch: 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Build Docker images 17 | run: | 18 | set -xe 19 | RUST_CI_IMAGE_TAG="ghcr.io/${{ github.repository_owner }}/jormungandr-rust-ci:latest" 20 | echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin 21 | docker build ./ci/docker/ --tag $RUST_CI_IMAGE_TAG 22 | docker push $RUST_CI_IMAGE_TAG 23 | -------------------------------------------------------------------------------- /.github/workflows/editorconfig.yml: -------------------------------------------------------------------------------- 1 | name: EditorConfig check 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | check: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: editorconfig-checker/action-editorconfig-checker@v1 15 | -------------------------------------------------------------------------------- /.github/workflows/python-scripts.yml: -------------------------------------------------------------------------------- 1 | name: Python scripts linters 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | lint: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Install linters 14 | run: pip3 install black 15 | 16 | - uses: actions/checkout@v3 17 | 18 | - name: Check formatting (black) 19 | run: black ./ci ./scripts --check 20 | -------------------------------------------------------------------------------- /.github/workflows/update-flake-lock.yml: -------------------------------------------------------------------------------- 1 | name: update-flake-lock 2 | on: 3 | workflow_dispatch: # allows manual triggering 4 | schedule: 5 | - cron: '0 0 * * 0' # runs weekly on Sunday at 00:00 6 | 7 | jobs: 8 | lockfile: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout repository 12 | uses: actions/checkout@v3 13 | - name: Install Nix 14 | uses: cachix/install-nix-action@v17 15 | with: 16 | extra_nix_config: | 17 | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} 18 | - name: Update flake.lock 19 | uses: DeterminateSystems/update-flake-lock@v14 20 | -------------------------------------------------------------------------------- /.github_changelog_generator: -------------------------------------------------------------------------------- 1 | user=input-output-hk 2 | project=jormungandr 3 | unreleased=false 4 | future-release=5.0.0 5 | since-tag=v0.1.0 6 | author=false 7 | max-issues=100 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/jormungandr/35d73ea50a021118a873fd0e365715736c16deb5/.gitmodules -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "jormungandr-lib", 4 | "jormungandr", 5 | "jcli", 6 | "explorer", 7 | "modules/settings", 8 | "modules/blockchain", 9 | "testing/jormungandr-automation", 10 | "testing/jormungandr-integration-tests", 11 | "testing/loki", 12 | "testing/mjolnir", 13 | "testing/hersir", 14 | "testing/thor", 15 | ] 16 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2019 Input Output HK 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Nicolas Di Prima"] 3 | multilingual = false 4 | src = "doc" 5 | title = "Jormungandr" 6 | 7 | [output.html] 8 | mathjax-support = true 9 | 10 | [output.linkcheck] 11 | # Should we check links on the internet? Enabling this option adds a 12 | # non-negligible performance impact 13 | follow-web-links = true 14 | 15 | # Are we allowed to link to files outside of the book's root directory? This 16 | # may help prevent linking to sensitive files (e.g. "../../../../etc/shadow") 17 | traverse-parent-directories = false 18 | -------------------------------------------------------------------------------- /ci/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.55-slim 2 | RUN apt-get update && apt-get install -y pkg-config libssl-dev && apt-get clean 3 | RUN cargo install cargo-audit 4 | -------------------------------------------------------------------------------- /ci/strip-own-version-from-cargo-lock.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -p 2 | 3 | BEGIN { 4 | $ln = 0; $ours = 0; 5 | } 6 | 7 | if (/^\[\[package\]\]/ .. ($ln == 2)) { 8 | if (/^name = "(jormungandr.*|jcli)"/) { 9 | $ours = 1; 10 | } else { 11 | s/^version =.*// if $ours; 12 | } 13 | ++$ln; 14 | } else { 15 | $ln = 0; $ours = 0; 16 | } 17 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | ( 2 | import 3 | ( 4 | let 5 | lock = builtins.fromJSON (builtins.readFile ./flake.lock); 6 | in 7 | fetchTarball { 8 | url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; 9 | sha256 = lock.nodes.flake-compat.locked.narHash; 10 | } 11 | ) 12 | {src = ./.;} 13 | ) 14 | .defaultNix 15 | -------------------------------------------------------------------------------- /doc/advanced/introduction.md: -------------------------------------------------------------------------------- 1 | # Advanced 2 | 3 | This section is meant for advanced users and developers of the node, or if 4 | you wish to learn more about the node. 5 | 6 | At the moment, it only covers details on how to create your own blockchain genesis 7 | configuration, but in normal case, the blockchain configuration should be available 8 | with the specific blockchain system. 9 | -------------------------------------------------------------------------------- /doc/concepts/introduction.md: -------------------------------------------------------------------------------- 1 | # General Concepts 2 | 3 | This chapter covers the general concepts of the blockchain, and their application 4 | in the node, and is followed by the node organisation and the user interaction with it. 5 | -------------------------------------------------------------------------------- /doc/configuration/leadership.md: -------------------------------------------------------------------------------- 1 | # Leadership 2 | 3 | The `leadership` field in your node config file is not mandatory, by default it is set 4 | as follow: 5 | 6 | ```yaml 7 | leadership: 8 | logs_capacity: 1024 9 | ``` 10 | 11 | * `logs_capacity`: the maximum number of logs to keep in memory. Once the capacity 12 | is reached, older logs will be removed in order to leave more space for new ones 13 | \[default: 1024\] 14 | -------------------------------------------------------------------------------- /doc/configuration/logging.md: -------------------------------------------------------------------------------- 1 | # Logging 2 | 3 | The following options are available in the `log` section: 4 | 5 | - `level`: log messages minimum severity. If not configured anywhere, defaults to `info`. 6 | Possible values: `off`, `critical`, `error`, `warn`, `info`, `debug`, `trace` 7 | 8 | - `format`: Log output format, `plain` or `json` 9 | 10 | - `output`: Log output destination (multiple destinations are supported). Possible values are: 11 | - `stdout`: standard output 12 | - `stderr`: standard error 13 | - `journald`: journald service (only available on Linux with systemd, 14 | (if jormungandr is built with the `systemd` feature) 15 | - `gelf`: Configuration fields for GELF (Graylog) network logging protocol 16 | (if jormungandr is built with the `gelf` feature): 17 | - `backend`: _hostname_:_port_ of a GELF server 18 | - `log_id`: identifier of the source of the log, for the `host` field in the messages 19 | - `file`: path to the log file 20 | 21 | ## Example 22 | 23 | A single configurable backend is supported. 24 | 25 | 26 | ### Output to stdout 27 | ```yaml 28 | log: 29 | output: stdout 30 | level: trace 31 | format: plain 32 | ``` 33 | 34 | ### Output to a file 35 | ```yaml 36 | log: 37 | output: 38 | file: example.log 39 | level: info 40 | format: json 41 | ``` 42 | -------------------------------------------------------------------------------- /doc/configuration/mempool.md: -------------------------------------------------------------------------------- 1 | # Mempool 2 | 3 | When running an active node (BFT leader or stake pool) it is interesting to be 4 | able to make choices on how to manage the pending transactions: how long to keep 5 | them, how to prioritize them etc. 6 | 7 | The `mempool` field in your node config file is not mandatory, by default it is set 8 | as follow: 9 | 10 | ```yaml 11 | mempool: 12 | pool_max_entries: 10000 13 | log_max_entries: 100000 14 | ``` 15 | 16 | * `pool_max_entries`: (optional, default is 10000). Set a maximum size of the mempool 17 | * `log_max_entries`: (optional, default is 100000). Set a maximum size of fragment logs 18 | * `persistent_log`: (optional, disabled by default) log all incoming fragments to log files, 19 | rotated on a hourly basis. The value is an object, with the `dir` field 20 | specifying the directory name where log files are stored. 21 | 22 | ## Persistent logs 23 | 24 | A persistent log is a collection of records comprised of a UNIX timestamp of when a fragment was 25 | registereed by the mempool followed by the hex-encoded fragment body. This log is a line-delimited 26 | JSON stream. 27 | 28 | Keep in mind that enabling persistent logs could result in impaired performance of the node if disk 29 | operations are slow. Consider using a reasonably fast ssd for best results. 30 | -------------------------------------------------------------------------------- /doc/configuration/prometheus.md: -------------------------------------------------------------------------------- 1 | # Prometheus 2 | 3 | ## Prerequisites 4 | 5 | To use Prometheus you need Jormungandr compiled with the `prometheus-metrics` feature enabled. 6 | 7 | ## Usage 8 | 9 | To enable Prometheus endpoint you need to enable it in the configuration file: 10 | 11 | ```yaml 12 | prometheus: 13 | enabled: true 14 | ``` 15 | 16 | Alternatively, you can use the `--prometheus-metrics` flag. 17 | 18 | When enabled, the Prometheus endpoint is exposed as `http(s)://:/prometheus`. 19 | -------------------------------------------------------------------------------- /doc/internal_design/architecture-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/jormungandr/35d73ea50a021118a873fd0e365715736c16deb5/doc/internal_design/architecture-1.png -------------------------------------------------------------------------------- /doc/internal_design/blockchain_structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/jormungandr/35d73ea50a021118a873fd0e365715736c16deb5/doc/internal_design/blockchain_structure.png -------------------------------------------------------------------------------- /doc/internal_design/blockchain_structure_block0.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | subgraph cluster_0 { 3 | style = filled; 4 | color = lightgrey; 5 | node [ style = filled; color = white ]; 6 | "block0"; 7 | label = "blocks"; 8 | } 9 | 10 | subgraph cluster_1 { 11 | node [style = filled, color = cyan ]; 12 | "ledger0"; 13 | color = none; 14 | } 15 | 16 | subgraph parameters { 17 | node [style = filled, color = orange ]; 18 | "epoch 1 parameters"; 19 | color = none; 20 | } 21 | 22 | subgraph stake { 23 | node [style = filled, color = pink ]; 24 | "epoch 0 stake distribution" ; 25 | color = none; 26 | } 27 | 28 | subgraph leadership { 29 | node [ color = red ]; 30 | "epoch 1 leadership" ; "epoch 2 leadership"; 31 | color = none; 32 | } 33 | 34 | "ledger0" -> "epoch 1 parameters" [ label = "create" ]; 35 | 36 | "ledger0" -> "epoch 0 stake distribution" [ label = "create" ]; 37 | 38 | "epoch 0 stake distribution" -> "epoch 1 leadership" [ label = "create" ]; 39 | "epoch 0 stake distribution" -> "epoch 2 leadership" [ label = "create" ]; 40 | 41 | "block0" -> "ledger0"; 42 | } 43 | -------------------------------------------------------------------------------- /doc/internal_design/blockchain_structure_block0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/jormungandr/35d73ea50a021118a873fd0e365715736c16deb5/doc/internal_design/blockchain_structure_block0.png -------------------------------------------------------------------------------- /doc/internal_design/blockchain_structure_blockk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/jormungandr/35d73ea50a021118a873fd0e365715736c16deb5/doc/internal_design/blockchain_structure_blockk.png -------------------------------------------------------------------------------- /doc/internal_design/blockchain_structure_transition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/jormungandr/35d73ea50a021118a873fd0e365715736c16deb5/doc/internal_design/blockchain_structure_transition.png -------------------------------------------------------------------------------- /doc/internal_design/network_nano_protocol_simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/jormungandr/35d73ea50a021118a873fd0e365715736c16deb5/doc/internal_design/network_nano_protocol_simple.png -------------------------------------------------------------------------------- /doc/introduction.md: -------------------------------------------------------------------------------- 1 | # Jörmungandr User Guide 2 | 3 | Welcome to the Jörmungandr User Guide. 4 | 5 | Jörmungandr is a node implementation, written in rust, with the 6 | initial aim to support the Ouroboros type of consensus protocol. 7 | 8 | A node is a participant of a blockchain network, continuously making, 9 | sending, receiving, and validating blocks. Each node is responsible 10 | to make sure that all the rules of the protocol are followed. 11 | 12 | ## Mythology 13 | 14 | Jörmungandr refers to the _Midgard Serpent_ in Norse mythology. It is a hint to 15 | _Ouroboros_, the Ancient Egyptian serpent, who eat its own tail, as well as the 16 | [IOHK paper](https://eprint.iacr.org/2016/889.pdf) on proof of stake. 17 | -------------------------------------------------------------------------------- /doc/jcli/genesis.md: -------------------------------------------------------------------------------- 1 | # Genesis 2 | 3 | Tooling for working with a genesis file 4 | 5 | ## Usage 6 | 7 | ```sh 8 | jcli genesis [subcommand] 9 | ``` 10 | 11 | ## Subcommands 12 | 13 | - decode: Print the YAML file corresponding to an encoded genesis block. 14 | - encode: Create the genesis block of the blockchain from a given yaml file. 15 | - hash: Print the block hash of the genesis 16 | - init: Create a default Genesis file with appropriate documentation to help creating the YAML file 17 | - help 18 | 19 | ## Examples 20 | 21 | ### Encode a genesis file 22 | 23 | ```sh 24 | jcli genesis encode --input genesis.yaml --output block-0.bin 25 | ``` 26 | 27 | or equivantely 28 | 29 | ```sh 30 | cat genesis.yaml | jcli genesis encode > block-0.bin 31 | ``` 32 | 33 | ### Get the hash of an encoded genesis file 34 | 35 | ```sh 36 | jcli genesis hash --input block-0.bin 37 | ``` 38 | -------------------------------------------------------------------------------- /doc/jcli/introduction.md: -------------------------------------------------------------------------------- 1 | # jcli 2 | 3 | This is the node command line helper. It is mostly meant for developers and 4 | stake pool operators. It allows offline operations: 5 | 6 | * generating cryptographic materials for the wallets and stake pools; 7 | * creating addresses, transactions and certificates; 8 | * prepare a new blockchain 9 | 10 | and it allows simple interactions with the node: 11 | 12 | * query stats; 13 | * send transactions and certificates; 14 | * get raw blocks and UTxOs. 15 | -------------------------------------------------------------------------------- /doc/quickstart/01_command_line.md: -------------------------------------------------------------------------------- 1 | # Command line tools 2 | 3 | The software is bundled with 2 different command line software: 4 | 5 | 1. **jormungandr**: the node; 6 | 2. **jcli**: Jörmungandr Command Line Interface, the helpers and primitives to run and interact with the node. 7 | 8 | ## Installation 9 | 10 | ### From a release 11 | 12 | This is the recommended method. Releases are all available 13 | [here](https://github.com/input-output-hk/jormungandr/releases). 14 | 15 | ### From source 16 | 17 | Jörmungandr's code source is available on 18 | [github](https://github.com/input-output-hk/jormungandr#how-to-install-from-sources). 19 | Follow the instructions to build the software from sources. 20 | 21 | ## Help and auto completion 22 | 23 | All commands come with usage help with the option `--help` or `-h`. 24 | 25 | For `jcli`, it is possible to generate the auto completion with: 26 | 27 | ```sh 28 | jcli auto-completion bash ${HOME}/.bash_completion.d 29 | ``` 30 | 31 | Supported shells are: 32 | 33 | - bash 34 | - fish 35 | - zsh 36 | - powershell 37 | - elvish 38 | 39 | **Note:** 40 | Make sure `${HOME}/.bash_completion.d` directory previously exists on your HD. 41 | In order to use auto completion you still need to: 42 | 43 | ```sh 44 | source ${HOME}/.bash_completion.d/jcli.bash 45 | ``` 46 | 47 | You can also put it in your `${HOME}/.bashrc`. 48 | -------------------------------------------------------------------------------- /doc/quickstart/03_rest_api.md: -------------------------------------------------------------------------------- 1 | # REST Api 2 | 3 | It is possible to query the node via its REST Interface. 4 | 5 | In the node configuration, you have set something like: 6 | 7 | ```yaml 8 | # ... 9 | 10 | rest: 11 | listen: "127.0.0.1:8443" 12 | 13 | #... 14 | ``` 15 | 16 | This is the REST endpoint to talk to the node, to query blocks or send transaction. 17 | 18 | It is possible to query the node stats with the following end point: 19 | 20 | ```sh 21 | curl http://127.0.0.1:8443/api/v0/node/stats 22 | ``` 23 | 24 | The result may be: 25 | 26 | ```json 27 | {"blockRecvCnt":120,"txRecvCnt":92,"uptime":245} 28 | ``` 29 | 30 | > THE REST API IS STILL UNDER DEVELOPMENT 31 | 32 | Please note that the end points and the results may change in the future. 33 | 34 | To see the whole Node API documentation, 35 | [click here](https://editor.swagger.io/?url=https://raw.githubusercontent.com/input-output-hk/jormungandr/master/doc/api/v0.yaml) 36 | -------------------------------------------------------------------------------- /doc/specs/introduction.md: -------------------------------------------------------------------------------- 1 | # Jormungandr Specifications 2 | 3 | This directory contains Jormungandr's specifications. 4 | 5 | | file | content | 6 | |:----:|:--------| 7 | | [network] | the node to node communication and the peer to peer topology | 8 | 9 | [network]: network.md 10 | -------------------------------------------------------------------------------- /doc/specs/quarantine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/input-output-hk/jormungandr/35d73ea50a021118a873fd0e365715736c16deb5/doc/specs/quarantine.png -------------------------------------------------------------------------------- /doc/stake_pool/introduction.md: -------------------------------------------------------------------------------- 1 | # Staking with Jörmungandr 2 | 3 | Here we will describe how to: 4 | 5 | * _delegate your stake to a stake pool_ - so that you can participate to the consensus and maybe collect rewards for that. 6 | * _register a stake pool_ 7 | * _retire a stake pool_ 8 | -------------------------------------------------------------------------------- /doc/testing/introduction.md: -------------------------------------------------------------------------------- 1 | # testing 2 | 3 | This section describes all libraries and tools in jormungandr repo which purpose is to satifsy quality needs of jormungandr and jcli components 4 | 5 | Jormungandr test libraries includes projects: 6 | 7 | * jormungandr-automation - sets of apis for automating all node calls and node sub-components (REST, GRPC, logging etc.), 8 | * hersir - api & cli for bootstrapping entire network of nodes with some predefined configuration. Project takes care of proper settings for all nodes as well as block0, 9 | * thor - testing api & cli for all wallet operations, 10 | * mjolnir - load tool (api & cli) for all kind of jormungandr transactions, 11 | * loki - api & cli for sending invalid/adversary load as well as boostraping adversary node. 12 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # Dockerfile 2 | 3 | Dockerfile used to build or download, and run jormungandr. 4 | 5 | ## Instructions 6 | 7 | The default build will download the latest release binaries. 8 | 9 | ### How To Build 10 | 11 | ```bash 12 | docker build -t jormungandr-node:0.1 . 13 | ``` 14 | 15 | #### Build Options 16 | 17 | The default build options are: 18 | - directory: /app 19 | - build mode: false 20 | - jormungandr version: v0.2.3 21 | 22 | These can be overridden during the docker build process: 23 | 24 | To run a different version 25 | ```bash 26 | docker build -t jormungandr-node:0.1 \ 27 | --build-arg VER=v0.2.2 . 28 | ``` 29 | 30 | To build from source: 31 | ```bash 32 | docker build -t jormungandr-node:0.1 \ 33 | --build-arg BUILD=true . 34 | ``` 35 | 36 | To build a different version from source: 37 | ```bash 38 | docker build -t jormungandr-node:0.1 \ 39 | --build-arg BUILD=true \ 40 | --build-arg VER=v0.2.2 . 41 | ``` 42 | 43 | ### How to run 44 | 45 | ```bash 46 | docker run jormungandr-node:0.1 47 | ``` 48 | -------------------------------------------------------------------------------- /explorer/src/api/graphql/error.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Error, Debug)] 4 | pub enum ApiError { 5 | #[error("internal error (this shouldn't happen) {0}")] 6 | InternalError(String), 7 | #[error("resource not found {0}")] 8 | NotFound(String), 9 | #[error("feature not implemented yet")] 10 | Unimplemented, 11 | #[error("invalid argument {0}")] 12 | ArgumentError(String), 13 | #[error("invalud pagination cursor {0}")] 14 | InvalidCursor(String), 15 | #[error("invalid address {0}")] 16 | InvalidAddress(String), 17 | } 18 | -------------------------------------------------------------------------------- /explorer/src/db/error.rs: -------------------------------------------------------------------------------- 1 | use chain_impl_mockchain::{ 2 | block::{ChainLength, HeaderId as HeaderHash}, 3 | fragment::FragmentId, 4 | }; 5 | use thiserror::Error; 6 | 7 | #[derive(Debug, Error, Clone)] 8 | pub enum ExplorerError { 9 | #[error(transparent)] 10 | BlockNotFound(#[from] BlockNotFound), 11 | #[error("ancestor of block '{0}' not found in explorer")] 12 | AncestorNotFound(HeaderHash), 13 | #[error("transaction '{0}' is already indexed")] 14 | TransactionAlreadyExists(FragmentId), 15 | #[error("tried to index block '{0}' twice")] 16 | BlockAlreadyExists(HeaderHash), 17 | #[error("block with {0} chain length already exists in explorer branch")] 18 | ChainLengthBlockAlreadyExists(ChainLength), 19 | #[error("the explorer's database couldn't be initialized: {0}")] 20 | BootstrapError(String), 21 | } 22 | 23 | #[derive(Debug, Error, Clone)] 24 | #[error("block {hash} not found in explorer")] 25 | pub struct BlockNotFound { 26 | pub hash: HeaderHash, 27 | } 28 | -------------------------------------------------------------------------------- /explorer/src/db/persistent_sequence.rs: -------------------------------------------------------------------------------- 1 | use imhamt::Hamt; 2 | use std::{collections::hash_map::DefaultHasher, sync::Arc}; 3 | 4 | // Use a Hamt to store a sequence, the indexes can be used for pagination 5 | // XXX: Maybe there is a better data structure for this? 6 | #[derive(Clone)] 7 | pub struct PersistentSequence { 8 | len: u64, 9 | elements: Hamt>, 10 | } 11 | 12 | impl PersistentSequence { 13 | pub fn new() -> Self { 14 | PersistentSequence { 15 | len: 0, 16 | elements: Hamt::new(), 17 | } 18 | } 19 | 20 | pub fn append(&self, t: T) -> Self { 21 | let len = self.len + 1; 22 | PersistentSequence { 23 | len, 24 | elements: self.elements.insert(len - 1, Arc::new(t)).unwrap(), 25 | } 26 | } 27 | 28 | pub fn get>(&self, i: I) -> Option<&Arc> { 29 | self.elements.lookup(&i.into()) 30 | } 31 | 32 | pub fn len(&self) -> u64 { 33 | self.len 34 | } 35 | 36 | pub fn is_empty(&self) -> bool { 37 | self.len() == 0 38 | } 39 | } 40 | 41 | impl Default for PersistentSequence { 42 | fn default() -> Self { 43 | PersistentSequence::new() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /explorer/src/db/set.rs: -------------------------------------------------------------------------------- 1 | use imhamt::{Hamt, HamtIter}; 2 | use std::collections::hash_map::DefaultHasher; 3 | use std::hash::Hash; 4 | 5 | #[derive(Clone)] 6 | pub struct HamtSet(Hamt); 7 | 8 | impl HamtSet { 9 | pub fn new() -> HamtSet { 10 | HamtSet(Hamt::new()) 11 | } 12 | 13 | pub fn add_element(&self, element: T) -> HamtSet { 14 | let new_hamt = match self.0.insert(element, ()) { 15 | Ok(new_hamt) => new_hamt, 16 | Err(_) => self.0.clone(), 17 | }; 18 | 19 | HamtSet(new_hamt) 20 | } 21 | 22 | pub fn iter(&self) -> HamtSetIter { 23 | HamtSetIter(self.0.iter()) 24 | } 25 | } 26 | 27 | pub struct HamtSetIter<'a, K>(HamtIter<'a, K, ()>); 28 | 29 | impl<'a, K> Iterator for HamtSetIter<'a, K> { 30 | type Item = &'a K; 31 | 32 | fn next(&mut self) -> Option { 33 | self.0.next().map(|(k, _v)| k) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /jcli/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let pkg_version = if let Ok(date) = std::env::var("DATE") { 3 | format!("{}.{}", env!("CARGO_PKG_VERSION"), date) 4 | } else { 5 | env!("CARGO_PKG_VERSION").to_string() 6 | }; 7 | 8 | println!("cargo:rustc-env=CARGO_PKG_VERSION={}", pkg_version); 9 | 10 | let version = versionisator::Version::new( 11 | env!("CARGO_MANIFEST_DIR"), 12 | env!("CARGO_PKG_NAME").to_string(), 13 | pkg_version, 14 | ); 15 | 16 | println!("cargo:rustc-env=FULL_VERSION={}", version.full()); 17 | println!("cargo:rustc-env=SIMPLE_VERSION={}", version.simple()); 18 | println!("cargo:rustc-env=SOURCE_VERSION={}", version.hash()); 19 | } 20 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/auto_completion.rs: -------------------------------------------------------------------------------- 1 | use std::path::{Path, PathBuf}; 2 | use structopt::{clap::Shell, StructOpt}; 3 | use thiserror::Error; 4 | 5 | #[derive(StructOpt)] 6 | #[structopt(rename_all = "kebab-case")] 7 | pub struct AutoCompletion { 8 | /// set the type shell for the auto completion output (bash, zsh...) 9 | shell: Shell, 10 | 11 | /// path to the directory to write the generated auto completion files 12 | output: PathBuf, 13 | } 14 | 15 | impl AutoCompletion { 16 | pub fn exec(self) -> Result<(), Error> { 17 | validate_output(&self.output)?; 18 | S::clap().gen_completions("jcli", self.shell, self.output); 19 | Ok(()) 20 | } 21 | } 22 | 23 | fn validate_output(output: &Path) -> Result<(), Error> { 24 | if !output.exists() { 25 | return Err(Error::OutputNotExist); 26 | } 27 | if !output.is_dir() { 28 | return Err(Error::OutputNotDir); 29 | } 30 | Ok(()) 31 | } 32 | 33 | #[derive(Debug, Error)] 34 | pub enum Error { 35 | #[error("output directory does not exist")] 36 | OutputNotExist, 37 | #[error("output is not a directory")] 38 | OutputNotDir, 39 | } 40 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/certificate/new_evm_mapping.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{ 2 | certificate::{write_cert, Error}, 3 | utils::key_parser::parse_pub_key, 4 | }; 5 | use chain_crypto::{Ed25519, PublicKey}; 6 | use chain_evm::ethereum_types::H160; 7 | use chain_impl_mockchain::certificate::{Certificate, EvmMapping}; 8 | use jormungandr_lib::interfaces::Certificate as CertificateType; 9 | use std::path::PathBuf; 10 | use structopt::StructOpt; 11 | 12 | #[derive(StructOpt, Debug)] 13 | #[structopt(rename_all = "kebab-case")] 14 | pub struct EvmMapCmd { 15 | /// jormungandr account id 16 | #[structopt(name = "ACCOUNT_KEY", parse(try_from_str = parse_pub_key))] 17 | account_id: PublicKey, 18 | /// hex encoded H160 address 19 | evm_address: H160, 20 | /// write the output to the given file or print it to the standard output if not defined 21 | #[structopt(short = "o", long = "output")] 22 | output: Option, 23 | } 24 | 25 | impl EvmMapCmd { 26 | pub fn exec(self) -> Result<(), Error> { 27 | let content = EvmMapping { 28 | account_id: self.account_id.into(), 29 | evm_address: self.evm_address, 30 | }; 31 | let cert = Certificate::EvmMapping(content); 32 | write_cert(self.output.as_deref(), CertificateType(cert)) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/certificate/new_owner_stake_delegation.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::certificate::{weighted_pool_ids::WeightedPoolIds, write_cert, Error}; 2 | use chain_impl_mockchain::certificate::{Certificate, OwnerStakeDelegation as Delegation}; 3 | use jormungandr_lib::interfaces::Certificate as CertificateType; 4 | use std::{convert::TryInto, path::PathBuf}; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | pub struct OwnerStakeDelegation { 9 | #[structopt(flatten)] 10 | pool_ids: WeightedPoolIds, 11 | 12 | /// write the output to the given file or print it to the standard output if not defined 13 | #[structopt(short = "o", long = "output")] 14 | output: Option, 15 | } 16 | 17 | impl OwnerStakeDelegation { 18 | pub fn exec(self) -> Result<(), Error> { 19 | let cert = Certificate::OwnerStakeDelegation(Delegation { 20 | delegation: (&self.pool_ids).try_into()?, 21 | }); 22 | write_cert(self.output.as_deref(), CertificateType(cert)) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/certificate/new_update_vote.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{ 2 | certificate::{write_cert, Error}, 3 | utils::key_parser::parse_pub_key, 4 | }; 5 | use chain_crypto::{Ed25519, PublicKey}; 6 | use chain_impl_mockchain::certificate::{self, Certificate, UpdateProposalId}; 7 | use std::path::PathBuf; 8 | use structopt::StructOpt; 9 | 10 | #[derive(StructOpt)] 11 | pub struct UpdateVote { 12 | /// the Proposal ID of the proposal. 13 | #[structopt(name = "PROPOSAL_ID")] 14 | proposal_id: UpdateProposalId, 15 | 16 | /// the voter ID. 17 | #[structopt(name = "VOTER_ID", parse(try_from_str = parse_pub_key))] 18 | voter_id: PublicKey, 19 | 20 | /// print the output signed certificate in the given file, if no file given 21 | /// the output will be printed in the standard output 22 | output: Option, 23 | } 24 | 25 | impl UpdateVote { 26 | pub fn exec(self) -> Result<(), Error> { 27 | let update_vote = certificate::UpdateVote::new(self.proposal_id, self.voter_id.into()); 28 | let cert = Certificate::UpdateVote(update_vote); 29 | write_cert(self.output.as_deref(), cert.into()) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/certificate/show.rs: -------------------------------------------------------------------------------- 1 | mod stake_pool_id; 2 | mod vote_plan_id; 3 | 4 | use crate::jcli_lib::certificate::Error; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub enum ShowArgs { 10 | /// get the stake pool id from the given stake pool registration certificate 11 | StakePoolId(stake_pool_id::GetStakePoolId), 12 | /// get the vote plan id from the given vote plan certificate 13 | VotePlanId(vote_plan_id::GetVotePlanId), 14 | } 15 | 16 | impl ShowArgs { 17 | pub fn exec(self) -> Result<(), Error> { 18 | match self { 19 | ShowArgs::StakePoolId(args) => args.exec(), 20 | ShowArgs::VotePlanId(args) => args.exec(), 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/certificate/show/stake_pool_id.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::certificate::{read_cert_or_signed_cert, write_output, Error}; 2 | use chain_impl_mockchain::certificate::Certificate; 3 | use jormungandr_lib::interfaces::Certificate as CertificateType; 4 | use std::path::PathBuf; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub struct GetStakePoolId { 10 | /// file to read the certificate from (defaults to stdin) 11 | #[structopt(long, parse(from_os_str), value_name = "PATH")] 12 | pub input: Option, 13 | /// file to write the output to (defaults to stdout) 14 | #[structopt(long, parse(from_os_str), value_name = "PATH")] 15 | pub output: Option, 16 | } 17 | 18 | impl GetStakePoolId { 19 | pub fn exec(self) -> Result<(), Error> { 20 | let cert: CertificateType = read_cert_or_signed_cert(self.input.as_deref())?; 21 | match cert.0 { 22 | Certificate::PoolRegistration(stake_pool_info) => { 23 | write_output(self.output.as_deref(), stake_pool_info.to_id()) 24 | } 25 | Certificate::PoolRetirement(stake_pool_info) => { 26 | write_output(self.output.as_deref(), stake_pool_info.pool_id) 27 | } 28 | _ => Err(Error::NotStakePoolRegistration), 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/certificate/show/vote_plan_id.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::certificate::{read_cert_or_signed_cert, write_output, Error}; 2 | use chain_impl_mockchain::certificate::Certificate; 3 | use jormungandr_lib::interfaces::Certificate as CertificateType; 4 | use std::path::PathBuf; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub struct GetVotePlanId { 10 | /// file to read the certificate from (defaults to stdin) 11 | #[structopt(long, parse(from_os_str), value_name = "PATH")] 12 | pub input: Option, 13 | /// file to write the output to (defaults to stdout) 14 | #[structopt(long, parse(from_os_str), value_name = "PATH")] 15 | pub output: Option, 16 | } 17 | 18 | impl GetVotePlanId { 19 | pub fn exec(self) -> Result<(), Error> { 20 | let cert: CertificateType = read_cert_or_signed_cert(self.input.as_deref())?; 21 | match cert.0 { 22 | Certificate::VotePlan(vote_plan_info) => { 23 | write_output(self.output.as_deref(), vote_plan_info.to_id()) 24 | } 25 | _ => Err(Error::NotVotePlanCertificate), 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/debug/block.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{debug::Error, utils::io}; 2 | use chain_core::{packer::Codec, property::Deserialize as _}; 3 | use chain_impl_mockchain::block::Block as BlockMock; 4 | use std::{ 5 | io::{BufRead, BufReader}, 6 | path::PathBuf, 7 | }; 8 | use structopt::StructOpt; 9 | 10 | #[derive(StructOpt)] 11 | pub struct Block { 12 | /// file containing hex-encoded message. If not provided, it will be read from stdin. 13 | #[structopt(short, long)] 14 | input: Option, 15 | } 16 | 17 | impl Block { 18 | pub fn exec(self) -> Result<(), Error> { 19 | let reader = io::open_file_read(&self.input).map_err(|source| Error::InputInvalid { 20 | source, 21 | path: self.input.unwrap_or_default(), 22 | })?; 23 | let mut hex_str = String::new(); 24 | BufReader::new(reader).read_line(&mut hex_str)?; 25 | let bytes = hex::decode(hex_str.trim())?; 26 | let message = BlockMock::deserialize(&mut Codec::new(bytes.as_slice())) 27 | .map_err(Error::MessageMalformed)?; 28 | println!("{:#?}", message); 29 | Ok(()) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/debug/message.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{debug::Error, utils::io}; 2 | use chain_core::{packer::Codec, property::DeserializeFromSlice as _}; 3 | use chain_impl_mockchain::fragment::Fragment as MockFragment; 4 | use std::{ 5 | io::{BufRead, BufReader}, 6 | path::PathBuf, 7 | }; 8 | use structopt::StructOpt; 9 | 10 | #[derive(StructOpt)] 11 | pub struct Message { 12 | /// file containing hex-encoded message. If not provided, it will be read from stdin. 13 | #[structopt(short, long)] 14 | input: Option, 15 | } 16 | 17 | impl Message { 18 | pub fn exec(self) -> Result<(), Error> { 19 | let reader = io::open_file_read(&self.input).map_err(|source| Error::InputInvalid { 20 | source, 21 | path: self.input.unwrap_or_default(), 22 | })?; 23 | let mut hex_str = String::new(); 24 | BufReader::new(reader).read_line(&mut hex_str)?; 25 | let bytes = hex::decode(hex_str.trim())?; 26 | let message = MockFragment::deserialize_from_slice(&mut Codec::new(bytes.as_slice())) 27 | .map_err(Error::MessageMalformed)?; 28 | println!("{:#?}", message); 29 | Ok(()) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/debug/mod.rs: -------------------------------------------------------------------------------- 1 | mod block; 2 | mod message; 3 | use chain_core::property::ReadError; 4 | use hex::FromHexError; 5 | use std::path::PathBuf; 6 | use structopt::StructOpt; 7 | use thiserror::Error; 8 | 9 | #[derive(StructOpt)] 10 | #[structopt(rename_all = "kebab-case")] 11 | pub enum Debug { 12 | /// Decode hex-encoded message and display its content 13 | Message(message::Message), 14 | /// Decode hex-encoded block and display its content 15 | Block(block::Block), 16 | } 17 | 18 | #[derive(Debug, Error)] 19 | pub enum Error { 20 | #[error("I/O Error")] 21 | Io(#[from] std::io::Error), 22 | #[error("invalid input file path '{path}'")] 23 | InputInvalid { 24 | #[source] 25 | source: std::io::Error, 26 | path: PathBuf, 27 | }, 28 | #[error("hex encoding malformed")] 29 | HexMalformed(#[from] FromHexError), 30 | #[error("message malformed")] 31 | MessageMalformed(#[source] ReadError), 32 | } 33 | 34 | impl Debug { 35 | pub fn exec(self) -> Result<(), Error> { 36 | match self { 37 | Debug::Message(message) => message.exec(), 38 | Debug::Block(block) => block.exec(), 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/block/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::rest::Error; 2 | use structopt::StructOpt; 3 | 4 | mod next_id; 5 | mod subcommand; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub struct Block { 10 | /// ID of the block 11 | block_id: String, 12 | 13 | #[structopt(subcommand)] 14 | subcommand: subcommand::Subcommand, 15 | } 16 | 17 | impl Block { 18 | pub fn exec(self) -> Result<(), Error> { 19 | self.subcommand.exec(self.block_id) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/block/next_id.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::rest::{Error, RestArgs}; 2 | use chain_crypto::Blake2b256; 3 | use structopt::StructOpt; 4 | 5 | #[derive(StructOpt)] 6 | #[structopt(rename_all = "kebab-case")] 7 | pub enum NextId { 8 | /// Get block descendant ID 9 | Get { 10 | #[structopt(flatten)] 11 | args: RestArgs, 12 | /// Maximum number of IDs, must be between 1 and 100, default 1 13 | #[structopt(short, long)] 14 | count: Option, 15 | }, 16 | } 17 | 18 | impl NextId { 19 | pub fn exec(self, block_id: String) -> Result<(), Error> { 20 | match self { 21 | NextId::Get { args, count } => exec_get(args, block_id, count), 22 | } 23 | } 24 | } 25 | 26 | fn exec_get(args: RestArgs, block_id: String, count: Option) -> Result<(), Error> { 27 | let response = args 28 | .client()? 29 | .get(&["v0", "block", &block_id, "next_id"]) 30 | .query(&[("count", count)]) 31 | .execute()? 32 | .bytes()?; 33 | for block_id in response.chunks(Blake2b256::HASH_SIZE) { 34 | println!("{}", hex::encode(block_id)); 35 | } 36 | Ok(()) 37 | } 38 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/block/subcommand.rs: -------------------------------------------------------------------------------- 1 | use super::next_id::NextId; 2 | use crate::jcli_lib::rest::{Error, RestArgs}; 3 | use structopt::StructOpt; 4 | 5 | #[derive(StructOpt)] 6 | #[structopt(rename_all = "kebab-case")] 7 | pub enum Subcommand { 8 | /// Get block 9 | Get { 10 | #[structopt(flatten)] 11 | args: RestArgs, 12 | }, 13 | /// Get block descendant ID 14 | NextId(NextId), 15 | } 16 | 17 | impl Subcommand { 18 | pub fn exec(self, block_id: String) -> Result<(), Error> { 19 | match self { 20 | Subcommand::Get { args } => exec_get(block_id, args), 21 | Subcommand::NextId(next_id) => next_id.exec(block_id), 22 | } 23 | } 24 | } 25 | 26 | fn exec_get(block_id: String, args: RestArgs) -> Result<(), Error> { 27 | let response = args 28 | .client()? 29 | .get(&["v0", "block", &block_id]) 30 | .execute()? 31 | .bytes()?; 32 | println!("{}", hex::encode(&response)); 33 | Ok(()) 34 | } 35 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/diagnostic/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::rest::{Error, RestArgs}; 2 | use structopt::StructOpt; 3 | 4 | #[derive(StructOpt)] 5 | #[structopt(rename_all = "kebab-case")] 6 | pub enum Diagnostic { 7 | /// Get system diagnostic information 8 | Get { 9 | #[structopt(flatten)] 10 | args: RestArgs, 11 | }, 12 | } 13 | 14 | impl Diagnostic { 15 | pub fn exec(self) -> Result<(), Error> { 16 | let args = match self { 17 | Diagnostic::Get { args } => args, 18 | }; 19 | let response = args 20 | .client()? 21 | .get(&["v0", "diagnostic"]) 22 | .execute()? 23 | .text()?; 24 | println!("{}", response); 25 | Ok(()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/leaders/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{ 2 | rest::{Error, RestArgs}, 3 | utils::OutputFormat, 4 | }; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub enum Leaders { 10 | /// Leadership log operations 11 | Logs(GetLogs), 12 | } 13 | 14 | #[derive(StructOpt)] 15 | #[structopt(rename_all = "kebab-case")] 16 | pub enum GetLogs { 17 | /// Get leadership log 18 | Get { 19 | #[structopt(flatten)] 20 | args: RestArgs, 21 | #[structopt(flatten)] 22 | output_format: OutputFormat, 23 | }, 24 | } 25 | 26 | impl Leaders { 27 | pub fn exec(self) -> Result<(), Error> { 28 | match self { 29 | Leaders::Logs(GetLogs::Get { 30 | args, 31 | output_format, 32 | }) => get_logs(args, output_format), 33 | } 34 | } 35 | } 36 | 37 | fn get_logs(args: RestArgs, output_format: OutputFormat) -> Result<(), Error> { 38 | let response = args 39 | .client()? 40 | .get(&["v0", "leaders", "logs"]) 41 | .execute()? 42 | .json()?; 43 | let formatted = output_format.format_json(response)?; 44 | println!("{}", formatted); 45 | Ok(()) 46 | } 47 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/network/mod.rs: -------------------------------------------------------------------------------- 1 | mod stats; 2 | 3 | use self::stats::Stats; 4 | use crate::jcli_lib::rest::Error; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub enum Network { 10 | /// Network information 11 | Stats(Stats), 12 | } 13 | 14 | impl Network { 15 | pub fn exec(self) -> Result<(), Error> { 16 | match self { 17 | Network::Stats(stats) => stats.exec(), 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/network/stats.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{ 2 | rest::{Error, RestArgs}, 3 | utils::OutputFormat, 4 | }; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub enum Stats { 10 | /// Get network information 11 | Get { 12 | #[structopt(flatten)] 13 | args: RestArgs, 14 | #[structopt(flatten)] 15 | output_format: OutputFormat, 16 | }, 17 | } 18 | 19 | impl Stats { 20 | pub fn exec(self) -> Result<(), Error> { 21 | let Stats::Get { 22 | args, 23 | output_format, 24 | } = self; 25 | let response = args 26 | .client()? 27 | .get(&["v0", "network", "stats"]) 28 | .execute()? 29 | .json()?; 30 | let formatted = output_format.format_json(response)?; 31 | println!("{}", formatted); 32 | Ok(()) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/node/mod.rs: -------------------------------------------------------------------------------- 1 | mod stats; 2 | 3 | use self::stats::Stats; 4 | use crate::jcli_lib::rest::Error; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub enum Node { 10 | /// Node information 11 | Stats(Stats), 12 | } 13 | 14 | impl Node { 15 | pub fn exec(self) -> Result<(), Error> { 16 | match self { 17 | Node::Stats(stats) => stats.exec(), 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/node/stats.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{ 2 | rest::{Error, RestArgs}, 3 | utils::OutputFormat, 4 | }; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub enum Stats { 10 | /// Get node information 11 | Get { 12 | #[structopt(flatten)] 13 | args: RestArgs, 14 | #[structopt(flatten)] 15 | output_format: OutputFormat, 16 | }, 17 | } 18 | 19 | impl Stats { 20 | pub fn exec(self) -> Result<(), Error> { 21 | let Stats::Get { 22 | args, 23 | output_format, 24 | } = self; 25 | let response = args 26 | .client()? 27 | .get(&["v0", "node", "stats"]) 28 | .execute()? 29 | .json()?; 30 | let formatted = output_format.format_json(response)?; 31 | println!("{}", formatted); 32 | Ok(()) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/rewards/epoch.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::rest::{Error, RestArgs}; 2 | use structopt::StructOpt; 3 | 4 | #[derive(StructOpt)] 5 | #[structopt(rename_all = "kebab-case")] 6 | pub enum Epoch { 7 | /// Get rewards for epoch 8 | Get { 9 | #[structopt(flatten)] 10 | args: RestArgs, 11 | /// Epoch number 12 | epoch: u32, 13 | }, 14 | } 15 | 16 | impl Epoch { 17 | pub fn exec(self) -> Result<(), Error> { 18 | let Epoch::Get { args, epoch } = self; 19 | let response = args 20 | .client()? 21 | .get(&["v0", "rewards", "epoch", &epoch.to_string()]) 22 | .execute()? 23 | .text()?; 24 | println!("{}", response); 25 | Ok(()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/rewards/history.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::rest::{Error, RestArgs}; 2 | use structopt::StructOpt; 3 | 4 | #[derive(StructOpt)] 5 | #[structopt(rename_all = "kebab-case")] 6 | pub enum History { 7 | /// Get rewards for one or more epochs 8 | Get { 9 | #[structopt(flatten)] 10 | args: RestArgs, 11 | /// Number of epochs 12 | length: usize, 13 | }, 14 | } 15 | 16 | impl History { 17 | pub fn exec(self) -> Result<(), Error> { 18 | let History::Get { args, length } = self; 19 | let response = args 20 | .client()? 21 | .get(&["v0", "rewards", "history", &length.to_string()]) 22 | .execute()? 23 | .text()?; 24 | println!("{}", response); 25 | Ok(()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/rewards/mod.rs: -------------------------------------------------------------------------------- 1 | mod epoch; 2 | mod history; 3 | 4 | use self::{epoch::Epoch, history::History}; 5 | use crate::jcli_lib::rest::Error; 6 | use structopt::StructOpt; 7 | 8 | #[derive(StructOpt)] 9 | #[structopt(name = "rewards", rename_all = "kebab-case")] 10 | pub enum Rewards { 11 | /// Rewards distribution history one or more epochs starting from the last one 12 | History(History), 13 | /// Rewards distribution for a specific epoch 14 | Epoch(Epoch), 15 | } 16 | 17 | impl Rewards { 18 | pub fn exec(self) -> Result<(), Error> { 19 | match self { 20 | Rewards::History(history) => history.exec(), 21 | Rewards::Epoch(epoch) => epoch.exec(), 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/settings/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{ 2 | rest::{Error, RestArgs}, 3 | utils::OutputFormat, 4 | }; 5 | use jormungandr_lib::interfaces::SettingsDto; 6 | use structopt::StructOpt; 7 | 8 | #[derive(StructOpt)] 9 | #[structopt(rename_all = "kebab-case")] 10 | pub enum Settings { 11 | /// Get node settings 12 | Get { 13 | #[structopt(flatten)] 14 | args: RestArgs, 15 | #[structopt(flatten)] 16 | output_format: OutputFormat, 17 | }, 18 | } 19 | 20 | impl Settings { 21 | pub fn exec(self) -> Result<(), Error> { 22 | let Settings::Get { 23 | args, 24 | output_format, 25 | } = self; 26 | let settings = request_settings(args)?; 27 | let formatted = output_format.format_json(serde_json::to_value(&settings)?)?; 28 | println!("{}", formatted); 29 | Ok(()) 30 | } 31 | } 32 | 33 | pub fn request_settings(args: RestArgs) -> Result { 34 | serde_json::from_str(&(args.client()?.get(&["v0", "settings"]).execute()?.text()?)) 35 | .map_err(Error::SerdeError) 36 | } 37 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/shutdown/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::rest::{Error, RestArgs}; 2 | use structopt::StructOpt; 3 | 4 | /// Shutdown node 5 | #[derive(StructOpt)] 6 | #[structopt(rename_all = "kebab-case")] 7 | pub enum Shutdown { 8 | Post { 9 | #[structopt(flatten)] 10 | args: RestArgs, 11 | }, 12 | } 13 | 14 | impl Shutdown { 15 | pub fn exec(self) -> Result<(), Error> { 16 | let Shutdown::Post { args } = self; 17 | args.client()?.get(&["v0", "shutdown"]).execute()?; 18 | println!("Success"); 19 | Ok(()) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/stake/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{ 2 | rest::{Error, RestArgs}, 3 | utils::OutputFormat, 4 | }; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub enum Stake { 10 | /// Get stake distribution 11 | Get { 12 | #[structopt(flatten)] 13 | args: RestArgs, 14 | #[structopt(flatten)] 15 | output_format: OutputFormat, 16 | /// Epoch to get the stake distribution from 17 | epoch: Option, 18 | }, 19 | } 20 | 21 | impl Stake { 22 | pub fn exec(self) -> Result<(), Error> { 23 | let Stake::Get { 24 | args, 25 | output_format, 26 | epoch, 27 | } = self; 28 | let epoch = epoch.map(|epoch| epoch.to_string()); 29 | let mut url = vec!["v0", "stake"]; 30 | if let Some(epoch) = &epoch { 31 | url.push(epoch); 32 | } 33 | let response = args.client()?.get(&url).execute()?.json()?; 34 | let formatted = output_format.format_json(response)?; 35 | println!("{}", formatted); 36 | Ok(()) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/stake_pool/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{ 2 | rest::{Error, RestArgs}, 3 | utils::OutputFormat, 4 | }; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub enum StakePool { 10 | /// Get stake pool details 11 | Get { 12 | #[structopt(flatten)] 13 | args: RestArgs, 14 | /// hex-encoded pool ID 15 | pool_id: String, 16 | #[structopt(flatten)] 17 | output_format: OutputFormat, 18 | }, 19 | } 20 | 21 | impl StakePool { 22 | pub fn exec(self) -> Result<(), Error> { 23 | let StakePool::Get { 24 | args, 25 | pool_id, 26 | output_format, 27 | } = self; 28 | let response = args 29 | .client()? 30 | .get(&["v0", "stake_pool", &pool_id]) 31 | .execute()? 32 | .json()?; 33 | let formatted = output_format.format_json(response)?; 34 | println!("{}", formatted); 35 | Ok(()) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/stake_pools/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{ 2 | rest::{Error, RestArgs}, 3 | utils::OutputFormat, 4 | }; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub enum StakePools { 10 | /// Get stake pool IDs 11 | Get { 12 | #[structopt(flatten)] 13 | args: RestArgs, 14 | #[structopt(flatten)] 15 | output_format: OutputFormat, 16 | }, 17 | } 18 | 19 | impl StakePools { 20 | pub fn exec(self) -> Result<(), Error> { 21 | let StakePools::Get { 22 | args, 23 | output_format, 24 | } = self; 25 | let response = args 26 | .client()? 27 | .get(&["v0", "stake_pools"]) 28 | .execute()? 29 | .json()?; 30 | let formatted = output_format.format_json(response)?; 31 | println!("{}", formatted); 32 | Ok(()) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/tip/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::rest::{Error, RestArgs}; 2 | use structopt::StructOpt; 3 | 4 | #[derive(StructOpt)] 5 | #[structopt(rename_all = "kebab-case")] 6 | pub enum Tip { 7 | /// Get tip ID 8 | Get { 9 | #[structopt(flatten)] 10 | args: RestArgs, 11 | }, 12 | } 13 | 14 | impl Tip { 15 | pub fn exec(self) -> Result<(), Error> { 16 | let args = match self { 17 | Tip::Get { args } => args, 18 | }; 19 | let response = args.client()?.get(&["v0", "tip"]).execute()?.text()?; 20 | println!("{}", response); 21 | Ok(()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/vote/active.rs: -------------------------------------------------------------------------------- 1 | use super::{committees::Committees, plans::Plans}; 2 | use crate::jcli_lib::rest::Error; 3 | use structopt::StructOpt; 4 | 5 | #[derive(StructOpt)] 6 | #[structopt(rename_all = "kebab-case")] 7 | pub enum Active { 8 | /// Committee members 9 | Committees(Committees), 10 | /// Active vote plans 11 | Plans(Plans), 12 | } 13 | 14 | impl Active { 15 | pub fn exec(self) -> Result<(), Error> { 16 | match self { 17 | Active::Committees(committees) => committees.exec(), 18 | Active::Plans(plans) => plans.exec(), 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/vote/committees.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{ 2 | rest::{Error, RestArgs}, 3 | utils::OutputFormat, 4 | }; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub enum Committees { 10 | /// Get committee members list 11 | Get { 12 | #[structopt(flatten)] 13 | args: RestArgs, 14 | #[structopt(flatten)] 15 | output_format: OutputFormat, 16 | }, 17 | } 18 | 19 | impl Committees { 20 | pub fn exec(self) -> Result<(), Error> { 21 | let Committees::Get { 22 | args, 23 | output_format, 24 | } = self; 25 | let response = args 26 | .client()? 27 | .get(&["v0", "vote", "active", "committees"]) 28 | .execute()? 29 | .json()?; 30 | let formatted = output_format.format_json(response)?; 31 | println!("{}", formatted); 32 | Ok(()) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/vote/mod.rs: -------------------------------------------------------------------------------- 1 | mod active; 2 | mod committees; 3 | mod plans; 4 | 5 | use self::active::Active; 6 | use crate::jcli_lib::rest::Error; 7 | use structopt::StructOpt; 8 | 9 | #[derive(StructOpt)] 10 | #[structopt(name = "active", rename_all = "kebab-case")] 11 | pub enum Vote { 12 | /// Active vote related operations 13 | Active(Active), 14 | } 15 | 16 | impl Vote { 17 | pub fn exec(self) -> Result<(), Error> { 18 | match self { 19 | Vote::Active(active) => active.exec(), 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v0/vote/plans.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{ 2 | rest::{Error, RestArgs}, 3 | utils::OutputFormat, 4 | }; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub enum Plans { 10 | /// Get active vote plans list 11 | Get { 12 | #[structopt(flatten)] 13 | args: RestArgs, 14 | #[structopt(flatten)] 15 | output_format: OutputFormat, 16 | }, 17 | } 18 | 19 | impl Plans { 20 | pub fn exec(self) -> Result<(), Error> { 21 | let Plans::Get { 22 | args, 23 | output_format, 24 | } = self; 25 | let response = args 26 | .client()? 27 | .get(&["v0", "vote", "active", "plans"]) 28 | .execute()? 29 | .json()?; 30 | let formatted = output_format.format_json(response)?; 31 | println!("{}", formatted); 32 | Ok(()) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/rest/v1/mod.rs: -------------------------------------------------------------------------------- 1 | mod vote; 2 | 3 | use crate::jcli_lib::rest::Error; 4 | use structopt::StructOpt; 5 | 6 | #[derive(StructOpt)] 7 | #[structopt(rename_all = "kebab-case")] 8 | pub enum V1 { 9 | Vote(vote::Vote), 10 | } 11 | 12 | impl V1 { 13 | pub fn exec(self) -> Result<(), Error> { 14 | match self { 15 | V1::Vote(vote) => vote.exec(), 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/transaction/add_account.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::transaction::{common, Error}; 2 | use jormungandr_lib::interfaces; 3 | use structopt::StructOpt; 4 | 5 | #[derive(StructOpt)] 6 | #[structopt(rename_all = "kebab-case")] 7 | pub struct AddAccount { 8 | #[structopt(flatten)] 9 | pub common: common::CommonTransaction, 10 | 11 | /// the account to debit the funds from 12 | #[structopt(name = "ACCOUNT")] 13 | pub account: interfaces::Address, 14 | 15 | /// the value 16 | #[structopt(name = "VALUE")] 17 | pub value: interfaces::Value, 18 | } 19 | 20 | impl AddAccount { 21 | pub fn exec(self) -> Result<(), Error> { 22 | let mut transaction = self.common.load()?; 23 | transaction.add_account(self.account, self.value)?; 24 | self.common.store(&transaction) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/transaction/add_certificate.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::transaction::{common, Error}; 2 | use jormungandr_lib::interfaces::Certificate; 3 | use structopt::StructOpt; 4 | 5 | #[derive(StructOpt)] 6 | #[structopt(rename_all = "kebab-case")] 7 | pub struct AddCertificate { 8 | #[structopt(flatten)] 9 | pub common: common::CommonTransaction, 10 | 11 | /// bech32-encoded certificate 12 | pub certificate: Certificate, 13 | } 14 | 15 | impl AddCertificate { 16 | pub fn exec(self) -> Result<(), Error> { 17 | let mut transaction = self.common.load()?; 18 | transaction.set_extra(self.certificate)?; 19 | self.common.store(&transaction) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/transaction/add_output.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::transaction::{common, Error}; 2 | use chain_impl_mockchain::transaction::Output; 3 | use jormungandr_lib::interfaces; 4 | use structopt::StructOpt; 5 | 6 | #[derive(StructOpt)] 7 | #[structopt(rename_all = "kebab-case")] 8 | pub struct AddOutput { 9 | #[structopt(flatten)] 10 | pub common: common::CommonTransaction, 11 | 12 | /// the UTxO address or account address to credit funds to 13 | #[structopt(name = "ADDRESS")] 14 | pub address: interfaces::Address, 15 | 16 | /// the value 17 | #[structopt(name = "VALUE")] 18 | pub value: interfaces::Value, 19 | } 20 | 21 | impl AddOutput { 22 | pub fn exec(self) -> Result<(), Error> { 23 | let mut transaction = self.common.load()?; 24 | 25 | transaction.add_output(Output { 26 | address: self.address.into(), 27 | value: self.value.into(), 28 | })?; 29 | 30 | self.common.store(&transaction) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/transaction/auth.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::{ 2 | certificate::read_input, 3 | transaction::{common, Error}, 4 | }; 5 | use std::path::PathBuf; 6 | use structopt::StructOpt; 7 | 8 | #[derive(StructOpt)] 9 | #[structopt(rename_all = "kebab-case")] 10 | pub struct Auth { 11 | #[structopt(flatten)] 12 | pub common: common::CommonTransaction, 13 | /// path to the file with the signing key 14 | #[structopt(short = "k", long = "key")] 15 | pub signing_keys: Vec, 16 | } 17 | 18 | impl Auth { 19 | pub fn exec(self) -> Result<(), Error> { 20 | let mut transaction = self.common.load()?; 21 | 22 | if self.signing_keys.is_empty() { 23 | return Err(Error::NoSigningKeys); 24 | } 25 | 26 | let keys_str: Result, Error> = self 27 | .signing_keys 28 | .iter() 29 | .map(|sk| { 30 | read_input(Some(sk.as_ref())).map_err(|e| Error::CertificateError { error: e }) 31 | }) 32 | .collect(); 33 | let keys_str = keys_str?; 34 | 35 | transaction.set_auth(&keys_str)?; 36 | 37 | self.common.store(&transaction) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/transaction/finalize.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | jcli_lib::transaction::{common, Error}, 3 | transaction::staging::Staging, 4 | }; 5 | use chain_impl_mockchain::transaction::OutputPolicy; 6 | use jormungandr_lib::interfaces; 7 | use structopt::StructOpt; 8 | 9 | #[derive(StructOpt)] 10 | #[structopt(rename_all = "kebab-case")] 11 | pub struct Finalize { 12 | #[structopt(flatten)] 13 | pub common: common::CommonTransaction, 14 | 15 | #[structopt(flatten)] 16 | pub fee: common::CommonFees, 17 | 18 | /// Set the change in the given address 19 | pub change: Option, 20 | } 21 | 22 | impl Finalize { 23 | pub fn exec(self) -> Result<(), Error> { 24 | let mut transaction = self.common.load()?; 25 | 26 | finalize(self.fee, self.change, &mut transaction)?; 27 | 28 | self.common.store(&transaction)?; 29 | Ok(()) 30 | } 31 | } 32 | 33 | pub fn finalize( 34 | fee: common::CommonFees, 35 | change: Option, 36 | transaction: &mut Staging, 37 | ) -> Result<(), Error> { 38 | let fee_algo = fee.linear_fee(); 39 | let output_policy = match change { 40 | None => OutputPolicy::Forget, 41 | Some(change) => OutputPolicy::One(change.into()), 42 | }; 43 | let _balance = transaction.balance_inputs_outputs(&fee_algo, output_policy)?; 44 | Ok(()) 45 | } 46 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/transaction/new.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::transaction::{common, staging::Staging, Error}; 2 | use structopt::StructOpt; 3 | 4 | #[derive(StructOpt)] 5 | #[structopt(rename_all = "kebab-case")] 6 | pub struct New { 7 | #[structopt(flatten)] 8 | pub common: common::CommonTransaction, 9 | } 10 | 11 | impl New { 12 | pub fn exec(self) -> Result<(), Error> { 13 | let staging = Staging::new(); 14 | self.common.store(&staging) 15 | } 16 | } 17 | 18 | #[cfg(test)] 19 | mod tests { 20 | 21 | use self::common::CommonTransaction; 22 | use super::*; 23 | use assert_fs::{prelude::*, NamedTempFile}; 24 | use predicates::prelude::*; 25 | 26 | #[test] 27 | pub fn test_staging_file_is_created() { 28 | let tempfile = NamedTempFile::new("staging").unwrap(); 29 | 30 | let new = New { 31 | common: CommonTransaction { 32 | staging_file: Some(tempfile.path().into()), 33 | }, 34 | }; 35 | new.exec().expect(" error while executing New action"); 36 | 37 | tempfile.assert(predicate::path::is_file()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/transaction/seal.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::transaction::{common, Error}; 2 | use structopt::StructOpt; 3 | 4 | #[derive(StructOpt)] 5 | #[structopt(rename_all = "kebab-case")] 6 | pub struct Seal { 7 | #[structopt(flatten)] 8 | pub common: common::CommonTransaction, 9 | } 10 | 11 | impl Seal { 12 | pub fn exec(self) -> Result<(), Error> { 13 | let mut transaction = self.common.load()?; 14 | transaction.seal()?; 15 | self.common.store(&transaction) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/transaction/set_expiry_date.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::transaction::{common, Error}; 2 | use jormungandr_lib::interfaces; 3 | use structopt::StructOpt; 4 | 5 | #[derive(StructOpt)] 6 | #[structopt(rename_all = "kebab-case")] 7 | pub struct SetExpiryDate { 8 | #[structopt(flatten)] 9 | pub common: common::CommonTransaction, 10 | 11 | /// the slot this transaction should be valid until, for example 3.14 12 | #[structopt(name = "BLOCKDATE")] 13 | pub valid_until: interfaces::BlockDate, 14 | } 15 | 16 | impl SetExpiryDate { 17 | pub fn exec(self) -> Result<(), Error> { 18 | let mut transaction = self.common.load()?; 19 | transaction.set_expiry_date(self.valid_until)?; 20 | self.common.store(&transaction) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/utils/output_file.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::utils::io; 2 | use std::{io::Write, path::PathBuf}; 3 | use structopt::StructOpt; 4 | 5 | #[derive(Debug, thiserror::Error)] 6 | pub enum Error { 7 | #[error("invalid output file path '{path}'")] 8 | CannotOpen { 9 | #[source] 10 | cause: std::io::Error, 11 | path: PathBuf, 12 | }, 13 | } 14 | 15 | #[derive(StructOpt, Debug)] 16 | pub struct OutputFile { 17 | /// output the key to the given file or to stdout if not provided 18 | #[structopt(name = "OUTPUT_FILE")] 19 | output: Option, 20 | } 21 | 22 | impl From for OutputFile { 23 | fn from(output: PathBuf) -> Self { 24 | Self { 25 | output: Some(output), 26 | } 27 | } 28 | } 29 | 30 | impl OutputFile { 31 | pub fn open(&self) -> Result { 32 | io::open_file_write(&self.output).map_err(|cause| Error::CannotOpen { 33 | cause, 34 | path: self.output.clone().unwrap_or_default(), 35 | }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/vote/committee/mod.rs: -------------------------------------------------------------------------------- 1 | mod communication_key; 2 | mod member_key; 3 | 4 | use super::Error; 5 | use structopt::StructOpt; 6 | 7 | #[derive(StructOpt)] 8 | #[structopt(rename_all = "kebab-case")] 9 | pub enum Committee { 10 | /// commands for managing committee member communication keys 11 | CommunicationKey(communication_key::CommunicationKey), 12 | /// commands for managing committee member stake keys 13 | MemberKey(member_key::MemberKey), 14 | } 15 | 16 | impl Committee { 17 | pub fn exec(self) -> Result<(), super::Error> { 18 | match self { 19 | Committee::CommunicationKey(args) => args.exec(), 20 | Committee::MemberKey(args) => args.exec(), 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /jcli/src/jcli_lib/vote/election_public_key.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli_lib::vote::{Error, OutputFile}; 2 | use chain_crypto::bech32::Bech32; 3 | use std::io::Write as _; 4 | use structopt::StructOpt; 5 | 6 | #[derive(StructOpt)] 7 | #[structopt(rename_all = "kebab-case")] 8 | pub struct ElectionPublicKey { 9 | /// Keys of all committee members 10 | #[structopt( 11 | parse(try_from_str = chain_vote::committee::MemberPublicKey::try_from_bech32_str), 12 | required = true, 13 | short = "k", 14 | long = "keys" 15 | )] 16 | member_keys: Vec, 17 | 18 | #[structopt(flatten)] 19 | output_file: OutputFile, 20 | } 21 | 22 | impl ElectionPublicKey { 23 | pub fn exec(&self) -> Result<(), Error> { 24 | let election_public_key = 25 | chain_vote::ElectionPublicKey::from_participants(&self.member_keys); 26 | 27 | let mut output = self.output_file.open()?; 28 | writeln!(output, "{}", election_public_key.to_bech32_str()).map_err(Error::from) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jcli/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(all(test, feature = "evm"))] 2 | #[macro_use] 3 | extern crate quickcheck; 4 | 5 | pub mod jcli_lib; 6 | pub use crate::jcli_lib::*; 7 | -------------------------------------------------------------------------------- /jcli/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use structopt::StructOpt; 3 | 4 | fn main() { 5 | jcli_lib::JCli::from_args() 6 | .exec() 7 | .unwrap_or_else(report_error) 8 | } 9 | 10 | fn report_error(error: Box) { 11 | eprintln!("{}", error); 12 | let mut source = error.source(); 13 | while let Some(sub_error) = source { 14 | eprintln!(" |-> {}", sub_error); 15 | source = sub_error.source(); 16 | } 17 | std::process::exit(1) 18 | } 19 | -------------------------------------------------------------------------------- /jormungandr-lib/src/crypto/mod.rs: -------------------------------------------------------------------------------- 1 | //! This module provides wrapper around the different cryptographic 2 | //! objects used in jormungandr, the jcli and the tests 3 | //! 4 | //! # Hash 5 | //! 6 | //! The [`Hash`] is a Blake2b256. It is used to identify a block, 7 | //! a transaction, a fragment, a Node Id. The type used here provides 8 | //! a consistent API for user interaction with a Hash. Which ever be 9 | //! its purpose. 10 | //! 11 | //! # Signing and Identifier keys 12 | //! 13 | //! This is a very generic type wrapper around `chain-crypto` secret 14 | //! and public keys. It provides the appropriate serialization format 15 | //! for human readable interfaces depending on the purpose. 16 | //! 17 | //! In a human readable serializer for `serde` (like `serde_yaml` or 18 | //! `serde_json`) it will give a bech32 encoding. But utilising 19 | //! `Display` will provide an hexadecimal encoding version of the key. 20 | //! 21 | //! # Account keys 22 | //! 23 | //! The proper type for the account management and interfaces. 24 | //! It provides the same interfaces as for the identifier in the 25 | //! `key` module but limited to Account only. 26 | //! 27 | 28 | pub mod account; 29 | pub mod hash; 30 | pub mod key; 31 | pub(crate) mod serde; 32 | -------------------------------------------------------------------------------- /jormungandr-lib/src/interfaces/block0_configuration/block_content_max_size.rs: -------------------------------------------------------------------------------- 1 | use crate::interfaces::DEFAULT_BLOCK_CONTENT_MAX_SIZE; 2 | use chain_impl_mockchain::fragment; 3 | use serde::{Deserialize, Serialize}; 4 | use std::fmt; 5 | 6 | /// the block content max size 7 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] 8 | pub struct BlockContentMaxSize(fragment::BlockContentSize); 9 | 10 | impl fmt::Display for BlockContentMaxSize { 11 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 12 | self.0.fmt(f) 13 | } 14 | } 15 | 16 | impl Default for BlockContentMaxSize { 17 | fn default() -> Self { 18 | BlockContentMaxSize(DEFAULT_BLOCK_CONTENT_MAX_SIZE) 19 | } 20 | } 21 | 22 | impl From for BlockContentMaxSize { 23 | fn from(v: fragment::BlockContentSize) -> Self { 24 | BlockContentMaxSize(v) 25 | } 26 | } 27 | 28 | impl From for fragment::BlockContentSize { 29 | fn from(v: BlockContentMaxSize) -> Self { 30 | v.0 31 | } 32 | } 33 | 34 | #[cfg(test)] 35 | mod test { 36 | use super::*; 37 | use quickcheck::{Arbitrary, Gen}; 38 | 39 | impl Arbitrary for BlockContentMaxSize { 40 | fn arbitrary(g: &mut G) -> Self { 41 | BlockContentMaxSize(Arbitrary::arbitrary(g)) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /jormungandr-lib/src/interfaces/block0_configuration/epoch_stability_depth.rs: -------------------------------------------------------------------------------- 1 | use crate::interfaces::DEFAULT_EPOCH_STABILITY_DEPTH; 2 | use serde::{Deserialize, Serialize}; 3 | use std::fmt; 4 | 5 | /// epoch stability depth 6 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] 7 | pub struct EpochStabilityDepth(u32); 8 | 9 | impl fmt::Display for EpochStabilityDepth { 10 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 11 | self.0.fmt(f) 12 | } 13 | } 14 | 15 | impl Default for EpochStabilityDepth { 16 | fn default() -> Self { 17 | Self(DEFAULT_EPOCH_STABILITY_DEPTH) 18 | } 19 | } 20 | 21 | impl From for EpochStabilityDepth { 22 | fn from(v: u32) -> Self { 23 | Self(v) 24 | } 25 | } 26 | 27 | impl From for u32 { 28 | fn from(v: EpochStabilityDepth) -> Self { 29 | v.0 30 | } 31 | } 32 | 33 | #[cfg(test)] 34 | mod test { 35 | use super::*; 36 | use quickcheck::{Arbitrary, Gen}; 37 | 38 | impl Arbitrary for EpochStabilityDepth { 39 | fn arbitrary(g: &mut G) -> Self { 40 | EpochStabilityDepth(Arbitrary::arbitrary(g)) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jormungandr-lib/src/interfaces/block0_configuration/proposal_expiration.rs: -------------------------------------------------------------------------------- 1 | use super::DEFAULT_PROPOSAL_EXPIRATION; 2 | use serde::{Deserialize, Serialize}; 3 | use std::fmt; 4 | 5 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] 6 | pub struct ProposalExpiration(u32); 7 | 8 | impl fmt::Display for ProposalExpiration { 9 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 10 | self.0.fmt(f) 11 | } 12 | } 13 | 14 | impl Default for ProposalExpiration { 15 | fn default() -> Self { 16 | ProposalExpiration(DEFAULT_PROPOSAL_EXPIRATION) 17 | } 18 | } 19 | 20 | impl From for ProposalExpiration { 21 | fn from(v: u32) -> Self { 22 | ProposalExpiration(v) 23 | } 24 | } 25 | 26 | impl From for u32 { 27 | fn from(v: ProposalExpiration) -> Self { 28 | v.0 29 | } 30 | } 31 | 32 | #[cfg(test)] 33 | mod test { 34 | use super::*; 35 | use quickcheck::{Arbitrary, Gen}; 36 | 37 | impl Arbitrary for ProposalExpiration { 38 | fn arbitrary(g: &mut G) -> Self { 39 | ProposalExpiration(Arbitrary::arbitrary(g)) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /jormungandr-lib/src/interfaces/config/log.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::path::{Path, PathBuf}; 3 | 4 | #[derive(Debug, Clone, Serialize, Deserialize)] 5 | pub struct Log(pub LogEntry); 6 | 7 | #[derive(Debug, Clone, Serialize, Deserialize)] 8 | pub struct LogEntry { 9 | pub format: String, 10 | pub level: String, 11 | pub output: LogOutput, 12 | } 13 | 14 | #[derive(Debug, Clone, Serialize, Deserialize)] 15 | #[serde(rename_all = "lowercase")] 16 | pub enum LogOutput { 17 | Stdout, 18 | Stderr, 19 | File(PathBuf), 20 | } 21 | 22 | impl Log { 23 | pub fn file_path(&self) -> Option<&Path> { 24 | match &self.0.output { 25 | LogOutput::File(path) => Some(path.as_path()), 26 | _ => None, 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /jormungandr-lib/src/interfaces/config/mod.rs: -------------------------------------------------------------------------------- 1 | mod log; 2 | mod mempool; 3 | mod node; 4 | mod secret; 5 | 6 | pub use log::{Log, LogEntry, LogOutput}; 7 | pub use mempool::{LogMaxEntries, Mempool, PersistentLog, PoolMaxEntries}; 8 | pub use node::{ 9 | Cors, CorsOrigin, JRpc, LayersConfig, NodeConfig, NodeId, P2p, Policy, PreferredListConfig, 10 | Rest, Tls, TopicsOfInterest, TrustedPeer, 11 | }; 12 | pub use secret::{Bft, GenesisPraos, NodeSecret}; 13 | -------------------------------------------------------------------------------- /jormungandr-lib/src/interfaces/config/secret.rs: -------------------------------------------------------------------------------- 1 | use crate::crypto::{hash::Hash, key::SigningKey}; 2 | use chain_crypto::{Ed25519, RistrettoGroup2HashDh, SumEd25519_12}; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | #[derive(Debug, Clone, Deserialize, Serialize)] 6 | pub struct NodeSecret { 7 | #[serde(skip_serializing_if = "Option::is_none")] 8 | pub bft: Option, 9 | #[serde(skip_serializing_if = "Option::is_none")] 10 | pub genesis: Option, 11 | } 12 | 13 | /// hold the node's bft secret setting 14 | #[derive(Debug, Clone, Deserialize, Serialize)] 15 | pub struct Bft { 16 | pub signing_key: SigningKey, 17 | } 18 | 19 | /// the genesis praos setting 20 | /// 21 | #[derive(Debug, Clone, Deserialize, Serialize)] 22 | pub struct GenesisPraos { 23 | pub node_id: Hash, 24 | pub sig_key: SigningKey, 25 | pub vrf_key: SigningKey, 26 | } 27 | -------------------------------------------------------------------------------- /jormungandr-lib/src/interfaces/fragments_batch.rs: -------------------------------------------------------------------------------- 1 | use crate::interfaces::FragmentDef; 2 | use chain_impl_mockchain::fragment::Fragment; 3 | use serde::{Deserialize, Serialize}; 4 | use serde_with::serde_as; 5 | 6 | /// Submission of a batch of fragments to the node. 7 | #[serde_as] 8 | #[derive(Debug, Deserialize, Serialize)] 9 | pub struct FragmentsBatch { 10 | /// Fragments are processed in the sequential order. When this option is enabled, fragments 11 | /// processing will stop upon meeting the first invalid fragment and the rest of fragments 12 | /// would be dropped. 13 | pub fail_fast: bool, 14 | /// Fragments themselves. 15 | #[serde_as(as = "Vec")] 16 | pub fragments: Vec, 17 | } 18 | -------------------------------------------------------------------------------- /jormungandr-lib/src/interfaces/peer_stats.rs: -------------------------------------------------------------------------------- 1 | use crate::time::SystemTime; 2 | use serde::{Deserialize, Serialize}; 3 | use std::net::SocketAddr; 4 | 5 | #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] 6 | #[serde(deny_unknown_fields, rename_all = "camelCase")] 7 | pub struct PeerStats { 8 | pub addr: Option, 9 | pub established_at: SystemTime, 10 | pub last_block_received: Option, 11 | pub last_fragment_received: Option, 12 | pub last_gossip_received: Option, 13 | } 14 | 15 | #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] 16 | #[serde(deny_unknown_fields)] 17 | pub struct PeerRecord { 18 | pub id: String, 19 | pub address: String, 20 | pub last_update: SystemTime, 21 | pub quarantined: Option, 22 | pub subscriptions: Vec, 23 | } 24 | 25 | #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] 26 | #[serde(deny_unknown_fields)] 27 | pub struct Subscription { 28 | pub interest: u32, 29 | pub topic: String, 30 | } 31 | -------------------------------------------------------------------------------- /jormungandr-lib/src/interfaces/stake_distribution.rs: -------------------------------------------------------------------------------- 1 | use crate::{crypto::hash::Hash, interfaces::stake::Stake}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] 5 | #[serde(deny_unknown_fields)] 6 | pub struct StakeDistributionDto { 7 | pub epoch: u32, 8 | pub stake: StakeDistribution, 9 | } 10 | 11 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 12 | #[serde(deny_unknown_fields)] 13 | pub struct StakeDistribution { 14 | pub dangling: Stake, 15 | pub unassigned: Stake, 16 | pub pools: Vec<(Hash, Stake)>, 17 | } 18 | -------------------------------------------------------------------------------- /jormungandr-lib/src/interfaces/stake_pool_stats.rs: -------------------------------------------------------------------------------- 1 | use crate::interfaces::{TaxTypeSerde, ValueDef}; 2 | use chain_impl_mockchain::value::Value; 3 | use serde::{Deserialize, Serialize}; 4 | 5 | #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] 6 | #[serde(deny_unknown_fields)] 7 | pub struct StakePoolStats { 8 | pub kes_public_key: String, 9 | pub vrf_public_key: String, 10 | pub total_stake: u64, 11 | pub rewards: Rewards, 12 | pub tax: TaxTypeSerde, 13 | } 14 | 15 | #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] 16 | #[serde(deny_unknown_fields)] 17 | pub struct Rewards { 18 | pub epoch: u32, 19 | #[serde(with = "ValueDef")] 20 | pub value_taxed: Value, 21 | #[serde(with = "ValueDef")] 22 | pub value_for_stakers: Value, 23 | } 24 | -------------------------------------------------------------------------------- /jormungandr-lib/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | #[macro_use(quickcheck)] 3 | extern crate quickcheck; 4 | 5 | pub mod crypto; 6 | pub mod interfaces; 7 | pub mod multiaddr; 8 | pub mod time; 9 | -------------------------------------------------------------------------------- /jormungandr/benches/rest_v0.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | use jormungandr::{context::Context, rest::v0::logic::get_message_logs}; 3 | use tokio::runtime::Runtime; 4 | 5 | fn tokio() -> Runtime { 6 | Runtime::new().unwrap() 7 | } 8 | 9 | fn empty_context_get_message_logs(c: &mut Criterion) { 10 | let context = Context::new(); 11 | 12 | c.bench_function("empty_context", |b| { 13 | let f = || get_message_logs(black_box(&context)); 14 | b.to_async(tokio()).iter(f); 15 | }); 16 | } 17 | 18 | criterion_group!(benches, empty_context_get_message_logs); 19 | criterion_main!(benches); 20 | -------------------------------------------------------------------------------- /jormungandr/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let pkg_version = if let Ok(date) = std::env::var("DATE") { 3 | format!("{}.{}", env!("CARGO_PKG_VERSION"), date) 4 | } else { 5 | env!("CARGO_PKG_VERSION").to_string() 6 | }; 7 | 8 | println!("cargo:rustc-env=CARGO_PKG_VERSION={}", pkg_version); 9 | 10 | let version = versionisator::Version::new( 11 | env!("CARGO_MANIFEST_DIR"), 12 | env!("CARGO_PKG_NAME").to_string(), 13 | pkg_version, 14 | ); 15 | 16 | println!("cargo:rustc-env=FULL_VERSION={}", version.full()); 17 | println!("cargo:rustc-env=SIMPLE_VERSION={}", version.simple()); 18 | println!("cargo:rustc-env=SOURCE_VERSION={}", version.hash()); 19 | } 20 | -------------------------------------------------------------------------------- /jormungandr/src/bin/jormungandr.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | jormungandr::main(); 3 | } 4 | -------------------------------------------------------------------------------- /jormungandr/src/blockchain/branch.rs: -------------------------------------------------------------------------------- 1 | use crate::blockchain::Ref; 2 | use std::sync::Arc; 3 | 4 | /// the data that is contained in a branch 5 | #[derive(Clone)] 6 | pub struct Branch { 7 | /// reference to the block where the branch points to 8 | reference: Arc, 9 | } 10 | 11 | impl Branch { 12 | /// create the branch data with the current `last_updated` to 13 | /// the current time this function was called 14 | pub fn new(reference: Arc) -> Self { 15 | Branch { reference } 16 | } 17 | 18 | pub fn get_ref(&self) -> Arc { 19 | Arc::clone(&self.reference) 20 | } 21 | 22 | pub fn into_ref(self) -> Arc { 23 | self.reference 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /jormungandr/src/blockchain/mod.rs: -------------------------------------------------------------------------------- 1 | mod bootstrap; 2 | mod branch; 3 | mod candidate; 4 | mod chain; 5 | mod chain_selection; 6 | mod checkpoints; 7 | mod multiverse; 8 | mod process; 9 | mod reference; 10 | mod reference_cache; 11 | mod storage; 12 | mod tip; 13 | 14 | // Constants 15 | 16 | mod chunk_sizes { 17 | // The maximum number of blocks to request per each GetBlocks request 18 | // or a Solicit event when pulling missing blocks. 19 | // 20 | // This may need to be made into a configuration parameter. 21 | // The number used here aims for this number of block IDs to fit within 22 | // a reasonable network path MTU, leaving room for gRPC and TCP/IP framing. 23 | pub const BLOCKS: u64 = 32; 24 | } 25 | 26 | // Re-exports 27 | 28 | pub use self::{ 29 | bootstrap::{bootstrap_from_stream, Error as BootstrapError}, 30 | branch::Branch, 31 | chain::{ 32 | new_epoch_leadership_from, Blockchain, CheckHeaderProof, EpochLeadership, Error, 33 | LeadershipBlock, PreCheckedHeader, MAIN_BRANCH_TAG, 34 | }, 35 | chain_selection::{compare_against, ComparisonResult}, 36 | checkpoints::Checkpoints, 37 | multiverse::Multiverse, 38 | process::{start, TaskData}, 39 | reference::Ref, 40 | storage::{Error as StorageError, Storage}, 41 | tip::Tip, 42 | }; 43 | -------------------------------------------------------------------------------- /jormungandr/src/fragment/mod.rs: -------------------------------------------------------------------------------- 1 | mod entry; 2 | mod logs; 3 | mod pool; 4 | mod process; 5 | pub mod selection; 6 | 7 | pub use self::{entry::PoolEntry, logs::Logs, pool::Pool, process::Process}; 8 | pub use crate::blockcfg::{Fragment, FragmentId}; 9 | -------------------------------------------------------------------------------- /jormungandr/src/jrpc/eth_miner/logic.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | context::Context, 3 | jrpc::{ 4 | eth_types::{number::Number, work::Work}, 5 | Error, 6 | }, 7 | }; 8 | use chain_evm::ethereum_types::{H160, H256, H64}; 9 | 10 | pub fn mining(_context: &Context) -> Result { 11 | Err(Error::MiningIsNotAllowed) 12 | } 13 | 14 | pub fn coinbase(_context: &Context) -> Result { 15 | Err(Error::MiningIsNotAllowed) 16 | } 17 | 18 | pub fn hashrate(_context: &Context) -> Result { 19 | Err(Error::MiningIsNotAllowed) 20 | } 21 | 22 | pub fn get_work(_context: &Context) -> Result { 23 | Err(Error::MiningIsNotAllowed) 24 | } 25 | 26 | pub fn submit_work( 27 | _nonce: H64, 28 | _pow_hash: H256, 29 | _mix_digest: H256, 30 | _context: &Context, 31 | ) -> Result { 32 | Err(Error::MiningIsNotAllowed) 33 | } 34 | 35 | pub fn submit_hashrate(_hash_rate: H256, _id: H256, _context: &Context) -> Result { 36 | Err(Error::MiningIsNotAllowed) 37 | } 38 | -------------------------------------------------------------------------------- /jormungandr/src/jrpc/eth_types/fee.rs: -------------------------------------------------------------------------------- 1 | use super::number::Number; 2 | 3 | /// FeeHistory 4 | #[derive(Debug, Serialize)] 5 | #[serde(rename_all = "camelCase")] 6 | pub struct FeeHistory { 7 | /// Lowest number block of the returned range. 8 | oldest_block: Number, 9 | /// An array of block base fees per gas. 10 | /// This includes the next block after the newest of the returned range, 11 | /// because this value can be derived from the newest block. Zeroes are 12 | /// returned for pre-EIP-1559 blocks. 13 | base_fee_per_gas: Vec, 14 | /// An array of effective priority fee per gas data points from a single 15 | /// block. All zeroes are returned if the block is empty. 16 | reward: Vec>, 17 | } 18 | 19 | #[cfg(test)] 20 | mod tests { 21 | use super::*; 22 | 23 | #[test] 24 | fn fee_history_serialize() { 25 | let fee_history = FeeHistory { 26 | oldest_block: 0.into(), 27 | base_fee_per_gas: vec![0.into()], 28 | reward: vec![vec![0.into()]], 29 | }; 30 | 31 | assert_eq!( 32 | serde_json::to_string(&fee_history).unwrap(), 33 | r#"{"oldestBlock":"0x0","baseFeePerGas":["0x0"],"reward":[["0x0"]]}"# 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /jormungandr/src/jrpc/eth_types/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod block; 2 | pub mod block_number; 3 | pub mod bytes; 4 | pub mod fee; 5 | pub mod filter; 6 | pub mod log; 7 | pub mod number; 8 | pub mod receipt; 9 | pub mod sync; 10 | pub mod transaction; 11 | pub mod work; 12 | -------------------------------------------------------------------------------- /jormungandr/src/jrpc/eth_types/work.rs: -------------------------------------------------------------------------------- 1 | use chain_evm::ethereum_types::H256; 2 | use serde::{Serialize, Serializer}; 3 | 4 | /// Work 5 | #[derive(Debug, PartialEq, Eq)] 6 | pub struct Work { 7 | /// The proof-of-work hash. 8 | pow_hash: H256, 9 | /// The seed hash. 10 | seed_hash: H256, 11 | /// The target. 12 | target: H256, 13 | } 14 | 15 | impl Serialize for Work { 16 | fn serialize(&self, s: S) -> Result 17 | where 18 | S: Serializer, 19 | { 20 | vec![self.pow_hash, self.seed_hash, self.target].serialize(s) 21 | } 22 | } 23 | 24 | #[cfg(test)] 25 | mod tests { 26 | use super::*; 27 | 28 | #[test] 29 | fn work_serialize() { 30 | let work = Work { 31 | pow_hash: H256::zero(), 32 | seed_hash: H256::zero(), 33 | target: H256::zero(), 34 | }; 35 | 36 | assert_eq!( 37 | serde_json::to_string(&work).unwrap(), 38 | r#"["0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"]"# 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jormungandr/src/log/mod.rs: -------------------------------------------------------------------------------- 1 | pub const KEY_TASK: &str = "task"; 2 | pub const KEY_SUB_TASK: &str = "sub_task"; 3 | pub const KEY_SCOPE: &str = "scope"; 4 | -------------------------------------------------------------------------------- /jormungandr/src/metrics/backends/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "prometheus-metrics")] 2 | mod prometheus_exporter; 3 | mod simple_counter; 4 | 5 | #[cfg(feature = "prometheus-metrics")] 6 | pub use prometheus_exporter::Prometheus; 7 | pub use simple_counter::SimpleCounter; 8 | -------------------------------------------------------------------------------- /jormungandr/src/network/grpc/mod.rs: -------------------------------------------------------------------------------- 1 | pub(super) mod client; 2 | mod server; 3 | 4 | pub use self::{ 5 | client::{connect, fetch_block, Client, ConnectError, FetchBlockError}, 6 | server::run_listen_socket, 7 | }; 8 | -------------------------------------------------------------------------------- /jormungandr/src/network/p2p/mod.rs: -------------------------------------------------------------------------------- 1 | /// This module is responsible for handling active peers and communication in a p2p setting. 2 | /// It takes care of managing connections with said peers and sending messages to them. 3 | /// The topology task is instead responsible for the discovery of active peers. 4 | pub mod comm; 5 | 6 | /// At the logical level, every peer is identified by its public key, and this is the only 7 | /// info exposed in the external interface. 8 | /// However, keeping the remote address of the peer is needed for some features, namely 9 | /// debugging and server side authentication of requests. 10 | /// In addition, keep in mind the address here is not always the public address included in the 11 | /// gossip, as it may be an ephemeral address used by a connected client. 12 | pub type Address = std::net::SocketAddr; 13 | -------------------------------------------------------------------------------- /jormungandr/src/rest/prometheus.rs: -------------------------------------------------------------------------------- 1 | use crate::rest::ContextLock; 2 | use warp::{Filter, Rejection, Reply}; 3 | 4 | pub fn filter( 5 | context: ContextLock, 6 | ) -> impl Filter + Clone { 7 | warp::path!("prometheus") 8 | .and(warp::get()) 9 | .and(warp::any().map(move || context.clone())) 10 | .and_then(|context: ContextLock| async move { 11 | let context = context.read().await; 12 | let full_context = context.try_full().map_err(warp::reject::custom)?; 13 | full_context 14 | .prometheus 15 | .as_ref() 16 | .expect("Prometheus metrics exporter not set in API context!") 17 | .http_response() 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /jormungandr/src/settings/mod.rs: -------------------------------------------------------------------------------- 1 | mod command_arguments; 2 | pub mod logging; 3 | pub mod start; 4 | 5 | pub use self::{command_arguments::CommandLine, start::Error}; 6 | use crate::blockcfg::HeaderHash; 7 | use std::path::PathBuf; 8 | 9 | lazy_static! { 10 | pub static ref LOG_FILTER_LEVEL_POSSIBLE_VALUES: Vec<&'static str> = { 11 | [ 12 | tracing::metadata::LevelFilter::OFF, 13 | tracing::metadata::LevelFilter::TRACE, 14 | tracing::metadata::LevelFilter::DEBUG, 15 | tracing::metadata::LevelFilter::INFO, 16 | tracing::metadata::LevelFilter::WARN, 17 | tracing::metadata::LevelFilter::ERROR, 18 | ] 19 | .iter() 20 | .map(|name| name.to_string().to_ascii_lowercase()) 21 | .map(|name| &*Box::leak(name.into_boxed_str())) 22 | .collect() 23 | }; 24 | } 25 | 26 | #[derive(Clone, Debug)] 27 | pub enum Block0Info { 28 | Path(PathBuf, Option), 29 | Hash(HeaderHash), 30 | } 31 | -------------------------------------------------------------------------------- /jormungandr/src/state.rs: -------------------------------------------------------------------------------- 1 | pub struct State { 2 | // utxo, protocol parameters 3 | } 4 | 5 | impl State { 6 | pub fn new() -> Self { 7 | State {} 8 | } 9 | } 10 | 11 | impl Default for State { 12 | fn default() -> Self { 13 | Self::new() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /jormungandr/src/topology/layers/mod.rs: -------------------------------------------------------------------------------- 1 | mod preferred_list; 2 | mod rings; 3 | 4 | pub use self::{ 5 | preferred_list::PreferredListConfig, 6 | rings::{ParseError, RingsConfig}, 7 | }; 8 | pub(super) use self::{preferred_list::PreferredListLayer, rings::Rings}; 9 | 10 | #[derive(Clone)] 11 | pub struct LayersConfig { 12 | pub preferred_list: PreferredListConfig, 13 | pub rings: RingsConfig, 14 | } 15 | -------------------------------------------------------------------------------- /jormungandr/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod async_msg; 2 | pub mod fire_forget_scheduler; 3 | pub mod task; 4 | -------------------------------------------------------------------------------- /modules/blockchain/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "blockchain" 3 | version = "0.1.0" 4 | authors = ["Nicolas Di Prima "] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | chain-impl-mockchain = { git = "https://github.com/input-output-hk/chain-libs.git", branch = "master" } 9 | chain-time = { git = "https://github.com/input-output-hk/chain-libs.git", branch = "master"} 10 | thiserror = "1.0.30" 11 | lru = "0.7" 12 | -------------------------------------------------------------------------------- /modules/blockchain/README.md: -------------------------------------------------------------------------------- 1 | # blockchain management 2 | 3 | This module provides all the necessary tooling to follow a blockchain. It 4 | also maintains multiple branches that can be used to quickly transition from 5 | one fork to another. 6 | -------------------------------------------------------------------------------- /modules/settings/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "settings" 3 | version = "0.1.0" 4 | authors = ["Nicolas Di Prima "] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | sled = "0.34" 11 | thiserror = "1.0" 12 | -------------------------------------------------------------------------------- /modules/settings/README.md: -------------------------------------------------------------------------------- 1 | # Settings interfaces for the jormungandr node 2 | 3 | Exposes only the APIs of how to update or get the settings of the node. 4 | The content is very much opinionated already. We expects the keys and the 5 | value to be `String`. 6 | 7 | Underlying, it uses `sled`. Though, except for the constructor itself 8 | the API hides entirely what's going on in the backend. 9 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | imports_granularity="Crate" 2 | group_imports="One" 3 | reorder_modules=true 4 | -------------------------------------------------------------------------------- /scripts/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !jormungandr-storage-test 4 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | ( 2 | import 3 | ( 4 | let 5 | lock = builtins.fromJSON (builtins.readFile ./flake.lock); 6 | in 7 | fetchTarball { 8 | url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; 9 | sha256 = lock.nodes.flake-compat.locked.narHash; 10 | } 11 | ) 12 | {src = ./.;} 13 | ) 14 | .shellNix 15 | -------------------------------------------------------------------------------- /testing/hersir/src/args.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | use structopt::StructOpt; 3 | 4 | /// 5 | /// Hersir is a command line tool that lets you deploy a network of Jormungandr nodes 6 | /// 7 | #[derive(StructOpt)] 8 | pub struct Args { 9 | /// Path to config file 10 | #[structopt(long, short)] 11 | pub config: PathBuf, 12 | 13 | /// Enable verbose mode 14 | #[structopt(long, short)] 15 | pub verbose: bool, 16 | } 17 | -------------------------------------------------------------------------------- /testing/hersir/src/builder/explorer.rs: -------------------------------------------------------------------------------- 1 | use crate::{builder::NodeSetting, config::ExplorerTemplate}; 2 | use jormungandr_automation::{ 3 | jormungandr::{explorer::configuration::ExplorerConfiguration, get_available_port, NodeAlias}, 4 | utils::MultiaddrExtension, 5 | }; 6 | use std::{collections::HashMap, path::Path}; 7 | 8 | pub fn generate_explorer( 9 | nodes: &HashMap, 10 | explorer_template: &ExplorerTemplate, 11 | ) -> Result { 12 | let settings = nodes 13 | .get(&explorer_template.connect_to) 14 | .ok_or_else(|| Error::CannotFindAlias(explorer_template.connect_to.clone()))?; 15 | 16 | Ok(ExplorerConfiguration { 17 | explorer_port: get_available_port(), 18 | explorer_listen_address: "127.0.0.1".to_string(), 19 | node_address: settings.config.p2p.public_address.clone().to_http_addr(), 20 | logs_dir: Some(Path::new("C:\\work\\iohk\\logs.txt").to_path_buf()), 21 | storage_dir: None, 22 | params: explorer_template.to_explorer_params(), 23 | }) 24 | } 25 | 26 | #[derive(thiserror::Error, Debug)] 27 | pub enum Error { 28 | #[error("cannot find alias '{0}' for any defined node")] 29 | CannotFindAlias(NodeAlias), 30 | } 31 | -------------------------------------------------------------------------------- /testing/hersir/src/builder/settings/node.rs: -------------------------------------------------------------------------------- 1 | use crate::builder::settings::NodeTemplate; 2 | use chain_crypto::Ed25519; 3 | use jormungandr_automation::jormungandr::NodeAlias; 4 | use jormungandr_lib::{ 5 | crypto::key::SigningKey, 6 | interfaces::{NodeConfig, NodeSecret}, 7 | }; 8 | 9 | /// contains all the data to start or interact with a node 10 | #[derive(Debug, Clone)] 11 | pub struct NodeSetting { 12 | /// for reference purpose only 13 | pub alias: NodeAlias, 14 | 15 | /// node secret, this will be passed to the node at start 16 | /// up of the node. It may contains the necessary crypto 17 | /// for the node to be a blockchain leader (BFT leader or 18 | /// stake pool) 19 | pub secret: NodeSecret, 20 | 21 | pub config: NodeConfig, 22 | 23 | pub topology_secret: SigningKey, 24 | 25 | pub node_topology: NodeTemplate, 26 | } 27 | -------------------------------------------------------------------------------- /testing/hersir/src/builder/settings/vote_plan.rs: -------------------------------------------------------------------------------- 1 | use chain_impl_mockchain::certificate::VotePlanId; 2 | use jormungandr_lib::interfaces::VotePlan; 3 | use thor::wallet::committee::CommitteeDataManager; 4 | 5 | #[derive(Debug, Clone)] 6 | pub enum VotePlanSettings { 7 | Public(VotePlan), 8 | Private { 9 | keys: CommitteeDataManager, 10 | vote_plan: VotePlan, 11 | }, 12 | } 13 | 14 | impl VotePlanSettings { 15 | pub fn vote_plan(&self) -> VotePlan { 16 | match self { 17 | Self::Public(vote_plan) => vote_plan.clone(), 18 | Self::Private { 19 | keys: _keys, 20 | vote_plan, 21 | } => vote_plan.clone(), 22 | } 23 | } 24 | 25 | pub fn to_id(&self) -> VotePlanId { 26 | let vote_plan: chain_impl_mockchain::certificate::VotePlan = self.vote_plan().into(); 27 | vote_plan.to_id() 28 | } 29 | 30 | pub fn from_public_vote_plan(vote_plan: VotePlan) -> Self { 31 | Self::Public(vote_plan) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /testing/hersir/src/builder/topology.rs: -------------------------------------------------------------------------------- 1 | use jormungandr_automation::jormungandr::NodeAlias; 2 | use std::collections::{HashMap, HashSet}; 3 | #[derive(Debug, Clone, Default)] 4 | pub struct Topology { 5 | pub nodes: HashMap, 6 | } 7 | 8 | impl Topology { 9 | pub fn with_node(mut self, node: Node) -> Self { 10 | self.nodes.insert(node.alias.clone(), node); 11 | self 12 | } 13 | } 14 | 15 | #[derive(Debug, Clone)] 16 | pub struct Node { 17 | pub alias: NodeAlias, 18 | pub trusted_peers: HashSet, 19 | } 20 | 21 | impl Node { 22 | pub fn new>(alias: S) -> Self { 23 | Self { 24 | alias: alias.into(), 25 | trusted_peers: HashSet::new(), 26 | } 27 | } 28 | 29 | pub fn with_trusted_peer>(mut self, peer: S) -> Self { 30 | self.trusted_peers.insert(peer.into()); 31 | self 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /testing/hersir/src/cli.rs: -------------------------------------------------------------------------------- 1 | use crate::config::SessionMode; 2 | use std::fmt; 3 | 4 | impl fmt::Display for SessionMode { 5 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 6 | write!(f, "{:?}", self) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /testing/hersir/src/config/committee.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | use thor::WalletAlias; 3 | 4 | #[derive(Clone, Debug, Deserialize)] 5 | #[serde(untagged)] 6 | pub enum CommitteeTemplate { 7 | Generated { 8 | alias: WalletAlias, 9 | member_pk: Option, 10 | communication_pk: Option, 11 | }, 12 | External { 13 | id: String, 14 | member_pk: Option, 15 | communication_pk: Option, 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /testing/hersir/src/config/vote_plan.rs: -------------------------------------------------------------------------------- 1 | use crate::{builder::VotePlanKey, config::CommitteeTemplate}; 2 | use chain_impl_mockchain::certificate::Proposals; 3 | use jormungandr_lib::interfaces::{BlockDate, TokenIdentifier}; 4 | use serde::Deserialize; 5 | 6 | #[derive(Clone, Debug, Deserialize)] 7 | pub struct VotePlanTemplate { 8 | pub committees: Vec, 9 | pub vote_start: BlockDate, 10 | pub vote_end: BlockDate, 11 | pub committee_end: BlockDate, 12 | #[serde(with = "jormungandr_lib::interfaces::serde_proposals")] 13 | pub proposals: Proposals, 14 | #[serde( 15 | with = "jormungandr_lib::interfaces::serde_committee_member_public_keys", 16 | default = "Vec::new" 17 | )] 18 | pub committee_member_public_keys: Vec, 19 | pub voting_token: TokenIdentifier, 20 | #[serde(flatten)] 21 | pub vote_plan_key: VotePlanKey, 22 | pub private: Option, 23 | } 24 | 25 | #[derive(Clone, Debug, Deserialize)] 26 | pub struct PrivateParameters { 27 | pub crs: Option, 28 | pub threshold: Option, 29 | } 30 | -------------------------------------------------------------------------------- /testing/hersir/src/controller/interactive/args/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod describe; 2 | pub mod explorer; 3 | pub mod send; 4 | pub mod show; 5 | pub mod spawn; 6 | -------------------------------------------------------------------------------- /testing/hersir/src/controller/interactive/args/send/mod.rs: -------------------------------------------------------------------------------- 1 | mod cast; 2 | mod tally; 3 | mod tx; 4 | 5 | use crate::controller::{Error, UserInteractionController}; 6 | use cast::CastVote; 7 | use structopt::StructOpt; 8 | use tally::VoteTally; 9 | use tx::SendTransaction; 10 | 11 | #[derive(StructOpt, Debug)] 12 | pub enum Send { 13 | /// Sends transaction 14 | Tx(SendTransaction), 15 | /// Tally the vote 16 | Tally(VoteTally), 17 | /// Send the vote 18 | Vote(CastVote), 19 | } 20 | 21 | impl Send { 22 | pub fn exec(&self, controller: &mut UserInteractionController) -> Result<(), Error> { 23 | match self { 24 | Send::Tx(transaction) => transaction.exec(controller), 25 | Send::Tally(vote_tally) => vote_tally.exec(controller), 26 | Send::Vote(cast_vote) => cast_vote.exec(controller), 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /testing/hersir/src/controller/interactive/args/send/tally.rs: -------------------------------------------------------------------------------- 1 | use super::UserInteractionController; 2 | use crate::{controller::Error, style}; 3 | use structopt::StructOpt; 4 | 5 | #[derive(StructOpt, Debug)] 6 | pub struct VoteTally { 7 | #[structopt(short = "c", long = "committee")] 8 | pub committee: String, 9 | #[structopt(short = "p", long = "vote-plan")] 10 | pub vote_plan: String, 11 | #[structopt(short = "v", long = "via")] 12 | pub via: String, 13 | } 14 | 15 | impl VoteTally { 16 | pub fn exec(&self, controller: &mut UserInteractionController) -> Result<(), Error> { 17 | let mem_pool_check = controller.tally_vote(&self.committee, &self.vote_plan, &self.via)?; 18 | println!( 19 | "{}", 20 | style::info.apply_to(format!( 21 | "tally vote fragment '{}' successfully sent", 22 | mem_pool_check.fragment_id() 23 | )) 24 | ); 25 | Ok(()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /testing/hersir/src/controller/interactive/args/send/tx.rs: -------------------------------------------------------------------------------- 1 | use super::UserInteractionController; 2 | use crate::{controller::Error, style}; 3 | use structopt::StructOpt; 4 | 5 | #[derive(StructOpt, Debug)] 6 | pub struct SendTransaction { 7 | #[structopt(short = "f", long = "from")] 8 | pub from: String, 9 | #[structopt(short = "t", long = "to")] 10 | pub to: String, 11 | #[structopt(short = "v", long = "via")] 12 | pub via: String, 13 | #[structopt(short = "a", long = "ada")] 14 | pub ada: Option, 15 | } 16 | 17 | impl SendTransaction { 18 | pub fn exec(&self, controller: &mut UserInteractionController) -> Result<(), Error> { 19 | let mem_pool_check = controller.send_transaction( 20 | &self.from, 21 | &self.to, 22 | &self.via, 23 | self.ada.unwrap_or(100).into(), 24 | )?; 25 | println!( 26 | "{}", 27 | style::info.apply_to(format!( 28 | "fragment '{}' successfully sent", 29 | mem_pool_check.fragment_id() 30 | )) 31 | ); 32 | Ok(()) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /testing/hersir/src/controller/interactive/command.rs: -------------------------------------------------------------------------------- 1 | use super::args::{describe, explorer, send, show, spawn}; 2 | use structopt::{clap::AppSettings, StructOpt}; 3 | 4 | #[derive(StructOpt, Debug)] 5 | #[structopt(setting = AppSettings::NoBinaryName)] 6 | pub enum InteractiveCommand { 7 | /// Prints nodes related data, like stats,fragments etc. 8 | Show(show::Show), 9 | /// Spawn leader or passive node (also legacy) 10 | Spawn(spawn::Spawn), 11 | /// Sends Explorer queries 12 | Explorer(explorer::Explorer), 13 | /// Exit interactive mode 14 | Exit, 15 | /// Prints wallets, nodes which can be used. Draw topology 16 | Describe(describe::Describe), 17 | /// send fragments 18 | Send(send::Send), 19 | } 20 | -------------------------------------------------------------------------------- /testing/hersir/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod args; 2 | pub mod builder; 3 | pub mod cli; 4 | pub mod config; 5 | pub mod controller; 6 | pub mod error; 7 | pub mod spawn; 8 | pub mod utils; 9 | 10 | pub use jortestkit::console::style; 11 | -------------------------------------------------------------------------------- /testing/hersir/src/main.rs: -------------------------------------------------------------------------------- 1 | use hersir::{args::Args, spawn}; 2 | use structopt::StructOpt; 3 | 4 | fn main() { 5 | let args = Args::from_args(); 6 | if let Err(e) = spawn::spawn_network(args) { 7 | eprintln!("{}", e); 8 | std::process::exit(1); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /testing/hersir/src/spawn/mod.rs: -------------------------------------------------------------------------------- 1 | mod interactive; 2 | mod monitor; 3 | mod standard; 4 | 5 | use crate::{ 6 | args::Args, 7 | config::{Config, SessionMode}, 8 | error::Error, 9 | }; 10 | use std::fs::File; 11 | 12 | pub fn spawn_network(args: Args) -> Result<(), Error> { 13 | let config: Config = serde_yaml::from_reader(File::open(&args.config)?)?; 14 | 15 | match &config.session.mode { 16 | SessionMode::Standard => standard::spawn_network(config, args), 17 | SessionMode::Monitor => monitor::spawn_network(config, args), 18 | SessionMode::Interactive => interactive::spawn_network(config), 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /testing/hersir/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | mod dotifier; 2 | mod introduction; 3 | 4 | pub use dotifier::Dotifier; 5 | pub use introduction::print_intro; 6 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | tonic_build::compile_protos("proto/node.proto").unwrap(); 3 | tonic_build::compile_protos("proto/watch.proto").unwrap(); 4 | 5 | let jor_cli_name = option_env!("JOR_CLI_NAME").unwrap_or("jcli"); 6 | let jormungandr_name = option_env!("JORMUNGANDR_NAME").unwrap_or("jormungandr"); 7 | let jor_explorer_name = option_env!("JOR_EXPLORER_NAME").unwrap_or("explorer"); 8 | println!("cargo:rustc-env=JOR_CLI_NAME={}", jor_cli_name); 9 | println!("cargo:rustc-env=JORMUNGANDR_NAME={}", jormungandr_name); 10 | println!("cargo:rustc-env=JOR_EXPLORER_NAME={}", jor_explorer_name); 11 | println!("cargo:rustc-env=RUST_BACKTRACE=full"); 12 | 13 | let pkg_version = if let Ok(date) = std::env::var("DATE") { 14 | format!("{}.{}", env!("CARGO_PKG_VERSION"), date) 15 | } else { 16 | env!("CARGO_PKG_VERSION").to_string() 17 | }; 18 | 19 | println!("cargo:rustc-env=CARGO_PKG_VERSION={}", pkg_version); 20 | 21 | let version = versionisator::Version::new( 22 | env!("CARGO_MANIFEST_DIR"), 23 | env!("CARGO_PKG_NAME").to_string(), 24 | pkg_version, 25 | ); 26 | 27 | println!("cargo:rustc-env=FULL_VERSION={}", version.full()); 28 | println!("cargo:rustc-env=SIMPLE_VERSION={}", version.simple()); 29 | println!("cargo:rustc-env=SOURCE_VERSION={}", version.hash()); 30 | } 31 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/proto/types.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | // Message types shared by protocol definitions 4 | package iohk.chain.types; 5 | 6 | // Representation of a block. 7 | message Block { 8 | // The serialized content of the block. 9 | bytes content = 1; 10 | } 11 | 12 | // Representation of a block header. 13 | message Header { 14 | // The serialized content of the block header. 15 | bytes content = 1; 16 | } 17 | 18 | // Representation of a block fragment, that is, a transaction or other 19 | // content item. 20 | message Fragment { 21 | // The serialized content of the fragment. 22 | bytes content = 1; 23 | } 24 | 25 | // A sequence of block identifiers used in fetch requests and solicitation. 26 | message BlockIds { 27 | // The identifiers of blocks for loading. 28 | repeated bytes ids = 1; 29 | } 30 | 31 | // A sequence of fragment identifiers used in fetch requests. 32 | message FragmentIds { 33 | // The identifiers of fragments. 34 | repeated bytes ids = 1; 35 | } 36 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/resources/explorer/graphql/address.graphql: -------------------------------------------------------------------------------- 1 | query Address($bech32: String!){ 2 | address(bech32: $bech32) { 3 | id #delegation{... poolInfo} not implemented yet NPG-2247 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/resources/explorer/graphql/allblocks.graphql: -------------------------------------------------------------------------------- 1 | query AllBlocks($last: Int!) { 2 | tip { 3 | blocks(last: $last) { 4 | edges { 5 | node { 6 | id 7 | date { 8 | epoch { 9 | id 10 | } 11 | slot 12 | } 13 | previousBlock { 14 | id 15 | } 16 | chainLength 17 | totalInput 18 | totalOutput 19 | } 20 | } 21 | totalCount 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/resources/explorer/graphql/allstakepools.graphql: -------------------------------------------------------------------------------- 1 | query AllStakePools($first: Int!){ 2 | tip { 3 | allStakePools(first: $first) { 4 | edges{ 5 | node { 6 | id 7 | } 8 | } 9 | totalCount 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/resources/explorer/graphql/block.graphql: -------------------------------------------------------------------------------- 1 | query Block($id: String!) { 2 | block(id:$id){ 3 | id 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/resources/explorer/graphql/blocksbychainlength.graphql: -------------------------------------------------------------------------------- 1 | query BlocksByChainLength($length: ChainLength!){ 2 | blocksByChainLength(length: $length) { 3 | id, 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/resources/explorer/graphql/epoch.graphql: -------------------------------------------------------------------------------- 1 | query Epoch($id: EpochNumber!, $blocks_limit: Int!) { 2 | epoch(id: $id) { 3 | id 4 | firstBlock { 5 | id 6 | } 7 | lastBlock { 8 | id 9 | } 10 | totalBlocks 11 | } 12 | tip { 13 | blocksByEpoch(epoch: $id, first: $blocks_limit) { 14 | edges { 15 | node { 16 | id 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/resources/explorer/graphql/generate_schema.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | if [ $# -ne 2 ]; then 5 | echo "usage: $0 " 6 | echo " graphql endpoint (http://127.0.0.1:10003/graphql)" 7 | echo " schema output location (schema.graphql)" 8 | exit 1 9 | fi 10 | 11 | echo "================Explorer schema generator =================" 12 | echo "This Script will dump schema into: '$2'" 13 | 14 | echo $(npm install -g get-graphql-schema) 15 | echo $(get-graphql-schema $1 > $2) 16 | echo "================ DONE =====================================" 17 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/resources/explorer/graphql/lastblock.graphql: -------------------------------------------------------------------------------- 1 | query LastBlock { 2 | tip { 3 | block { 4 | id 5 | chainLength 6 | date { 7 | epoch { 8 | id 9 | } 10 | slot 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/resources/explorer/graphql/settings.graphql: -------------------------------------------------------------------------------- 1 | query Settings { 2 | settings { 3 | epochStabilityDepth { 4 | epochStabilityDepth 5 | } 6 | fees { 7 | constant 8 | coefficient 9 | certificate 10 | perCertificateFees { 11 | certificatePoolRegistration 12 | certificateStakeDelegation 13 | certificateOwnerStakeDelegation 14 | } 15 | perVoteCertificateFees { 16 | certificateVotePlan 17 | certificateVoteCast 18 | } 19 | } 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/resources/explorer/graphql/stakepool.graphql: -------------------------------------------------------------------------------- 1 | query StakePool($id: PoolId!, $first: Int!){ 2 | stakePool(id: $id) { 3 | id, 4 | registration { 5 | pool { 6 | id 7 | } 8 | }, 9 | retirement { 10 | poolId 11 | }, 12 | blocks(first: $first) { 13 | edges { 14 | node { 15 | id 16 | } 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/resources/explorer/graphql/transactions_by_address.graphql: -------------------------------------------------------------------------------- 1 | query TransactionsByAddress($bech32: String!){ 2 | tip { 3 | transactionsByAddress(addressBech32: $bech32) { 4 | totalCount 5 | edges { 6 | node { 7 | id 8 | blocks{id date{...blockDate}} 9 | #inputs{amount address{id}} // BUG NPG-2869 10 | #outputs{amount address{id}} 11 | #certificate 12 | } 13 | } 14 | } 15 | } 16 | } 17 | 18 | fragment blockDate on BlockDate{ 19 | epoch{id} 20 | slot 21 | } 22 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/resources/explorer/graphql/voteplans.graphql: -------------------------------------------------------------------------------- 1 | query AllVotePlans($first: Int!) { 2 | tip { 3 | allVotePlans(first: $first) { 4 | edges { 5 | node { 6 | id 7 | voteStart { 8 | epoch { 9 | id 10 | } 11 | slot 12 | } 13 | voteEnd { 14 | epoch { 15 | id 16 | } 17 | slot 18 | } 19 | committeeEnd { 20 | epoch { 21 | id 22 | } 23 | slot 24 | } 25 | payloadType 26 | proposals { 27 | # proposalId 28 | options { 29 | start 30 | end 31 | } 32 | votes { 33 | edges { 34 | node { 35 | address { 36 | id 37 | } 38 | payload { 39 | __typename 40 | ... on VotePayloadPublicStatus { 41 | choice 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | } 49 | } 50 | totalCount 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/resources/tls/ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDRTCCAi2gAwIBAgIUelrAc2rBUZPZF3fiMjRzJ3YVw5UwDQYJKoZIhvcNAQEL 3 | BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMTEyMTA5NDcwNloXDTMwMTEx 4 | OTA5NDcwNlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF 5 | AAOCAQ8AMIIBCgKCAQEAlDO8ySUWZXK0GrL6Wn7en/7kbgYmoVSasjnjYyHpj93p 6 | 09sad9I7sXB2zHen9j/wxlNIU4zwkWzDk0WvmU8GLKRz/dxLGQsmdz+F1ivqZzlC 7 | 9hPx02igRWsmJ8SfnPAh5SpIFHUT5IGNUMegV1XFczVAMmQ/UtlTMu690+8Lbo2L 8 | fnGcB1tEG4F8yUfXsS2I63W6XffuAWqnku7m/+o6uSwqI8v5217PLah/lDPeKc+O 9 | JmxO/E0enBhSWnOIus4ajZIc3EN5sS0PNTE2enfmRsFZCmAHoYa7RDabDrs9uct1 10 | hTcDtHILn5WsKCHHIg60Ge+4LunIzr+FY8dmjIiO4wIDAQABo4GOMIGLMB0GA1Ud 11 | DgQWBBRTmhB7VH4tTsiBu02hkRrBhKuOljBPBgNVHSMESDBGgBRTmhB7VH4tTsiB 12 | u02hkRrBhKuOlqEYpBYwFDESMBAGA1UEAwwJbG9jYWxob3N0ghR6WsBzasFRk9kX 13 | d+IyNHMndhXDlTAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0B 14 | AQsFAAOCAQEAMiWzJwGGrC8ViJd33vvuR7/kdODg/uSIK4+pxzBGKRF0j5Ram5Gz 15 | a6fyrYfHtv/W5EqKPD8/NquJkcI0hXHPT/RgMbHkceWvCELedrXdg+ovAN03COIF 16 | l6Z4UhKWIoIXx9EmEZr0uebaTN49vZTda0JJMW/WB9VfN+xVvBTwqFlgtN8y7qvy 17 | 2AcE89E8i8yMaqkBoppm2zNqay2DScnqw7DGJNDra7mdWBKAjbqeh1kuJLhrxdO+ 18 | yt4p/dC8oQVo3ayFRORFCQNJEpogpF7gGC8R7eyXkoV2XO+qPEBMhKtdkI6mIT32 19 | BsqrtoUME9jKap4Y47i6+ZS0jxfpKbEMSA== 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/bin/grpc_client_app.rs: -------------------------------------------------------------------------------- 1 | use jormungandr_automation::jormungandr::grpc::client::JormungandrClient; 2 | use rand::Rng; 3 | use std::env; 4 | 5 | fn main() { 6 | let args: Vec = env::args().collect(); 7 | let client = JormungandrClient::from_address(&format!("{}:{}", args[1], args[2])).unwrap(); 8 | let mut auth_nonce = [0u8; 32]; 9 | rand::thread_rng().fill(&mut auth_nonce[..]); 10 | let response = client.handshake(&auth_nonce); 11 | println!("{:?}", response); 12 | } 13 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/bin/grpc_server_app.rs: -------------------------------------------------------------------------------- 1 | use chain_impl_mockchain::{ 2 | header::BlockDate, 3 | testing::{GenesisPraosBlockBuilder, StakePoolBuilder}, 4 | }; 5 | use chain_time::{Epoch, TimeEra}; 6 | use jormungandr_automation::jormungandr::grpc::server::MockBuilder; 7 | use std::env; 8 | 9 | fn main() { 10 | let args: Vec = env::args().collect(); 11 | let port: u16 = args[1].parse().unwrap(); 12 | 13 | let mut mock_controller = MockBuilder::default().with_port(port).build(); 14 | 15 | std::thread::sleep(std::time::Duration::from_secs(60)); 16 | 17 | let stake_pool = StakePoolBuilder::new().build(); 18 | let time_era = TimeEra::new(0u64.into(), Epoch(0u32), 30); 19 | 20 | let block = GenesisPraosBlockBuilder::new() 21 | .with_parent_id(mock_controller.genesis_hash()) 22 | .with_date(BlockDate { 23 | epoch: 0, 24 | slot_id: 1, 25 | }) 26 | .with_chain_length(1.into()) 27 | .build(&stake_pool, &time_era); 28 | 29 | mock_controller.set_tip_block(&block); 30 | std::thread::sleep(std::time::Duration::from_secs(60)); 31 | mock_controller.stop(); 32 | } 33 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/api/mod.rs: -------------------------------------------------------------------------------- 1 | mod address; 2 | mod certificate; 3 | mod genesis; 4 | mod key; 5 | mod rest; 6 | mod transaction; 7 | mod votes; 8 | 9 | pub use address::Address; 10 | pub use certificate::Certificate; 11 | pub use genesis::Genesis; 12 | pub use key::Key; 13 | pub use rest::Rest; 14 | pub use transaction::Transaction; 15 | pub use votes::Votes; 16 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/api/rest/mod.rs: -------------------------------------------------------------------------------- 1 | mod v0; 2 | mod v1; 3 | 4 | use crate::jcli::command::RestCommand; 5 | use v0::RestV0; 6 | use v1::RestV1; 7 | 8 | pub struct Rest { 9 | rest_command: RestCommand, 10 | } 11 | 12 | impl Rest { 13 | pub fn new(rest_command: RestCommand) -> Self { 14 | Self { rest_command } 15 | } 16 | 17 | pub fn v0(self) -> RestV0 { 18 | RestV0::new(self.rest_command.v0()) 19 | } 20 | 21 | pub fn v1(self) -> RestV1 { 22 | RestV1::new(self.rest_command.v1()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/api/rest/v0/node.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli::command::rest::v0::NodeCommand; 2 | use assert_cmd::assert::OutputAssertExt; 3 | use jortestkit::prelude::ProcessOutput; 4 | use std::collections::BTreeMap; 5 | 6 | pub struct Node { 7 | node_command: NodeCommand, 8 | } 9 | 10 | impl Node { 11 | pub fn new(node_command: NodeCommand) -> Self { 12 | Self { node_command } 13 | } 14 | 15 | pub fn stats>(self, host: S) -> BTreeMap { 16 | self.node_command 17 | .stats(host) 18 | .build() 19 | .assert() 20 | .success() 21 | .get_output() 22 | .as_single_node_yaml() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/api/rest/v0/vote.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli::command::rest::v0::VoteCommand; 2 | use assert_cmd::assert::OutputAssertExt; 3 | use jormungandr_lib::interfaces::{CommitteeIdDef, VotePlanStatus}; 4 | use jortestkit::prelude::ProcessOutput; 5 | 6 | pub struct Vote { 7 | vote_command: VoteCommand, 8 | } 9 | 10 | impl Vote { 11 | pub fn new(vote_command: VoteCommand) -> Self { 12 | Self { vote_command } 13 | } 14 | 15 | pub fn active_voting_committees>(self, host: S) -> Vec { 16 | let content = self 17 | .vote_command 18 | .active_committees(host) 19 | .build() 20 | .assert() 21 | .success() 22 | .get_output() 23 | .as_lossy_string(); 24 | serde_yaml::from_str(&content).expect("JCLI returned malformed CommitteeIdDef") 25 | } 26 | 27 | pub fn active_vote_plans>(self, host: S) -> Vec { 28 | let content = self 29 | .vote_command 30 | .active_vote_plans(host) 31 | .build() 32 | .assert() 33 | .success() 34 | .get_output() 35 | .as_lossy_string(); 36 | serde_yaml::from_str(&content).expect("JCLI returned malformed VotePlan") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/api/rest/v1/mod.rs: -------------------------------------------------------------------------------- 1 | mod vote; 2 | 3 | use crate::jcli::command::rest::V1Command; 4 | use vote::Vote; 5 | 6 | pub struct RestV1 { 7 | v1_command: V1Command, 8 | } 9 | 10 | impl RestV1 { 11 | pub fn new(v1_command: V1Command) -> Self { 12 | Self { v1_command } 13 | } 14 | 15 | pub fn vote(self) -> Vote { 16 | Vote::new(self.v1_command.vote()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/api/rest/v1/vote.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli::command::rest::v1::VoteCommand; 2 | use assert_cmd::assert::OutputAssertExt; 3 | use jortestkit::prelude::ProcessOutput; 4 | 5 | pub struct Vote { 6 | vote_command: VoteCommand, 7 | } 8 | 9 | impl Vote { 10 | pub fn new(vote_command: VoteCommand) -> Self { 11 | Self { vote_command } 12 | } 13 | 14 | pub fn account_votes( 15 | self, 16 | account: impl Into, 17 | voteplan: impl Into, 18 | host: impl Into, 19 | ) -> Vec { 20 | let content = self 21 | .vote_command 22 | .account_votes(account, voteplan, host) 23 | .build() 24 | .assert() 25 | .success() 26 | .get_output() 27 | .as_lossy_string(); 28 | serde_yaml::from_str(&content).expect("JCLI returned malformed proposals") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/api/votes/committee/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli::command::votes::CommitteeCommand; 2 | 3 | mod communication_key; 4 | mod member_key; 5 | 6 | pub use communication_key::CommunicationKey; 7 | pub use member_key::MemberKey; 8 | 9 | pub struct Committee { 10 | committee_command: CommitteeCommand, 11 | } 12 | 13 | impl Committee { 14 | pub fn new(committee_command: CommitteeCommand) -> Self { 15 | Self { committee_command } 16 | } 17 | 18 | pub fn member_key(self) -> MemberKey { 19 | MemberKey::new(self.committee_command.member_key()) 20 | } 21 | 22 | pub fn communication_key(self) -> CommunicationKey { 23 | CommunicationKey::new(self.committee_command.communication_key()) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/api/votes/crs.rs: -------------------------------------------------------------------------------- 1 | use crate::jcli::command::votes::CrsCommand; 2 | use assert_cmd::assert::OutputAssertExt; 3 | use jortestkit::prelude::ProcessOutput; 4 | 5 | pub struct Crs { 6 | crs_command: CrsCommand, 7 | } 8 | 9 | impl Crs { 10 | pub fn new(crs_command: CrsCommand) -> Self { 11 | Self { crs_command } 12 | } 13 | 14 | pub fn generate(self) -> String { 15 | self.crs_command 16 | .generate() 17 | .build() 18 | .assert() 19 | .success() 20 | .get_output() 21 | .as_single_line() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/address/account.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | pub struct AccountCommand { 3 | command: Command, 4 | } 5 | 6 | impl AccountCommand { 7 | pub fn new(command: Command) -> Self { 8 | Self { command } 9 | } 10 | 11 | pub fn public_key>(mut self, public_key: S) -> Self { 12 | self.command.arg(public_key.into()); 13 | self 14 | } 15 | 16 | pub fn test_discrimination(mut self) -> Self { 17 | self.command.arg("--testing"); 18 | self 19 | } 20 | 21 | pub fn prefix>(mut self, prefix: S) -> Self { 22 | self.command.arg("--prefix").arg(prefix.into()); 23 | self 24 | } 25 | 26 | pub fn build(self) -> Command { 27 | self.command 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/address/info.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | pub struct InfoCommand { 3 | command: Command, 4 | } 5 | 6 | impl InfoCommand { 7 | pub fn new(command: Command) -> Self { 8 | Self { command } 9 | } 10 | 11 | pub fn address>(mut self, address: S) -> Self { 12 | self.command.arg(address.into()); 13 | self 14 | } 15 | 16 | pub fn build(self) -> Command { 17 | self.command 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/address/mod.rs: -------------------------------------------------------------------------------- 1 | mod account; 2 | mod info; 3 | mod single; 4 | 5 | pub use account::AccountCommand; 6 | pub use info::InfoCommand; 7 | pub use single::SingleCommand; 8 | use std::process::Command; 9 | pub struct AddressCommand { 10 | command: Command, 11 | } 12 | 13 | impl AddressCommand { 14 | pub fn new(command: Command) -> Self { 15 | Self { command } 16 | } 17 | 18 | pub fn account(mut self) -> AccountCommand { 19 | self.command.arg("account"); 20 | AccountCommand::new(self.command) 21 | } 22 | 23 | pub fn info(mut self) -> InfoCommand { 24 | self.command.arg("info"); 25 | InfoCommand::new(self.command) 26 | } 27 | 28 | pub fn single(mut self) -> SingleCommand { 29 | self.command.arg("single"); 30 | SingleCommand::new(self.command) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/address/single.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | pub struct SingleCommand { 3 | command: Command, 4 | } 5 | 6 | impl SingleCommand { 7 | pub fn new(command: Command) -> Self { 8 | Self { command } 9 | } 10 | 11 | pub fn public_key>(mut self, public_key: S) -> Self { 12 | self.command.arg(public_key.into()); 13 | self 14 | } 15 | 16 | pub fn test_discrimination(mut self) -> Self { 17 | self.command.arg("--testing"); 18 | self 19 | } 20 | 21 | pub fn delegation_key>(mut self, delegation_key: S) -> Self { 22 | self.command.arg(delegation_key.into()); 23 | self 24 | } 25 | 26 | pub fn prefix>(mut self, prefix: S) -> Self { 27 | self.command.arg("--prefix").arg(prefix.into()); 28 | self 29 | } 30 | 31 | pub fn build(self) -> Command { 32 | self.command 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/genesis/decode.rs: -------------------------------------------------------------------------------- 1 | use std::{path::Path, process::Command}; 2 | pub struct GenesisDecodeCommand { 3 | command: Command, 4 | } 5 | 6 | impl GenesisDecodeCommand { 7 | pub fn new(command: Command) -> Self { 8 | Self { command } 9 | } 10 | 11 | pub fn input>(mut self, input: P) -> Self { 12 | self.command.arg("--input").arg(input.as_ref()); 13 | self 14 | } 15 | 16 | pub fn output>(mut self, output: P) -> Self { 17 | self.command.arg("--output").arg(output.as_ref()); 18 | self 19 | } 20 | 21 | pub fn build(self) -> Command { 22 | self.command 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/genesis/encode.rs: -------------------------------------------------------------------------------- 1 | use std::{path::Path, process::Command}; 2 | pub struct GenesisEncodeCommand { 3 | command: Command, 4 | } 5 | 6 | impl GenesisEncodeCommand { 7 | pub fn new(command: Command) -> Self { 8 | Self { command } 9 | } 10 | 11 | pub fn input>(mut self, input: P) -> Self { 12 | self.command.arg("--input").arg(input.as_ref()); 13 | self 14 | } 15 | 16 | pub fn output>(mut self, output: P) -> Self { 17 | self.command.arg("--output").arg(output.as_ref()); 18 | self 19 | } 20 | 21 | pub fn build(self) -> Command { 22 | self.command 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/genesis/hash.rs: -------------------------------------------------------------------------------- 1 | use std::{path::Path, process::Command}; 2 | pub struct GenesisHashCommand { 3 | command: Command, 4 | } 5 | 6 | impl GenesisHashCommand { 7 | pub fn new(command: Command) -> Self { 8 | Self { command } 9 | } 10 | 11 | pub fn input>(mut self, input: P) -> Self { 12 | self.command.arg("--input").arg(input.as_ref()); 13 | self 14 | } 15 | 16 | pub fn build(self) -> Command { 17 | self.command 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/genesis/mod.rs: -------------------------------------------------------------------------------- 1 | mod decode; 2 | mod encode; 3 | mod hash; 4 | 5 | pub use decode::GenesisDecodeCommand; 6 | pub use encode::GenesisEncodeCommand; 7 | pub use hash::GenesisHashCommand; 8 | use std::process::Command; 9 | pub struct GenesisCommand { 10 | command: Command, 11 | } 12 | 13 | impl GenesisCommand { 14 | pub fn new(command: Command) -> Self { 15 | Self { command } 16 | } 17 | 18 | pub fn encode(mut self) -> GenesisEncodeCommand { 19 | self.command.arg("encode"); 20 | GenesisEncodeCommand::new(self.command) 21 | } 22 | 23 | pub fn decode(mut self) -> GenesisDecodeCommand { 24 | self.command.arg("decode"); 25 | GenesisDecodeCommand::new(self.command) 26 | } 27 | 28 | pub fn hash(mut self) -> GenesisHashCommand { 29 | self.command.arg("hash"); 30 | GenesisHashCommand::new(self.command) 31 | } 32 | 33 | pub fn init(mut self) -> Command { 34 | self.command.arg("init"); 35 | self.command 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/key/from_bytes.rs: -------------------------------------------------------------------------------- 1 | use std::{path::Path, process::Command}; 2 | pub struct KeyFromBytesCommand { 3 | command: Command, 4 | } 5 | 6 | impl KeyFromBytesCommand { 7 | pub fn new(command: Command) -> Self { 8 | Self { command } 9 | } 10 | 11 | pub fn input>(mut self, input: P) -> Self { 12 | self.command.arg(input.as_ref()); 13 | self 14 | } 15 | 16 | pub fn key_type>(mut self, key_type: S) -> Self { 17 | self.command.arg("--type").arg(key_type.into()); 18 | self 19 | } 20 | 21 | pub fn build(self) -> Command { 22 | self.command 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/key/generate.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | pub struct KeyGenerateCommand { 3 | command: Command, 4 | } 5 | 6 | impl KeyGenerateCommand { 7 | pub fn new(command: Command) -> Self { 8 | Self { command } 9 | } 10 | 11 | pub fn key_type>(mut self, key_type: S) -> Self { 12 | self.command.arg("--type").arg(key_type.into()); 13 | self 14 | } 15 | 16 | pub fn seed>(mut self, seed: S) -> Self { 17 | self.command.arg("--seed").arg(seed.into()); 18 | self 19 | } 20 | 21 | pub fn build(self) -> Command { 22 | self.command 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/key/mod.rs: -------------------------------------------------------------------------------- 1 | mod from_bytes; 2 | mod generate; 3 | mod to_bytes; 4 | mod to_public; 5 | 6 | pub use from_bytes::KeyFromBytesCommand; 7 | pub use generate::KeyGenerateCommand; 8 | use std::process::Command; 9 | pub use to_bytes::KeyToBytesCommand; 10 | pub use to_public::KeyToPublicCommand; 11 | 12 | pub struct KeyCommand { 13 | command: Command, 14 | } 15 | 16 | #[allow(clippy::wrong_self_convention)] 17 | impl KeyCommand { 18 | pub fn new(command: Command) -> Self { 19 | Self { command } 20 | } 21 | 22 | pub fn generate(mut self) -> KeyGenerateCommand { 23 | self.command.arg("generate"); 24 | KeyGenerateCommand::new(self.command) 25 | } 26 | 27 | pub fn to_bytes(mut self) -> KeyToBytesCommand { 28 | self.command.arg("to-bytes"); 29 | KeyToBytesCommand::new(self.command) 30 | } 31 | 32 | pub fn from_bytes(mut self) -> KeyFromBytesCommand { 33 | self.command.arg("from-bytes"); 34 | KeyFromBytesCommand::new(self.command) 35 | } 36 | 37 | pub fn to_public(mut self) -> KeyToPublicCommand { 38 | self.command.arg("to-public"); 39 | KeyToPublicCommand::new(self.command) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/key/to_bytes.rs: -------------------------------------------------------------------------------- 1 | use std::{path::Path, process::Command}; 2 | pub struct KeyToBytesCommand { 3 | command: Command, 4 | } 5 | 6 | impl KeyToBytesCommand { 7 | pub fn new(command: Command) -> Self { 8 | Self { command } 9 | } 10 | 11 | pub fn input>(mut self, input: P) -> Self { 12 | self.command.arg(input.as_ref()); 13 | self 14 | } 15 | 16 | pub fn output>(mut self, output: P) -> Self { 17 | self.command.arg(output.as_ref()); 18 | self 19 | } 20 | 21 | pub fn build(self) -> Command { 22 | self.command 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/key/to_public.rs: -------------------------------------------------------------------------------- 1 | use std::{path::Path, process::Command}; 2 | pub struct KeyToPublicCommand { 3 | command: Command, 4 | } 5 | 6 | impl KeyToPublicCommand { 7 | pub fn new(command: Command) -> Self { 8 | Self { command } 9 | } 10 | 11 | pub fn input>(mut self, input: P) -> Self { 12 | self.command.arg("--input").arg(input.as_ref()); 13 | self 14 | } 15 | 16 | pub fn output>(mut self, output: P) -> Self { 17 | self.command.arg(output.as_ref()); 18 | self 19 | } 20 | 21 | pub fn build(self) -> Command { 22 | self.command 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/rest/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod v0; 2 | pub mod v1; 3 | 4 | use std::process::Command; 5 | pub use v0::V0Command; 6 | pub use v1::V1Command; 7 | 8 | pub struct RestCommand { 9 | command: Command, 10 | } 11 | 12 | impl RestCommand { 13 | pub fn new(command: Command) -> Self { 14 | Self { command } 15 | } 16 | 17 | pub fn v0(mut self) -> V0Command { 18 | self.command.arg("v0"); 19 | V0Command::new(self.command) 20 | } 21 | 22 | pub fn v1(mut self) -> V1Command { 23 | self.command.arg("v1"); 24 | V1Command::new(self.command) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/rest/v0/block.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | pub struct BlockCommand { 4 | command: Command, 5 | } 6 | 7 | impl BlockCommand { 8 | pub fn new(command: Command) -> Self { 9 | Self { command } 10 | } 11 | 12 | pub fn get, S: Into>(mut self, block_id: P, host: S) -> Self { 13 | self.command 14 | .arg(block_id.into()) 15 | .arg("get") 16 | .arg("-h") 17 | .arg(host.into()); 18 | self 19 | } 20 | pub fn next, S: Into>( 21 | mut self, 22 | block_id: P, 23 | limit: u32, 24 | host: S, 25 | ) -> Self { 26 | self.command 27 | .arg(block_id.into()) 28 | .arg("next-id") 29 | .arg("get") 30 | .arg("--count") 31 | .arg(limit.to_string()) 32 | .arg("-h") 33 | .arg(host.into()); 34 | self 35 | } 36 | 37 | pub fn build(self) -> Command { 38 | self.command 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/rest/v0/message.rs: -------------------------------------------------------------------------------- 1 | use std::{path::Path, process::Command}; 2 | 3 | pub struct MessageCommand { 4 | command: Command, 5 | } 6 | 7 | impl MessageCommand { 8 | pub fn new(command: Command) -> Self { 9 | Self { command } 10 | } 11 | 12 | pub fn post, S: Into>(mut self, transaction_file: P, host: S) -> Self { 13 | self.command 14 | .arg("post") 15 | .arg("--file") 16 | .arg(transaction_file.as_ref()) 17 | .arg("--host") 18 | .arg(host.into()); 19 | self 20 | } 21 | 22 | pub fn logs>(mut self, host: S) -> Self { 23 | self.command.arg("logs").arg("--host").arg(host.into()); 24 | self 25 | } 26 | 27 | pub fn build(self) -> Command { 28 | self.command 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/rest/v0/node.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | pub struct NodeCommand { 4 | command: Command, 5 | } 6 | 7 | impl NodeCommand { 8 | pub fn new(command: Command) -> Self { 9 | Self { command } 10 | } 11 | 12 | pub fn stats>(mut self, host: S) -> Self { 13 | self.command 14 | .arg("stats") 15 | .arg("get") 16 | .arg("-h") 17 | .arg(host.into()); 18 | self 19 | } 20 | 21 | pub fn build(self) -> Command { 22 | self.command 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/rest/v0/utxo.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | pub struct UtxOCommand { 4 | command: Command, 5 | } 6 | 7 | impl UtxOCommand { 8 | pub fn new(command: Command) -> Self { 9 | Self { command } 10 | } 11 | 12 | pub fn get(mut self) -> Self { 13 | self.command.arg("get"); 14 | self 15 | } 16 | 17 | pub fn host>(mut self, host: S) -> Self { 18 | self.command.arg("--host").arg(host.into()); 19 | self 20 | } 21 | 22 | pub fn fragment_id>(mut self, fragment_id: S) -> Self { 23 | self.command.arg(fragment_id.into()); 24 | self 25 | } 26 | 27 | pub fn output_index(mut self, output_index: u8) -> Self { 28 | self.command.arg(output_index.to_string()); 29 | self 30 | } 31 | 32 | pub fn build(self) -> Command { 33 | self.command 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/rest/v0/vote.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | pub struct VoteCommand { 4 | command: Command, 5 | } 6 | 7 | impl VoteCommand { 8 | pub fn new(command: Command) -> Self { 9 | Self { command } 10 | } 11 | 12 | pub fn active_committees>(mut self, host: S) -> Self { 13 | self.command 14 | .arg("active") 15 | .arg("committees") 16 | .arg("get") 17 | .arg("--host") 18 | .arg(host.into()); 19 | self 20 | } 21 | 22 | pub fn active_vote_plans>(mut self, host: S) -> Self { 23 | self.command 24 | .arg("active") 25 | .arg("plans") 26 | .arg("get") 27 | .arg("--host") 28 | .arg(host.into()); 29 | self 30 | } 31 | 32 | pub fn build(self) -> Command { 33 | println!("{:?}", self.command); 34 | self.command 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/rest/v1/mod.rs: -------------------------------------------------------------------------------- 1 | mod vote; 2 | 3 | use std::process::Command; 4 | pub use vote::VoteCommand; 5 | 6 | pub struct V1Command { 7 | command: Command, 8 | } 9 | 10 | impl V1Command { 11 | pub fn new(command: Command) -> Self { 12 | Self { command } 13 | } 14 | 15 | pub fn vote(mut self) -> VoteCommand { 16 | self.command.arg("vote"); 17 | VoteCommand::new(self.command) 18 | } 19 | 20 | pub fn build(self) -> Command { 21 | println!("{:?}", self.command); 22 | self.command 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/rest/v1/vote.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | pub struct VoteCommand { 4 | command: Command, 5 | } 6 | 7 | impl VoteCommand { 8 | pub fn new(command: Command) -> Self { 9 | Self { command } 10 | } 11 | 12 | pub fn account_votes( 13 | mut self, 14 | account: impl Into, 15 | voteplan: impl Into, 16 | host: impl Into, 17 | ) -> Self { 18 | self.command 19 | .arg("account-votes") 20 | .arg("--host") 21 | .arg(host.into()) 22 | .arg("--account-id") 23 | .arg(account.into()) 24 | .arg("--vote-plan-id") 25 | .arg(voteplan.into()); 26 | self 27 | } 28 | 29 | pub fn build(self) -> Command { 30 | println!("{:?}", self.command); 31 | self.command 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/votes/committee/communication_key.rs: -------------------------------------------------------------------------------- 1 | use std::{path::Path, process::Command}; 2 | 3 | pub struct CommunicationKeyCommand { 4 | command: Command, 5 | } 6 | 7 | impl CommunicationKeyCommand { 8 | pub fn new(command: Command) -> Self { 9 | Self { command } 10 | } 11 | 12 | #[allow(clippy::wrong_self_convention)] 13 | pub fn to_public, Q: AsRef>( 14 | mut self, 15 | private_key_file: P, 16 | output_file: Q, 17 | ) -> Self { 18 | self.command 19 | .arg("to-public") 20 | .arg("--input") 21 | .arg(private_key_file.as_ref()) 22 | .arg(output_file.as_ref()); 23 | self 24 | } 25 | 26 | pub fn generate(mut self) -> Self { 27 | self.command.arg("generate"); 28 | self 29 | } 30 | 31 | pub fn build(self) -> Command { 32 | println!("{:?}", self.command); 33 | self.command 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/votes/committee/mod.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | mod communication_key; 4 | mod member_key; 5 | 6 | pub use communication_key::CommunicationKeyCommand; 7 | pub use member_key::MemberKeyCommand; 8 | 9 | pub struct CommitteeCommand { 10 | command: Command, 11 | } 12 | 13 | impl CommitteeCommand { 14 | pub fn new(command: Command) -> Self { 15 | Self { command } 16 | } 17 | 18 | pub fn member_key(mut self) -> MemberKeyCommand { 19 | self.command.arg("member-key"); 20 | MemberKeyCommand::new(self.command) 21 | } 22 | 23 | pub fn communication_key(mut self) -> CommunicationKeyCommand { 24 | self.command.arg("communication-key"); 25 | CommunicationKeyCommand::new(self.command) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/votes/crs.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | pub struct CrsCommand { 3 | command: Command, 4 | } 5 | 6 | impl CrsCommand { 7 | pub fn new(command: Command) -> Self { 8 | Self { command } 9 | } 10 | 11 | pub fn generate(mut self) -> Self { 12 | self.command.arg("generate"); 13 | self 14 | } 15 | 16 | pub fn build(self) -> Command { 17 | println!("{:?}", self.command); 18 | self.command 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/command/votes/election_public_key.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | pub struct ElectionPublicKeyCommand { 3 | command: Command, 4 | } 5 | 6 | impl ElectionPublicKeyCommand { 7 | pub fn new(command: Command) -> Self { 8 | Self { command } 9 | } 10 | 11 | pub fn generate(mut self) -> Self { 12 | self.command.arg("generate"); 13 | self 14 | } 15 | 16 | pub fn build(self) -> Command { 17 | println!("{:?}", self.command); 18 | self.command 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/data/mod.rs: -------------------------------------------------------------------------------- 1 | mod witness; 2 | 3 | pub use witness::{Witness, WitnessData, WitnessType}; 4 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/services/mod.rs: -------------------------------------------------------------------------------- 1 | mod certificate_builder; 2 | mod fragment_check; 3 | mod fragment_sender; 4 | mod fragments_check; 5 | mod transaction_builder; 6 | 7 | pub use certificate_builder::CertificateBuilder; 8 | pub use fragment_check::FragmentCheck; 9 | pub use fragment_sender::FragmentSender; 10 | pub use fragments_check::FragmentsCheck; 11 | use jormungandr_lib::crypto::hash::Hash; 12 | use thiserror::Error; 13 | pub use transaction_builder::TransactionBuilder; 14 | 15 | #[derive(Debug, Error)] 16 | pub enum Error { 17 | #[error("transaction {transaction_id} is not in block. message log: {message_log}. Jormungandr log: {log_content}")] 18 | TransactionNotInBlock { 19 | message_log: String, 20 | transaction_id: Hash, 21 | log_content: String, 22 | }, 23 | #[error("at least one transaction is not in block. message log: {message_log}. Jormungandr log: {log_content}")] 24 | TransactionsNotInBlock { 25 | message_log: String, 26 | log_content: String, 27 | }, 28 | } 29 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jcli/utxo.rs: -------------------------------------------------------------------------------- 1 | extern crate serde_derive; 2 | use self::serde_derive::{Deserialize, Serialize}; 3 | 4 | #[derive(Debug, Serialize, Deserialize)] 5 | pub struct Utxo { 6 | pub in_idx: i32, 7 | pub in_txid: String, 8 | pub out_addr: String, 9 | pub out_value: i32, 10 | } 11 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jormungandr/explorer/wrappers.rs: -------------------------------------------------------------------------------- 1 | use crate::jormungandr::explorer::{data::last_block, BlockDate}; 2 | use chain_impl_mockchain::block::BlockDate as LibBlockDate; 3 | use graphql_client::Response; 4 | 5 | #[derive(Debug)] 6 | pub struct LastBlockResponse { 7 | data: Response, 8 | } 9 | 10 | impl LastBlockResponse { 11 | pub fn new(data: Response) -> Self { 12 | Self { data } 13 | } 14 | 15 | pub fn block(&self) -> &last_block::LastBlockTipBlock { 16 | &self.data.data.as_ref().unwrap().tip.block 17 | } 18 | 19 | pub fn block_date(&self) -> BlockDate { 20 | let date = &self.data.data.as_ref().unwrap().tip.block.date; 21 | 22 | let block_date = LibBlockDate { 23 | epoch: date.epoch.id.parse().unwrap(), 24 | slot_id: date.slot.parse().unwrap(), 25 | }; 26 | BlockDate::from(block_date) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jormungandr/grpc/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod client; 2 | pub mod server; 3 | 4 | pub use client::JormungandrClient; 5 | pub use server::JormungandrServerImpl; 6 | 7 | mod node { 8 | tonic::include_proto!("iohk.chain.node"); // The string specified here must match the proto package name 9 | } 10 | 11 | mod types { 12 | tonic::include_proto!("iohk.chain.types"); // The string specified here must match the proto package name 13 | } 14 | 15 | mod watch { 16 | tonic::include_proto!("iohk.chain.watch"); // The string specified here must match the proto package name 17 | } 18 | 19 | use chain_core::{packer::Codec, property::DeserializeFromSlice}; 20 | 21 | pub fn read_into(bytes: &[u8]) -> T { 22 | let mut buf = Codec::new(bytes); 23 | T::deserialize_from_slice(&mut buf).unwrap() 24 | } 25 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jormungandr/grpc/server/verifier.rs: -------------------------------------------------------------------------------- 1 | use super::{logger::MethodType, MockLogger}; 2 | 3 | pub struct MockVerifier { 4 | logger: MockLogger, 5 | } 6 | 7 | impl MockVerifier { 8 | pub fn new(logger: MockLogger) -> Self { 9 | Self { logger } 10 | } 11 | 12 | pub fn method_executed_at_least_once(&self, method: MethodType) -> bool { 13 | self.logger.executed_at_least_once(method) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jormungandr/legacy/config/node.rs: -------------------------------------------------------------------------------- 1 | use super::NodeConfig; 2 | use crate::jormungandr::configuration::TestConfig; 3 | use jormungandr_lib::multiaddr::to_tcp_socket_addr; 4 | use multiaddr::Multiaddr; 5 | use std::{net::SocketAddr, path::Path}; 6 | 7 | impl TestConfig for NodeConfig { 8 | fn log_file_path(&self) -> Option<&Path> { 9 | self.log.as_ref().and_then(|log| log.file_path()) 10 | } 11 | 12 | fn p2p_listen_address(&self) -> SocketAddr { 13 | if let Some(address) = &self.p2p.listen { 14 | *address 15 | } else { 16 | to_tcp_socket_addr(&self.p2p.public_address).unwrap() 17 | } 18 | } 19 | 20 | fn p2p_public_address(&self) -> Multiaddr { 21 | self.p2p.public_address.clone() 22 | } 23 | 24 | fn set_p2p_public_address(&mut self, address: Multiaddr) { 25 | self.p2p.public_address = address; 26 | } 27 | 28 | fn rest_socket_addr(&self) -> SocketAddr { 29 | self.rest.listen 30 | } 31 | 32 | fn set_rest_socket_addr(&mut self, addr: SocketAddr) { 33 | self.rest.listen = addr; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jormungandr/legacy/version.rs: -------------------------------------------------------------------------------- 1 | pub use semver::Version; 2 | 3 | pub fn version_0_8_19() -> Version { 4 | Version::new(0, 8, 19) 5 | } 6 | 7 | pub fn version_0_13_0() -> Version { 8 | Version::new(0, 13, 0) 9 | } 10 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/jormungandr/rest/settings.rs: -------------------------------------------------------------------------------- 1 | use reqwest::Certificate; 2 | 3 | #[derive(Debug, Clone, Default)] 4 | pub struct RestSettings { 5 | pub enable_debug: bool, 6 | pub use_https: bool, 7 | pub certificate: Option, 8 | pub cors: Option, 9 | } 10 | 11 | impl RestSettings { 12 | pub fn new_use_https() -> Self { 13 | RestSettings { 14 | enable_debug: false, 15 | use_https: true, 16 | certificate: None, 17 | cors: None, 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn(clippy::all)] 2 | pub mod jcli; 3 | pub mod jormungandr; 4 | pub mod testing; 5 | pub mod utils; 6 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/testing/benchmark/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod node; 2 | pub mod sync; 3 | 4 | pub use node::{speed_benchmark_from_log, storage_loading_benchmark_from_log}; 5 | pub use sync::*; 6 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/testing/keys.rs: -------------------------------------------------------------------------------- 1 | use chain_crypto::AsymmetricKey; 2 | use jormungandr_lib::crypto::key::KeyPair; 3 | 4 | pub fn create_new_key_pair() -> KeyPair { 5 | KeyPair::generate(rand::rngs::OsRng) 6 | } 7 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/testing/observer.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | #[derive(Debug, Clone)] 4 | pub struct Event { 5 | pub message: String, 6 | } 7 | 8 | impl Event { 9 | pub fn new>(s: S) -> Self { 10 | Self { message: s.into() } 11 | } 12 | } 13 | 14 | pub trait Observable { 15 | fn register(self, observer: &Rc) -> Self; 16 | fn notify_all(&self, event: Event); 17 | fn finish_all(&self); 18 | } 19 | 20 | pub trait Observer { 21 | fn notify(&self, event: Event); 22 | fn finished(&self); 23 | } 24 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/testing/process.rs: -------------------------------------------------------------------------------- 1 | use jormungandr_lib::crypto::hash::Hash; 2 | use jortestkit::prelude::ProcessOutput as _; 3 | use std::process::Output; 4 | 5 | pub trait ProcessOutput { 6 | fn as_hash(&self) -> Hash; 7 | } 8 | 9 | impl ProcessOutput for Output { 10 | fn as_hash(&self) -> Hash { 11 | let single_line = self.as_single_line(); 12 | let result = Hash::from_hex(&single_line); 13 | assert!(result.is_ok(), "Cannot parse line {} as hash", single_line); 14 | result.unwrap() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/testing/resources.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | fn root_dir() -> PathBuf { 4 | PathBuf::from(env!("CARGO_MANIFEST_DIR")) 5 | } 6 | 7 | pub fn tls_server_private_key() -> PathBuf { 8 | let mut tls_server_private_key = root_dir(); 9 | tls_server_private_key.push("resources/tls/server.key"); 10 | tls_server_private_key 11 | } 12 | 13 | pub fn tls_server_crt() -> PathBuf { 14 | let mut tls_server_crt = root_dir(); 15 | tls_server_crt.push("resources/tls/server.crt"); 16 | tls_server_crt 17 | } 18 | 19 | pub fn tls_ca_crt() -> PathBuf { 20 | let mut tls_ca_crt = root_dir(); 21 | tls_ca_crt.push("resources/tls/ca.crt"); 22 | tls_ca_crt 23 | } 24 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/testing/time.rs: -------------------------------------------------------------------------------- 1 | use crate::jormungandr::JormungandrRest; 2 | use chain_impl_mockchain::block::BlockDate as ChainBlockDate; 3 | use jormungandr_lib::interfaces::BlockDate; 4 | use std::str::FromStr; 5 | 6 | pub fn wait_for_epoch(epoch: u32, rest: JormungandrRest) { 7 | wait_for_date(ChainBlockDate { epoch, slot_id: 0 }.into(), rest) 8 | } 9 | 10 | pub fn wait_for_date(target_block_date: BlockDate, mut rest: JormungandrRest) { 11 | let settings = rest.settings().unwrap(); 12 | while is_it_due(get_current_date(&mut rest), target_block_date) { 13 | std::thread::sleep(std::time::Duration::from_secs(settings.slot_duration)); 14 | } 15 | } 16 | 17 | fn is_it_due(current_block_date: BlockDate, target_block_date: BlockDate) -> bool { 18 | println!( 19 | "waiting for block date : {}.{}/{}.{}", 20 | current_block_date.epoch(), 21 | current_block_date.slot(), 22 | target_block_date.epoch(), 23 | target_block_date.slot() 24 | ); 25 | current_block_date < target_block_date 26 | } 27 | 28 | pub fn get_current_date(rest: &mut JormungandrRest) -> BlockDate { 29 | BlockDate::from_str( 30 | rest.stats() 31 | .unwrap() 32 | .stats 33 | .unwrap() 34 | .last_block_date 35 | .unwrap() 36 | .as_ref(), 37 | ) 38 | .unwrap() 39 | } 40 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/testing/verify.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use thiserror::Error; 3 | 4 | #[derive(Debug, Error)] 5 | pub enum Error { 6 | #[error("{0}")] 7 | VerificationFailed(String), 8 | } 9 | 10 | pub fn assert_equals( 11 | left: &A, 12 | right: &A, 13 | info: &str, 14 | ) -> Result<(), Error> { 15 | if left != right { 16 | return Err(Error::VerificationFailed(format!( 17 | "{}. {:?} vs {:?}", 18 | info, left, right 19 | ))); 20 | } 21 | Ok(()) 22 | } 23 | 24 | pub fn assert(statement: bool, info: &str) -> Result<(), Error> { 25 | if !statement { 26 | return Err(Error::VerificationFailed(info.to_string())); 27 | } 28 | Ok(()) 29 | } 30 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | mod multiaddr; 2 | 3 | pub use self::multiaddr::MultiaddrExtension; 4 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/utils/multiaddr.rs: -------------------------------------------------------------------------------- 1 | use multiaddr::Multiaddr; 2 | 3 | pub trait MultiaddrExtension { 4 | fn to_http_addr(self) -> String; 5 | } 6 | 7 | impl MultiaddrExtension for Multiaddr { 8 | fn to_http_addr(mut self) -> String { 9 | let port = match self.pop().unwrap() { 10 | multiaddr::Protocol::Tcp(port) => port, 11 | _ => todo!("explorer can only be attached through grpc(http)"), 12 | }; 13 | 14 | let address = match self.pop().unwrap() { 15 | multiaddr::Protocol::Ip4(address) => address, 16 | _ => todo!("only ipv4 supported for now"), 17 | }; 18 | format!("http://{}:{}/", address, port) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /testing/jormungandr-automation/src/utils/observer.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | #[derive(Debug, Clone)] 4 | pub struct Event { 5 | pub message: String, 6 | } 7 | 8 | impl Event { 9 | pub fn new>(s: S) -> Self { 10 | Self { message: s.into() } 11 | } 12 | } 13 | 14 | pub trait Observable { 15 | fn register(self, observer: &Rc) -> Self; 16 | fn notify_all(&self, event: Event); 17 | fn finish_all(&self); 18 | } 19 | 20 | pub trait Observer { 21 | fn notify(&self, event: Event); 22 | fn finished(&self); 23 | } 24 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let jor_cli_name = option_env!("JOR_CLI_NAME").unwrap_or("jcli"); 3 | let jormungandr_name = option_env!("JORMUNGANDR_NAME").unwrap_or("jormungandr"); 4 | let jor_explorer_name = option_env!("JOR_EXPLORER_NAME").unwrap_or("explorer"); 5 | println!("cargo:rustc-env=JOR_CLI_NAME={}", jor_cli_name); 6 | println!("cargo:rustc-env=JORMUNGANDR_NAME={}", jormungandr_name); 7 | println!("cargo:rustc-env=JOR_EXPLORER_NAME={}", jor_explorer_name); 8 | println!("cargo:rustc-env=RUST_BACKTRACE=full"); 9 | } 10 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/address/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod account; 2 | pub mod info; 3 | pub mod single; 4 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/certificate/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod e2e; 2 | pub mod retirement; 3 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/genesis/hash.rs: -------------------------------------------------------------------------------- 1 | use assert_fs::{prelude::*, TempDir}; 2 | use jormungandr_automation::jcli::JCli; 3 | 4 | #[test] 5 | pub fn test_correct_hash_is_returned_for_correct_block() { 6 | let jcli: JCli = Default::default(); 7 | let content = jcli.genesis().init(); 8 | let temp_dir = TempDir::new().unwrap(); 9 | let yaml_file = temp_dir.child("init_file.yaml"); 10 | yaml_file.write_str(&content).unwrap(); 11 | let block_file = temp_dir.child("block-0.bin"); 12 | 13 | jcli.genesis().encode(yaml_file.path(), &block_file); 14 | jcli.genesis().hash(block_file.path()); 15 | } 16 | 17 | #[test] 18 | pub fn test_correct_error_is_returned_for_non_existent_genesis_block() { 19 | let temp_dir = TempDir::new().unwrap(); 20 | let block_file = temp_dir.child("block-0.bin"); 21 | let jcli: JCli = Default::default(); 22 | jcli.genesis().hash_expect_fail(block_file.path(), "file"); 23 | } 24 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/genesis/init.rs: -------------------------------------------------------------------------------- 1 | use assert_fs::{prelude::*, TempDir}; 2 | use jormungandr_automation::jcli::JCli; 3 | 4 | #[test] 5 | pub fn test_genesis_block_is_built_from_init_yaml() { 6 | let jcli: JCli = Default::default(); 7 | 8 | let content = jcli.genesis().init(); 9 | let temp_dir = TempDir::new().unwrap(); 10 | let yaml_file = temp_dir.child("init_file.yaml"); 11 | yaml_file.write_str(&content).unwrap(); 12 | let block_file = temp_dir.child("block-0.bin"); 13 | jcli.genesis().encode(yaml_file.path(), &block_file); 14 | } 15 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/genesis/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod encode; 2 | pub mod hash; 3 | pub mod init; 4 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/key/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod from_bytes; 2 | pub mod generate; 3 | pub mod to_bytes; 4 | pub mod to_public; 5 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/key/to_public.rs: -------------------------------------------------------------------------------- 1 | use jormungandr_automation::jcli::JCli; 2 | 3 | #[test] 4 | pub fn test_key_to_public() { 5 | let jcli: JCli = Default::default(); 6 | let private_key = "ed25519_sk1357nu8uaxvdekg6uhqmdd0zcd3tjv3qq0p2029uk6pvfxuks5rzstp5ceq"; 7 | let public_key = jcli.key().convert_to_public_string(private_key.to_owned()); 8 | assert_ne!(public_key, "", "generated key is empty"); 9 | } 10 | 11 | #[test] 12 | pub fn test_key_to_public_invalid_key() { 13 | let jcli: JCli = Default::default(); 14 | jcli.key().convert_to_public_string_expect_fail( 15 | "ed2551ssss9_sk1357nu8uaxvdekg6uhqmdd0zcd3tjv3qq0p2029uk6pvfxuks5rzstp5ceq", 16 | "invalid checksum", 17 | ); 18 | } 19 | 20 | #[test] 21 | pub fn test_key_to_public_invalid_chars_key() { 22 | let jcli: JCli = Default::default(); 23 | jcli.key().convert_to_public_string_expect_fail( 24 | "node:: ed2551ssss9_sk1357nu8uaxvdekg6uhqmdd0zcd3tjv3qq0p2029uk6pvfxuks5rzstp5ceq", 25 | "invalid character", 26 | ); 27 | } 28 | 29 | #[test] 30 | pub fn test_private_key_to_public_key() { 31 | let jcli: JCli = Default::default(); 32 | let private_key = jcli.key().generate("Ed25519Extended"); 33 | let public_key = jcli.key().convert_to_public_string(&private_key); 34 | assert_ne!(public_key, "", "generated key is empty"); 35 | } 36 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod address; 2 | pub mod certificate; 3 | pub mod genesis; 4 | pub mod key; 5 | pub mod rest; 6 | pub mod tally; 7 | pub mod transaction; 8 | pub mod update_proposal; 9 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/rest/host.rs: -------------------------------------------------------------------------------- 1 | use jormungandr_automation::jcli::JCli; 2 | 3 | #[test] 4 | 5 | pub fn test_correct_error_is_returned_for_incorrect_host_syntax() { 6 | let jcli: JCli = Default::default(); 7 | let incorrect_host = "not_a_correct_syntax"; 8 | 9 | jcli.rest().v0().tip_expect_fail( 10 | incorrect_host, 11 | "Invalid value for '--host ': relative URL without a base", 12 | ); 13 | } 14 | 15 | #[test] 16 | pub fn test_correct_error_is_returned_for_incorrect_host_address() { 17 | let jcli: JCli = Default::default(); 18 | // Port 9 is standard port discarding all requests 19 | let incorrect_host = "http://127.0.0.1:9/api"; 20 | jcli.rest() 21 | .v0() 22 | .tip_expect_fail(incorrect_host, "tcp connect error"); 23 | } 24 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/rest/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod block; 2 | pub mod host; 3 | pub mod tip; 4 | pub mod utxo; 5 | pub mod vote; 6 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/rest/tip.rs: -------------------------------------------------------------------------------- 1 | use jormungandr_automation::{ 2 | jcli::JCli, 3 | jormungandr::{NodeConfigBuilder, Starter}, 4 | }; 5 | 6 | #[test] 7 | pub fn test_correct_id_is_returned_for_block_tip_if_only_genesis_block_exists() { 8 | let jcli: JCli = Default::default(); 9 | let jormungandr = Starter::new().start().unwrap(); 10 | let block_id = jcli.rest().v0().tip(jormungandr.rest_uri()); 11 | 12 | assert_ne!(&block_id, "", "empty block hash"); 13 | } 14 | 15 | #[test] 16 | pub fn test_correct_error_is_returned_for_incorrect_path() { 17 | let jcli: JCli = Default::default(); 18 | let config = NodeConfigBuilder::new().build(); 19 | let incorrect_uri = format!("http://{}/api/api", config.rest.listen); 20 | 21 | jcli.rest() 22 | .v0() 23 | .tip_expect_fail(incorrect_uri, "tcp connect error"); 24 | } 25 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/tally/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod merge_results; 2 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/transaction/add_account.rs: -------------------------------------------------------------------------------- 1 | const FAKE_GENESIS_HASH: &str = "19c9852ca0a68f15d0f7de5d1a26acd67a3a3251640c6066bdb91d22e2000193"; 2 | use jormungandr_automation::{jcli_wrapper::JCLITransactionWrapper, startup}; 3 | 4 | #[test] 5 | pub fn test_add_account_for_utxo_delegation_address_fails() { 6 | let sender = startup::create_new_delegation_address(); 7 | 8 | JCLITransactionWrapper::new_transaction(FAKE_GENESIS_HASH).assert_add_account_fail( 9 | &sender.address, 10 | &100, 11 | "Invalid input account, this is a UTxO address", 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/transaction/finalize.rs: -------------------------------------------------------------------------------- 1 | use jormungandr_automation::jcli::JCli; 2 | use jormungandr_lib::{crypto::hash::Hash, interfaces::BlockDate}; 3 | 4 | lazy_static! { 5 | static ref FAKE_INPUT_TRANSACTION_ID: Hash = { 6 | "19c9852ca0a68f15d0f7de5d1a26acd67a3a3251640c6066bdb91d22e2000193" 7 | .parse() 8 | .unwrap() 9 | }; 10 | static ref FAKE_GENESIS_HASH: Hash = { 11 | "19c9852ca0a68f15d0f7de5d1a26acd67a3a3251640c6066bdb91d22e2000193" 12 | .parse() 13 | .unwrap() 14 | }; 15 | } 16 | 17 | #[test] 18 | pub fn test_unbalanced_output_utxo_transaction_is_not_finalized() { 19 | let receiver = thor::Wallet::new_utxo(&mut rand::rngs::OsRng); 20 | let jcli: JCli = Default::default(); 21 | 22 | jcli.transaction_builder(*FAKE_GENESIS_HASH) 23 | .new_transaction() 24 | .add_input(&FAKE_INPUT_TRANSACTION_ID, 0, "100") 25 | .add_output(&receiver.address().to_string(), 150.into()) 26 | .set_expiry_date(BlockDate::new(1, 0)) 27 | .finalize_expect_fail("not enough input for making transaction"); 28 | } 29 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/transaction/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod e2e; 2 | pub mod finalize; 3 | pub mod input; 4 | pub mod simplified; 5 | mod witness; 6 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/transaction/new.rs: -------------------------------------------------------------------------------- 1 | use jortestkit::file::make_readonly; 2 | use chain_impl_mockchain::key::Hash; 3 | const FAKE_GENESIS_HASH: &str = "19c9852ca0a68f15d0f7de5d1a26acd67a3a3251640c6066bdb91d22e2000193"; 4 | const FAKE_INPUT_TRANSACTION_ID: Hash = { 5 | "19c9852ca0a68f15d0f7de5d1a26acd67a3a3251640c6066bdb91d22e2000193" 6 | .parse() 7 | .unwrap() 8 | }; 9 | #[test] 10 | #[cfg(not(target_os = "linux"))] 11 | pub fn test_cannot_create_input_when_staging_file_is_readonly() { 12 | let mut transaction_wrapper = JCLITransactionWrapper::new_transaction(FAKE_GENESIS_HASH); 13 | make_readonly(&transaction_wrapper.staging_file_path()); 14 | transaction_wrapper.assert_add_input_fail(&FAKE_INPUT_TRANSACTION_ID, &0, "100", "denied"); 15 | } 16 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jcli/update_proposal/mod.rs: -------------------------------------------------------------------------------- 1 | mod e2e; 2 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/bft/mempool/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod v0; 2 | pub mod v1; 3 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/bft/mod.rs: -------------------------------------------------------------------------------- 1 | mod block; 2 | mod counter; 3 | mod mempool; 4 | mod start_node; 5 | mod update_proposal; 6 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/explorer/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod address; 2 | pub mod block; 3 | pub mod certificates; 4 | pub mod explorer_sanity; 5 | pub mod settings; 6 | pub mod transaction; 7 | pub mod vote_plan; 8 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/genesis/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod fragments; 2 | pub mod pool_update; 3 | pub mod rewards; 4 | pub mod stake_distribution; 5 | pub mod stake_pool; 6 | pub mod start_node; 7 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/genesis/start_node.rs: -------------------------------------------------------------------------------- 1 | use crate::startup; 2 | use chain_crypto::Ed25519Extended; 3 | use jormungandr_automation::{jormungandr::ConfigurationBuilder, testing::keys}; 4 | 5 | #[test] 6 | pub fn test_genesis_stake_pool_with_account_faucet_starts_successfully() { 7 | let faucet = thor::Wallet::default(); 8 | let (_jormungandr, _) = 9 | startup::start_stake_pool(&[faucet], &[], &mut ConfigurationBuilder::new()).unwrap(); 10 | } 11 | 12 | #[test] 13 | pub fn test_genesis_stake_pool_with_utxo_faucet_starts_successfully() { 14 | let stake_key = keys::create_new_key_pair::(); 15 | let faucet = startup::create_new_delegation_address_for(&stake_key.identifier()); 16 | let (_jormungandr, _) = 17 | startup::start_stake_pool(&[faucet], &[], &mut ConfigurationBuilder::new()).unwrap(); 18 | } 19 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/grpc/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod client_tests; 2 | pub mod server_tests; 3 | pub mod setup; 4 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bft; 2 | pub mod block; 3 | pub mod cors; 4 | #[cfg(feature = "evm")] 5 | pub mod evm_mapping; 6 | #[cfg(feature = "evm")] 7 | pub mod evm_transaction; 8 | pub mod explorer; 9 | pub mod fragments; 10 | pub mod genesis; 11 | pub mod grpc; 12 | mod leadership; 13 | pub mod legacy; 14 | pub mod mempool; 15 | pub mod persistent_log; 16 | pub mod recovery; 17 | pub mod rest; 18 | pub mod tls; 19 | pub mod tokens; 20 | pub mod transactions; 21 | pub mod vit; 22 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/rest/mod.rs: -------------------------------------------------------------------------------- 1 | mod v0; 2 | mod v1; 3 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/rest/v0/mod.rs: -------------------------------------------------------------------------------- 1 | mod errors; 2 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/rest/v1/fragments/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod fail_fast; 2 | pub mod statuses; 3 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/rest/v1/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod fragments; 2 | pub mod utils; 3 | pub mod votes; 4 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/rest/v1/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod settings; 2 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/tls.rs: -------------------------------------------------------------------------------- 1 | use assert_fs::TempDir; 2 | use jormungandr_automation::{ 3 | jormungandr::{ConfigurationBuilder, Starter, StartupVerificationMode}, 4 | testing::resources, 5 | }; 6 | use jormungandr_lib::interfaces::Tls; 7 | 8 | #[test] 9 | #[cfg(any(unix, windows))] 10 | pub fn test_rest_tls_config() { 11 | let temp_dir = TempDir::new().unwrap().into_persistent(); 12 | let prv_key_file = resources::tls_server_private_key(); 13 | let server_crt_file = resources::tls_server_crt(); 14 | let ca_crt_file = resources::tls_ca_crt(); 15 | 16 | let config = ConfigurationBuilder::new() 17 | .with_rest_tls_config(Tls { 18 | cert_file: server_crt_file.as_os_str().to_str().unwrap().to_owned(), 19 | priv_key_file: prv_key_file.as_os_str().to_str().unwrap().to_owned(), 20 | }) 21 | .build(&temp_dir); 22 | 23 | let jormungandr = Starter::new() 24 | .temp_dir(temp_dir) 25 | .config(config) 26 | .verify_by(StartupVerificationMode::Log) 27 | .start() 28 | .unwrap(); 29 | println!("Bootstrapped"); 30 | jormungandr.assert_no_errors_in_log(); 31 | 32 | println!( 33 | "{:?}", 34 | jormungandr.secure_rest(&ca_crt_file).stats().unwrap() 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/jormungandr/vit/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod private; 2 | pub mod public; 3 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | #[macro_use(lazy_static)] 3 | extern crate lazy_static; 4 | 5 | #[cfg(test)] 6 | pub mod jcli; 7 | #[cfg(test)] 8 | pub mod jormungandr; 9 | #[cfg(all(test, feature = "network"))] 10 | pub mod networking; 11 | #[cfg(all(test, feature = "non-functional"))] 12 | pub mod non_functional; 13 | 14 | pub mod startup; 15 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/networking/communication/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod leader_leader; 2 | pub mod parallel_spending_counter; 3 | pub mod passive_leader; 4 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/networking/cross_version/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod disruption; 2 | pub mod fragment_propagation; 3 | 4 | const PASSIVE: &str = "Passive"; 5 | const LEADER: &str = "Leader"; 6 | const LEADER_1: &str = "Leader1"; 7 | const LEADER_2: &str = "Leader2"; 8 | const LEADER_3: &str = "Leader3"; 9 | const LEADER_4: &str = "Leader4"; 10 | 11 | const ALICE: &str = "ALICE"; 12 | const BOB: &str = "BOB"; 13 | const CLARICE: &str = "CLARICE"; 14 | const DAVID: &str = "DAVID"; 15 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/networking/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bft; 2 | pub mod communication; 3 | #[cfg(feature = "cross-version")] 4 | pub mod cross_version; 5 | pub mod explorer; 6 | pub mod leadership_log; 7 | pub mod p2p; 8 | pub mod stake_pool; 9 | #[cfg(feature = "testnet")] 10 | pub mod testnet; 11 | pub mod topology; 12 | pub mod utils; 13 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/networking/stake_pool/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod retire; 2 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/non_functional/network/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod big; 2 | pub mod desync; 3 | pub mod disruption; 4 | #[cfg(feature = "soak")] 5 | pub mod soak; 6 | 7 | const ALICE: &str = "ALICE"; 8 | const BOB: &str = "BOB"; 9 | 10 | const PASSIVE: &str = "Passive"; 11 | const LEADER: &str = "Leader"; 12 | const LEADER_1: &str = "Leader1"; 13 | const LEADER_2: &str = "Leader2"; 14 | const LEADER_3: &str = "Leader3"; 15 | const LEADER_4: &str = "Leader4"; 16 | const LEADER_5: &str = "Leader5"; 17 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/non_functional/voting/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod config; 2 | pub mod private; 3 | pub mod public; 4 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/non_functional/voting/private/load.rs: -------------------------------------------------------------------------------- 1 | use crate::non_functional::voting::private::{ 2 | private_vote_load_scenario, PrivateVotingLoadTestConfig, 3 | }; 4 | 5 | #[test] 6 | pub fn private_vote_load_quick_test() { 7 | let quick_config = PrivateVotingLoadTestConfig::quick(); 8 | private_vote_load_scenario(quick_config) 9 | } 10 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/non_functional/voting/private/noise.rs: -------------------------------------------------------------------------------- 1 | use crate::non_functional::voting::{ 2 | config::adversary_noise_config, 3 | private::{adversary_private_vote_load_scenario, PrivateVotingLoadTestConfig}, 4 | }; 5 | 6 | #[test] 7 | pub fn adversary_private_vote_quick_test() { 8 | let quick_config = PrivateVotingLoadTestConfig::quick(); 9 | let adversary_noise_config = adversary_noise_config(30, quick_config.test_duration()); 10 | adversary_private_vote_load_scenario(quick_config, adversary_noise_config) 11 | } 12 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/non_functional/voting/private/soak.rs: -------------------------------------------------------------------------------- 1 | use crate::non_functional::voting::{ 2 | config::{adversary_noise_config, PrivateVotingLoadTestConfig}, 3 | private::{adversary_private_vote_load_scenario, private_vote_load_scenario}, 4 | }; 5 | 6 | #[test] 7 | pub fn private_vote_load_long_test() { 8 | let quick_config = PrivateVotingLoadTestConfig::long(); 9 | private_vote_load_scenario(quick_config) 10 | } 11 | 12 | #[test] 13 | pub fn adversary_private_vote_load_long_test() { 14 | let long_config = PrivateVotingLoadTestConfig::long(); 15 | let adversary_noise_config = adversary_noise_config(30, long_config.test_duration()); 16 | adversary_private_vote_load_scenario(long_config, adversary_noise_config) 17 | } 18 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/non_functional/voting/public/load.rs: -------------------------------------------------------------------------------- 1 | use crate::non_functional::voting::{ 2 | config::PublicVotingLoadTestConfig, public::public_vote_load_scenario, 3 | }; 4 | 5 | #[test] 6 | pub fn public_vote_load_quick_test() { 7 | let quick_config = PublicVotingLoadTestConfig::quick(); 8 | public_vote_load_scenario(quick_config) 9 | } 10 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/non_functional/voting/public/noise.rs: -------------------------------------------------------------------------------- 1 | use crate::non_functional::voting::{ 2 | config::adversary_noise_config, 3 | public::{adversary_public_vote_load_scenario, PublicVotingLoadTestConfig}, 4 | }; 5 | 6 | #[test] 7 | pub fn adversary_public_vote_quick_test() { 8 | let quick_config = PublicVotingLoadTestConfig::quick(); 9 | let adversary_noise_config = adversary_noise_config(30, quick_config.test_duration()); 10 | adversary_public_vote_load_scenario(quick_config, adversary_noise_config) 11 | } 12 | -------------------------------------------------------------------------------- /testing/jormungandr-integration-tests/src/non_functional/voting/public/soak.rs: -------------------------------------------------------------------------------- 1 | use crate::non_functional::voting::{ 2 | config::{adversary_noise_config, PublicVotingLoadTestConfig}, 3 | public::{adversary_public_vote_load_scenario, public_vote_load_scenario}, 4 | }; 5 | 6 | #[test] 7 | pub fn public_vote_load_long_test() { 8 | let long_config = PublicVotingLoadTestConfig::long(); 9 | public_vote_load_scenario(long_config) 10 | } 11 | 12 | #[test] 13 | pub fn adversary_public_vote_load_long_test() { 14 | let long_config = PublicVotingLoadTestConfig::long(); 15 | let adversary_noise_config = adversary_noise_config(30, long_config.test_duration()); 16 | adversary_public_vote_load_scenario(long_config, adversary_noise_config) 17 | } 18 | -------------------------------------------------------------------------------- /testing/loki/src/args.rs: -------------------------------------------------------------------------------- 1 | use std::{net::SocketAddr, path::PathBuf}; 2 | use structopt::StructOpt; 3 | 4 | #[derive(StructOpt, Debug)] 5 | #[structopt(rename_all = "kebab")] 6 | pub struct Args { 7 | /// Path to the genesis block (the block0) of the blockchain 8 | #[structopt(long, short, parse(try_from_str))] 9 | pub genesis_block: PathBuf, 10 | 11 | /// Set the secret node config (in YAML format). 12 | #[structopt(long, short, parse(from_os_str))] 13 | pub secret: Option, 14 | 15 | /// Specifies the address the node will listen. 16 | #[structopt(short = "a", long = "listen-address")] 17 | pub listen_address: Option, 18 | } 19 | -------------------------------------------------------------------------------- /testing/loki/src/error.rs: -------------------------------------------------------------------------------- 1 | use chain_core::property::ReadError; 2 | use jormungandr_lib::interfaces::Block0ConfigurationError; 3 | use thiserror::Error; 4 | 5 | #[derive(Debug, Error)] 6 | pub enum Error { 7 | #[error("IO error: {0}")] 8 | IO(#[from] std::io::Error), 9 | #[error("Read error: {0}")] 10 | Read(#[from] ReadError), 11 | #[error("Could not parse YAML file: {0}")] 12 | Yaml(#[from] serde_yaml::Error), 13 | #[error("Block0 error: {0}")] 14 | Block0(#[from] Block0ConfigurationError), 15 | } 16 | -------------------------------------------------------------------------------- /testing/loki/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod args; 2 | pub mod block; 3 | pub mod error; 4 | pub mod process; 5 | pub mod rest; 6 | 7 | mod sender; 8 | 9 | pub use sender::{ 10 | AdversaryFragmentSender, AdversaryFragmentSenderError, AdversaryFragmentSenderSetup, 11 | FaultyTransactionBuilder, 12 | }; 13 | -------------------------------------------------------------------------------- /testing/loki/src/main.rs: -------------------------------------------------------------------------------- 1 | use chain_core::{packer::Codec, property::Deserialize}; 2 | use chain_impl_mockchain::block::Block; 3 | use jormungandr_lib::interfaces::NodeSecret; 4 | use loki::{args::Args, error::Error, process::AdversaryNodeBuilder, rest::AdversaryRest}; 5 | use std::{fs::File, io::BufReader}; 6 | use structopt::StructOpt; 7 | 8 | fn main() { 9 | let args = Args::from_args(); 10 | 11 | if let Err(e) = launch(&args) { 12 | eprintln!("{}", e); 13 | std::process::exit(1); 14 | } 15 | } 16 | 17 | fn launch(args: &Args) -> Result<(), Error> { 18 | let block0 = Block::deserialize(&mut Codec::new(File::open(&args.genesis_block)?))?; 19 | 20 | let mut rest = AdversaryRest::new(AdversaryNodeBuilder::new(block0).build()); 21 | 22 | if let Some(secret_file) = args.secret.as_ref() { 23 | let secret: NodeSecret = serde_yaml::from_reader(BufReader::new(File::open(secret_file)?))?; 24 | 25 | if let Some(bft) = secret.bft { 26 | rest = rest.signing_key(bft.signing_key); 27 | } 28 | } 29 | 30 | if let Some(address) = args.listen_address { 31 | rest = rest.address(address); 32 | } 33 | 34 | rest.start(); 35 | 36 | Ok(()) 37 | } 38 | -------------------------------------------------------------------------------- /testing/mjolnir/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let pkg_version = if let Ok(date) = std::env::var("DATE") { 3 | format!("{}.{}", env!("CARGO_PKG_VERSION"), date) 4 | } else { 5 | env!("CARGO_PKG_VERSION").to_string() 6 | }; 7 | 8 | println!("cargo:rustc-env=CARGO_PKG_VERSION={}", pkg_version); 9 | 10 | let version = versionisator::Version::new( 11 | env!("CARGO_MANIFEST_DIR"), 12 | env!("CARGO_PKG_NAME").to_string(), 13 | pkg_version, 14 | ); 15 | 16 | println!("cargo:rustc-env=FULL_VERSION={}", version.full()); 17 | println!("cargo:rustc-env=SIMPLE_VERSION={}", version.simple()); 18 | println!("cargo:rustc-env=SOURCE_VERSION={}", version.hash()); 19 | } 20 | -------------------------------------------------------------------------------- /testing/mjolnir/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod mjolnir_lib; 2 | pub use crate::mjolnir_lib::*; 3 | -------------------------------------------------------------------------------- /testing/mjolnir/src/main.rs: -------------------------------------------------------------------------------- 1 | use mjolnir::Mjolnir; 2 | use std::error::Error; 3 | use structopt::StructOpt; 4 | 5 | fn main() { 6 | Mjolnir::from_args().exec().unwrap_or_else(report_error) 7 | } 8 | 9 | fn report_error(error: Box) { 10 | eprintln!("{}", error); 11 | let mut source = error.source(); 12 | while let Some(sub_error) = source { 13 | eprintln!(" |-> {}", sub_error); 14 | source = sub_error.source(); 15 | } 16 | std::process::exit(1) 17 | } 18 | -------------------------------------------------------------------------------- /testing/mjolnir/src/mjolnir_lib/args.rs: -------------------------------------------------------------------------------- 1 | use chain_core::property::FromStr; 2 | use chain_impl_mockchain::block::{BlockDate, BlockDateParseError}; 3 | 4 | pub fn parse_shift(from: &str) -> Result<(BlockDate, bool), BlockDateParseError> { 5 | if let Some(stripped) = from.strip_prefix('~') { 6 | BlockDate::from_str(stripped).map(|d| (d, true)) 7 | } else { 8 | BlockDate::from_str(from).map(|d| (d, false)) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /testing/mjolnir/src/mjolnir_lib/error.rs: -------------------------------------------------------------------------------- 1 | use jormungandr_automation::{ 2 | jormungandr::{JormungandrError, RestError, StartupError}, 3 | testing::block0::Block0Error, 4 | }; 5 | use thiserror::Error; 6 | 7 | #[derive(Error, Debug)] 8 | #[allow(clippy::large_enum_variant)] 9 | pub enum MjolnirError { 10 | #[error("cannot query rest")] 11 | RestError(#[from] RestError), 12 | #[error("cannot bootstrap node")] 13 | StartupError(#[from] StartupError), 14 | #[error("jormungandr error")] 15 | JormungandrError(#[from] JormungandrError), 16 | #[error("node client error")] 17 | InternalClientError, 18 | #[error("pace is too low ({0})")] 19 | PaceTooLow(u64), 20 | #[error("get block0 error")] 21 | Block0Error(#[from] Block0Error), 22 | } 23 | -------------------------------------------------------------------------------- /testing/mjolnir/src/mjolnir_lib/fragment/batch/adversary/mod.rs: -------------------------------------------------------------------------------- 1 | mod all; 2 | mod votes_only; 3 | 4 | use crate::mjolnir_lib::MjolnirError; 5 | use structopt::StructOpt; 6 | pub use votes_only::VotesOnly; 7 | #[derive(StructOpt, Debug)] 8 | pub enum Adversary { 9 | VotesOnly(votes_only::VotesOnly), 10 | All(all::AdversaryAll), 11 | } 12 | 13 | impl Adversary { 14 | pub fn exec(&self) -> Result<(), MjolnirError> { 15 | match self { 16 | Adversary::VotesOnly(votes_only_command) => votes_only_command.exec(), 17 | Adversary::All(all_command) => all_command.exec(), 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /testing/mjolnir/src/mjolnir_lib/fragment/batch/mod.rs: -------------------------------------------------------------------------------- 1 | mod adversary; 2 | mod tx_only; 3 | 4 | use crate::mjolnir_lib::MjolnirError; 5 | use structopt::StructOpt; 6 | pub use tx_only::TxOnly; 7 | #[derive(StructOpt, Debug)] 8 | pub enum Batch { 9 | /// Prints nodes related data, like stats,fragments etc. 10 | TxOnly(tx_only::TxOnly), 11 | Adversary(adversary::Adversary), 12 | } 13 | 14 | impl Batch { 15 | pub fn exec(&self) -> Result<(), MjolnirError> { 16 | match self { 17 | Batch::TxOnly(tx_only_command) => tx_only_command.exec(), 18 | Batch::Adversary(adversary_command) => adversary_command.exec(), 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /testing/mjolnir/src/mjolnir_lib/fragment/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::mjolnir_lib::MjolnirError; 2 | use structopt::StructOpt; 3 | use thiserror::Error; 4 | 5 | mod batch; 6 | mod standard; 7 | 8 | #[derive(StructOpt, Debug)] 9 | pub enum FragmentLoadCommand { 10 | /// sends fragments using batch endpoint 11 | Batch(batch::Batch), 12 | /// sends fragments in single manner 13 | Standard(standard::Standard), 14 | } 15 | 16 | #[derive(Error, Debug)] 17 | pub enum FragmentLoadCommandError { 18 | #[error("Client Error")] 19 | ClientError(#[from] MjolnirError), 20 | } 21 | 22 | impl FragmentLoadCommand { 23 | pub fn exec(&self) -> Result<(), MjolnirError> { 24 | match self { 25 | FragmentLoadCommand::Batch(batch) => batch.exec(), 26 | FragmentLoadCommand::Standard(standard) => standard.exec(), 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /testing/mjolnir/src/mjolnir_lib/fragment/standard/adversary/mod.rs: -------------------------------------------------------------------------------- 1 | mod all; 2 | mod votes_only; 3 | 4 | use crate::mjolnir_lib::MjolnirError; 5 | use structopt::StructOpt; 6 | pub use votes_only::VotesOnly; 7 | 8 | #[derive(StructOpt, Debug)] 9 | pub enum Adversary { 10 | VotesOnly(votes_only::VotesOnly), 11 | All(all::AllAdversary), 12 | } 13 | 14 | impl Adversary { 15 | pub fn exec(&self) -> Result<(), MjolnirError> { 16 | match self { 17 | Adversary::VotesOnly(votes_only_command) => votes_only_command.exec(), 18 | Adversary::All(all_command) => all_command.exec(), 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /testing/mjolnir/src/mjolnir_lib/fragment/standard/mod.rs: -------------------------------------------------------------------------------- 1 | mod adversary; 2 | mod all; 3 | mod tx_only; 4 | 5 | use crate::mjolnir_lib::MjolnirError; 6 | pub use adversary::Adversary; 7 | pub use all::AllFragments; 8 | use structopt::StructOpt; 9 | pub use tx_only::TxOnly; 10 | #[derive(StructOpt, Debug)] 11 | pub enum Standard { 12 | /// Put load on endpoint using transaction fragments only. 13 | TxOnly(tx_only::TxOnly), 14 | /// Put load on endpoint using all supported fragment types 15 | All(all::AllFragments), 16 | /// Put load on endpoint using invalid fragments 17 | Adversary(adversary::Adversary), 18 | } 19 | 20 | impl Standard { 21 | pub fn exec(&self) -> Result<(), MjolnirError> { 22 | match self { 23 | Standard::TxOnly(tx_only_command) => tx_only_command.exec(), 24 | Standard::All(all_command) => all_command.exec(), 25 | Standard::Adversary(adversary) => adversary.exec(), 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /testing/mjolnir/src/mjolnir_lib/generators/mod.rs: -------------------------------------------------------------------------------- 1 | mod adversary_generator; 2 | mod adversary_vote_casts_generator; 3 | mod batch_generator; 4 | mod explorer; 5 | mod fragment_generator; 6 | mod rest; 7 | mod status_provider; 8 | mod transaction_generator; 9 | mod vote_casts_generator; 10 | mod wallet_lane_iter; 11 | 12 | pub use adversary_generator::AdversaryFragmentGenerator; 13 | pub use adversary_vote_casts_generator::AdversaryVoteCastsGenerator; 14 | pub use batch_generator::BatchFragmentGenerator; 15 | pub use explorer::ExplorerRequestGen; 16 | pub use fragment_generator::FragmentGenerator; 17 | pub use rest::RestRequestGen; 18 | pub use status_provider::FragmentStatusProvider; 19 | pub use transaction_generator::TransactionGenerator; 20 | pub use vote_casts_generator::VoteCastsGenerator; 21 | -------------------------------------------------------------------------------- /testing/thor/src/bin/cli/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod command; 2 | pub mod send; 3 | pub mod wallet; 4 | -------------------------------------------------------------------------------- /testing/thor/src/bin/cli/send.rs: -------------------------------------------------------------------------------- 1 | use crate::cli::command::Error; 2 | use chain_addr::AddressReadable; 3 | use structopt::StructOpt; 4 | use thor::cli::CliController; 5 | 6 | #[derive(StructOpt, Debug)] 7 | pub struct SendCommand { 8 | // pin 9 | #[structopt(long, short)] 10 | pub wait: bool, 11 | 12 | #[structopt(subcommand)] // Note that we mark a field as a subcommand 13 | cmd: SendSubCommand, 14 | } 15 | 16 | impl SendCommand { 17 | pub fn exec(self, contoller: CliController) -> Result<(), Error> { 18 | match self.cmd { 19 | SendSubCommand::Tx(send_tx) => send_tx.exec(contoller, self.wait), 20 | } 21 | } 22 | } 23 | 24 | #[derive(StructOpt, Debug)] 25 | pub enum SendSubCommand { 26 | Tx(Tx), 27 | } 28 | 29 | #[derive(StructOpt, Debug)] 30 | pub struct Tx { 31 | /// address in bech32 format 32 | #[structopt(long)] 33 | pub address: AddressReadable, 34 | 35 | /// ada to send 36 | #[structopt(long)] 37 | pub ada: u64, 38 | 39 | // pin 40 | #[structopt(long, short)] 41 | pub pin: String, 42 | } 43 | 44 | impl Tx { 45 | pub fn exec(self, mut contoller: CliController, wait: bool) -> Result<(), Error> { 46 | contoller.transaction(&self.pin, wait, self.address.to_address().into(), self.ada)?; 47 | contoller.save_config().map_err(Into::into) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /testing/thor/src/bin/thor.rs: -------------------------------------------------------------------------------- 1 | mod cli; 2 | 3 | use cli::command::Command; 4 | use structopt::StructOpt; 5 | use thor::cli::CliController; 6 | 7 | pub fn main() { 8 | let controller = CliController::new().unwrap(); 9 | Command::from_args().exec(controller).unwrap(); 10 | } 11 | -------------------------------------------------------------------------------- /testing/thor/src/cli/mod.rs: -------------------------------------------------------------------------------- 1 | mod config; 2 | mod controller; 3 | mod error; 4 | mod wallet_controller; 5 | 6 | pub use config::{Alias, Config, ConfigManager, Connection, Error as ConfigError, WalletState}; 7 | pub use controller::CliController; 8 | pub use error::Error; 9 | pub use wallet_controller::WalletController; 10 | -------------------------------------------------------------------------------- /testing/thor/src/fragment/transaction_utils.rs: -------------------------------------------------------------------------------- 1 | use chain_core::property::Serialize as _; 2 | use chain_impl_mockchain::fragment::Fragment; 3 | 4 | pub trait TransactionHash { 5 | fn encode(&self) -> String; 6 | } 7 | 8 | impl TransactionHash for Fragment { 9 | fn encode(&self) -> String { 10 | let bytes = self.serialize_as_vec().unwrap(); 11 | hex::encode(&bytes) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /testing/thor/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod cli; 2 | mod fragment; 3 | mod stake_pool; 4 | pub mod wallet; 5 | 6 | pub use fragment::{ 7 | signed_delegation_cert, signed_stake_pool_cert, vote_plan_cert, write_into_persistent_log, 8 | BlockDateGenerator, DummySyncNode, FragmentBuilder, FragmentBuilderError, FragmentChainSender, 9 | FragmentExporter, FragmentExporterError, FragmentSender, FragmentSenderError, 10 | FragmentSenderSetup, FragmentSenderSetupBuilder, FragmentVerifier, FragmentVerifierError, 11 | PersistentLogViewer, TransactionHash, VerifyExitStrategy, 12 | }; 13 | pub use stake_pool::StakePool; 14 | pub use wallet::{ 15 | account::Wallet as AccountWallet, committee::CommitteeDataManager, 16 | delegation::Wallet as DelegationWallet, discrimination::DiscriminationExtension, 17 | utxo::Wallet as UTxOWallet, Wallet, WalletAlias, WalletError, 18 | }; 19 | -------------------------------------------------------------------------------- /testing/thor/src/wallet/discrimination.rs: -------------------------------------------------------------------------------- 1 | use chain_addr::Discrimination; 2 | 3 | pub trait DiscriminationExtension { 4 | fn into_prefix(self) -> String; 5 | fn from_testing_bool(testing: bool) -> Self; 6 | fn from_prefix(prefix: &str) -> Self; 7 | } 8 | 9 | impl DiscriminationExtension for Discrimination { 10 | fn into_prefix(self) -> String { 11 | match self { 12 | Discrimination::Test => "ta".to_string(), 13 | Discrimination::Production => "ca".to_string(), 14 | } 15 | } 16 | fn from_testing_bool(testing: bool) -> Discrimination { 17 | if testing { 18 | Discrimination::Test 19 | } else { 20 | Discrimination::Production 21 | } 22 | } 23 | 24 | fn from_prefix(prefix: &str) -> Self { 25 | if prefix == "ca" { 26 | Discrimination::Production 27 | } else if prefix == "ta" { 28 | Discrimination::Test 29 | } else { 30 | unreachable!("unknown prefix"); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tools/prepare-changelog.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | function usage { 4 | echo "${0} GITHUB_TOKEN NEW_VERSION" >&2 5 | } 6 | 7 | if [ ${#} -ne 2 ]; then 8 | usage 9 | exit 1 10 | fi 11 | 12 | if [ ${1} = "help" ]; then 13 | usage 14 | exit 0 15 | fi 16 | 17 | GITHUB_TOKEN=${1} 18 | NEW_VERSION=${2} 19 | 20 | # check that the command exists 21 | command -v github_changelog_generator > /dev/null 22 | # a non-zero code indicates that the command was not found 23 | if [ $? -ne 0 ]; then 24 | echo "'github_changelog_generator' not installed? see https://github.com/github-changelog-generator/github-changelog-generator" >&2 25 | exit 1 26 | fi 27 | 28 | 29 | github_changelog_generator \ 30 | --user input-output-hk \ 31 | --project jormungandr \ 32 | --output release.latest \ 33 | --token ${GITHUB_TOKEN} \ 34 | --breaking-labels "breaking-change" \ 35 | --unreleased-only \ 36 | --future-release ${NEW_VERSION} 37 | -------------------------------------------------------------------------------- /tools/update-version.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | PACKAGES='jormungandr jormungandr-lib jcli testing/jormungandr-integration-tests testing/jormungandr-automation' 4 | 5 | if [ "${EDITOR}x" = "x" ]; then 6 | echo "> no environment variable \`EDITOR', trying known editors'" 7 | 8 | for CANDIDATE in vim emacs nano 9 | do 10 | echo ">> trying \`${CANDIDATE}'" 11 | which ${CANDIDATE} &> /dev/null 12 | if [ ${?} -eq 0 ]; then 13 | echo ">> \`${CANDIDATE}' found, using it as an editor" 14 | export EDITOR=${CANDIDATE} 15 | break; 16 | fi 17 | done 18 | fi 19 | 20 | if [ "${EDITOR}x" = "x" ]; then 21 | echo "> no known editor... giving up" 22 | exit 1 23 | fi 24 | 25 | for PACKAGE in ${PACKAGES} 26 | do 27 | ${EDITOR} ${PACKAGE}/Cargo.toml 28 | done 29 | --------------------------------------------------------------------------------