diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000000..e19b937604 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,80 @@ +name: Bug report +description: Create a bug report to help us improve the project +title: "[Bug]: " +labels: ["bug"] +projects: ["qdrvm/1"] +body: + - type: markdown + attributes: + value: | + ## Bug Report + + Before you submit a bug report, please ensure that: + + - The bug has not already been reported in the project. + - You have searched the existing issues to make sure the bug has not already been reported. + + If the above conditions are met, please fill out the following information. + + - type: input + id: bug-summary + attributes: + label: Bug Summary + description: Provide a brief summary of the bug. + placeholder: e.g., "Error occurs when..." + validations: + required: true + + - type: textarea + id: bug-description + attributes: + label: Bug Description + description: Provide a detailed description of the bug. + placeholder: Describe the bug in detail... + validations: + required: true + + - type: textarea + id: bug-reproduction + attributes: + label: Steps to Reproduce + description: Provide detailed steps to reproduce the bug. Explain what command was executed to start the node, what mode (validator, sync node, etc.) was used, how many nodes were running, etc. + placeholder: e.g., "1. Start the node with the following command..." + validations: + required: true + + - type: textarea + id: bug-effects + attributes: + label: Effects of the Bug + description: Explain the effects of the bug, including any incorrect behavior, error messages, logs, stack traces, core dumps, etc. + placeholder: e.g., "The application crashes with the error message..." + validations: + required: true + + - type: textarea + id: bug-expected-behavior + attributes: + label: Expected Behavior + description: Describe what you expected to happen. + placeholder: e.g., "I expected the application to..." + validations: + required: false + + - type: textarea + id: bug-system-info + attributes: + label: System Information + description: Provide information about your system, such as OS, compiler, and docker image version or project version (or commit hash). + placeholder: e.g., OS, Compiler, Project Version + validations: + required: true + + - type: textarea + id: bug-additional-context + attributes: + label: Additional Context + description: Add any other context about the problem here. + placeholder: e.g., "This bug only seems to occur when..." + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..3ba13e0cec --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/enhancement.yml b/.github/ISSUE_TEMPLATE/enhancement.yml new file mode 100644 index 0000000000..607de3f0ea --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement.yml @@ -0,0 +1,28 @@ +name: Enhancement for KAGOME +description: Suggest an improvement to an existing feature in the KAGOME project. +title: "[Bug]: " +labels: ["Enhancement"] +projects: ["qdrvm/1"] +body: + - type: textarea + attributes: + label: Description + description: Describe the enhancement that you are proposing for the KAGOME project. + validations: + required: true + - type: textarea + attributes: + label: Motivation + description: Explain why this enhancement is beneficial + validations: + required: true + - type: dropdown + attributes: + label: Are you planning to do it yourself in a pull request ? + description: Any contribution is greatly appreciated. We are more than happy to provide help on the process. + options: + - "Yes" + - "No" + - Maybe + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000000..10b4408665 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,56 @@ +name: Feature request +description: Suggest a new feature for the KAGOME project +title: "[Feature Request]: " +projects: ["qdrvm/1"] +body: + - type: markdown + attributes: + value: | + ## Feature Request + + Before you submit a feature request, please ensure that: + + - The feature does not already exist in the project. + - The feature is aligned with the project's goals and roadmap. + - You have searched the existing issues to make sure the feature has not already been requested. + + If the above conditions are met, please fill out the following information. + + - type: dropdown + id: feature-type + attributes: + label: Component + description: Select the component that this feature request is related to. + options: + - Grandpa + - Babe + - Parachains validation + - Runtime + - Host functions + - Network + - RPC + - Storage + - Transaction pool + - Off-chain workers + - Consensus + - Utilities + - Other + default: 12 # index of "Other" + + - type: textarea + id: feature-description + attributes: + label: Feature Description + description: Provide a detailed description of the feature. Mention benefits this feature will bring to the project and its users or developers. + placeholder: Describe the feature in detail... + validations: + required: true + + - type: textarea + id: feature-additional-info + attributes: + label: References and additional Information + description: Add any references (e.g. to specification or existing implementation in other repos) or additional information that may be relevant to the feature request. + placeholder: e.g., "This feature is important because..." + validations: + required: false diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 025ba21ded..f89217b236 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -21,19 +21,19 @@ SPDX-License-Identifier: Apache-2.0 -### Benefits - - - ### Possible Drawbacks -### Usage Examples or Tests +## Checklist Before Opening a PR + +Before you open a Pull Request (PR), please make sure you've completed the following steps and confirm by answering 'Yes' to each item: - +1. **Code is formatted**: Have you run your code through clang-format to ensure it adheres to the project's coding standards? **[Yes|No]** +2. **Code is documented**: Have you added comments and documentation to your code according to the guidelines in the project's [contributing guidelines](https://github.com/qdrvm/kagome/CONTRIBUTING.md)? **[Yes|No]** +3. **Self-review**: Have you reviewed your own code to ensure it is free of typos, syntax errors, logical errors, and unresolved TODOs or FIXME without linking to an issue? **[Yes|No]** +4. **Zombienet Tests**: Have you ensured that the zombienet tests are passing? Zombienet is a network simulation and testing tool used in this project. It's important to ensure that these tests pass to maintain the stability and reliability of the project. **[Yes|No]** -### Alternate Designs + - diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..0636634ef5 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,52 @@ +# Code of Conduct + +## 1. Purpose + +A primary goal of open-sourcing KAGOME is to be inclusive to the largest number of contributors, with the most varied and diverse backgrounds possible. As such, we are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof). + +## 2. Expected Behavior + +The following behaviors are expected and requested of all community members: + +- Participate in an authentic and active way. In doing so, you contribute to the health and longevity of this community. +- Exercise consideration and respect in your speech and actions. +- Attempt collaboration before conflict. +- Refrain from demeaning, discriminatory, or harassing behavior and speech. +- Be mindful of your surroundings and of your fellow participants. + +## 3. Unacceptable Behavior + +The following behaviors are considered harassment and are unacceptable within our community: + +- Violence, threats of violence or violent language directed against another person. +- Sexist, racist, homophobic, transphobic, ableist or otherwise discriminatory jokes and language. +- Posting or displaying sexually explicit or violent material. +- Personal insults, particularly those related to gender, sexual orientation, race, religion, or disability. + +## 4. Consequences of Unacceptable Behavior + +Unacceptable behavior from any community member will not be tolerated. Anyone asked to stop unacceptable behavior is expected to comply immediately. + +If a community member engages in unacceptable behavior, the project maintainers may take any action they deem appropriate, up to and including a temporary ban or permanent expulsion from the community without warning. + +## 5. Reporting Guidelines + +If you are subject to or witness unacceptable behavior, or have any other concerns, please notify a community moderator as soon as possible. + +## 6. Addressing Grievances + +If you feel you have been falsely or unfairly accused of violating this Code of Conduct, you should notify the project maintainers with a concise description of your grievance. + +## 7. Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. + +## 8. Contact info + +Quadrivium Numera Pte. Ltd. can be reached at github[at]qdrvm.io + +## 9. License and attribution + +This Code of Conduct is distributed under a Creative Commons Attribution-ShareAlike license. + +Portions of text derived from the [Django Code of Conduct](https://www.djangoproject.com/conduct/) and the [Geek Feminism Anti-Harassment Policy](http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy). \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9abe431d21..b982766741 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,10 +4,178 @@ All Rights Reserved SPDX-License-Identifier: Apache-2.0 ) -# CONTRIBUTING +# Contributing to Kagome + +All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉 + +## Table of Contents + +- [Code of Conduct](#code-of-conduct) +- [I Have a Question](#i-have-a-question) +- [Contributing](#contributing) + - [Styleguides](#styleguides) + - [Documentation](#documentation) + - [Commit Messages](#commit-messages) + - [Pull Requests](#pull-requests) + - [Reporting Bugs](#reporting-bugs) + +## Code of Conduct + +This project and everyone participating in it is governed by the [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. + +## I Have a Question + +Before you ask a question, it is best to search for existing [Issues](https://github.com/qdrvm/kagome/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first. + +If you then still feel the need to ask a question and need clarification, we recommend the following: + +- Open an [Issue](https://github.com/qdrvm/kagome/issues/new). +- Provide as much context as you can about what you're running into. +- Provide version of KAGOME and platform (OS, compiler, etc.) you are using if applicable. + +We will then take care of the issue as soon as possible. Be patient, as we are all volunteers and have other obligations as well. + +## Contributing + +### Styleguides + +1. KAGOME uses C++20 as target language. +2. We are following Google C++ Style Guide. Please refer to [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) for more details. +2. Every new code should be documented. Ensure that your code is clear and well-commented. +3. New code cannot be merged into master if it contains unresolved TODOs without a link to the opened issue, where this TODO should be resolved. +4. New code should be covered by unit tests using gtest/gmock. Make sure to write and run tests to ensure your code works as expected. +5. Use `clang-format` to maintain the code style. +7. Open PR with base branch = `master`, fix CI and follow guide in PR template. + +#### Documentation + +Good documentation is crucial for understanding the purpose and usage of different parts of the code. Here are some guidelines on how to document your code: + +1. **File-Level Comments**: At the top of each file, you should have comments that describe the content of the file, its purpose, and how it interacts with the rest of the codebase. This is especially important for header files (`.hpp`), as they define the interface of your code. + +```cpp +// File: example.hpp +// This file provides an example interface for ... +``` + +2. **Class Comments**: Each class should have an associated comment that describes what it is and what it does. This should be placed immediately before the class definition in the header file (.hpp). + +```cpp +// @class Example +// @brief The Example class is used to ... +// The Example class is doing that as follows: ... +class Example { + ... +}; +``` + +3. **Method Comments**: Each method should have a comment describing what it does. This should be placed immediately before the method declaration in the header file (.hpp). For non-trivial methods, also document its parameters and return value. For trivial methods, these can be omitted. + +```cpp +// @brief This method is used to ... +// Parameters: +// @param param1 is used to ... +// @param param2 is used to ... +// @return Returns value that contains ... +Value exampleMethod(int param1, std::string param2); +``` + +4. **Method Body Comments**: Inside method bodies in the source files (.cpp), use comments to explain complex or non-obvious parts of the code. Avoid obvious comments that don't add any new information. + +```cpp +void Example::exampleMethod(int param1, std::string param2) { + // Here we're doing a complex operation + ... + // Here we're doing another complex operation + ... +} +``` + +5. **References**: If you're using external libraries, APIs, or resources, provide references to them in your comments. Considering that we are developing a Polkadot Host, it is important to reference the Polkadot Wiki, Polkadot Spec, Polkadot-SDK documentation, or other relevant resources when necessary. This helps other developers understand where the code comes from and how it works. + +```cpp +// This code is based on the algorithm described in the paper "Title of the Paper" by Author et al. +``` + +```cpp +/** +* Make ancestry merke proof for GrandpaJustification. +* https://github.com/paritytech/polkadot-sdk/blob/4842faf65d3628586d304fbcb6cb19b17b4a629c/substrate/client/consensus/grandpa/src/justification.rs#L64-L126 +*/ +inline outcome::result makeAncestry( + GrandpaJustification &justification, + const blockchain::BlockTree &block_tree) { +... +} +``` + +Remember, the goal of comments is to help other developers (and your future self) understand the code. They should be clear, concise, and informative. + +#### Commit Messages + +Here's a general guideline for writing good commit messages: +1. **Use the Imperative Mood**: Start your commit messages in the imperative mood, "Fix bug" and not "Fixed bug" or "Fixes bug". This convention matches up with commit messages generated by commands like git merge and git revert. +2. **First Line is a Summary**: The first line of the commit message should be a brief summary of the changes, followed by a blank line, and then a detailed description (if needed). The first line should be limited to 50 characters and written in the imperative mood. +3. **Explain the Why, not the What**: The code diff already shows what changes you made, so use the commit message to explain why you made those changes. +Here's an example of a good commit message: +``` +Add error handling for invalid user input + +- Add try/catch block in user input processing function +- Return meaningful error messages to the user +- This change is necessary to improve user experience and handle potential errors +- Related to issue #123 +``` + +#### Pull Requests + +Pull Requests (PRs) are a vital part of any collaborative project. They allow developers to propose changes, get feedback, and merge their code into the main codebase. Here are some good practices for opening PRs: + +1. **Branch Naming**: Name your branch something descriptive and relevant to the changes you're proposing. This makes it easier for others to understand what your PR is about just by looking at the branch name. It's a good practice to prefix your branch name with a category such as `feature/`, `bug/`, `test/`, `doc/`, `refactor/`, or `fix/`. For example, if you're adding a new feature related to authentication, you might name your branch `feature/authentication`. + +2. **PR Title**: Like the branch name, the PR title should be descriptive of the changes. If your PR fixes a bug or adds a feature, state that in the title. + +3. **PR Description**: The description should provide a detailed explanation of the changes you've made. Explain why you made the changes, how you made them, and any other relevant information. This helps reviewers understand your thought process and the context behind the PR. + +4. **Linking Issues**: If your PR corresponds to an existing issue, mention this in the PR's description. You can do this by typing `#` followed by the issue number. This creates a link between the PR and the issue, providing further context and helping track the progress of tasks. + +In addition, GitHub recognizes certain keywords to close an issue automatically once the PR is merged. These keywords are: `close`, `closes`, `closed`, `fix`, `fixes`, `fixed`, `resolve`, `resolves`, `resolved`. If your PR completely resolves the issue, you can include one of these keywords before the issue number. For example: + +```markdown +Closes #123 +``` + +This will automatically close the issue #123 when the PR is merged into the main branch. This practice helps to automate the issue tracking process and ensures that no issue is accidentally left open after its corresponding changes are merged. + +5. **Small, Focused PRs**: Try to keep your PRs small and focused on a single task, feature, or bug fix. This makes the PR easier to review and understand. Large, complex PRs can be difficult to review and may delay the merging process. + +6. **Review Your Own PR**: Before requesting reviews from others, review your own PR. This can help you catch errors, improve the quality of your code, and make the review process smoother for everyone. + +7. **Approval by Maintainers**: Before a PR can be merged, it should be approved by at least two maintainers. This ensures that the changes have been thoroughly reviewed and are in line with the project's standards and goals. When assigning reviewers, try to choose maintainers who are most familiar with the code you've changed. Alternatively, you can use GitHub's reviewer suggestions, but it's a good practice to try to assign maintainers who don't already have a large number of PRs assigned for their review. This helps distribute the review workload evenly among the team. + +8. **Merging Approach**: In our project, all branches should be merged using the "Squash and Merge" approach. This means that all commits in the branch will be squashed into a single commit when merging into the main branch. This approach helps to keep the commit history of the main branch clean and understandable. It's important to ensure that your branch has a meaningful and comprehensive commit message that reflects the changes made in the entire branch. + +9. **Merge Commit Title**: When merging your branch, ensure that the merge commit has a meaningful title. This title should summarize the changes made in the branch and provide context about what the merge adds to the main branch. This is especially important when using the "Squash and Merge" approach, as all the changes from the branch will be represented by this single commit in the main branch's history. A good practice is to use the PR title or a summary of it as the merge commit title. + +Remember, the goal of a PR is not just to merge code into the main codebase. It's also an opportunity for team collaboration, code review, and learning. Make your PRs clear, concise, and informative to make the most of this process. + +### Reporting Bugs + +If you've found a bug in KAGOME, your contribution towards fixing it is greatly appreciated. Here are some guidelines to follow when reporting bugs: + +1. **Check Existing Issues**: Before reporting a bug, please check the existing [Issues](https://github.com/qdrvm/kagome/issues) to see if it has already been reported. If it has, you can add any additional information you have to the existing issue. + +2. **Create a New Issue**: If the bug hasn't been reported yet, create a new issue in the [Issues](https://github.com/qdrvm/kagome/issues/new) section. Use a clear and descriptive title for the issue to help others understand what the bug is about. + +3. **Describe the Bug**: In the issue description, provide a detailed explanation of the bug. Include information about what you expected to happen and what actually happened. If possible, provide steps to reproduce the bug. This will help others to understand and fix the bug. + +4. **Include Error Messages and Debugging Artifacts**: If there are any error messages, stack traces, or core dumps related to the bug, include them in the issue. These can provide valuable information for diagnosing the problem. + +5. **Provide System Information**: Include information about your system, such as the operating system, the version of KAGOME you're using, and any other relevant software versions. This can help identify if the bug is specific to certain environments. + +6. **Use Labels**: If possible, use labels to categorize the bug. This can help maintainers and other contributors to find and prioritize the bug. + +7. **Be Respectful and Constructive**: Remember that KAGOME is maintained by volunteers who are donating their time to the project. When reporting bugs, be respectful and constructive, and remember to follow the project's [Code of Conduct](#code-of-conduct). + +Remember, the goal of reporting bugs is not just to get them fixed, but also to contribute to the project and the community. Your bug reports help to make KAGOME better for everyone. Thank you for your contributions! -1. Kagome uses C++20 as target language -2. Use `clang-format` -3. Test your code with gtest/gmock. -4. Open PR with base branch = `master`, fix CI and follow guide in PR template. -5. Read [docs](./docs) diff --git a/core/api/CMakeLists.txt b/core/api/CMakeLists.txt index b537f1095f..eb95610faa 100644 --- a/core/api/CMakeLists.txt +++ b/core/api/CMakeLists.txt @@ -57,7 +57,7 @@ target_link_libraries(api logger app_state_manager p2p::p2p_peer_id - crypto_store + key_store hexutil scale::scale storage diff --git a/core/api/service/author/author_api.hpp b/core/api/service/author/author_api.hpp index fe0b2b4280..06b2898872 100644 --- a/core/api/service/author/author_api.hpp +++ b/core/api/service/author/author_api.hpp @@ -10,7 +10,7 @@ #include "common/buffer.hpp" #include "common/buffer_view.hpp" #include "crypto/common.hpp" -#include "crypto/crypto_store/key_type.hpp" +#include "crypto/key_store/key_type.hpp" #include "primitives/author_api_primitives.hpp" #include "primitives/transaction_validity.hpp" diff --git a/core/api/service/author/impl/author_api_impl.cpp b/core/api/service/author/impl/author_api_impl.cpp index 1180a2cc13..b2d36988bf 100644 --- a/core/api/service/author/impl/author_api_impl.cpp +++ b/core/api/service/author/impl/author_api_impl.cpp @@ -13,12 +13,11 @@ #include "api/service/api_service.hpp" #include "blockchain/block_tree.hpp" -#include "crypto/crypto_store.hpp" -#include "crypto/crypto_store/crypto_store_impl.hpp" -#include "crypto/crypto_store/crypto_suites.hpp" -#include "crypto/crypto_store/key_file_storage.hpp" -#include "crypto/crypto_store/session_keys.hpp" #include "crypto/hasher.hpp" +#include "crypto/key_store.hpp" +#include "crypto/key_store/key_file_storage.hpp" +#include "crypto/key_store/session_keys.hpp" +#include "crypto/sr25519_types.hpp" #include "primitives/transaction.hpp" #include "runtime/runtime_api/session_keys_api.hpp" #include "scale/scale_decoder_stream.hpp" @@ -34,7 +33,7 @@ namespace kagome::api { AuthorApiImpl::AuthorApiImpl(sptr key_api, sptr pool, - sptr store, + sptr store, sptr keys, sptr key_store, LazySPtr block_tree, @@ -68,33 +67,33 @@ namespace kagome::api { == kKeyTypes.end()) { std::string types; for (auto &type : kKeyTypes) { - types.append(crypto::encodeKeyTypeToStr(type)); + types.append(type.toString()); types.push_back(' '); } types.pop_back(); SL_INFO(logger_, "Unsupported key type, only [{}] are accepted", types); - return outcome::failure(crypto::CryptoStoreError::UNSUPPORTED_KEY_TYPE); + return outcome::failure(crypto::KeyStoreError::UNSUPPORTED_KEY_TYPE); }; if (crypto::KeyTypes::BABE == key_type_id or crypto::KeyTypes::AUTHORITY_DISCOVERY == key_type_id) { - OUTCOME_TRY(seed_typed, crypto::Sr25519Seed::from(seed)); OUTCOME_TRY(public_key_typed, crypto::Sr25519PublicKey::fromSpan(public_key)); + OUTCOME_TRY(seed_typed, crypto::Sr25519Seed::from(std::move(seed))); OUTCOME_TRY(keypair, - store_->generateSr25519Keypair(key_type_id, seed_typed)); + store_->sr25519().generateKeypair(key_type_id, seed_typed)); if (public_key_typed != keypair.public_key) { - return outcome::failure(crypto::CryptoStoreError::WRONG_PUBLIC_KEY); + return outcome::failure(crypto::KeyStoreError::WRONG_PUBLIC_KEY); } } if (crypto::KeyTypes::GRANDPA == key_type_id) { - OUTCOME_TRY(seed_typed, crypto::Ed25519Seed::from(seed)); OUTCOME_TRY(public_key_typed, crypto::Ed25519PublicKey::fromSpan(public_key)); + OUTCOME_TRY(seed_typed, crypto::Ed25519Seed::from(std::move(seed))); OUTCOME_TRY(keypair, - store_->generateEd25519Keypair(crypto::KeyTypes::GRANDPA, - seed_typed)); + store_->ed25519().generateKeypair(crypto::KeyTypes::GRANDPA, + seed_typed)); if (public_key_typed != keypair.public_key) { - return outcome::failure(crypto::CryptoStoreError::WRONG_PUBLIC_KEY); + return outcome::failure(crypto::KeyStoreError::WRONG_PUBLIC_KEY); } } auto res = @@ -123,13 +122,13 @@ namespace kagome::api { return false; } stream >> key; - if (store_->findEd25519Keypair( + if (store_->ed25519().findKeypair( crypto::KeyTypes::GRANDPA, crypto::Ed25519PublicKey(common::Blob<32>(key)))) { unsigned count = 1; while (stream.currentIndex() < keys.size()) { stream >> key; - if (not store_->findSr25519Keypair( + if (not store_->sr25519().findKeypair( crypto::polkadot_key_order[count++], crypto::Sr25519PublicKey(common::Blob<32>(key)))) { return false; @@ -142,12 +141,11 @@ namespace kagome::api { outcome::result AuthorApiImpl::hasKey(const BufferView &public_key, crypto::KeyType key_type) { - auto res = key_store_->searchForPhrase(key_type, public_key); + auto res = key_store_->searchForKey(key_type, public_key); if (not res) { return res.error(); - } else { - return res.value() ? true : false; } + return res.value(); } outcome::result> diff --git a/core/api/service/author/impl/author_api_impl.hpp b/core/api/service/author/impl/author_api_impl.hpp index 51c5b3cd53..da7230f465 100644 --- a/core/api/service/author/impl/author_api_impl.hpp +++ b/core/api/service/author/impl/author_api_impl.hpp @@ -30,7 +30,7 @@ namespace kagome::blockchain { class BlockTree; } namespace kagome::crypto { - class CryptoStore; + class KeyStore; class Hasher; class KeyFileStorage; class SessionKeys; @@ -70,7 +70,7 @@ namespace kagome::api { */ AuthorApiImpl(sptr key_api, sptr pool, - sptr store, + sptr store, sptr keys, sptr key_store, LazySPtr block_tree, @@ -108,7 +108,7 @@ namespace kagome::api { private: sptr keys_api_; sptr pool_; - sptr store_; + sptr store_; sptr keys_; sptr key_store_; LazySPtr api_service_; diff --git a/core/api/service/author/requests/has_key.hpp b/core/api/service/author/requests/has_key.hpp index 5bb879aeb6..aeab4da955 100644 --- a/core/api/service/author/requests/has_key.hpp +++ b/core/api/service/author/requests/has_key.hpp @@ -10,6 +10,7 @@ #include "api/service/author/author_api.hpp" #include "api/service/base_request.hpp" +#include "crypto/key_store/key_type.hpp" #include "outcome/outcome.hpp" namespace kagome::api::author::request { @@ -23,8 +24,10 @@ namespace kagome::api::author::request { outcome::result execute() override { OUTCOME_TRY(public_key, common::unhexWith0x(getParam<0>())); - return api_->hasKey(public_key, - crypto::decodeKeyTypeFromStr(getParam<1>())); + if (auto key_type = crypto::KeyType::fromString(getParam<1>())) { + return api_->hasKey(public_key, *key_type); + } + return crypto::KeyTypeError::UNSUPPORTED_KEY_TYPE; } private: diff --git a/core/api/service/author/requests/insert_key.hpp b/core/api/service/author/requests/insert_key.hpp index 63131b9116..43e480276c 100644 --- a/core/api/service/author/requests/insert_key.hpp +++ b/core/api/service/author/requests/insert_key.hpp @@ -11,6 +11,7 @@ #include "api/service/author/author_api.hpp" #include "api/service/base_request.hpp" #include "crypto/common.hpp" +#include "crypto/key_store/key_type.hpp" #include "outcome/outcome.hpp" namespace kagome::api::author::request { @@ -33,9 +34,10 @@ namespace kagome::api::author::request { std::string_view{seed_hex.data(), seed_hex.size()}, seed_buf.begin())); OUTCOME_TRY(public_key, common::unhexWith0x(getParam<2>())); - return api_->insertKey(crypto::decodeKeyTypeFromStr(getParam<0>()), - std::move(seed_buf), - public_key); + if (auto key_type = crypto::KeyType::fromString(getParam<0>())) { + return api_->insertKey(*key_type, std::move(seed_buf), public_key); + } + return crypto::KeyTypeError::UNSUPPORTED_KEY_TYPE; } private: diff --git a/core/authority_discovery/publisher/address_publisher.hpp b/core/authority_discovery/publisher/address_publisher.hpp index 2f8135488a..33d498e424 100644 --- a/core/authority_discovery/publisher/address_publisher.hpp +++ b/core/authority_discovery/publisher/address_publisher.hpp @@ -8,7 +8,7 @@ #include "application/app_state_manager.hpp" #include "blockchain/block_tree.hpp" -#include "crypto/crypto_store/session_keys.hpp" +#include "crypto/key_store/session_keys.hpp" #include "crypto/ed25519_provider.hpp" #include "crypto/sr25519_provider.hpp" #include "log/logger.hpp" diff --git a/core/authority_discovery/query/query_impl.cpp b/core/authority_discovery/query/query_impl.cpp index 32160c1fa4..f84b5024ac 100644 --- a/core/authority_discovery/query/query_impl.cpp +++ b/core/authority_discovery/query/query_impl.cpp @@ -36,7 +36,7 @@ namespace kagome::authority_discovery { std::shared_ptr app_state_manager, std::shared_ptr block_tree, std::shared_ptr authority_discovery_api, - std::shared_ptr crypto_store, + std::shared_ptr key_store, std::shared_ptr sr_crypto_provider, std::shared_ptr libp2p_crypto_provider, std::shared_ptr key_marshaller, @@ -45,7 +45,7 @@ namespace kagome::authority_discovery { std::shared_ptr scheduler) : block_tree_{std::move(block_tree)}, authority_discovery_api_{std::move(authority_discovery_api)}, - crypto_store_{std::move(crypto_store)}, + key_store_{std::move(key_store)}, sr_crypto_provider_{std::move(sr_crypto_provider)}, libp2p_crypto_provider_{std::move(libp2p_crypto_provider)}, key_marshaller_{std::move(key_marshaller)}, @@ -101,7 +101,7 @@ namespace kagome::authority_discovery { authorities, authority_discovery_api_->authorities(block_tree_->bestBlock().hash)); OUTCOME_TRY(local_keys, - crypto_store_->getSr25519PublicKeys( + key_store_->sr25519().getPublicKeys( crypto::KeyTypes::AUTHORITY_DISCOVERY)); auto has = [](const std::vector &keys, const primitives::AuthorityDiscoveryId &key) { diff --git a/core/authority_discovery/query/query_impl.hpp b/core/authority_discovery/query/query_impl.hpp index a9c93a7119..b2ad8dfd9d 100644 --- a/core/authority_discovery/query/query_impl.hpp +++ b/core/authority_discovery/query/query_impl.hpp @@ -11,7 +11,7 @@ #include "application/app_state_manager.hpp" #include "authority_discovery/interval.hpp" #include "blockchain/block_tree.hpp" -#include "crypto/crypto_store.hpp" +#include "crypto/key_store.hpp" #include "crypto/sr25519_provider.hpp" #include "log/logger.hpp" #include "runtime/runtime_api/authority_discovery_api.hpp" @@ -38,7 +38,7 @@ namespace kagome::authority_discovery { std::shared_ptr app_state_manager, std::shared_ptr block_tree, std::shared_ptr authority_discovery_api, - std::shared_ptr crypto_store, + std::shared_ptr key_store, std::shared_ptr sr_crypto_provider, std::shared_ptr libp2p_crypto_provider, std::shared_ptr @@ -64,7 +64,7 @@ namespace kagome::authority_discovery { std::shared_ptr block_tree_; std::shared_ptr authority_discovery_api_; - std::shared_ptr crypto_store_; + std::shared_ptr key_store_; std::shared_ptr sr_crypto_provider_; std::shared_ptr libp2p_crypto_provider_; std::shared_ptr key_marshaller_; diff --git a/core/benchmark/block_execution_benchmark.cpp b/core/benchmark/block_execution_benchmark.cpp index c4f9e775c5..2b159a6dd2 100644 --- a/core/benchmark/block_execution_benchmark.cpp +++ b/core/benchmark/block_execution_benchmark.cpp @@ -123,18 +123,15 @@ namespace kagome::benchmark { std::shared_ptr core_api, std::shared_ptr block_tree, std::shared_ptr module_repo, - std::shared_ptr code_provider, std::shared_ptr trie_storage) : logger_{log::createLogger("BlockExecutionBenchmark", "benchmark")}, core_api_{core_api}, block_tree_{block_tree}, module_repo_{module_repo}, - code_provider_{code_provider}, trie_storage_{trie_storage} { BOOST_ASSERT(block_tree_ != nullptr); BOOST_ASSERT(core_api_ != nullptr); BOOST_ASSERT(module_repo_ != nullptr); - BOOST_ASSERT(code_provider_ != nullptr); BOOST_ASSERT(trie_storage_ != nullptr); } diff --git a/core/benchmark/block_execution_benchmark.hpp b/core/benchmark/block_execution_benchmark.hpp index c5de1afb47..33290722c0 100644 --- a/core/benchmark/block_execution_benchmark.hpp +++ b/core/benchmark/block_execution_benchmark.hpp @@ -19,7 +19,6 @@ namespace kagome::blockchain { namespace kagome::runtime { class Core; class ModuleRepository; - class RuntimeCodeProvider; } // namespace kagome::runtime namespace kagome::storage::trie { @@ -45,7 +44,6 @@ namespace kagome::benchmark { std::shared_ptr core_api, std::shared_ptr block_tree, std::shared_ptr module_repo, - std::shared_ptr code_provider, std::shared_ptr trie_storage); outcome::result run(Config config); @@ -55,7 +53,6 @@ namespace kagome::benchmark { std::shared_ptr core_api_; std::shared_ptr block_tree_; std::shared_ptr module_repo_; - std::shared_ptr code_provider_; std::shared_ptr trie_storage_; }; diff --git a/core/common/bytestr.hpp b/core/common/bytestr.hpp index 30be0639d1..b945adc963 100644 --- a/core/common/bytestr.hpp +++ b/core/common/bytestr.hpp @@ -6,6 +6,7 @@ #pragma once +#include #include #include @@ -19,6 +20,11 @@ namespace kagome { return {reinterpret_cast(s.data()), s.size()}; } + inline std::span str2byte(std::span s) { + // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + return {reinterpret_cast(s.data()), s.size()}; + } + inline std::string_view byte2str(const common::BufferView &s) { // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) return {reinterpret_cast(s.data()), s.size()}; diff --git a/core/common/optref.hpp b/core/common/optref.hpp new file mode 100644 index 0000000000..35a3684ad5 --- /dev/null +++ b/core/common/optref.hpp @@ -0,0 +1,75 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +namespace kagome { + template + class OptRef { + public: + OptRef() : data{nullptr} {} + OptRef(T &data) : data{&data} {} + OptRef(T &&) = delete; + OptRef(std::nullopt_t) : data{nullptr} {} + + OptRef(const OptRef &) = default; + + OptRef &operator=(const OptRef &) = default; + + T &operator*() { + BOOST_ASSERT(data); + return *data; + } + + const T &operator*() const { + BOOST_ASSERT(data); + return *data; + } + + T *operator->() { + BOOST_ASSERT(data); + return data; + } + + const T *operator->() const { + BOOST_ASSERT(data); + return data; + } + + T &value() { + BOOST_ASSERT(data); + return *data; + } + + const T &value() const { + BOOST_ASSERT(data); + return *data; + } + + explicit operator bool() const noexcept { + return data != nullptr; + } + + bool operator!() const noexcept { + return data == nullptr; + } + + bool has_value() const noexcept { + return data != nullptr; + } + + bool operator==(const OptRef &) const = default; + + bool operator==(const T &other) const { + return has_value() && (*data == other); + } + + private: + T *data; + }; +} // namespace kagome diff --git a/core/consensus/babe/impl/babe.cpp b/core/consensus/babe/impl/babe.cpp index 57105df0a7..5b73d64811 100644 --- a/core/consensus/babe/impl/babe.cpp +++ b/core/consensus/babe/impl/babe.cpp @@ -26,7 +26,7 @@ #include "consensus/timeline/impl/slot_leadership_error.hpp" #include "consensus/timeline/slots_util.hpp" #include "crypto/blake2/blake2b.h" -#include "crypto/crypto_store/session_keys.hpp" +#include "crypto/key_store/session_keys.hpp" #include "crypto/sr25519_provider.hpp" #include "dispute_coordinator/dispute_coordinator.hpp" #include "metrics/histogram_timer.hpp" diff --git a/core/consensus/babe/impl/babe_lottery_impl.cpp b/core/consensus/babe/impl/babe_lottery_impl.cpp index 44433ae3c2..20ac6ede00 100644 --- a/core/consensus/babe/impl/babe_lottery_impl.cpp +++ b/core/consensus/babe/impl/babe_lottery_impl.cpp @@ -9,7 +9,7 @@ #include "consensus/babe/babe_config_repository.hpp" #include "consensus/babe/impl/prepare_transcript.hpp" #include "consensus/babe/impl/threshold_util.hpp" -#include "crypto/crypto_store/session_keys.hpp" +#include "crypto/key_store/session_keys.hpp" #include "crypto/hasher.hpp" #include "crypto/vrf_provider.hpp" diff --git a/core/consensus/beefy/impl/beefy_impl.cpp b/core/consensus/beefy/impl/beefy_impl.cpp index cc8d7238ef..84ef40dcf0 100644 --- a/core/consensus/beefy/impl/beefy_impl.cpp +++ b/core/consensus/beefy/impl/beefy_impl.cpp @@ -18,7 +18,7 @@ #include "consensus/beefy/impl/beefy_thread_pool.hpp" #include "consensus/beefy/sig.hpp" #include "consensus/timeline/timeline.hpp" -#include "crypto/crypto_store/session_keys.hpp" +#include "crypto/key_store/session_keys.hpp" #include "metrics/histogram_timer.hpp" #include "network/impl/protocols/beefy_protocol_impl.hpp" #include "runtime/common/runtime_execution_error.hpp" diff --git a/core/consensus/grandpa/impl/grandpa_impl.cpp b/core/consensus/grandpa/impl/grandpa_impl.cpp index 2dc0a183e3..dd71e5d7ca 100644 --- a/core/consensus/grandpa/impl/grandpa_impl.cpp +++ b/core/consensus/grandpa/impl/grandpa_impl.cpp @@ -28,7 +28,7 @@ #include "consensus/grandpa/voting_round_error.hpp" #include "consensus/grandpa/voting_round_update.hpp" #include "consensus/timeline/timeline.hpp" -#include "crypto/crypto_store/session_keys.hpp" +#include "crypto/key_store/session_keys.hpp" #include "network/peer_manager.hpp" #include "network/reputation_repository.hpp" #include "network/synchronizer.hpp" @@ -815,7 +815,7 @@ namespace kagome::consensus::grandpa { } GrandpaContext grandpa_context; - VotingRoundUpdate update{*current_round_, &grandpa_context}; + VotingRoundUpdate update{*current_round_, grandpa_context}; for (auto &vote : msg.prevote_justification) { update.vote(vote); } @@ -1018,7 +1018,7 @@ namespace kagome::consensus::grandpa { peer_id); GrandpaContext grandpa_context; - VotingRoundUpdate update{*target_round, &grandpa_context, true}; + VotingRoundUpdate update{*target_round, grandpa_context, true}; update.vote(msg.vote); update.update(); diff --git a/core/consensus/grandpa/voting_round.hpp b/core/consensus/grandpa/voting_round.hpp index 856fd72b55..792e7d5adc 100644 --- a/core/consensus/grandpa/voting_round.hpp +++ b/core/consensus/grandpa/voting_round.hpp @@ -9,7 +9,7 @@ #include "common/tagged.hpp" #include "consensus/grandpa/movable_round_state.hpp" #include "consensus/grandpa/round_observer.hpp" -#include "utils/optref.hpp" +#include "common/optref.hpp" namespace kagome::consensus::grandpa { diff --git a/core/crypto/CMakeLists.txt b/core/crypto/CMakeLists.txt index 108918a44c..6be9645aeb 100644 --- a/core/crypto/CMakeLists.txt +++ b/core/crypto/CMakeLists.txt @@ -117,7 +117,7 @@ kagome_install(pbkdf2_provider) add_subdirectory(bip39) add_subdirectory(blake2) -add_subdirectory(crypto_store) +add_subdirectory(key_store) add_subdirectory(keccak) add_subdirectory(sha) add_subdirectory(twox) diff --git a/core/crypto/common.hpp b/core/crypto/common.hpp index ea4c810cc9..c2db928275 100644 --- a/core/crypto/common.hpp +++ b/core/crypto/common.hpp @@ -6,12 +6,13 @@ #pragma once -#include -#include #include #include #include +#include +#include + #include "common/blob.hpp" #include "common/buffer.hpp" #include "log/logger.hpp" @@ -63,14 +64,14 @@ namespace kagome::crypto { template SecureCleanGuard(common::Blob &&) -> SecureCleanGuard; + inline std::once_flag secure_heap_init_flag{}; + inline log::Logger secure_heap_logger; + /** * An allocator on the OpenSSL secure heap */ - template + template class SecureHeapAllocator { - inline static std::once_flag flag; - inline static log::Logger logger; - public: using value_type = T; using pointer = T *; @@ -82,15 +83,15 @@ namespace kagome::crypto { }; static pointer allocate(size_type n) { - std::call_once(flag, []() { + std::call_once(secure_heap_init_flag, []() { if (CRYPTO_secure_malloc_init(HeapSize, MinAllocationSize) != 1) { throw std::runtime_error{"Failed to allocate OpenSSL secure heap"}; } - logger = log::createLogger("SecureAllocator", "crypto"); + secure_heap_logger = log::createLogger("SecureAllocator", "crypto"); }); BOOST_ASSERT(CRYPTO_secure_malloc_initialized()); auto p = OPENSSL_secure_malloc(n * sizeof(T)); - SL_TRACE(logger, + SL_TRACE(secure_heap_logger, "allocated {} bytes in secure heap, {} used", OPENSSL_secure_actual_size(p), CRYPTO_secure_used()); @@ -103,6 +104,10 @@ namespace kagome::crypto { static void deallocate(pointer p, size_type) noexcept { BOOST_ASSERT(CRYPTO_secure_malloc_initialized()); + SL_TRACE(secure_heap_logger, + "free {} bytes in secure heap, {} used", + OPENSSL_secure_actual_size(p), + CRYPTO_secure_used()); OPENSSL_secure_free(p); } @@ -231,4 +236,5 @@ namespace kagome::crypto { SecureBuffer data; }; + } // namespace kagome::crypto diff --git a/core/crypto/crypto_store.hpp b/core/crypto/crypto_store.hpp deleted file mode 100644 index 6717a91d8a..0000000000 --- a/core/crypto/crypto_store.hpp +++ /dev/null @@ -1,174 +0,0 @@ -/** - * Copyright Quadrivium LLC - * All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include -#include - -#include - -#include "crypto/bip39/bip39_provider.hpp" -#include "crypto/crypto_store/key_type.hpp" -#include "crypto/ecdsa_types.hpp" -#include "crypto/ed25519_types.hpp" -#include "crypto/secp256k1_types.hpp" -#include "crypto/sr25519_types.hpp" -#include "filesystem/common.hpp" - -namespace kagome::crypto { - class CryptoStore { - public: - using Path = filesystem::path; - - virtual ~CryptoStore() = default; - - using EcdsaKeys = std::vector; - using Ed25519Keys = std::vector; - using Sr25519Keys = std::vector; - using EcdsaKeypairs = std::vector; - using Ed25519Keypairs = std::vector; - using Sr25519Keypairs = std::vector; - - /** - * @brief generates ecdsa keypair and stores it in memory - * @param key_type key type identifier - * @param mnemonic_phrase mnemonic phrase - * @return generated key pair or error - */ - virtual outcome::result generateEcdsaKeypair( - KeyType key_type, std::string_view mnemonic_phrase) = 0; - - /** - * @brief generates Ed25519 keypair and stores it in memory - * @param key_type key type identifier - * @param mnemonic_phrase mnemonic phrase - * @return generated key pair or error - */ - virtual outcome::result generateEd25519Keypair( - KeyType key_type, std::string_view mnemonic_phrase) = 0; - - /** - * @brief generates SR25519 keypair and stores it in memory - * @param key_type key type identifier - * @param mnemonic_phrase mnemonic phrase - * @return generated key pair or error - */ - virtual outcome::result generateSr25519Keypair( - KeyType key_type, std::string_view mnemonic_phrase) = 0; - - /** - * @brief generates ecdsa keypair and stores it in memory - * @param key_type key type identifier - * @param seed seed for generating keys - * @return generated key pair - */ - virtual outcome::result generateEcdsaKeypair( - KeyType key_type, const EcdsaSeed &seed) = 0; - - /** - * @brief generates Ed25519 keypair and stores it in memory - * @param key_type key type identifier - * @param seed seed for generating keys - * @return generated key pair - */ - virtual outcome::result generateEd25519Keypair( - KeyType key_type, const Ed25519Seed &seed) = 0; - - /** - * @brief generates SR25519 keypair and stores it in memory - * @param key_type key type identifier - * @param seed seed for generating keys - * @return generated key - */ - virtual outcome::result generateSr25519Keypair( - KeyType key_type, const Sr25519Seed &seed) = 0; - - /** - * @brief generates ecdsa keypair and stores it on disk - * @param key_type key type identifier - * @return generated key pair or error - */ - virtual outcome::result generateEcdsaKeypairOnDisk( - KeyType key_type) = 0; - - /** - * @brief generates Ed25519 keypair and stores it on disk - * @param key_type key type identifier - * @return generated key pair or error - */ - virtual outcome::result generateEd25519KeypairOnDisk( - KeyType key_type) = 0; - - /** - * @brief generates SR25519 keypair and stores it on disk - * @param key_type key type identifier - * @return generated key pair or error - */ - virtual outcome::result generateSr25519KeypairOnDisk( - KeyType key_type) = 0; - - /** - * @brief searches for key pair - * @param key_type key category - * @param pk public key to look for - * @return found key pair if exists - */ - virtual outcome::result findEcdsaKeypair( - KeyType key_type, const EcdsaPublicKey &pk) const = 0; - - /** - * @brief searches for key pair - * @param key_type key category - * @param pk public key to look for - * @return found key pair if exists - */ - virtual outcome::result findEd25519Keypair( - KeyType key_type, const Ed25519PublicKey &pk) const = 0; - - /** - * @brief searches for key pair - * @param key_type key category - * @param pk public key to look for - * @return found key pair if exists - */ - virtual outcome::result findSr25519Keypair( - KeyType key_type, const Sr25519PublicKey &pk) const = 0; - - /** - * @brief searches for ecdsa keys of specified type - * @param key_type key type identifier to look for - * @return vector of found public keys - */ - virtual outcome::result getEcdsaPublicKeys( - KeyType key_type) const = 0; - - /** - * @brief searches for Ed25519 keys of specified type - * @param key_type key type identifier to look for - * @return vector of found public keys - */ - virtual outcome::result getEd25519PublicKeys( - KeyType key_type) const = 0; - - /** - * @brief searches for SR25519 keys of specified type - * @param key_type key type identifier to look for - * @return vector of found public keys - */ - virtual outcome::result getSr25519PublicKeys( - KeyType key_type) const = 0; - - /** - * Acquires the key from user-provided path or generates and saves the - * key under the path. Used when --node-key-file flag gets processed. - * @param path - path the key file (raw bytes or hex-encoded) - * @return LibP2P keypair - */ - virtual outcome::result loadLibp2pKeypair( - const Path &key_path) const = 0; - }; -} // namespace kagome::crypto diff --git a/core/crypto/crypto_store/CMakeLists.txt b/core/crypto/crypto_store/CMakeLists.txt deleted file mode 100644 index a4c0df339f..0000000000 --- a/core/crypto/crypto_store/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -# -# Copyright Quadrivium LLC -# All Rights Reserved -# SPDX-License-Identifier: Apache-2.0 -# - -add_library(crypto_store_key_type - key_type.cpp - ) -target_link_libraries(crypto_store_key_type - blob - Boost::boost - outcome - ) -kagome_install(crypto_store_key_type) - -add_library(key_file_storage - key_file_storage.cpp - ) -target_link_libraries(key_file_storage - filesystem - crypto_store_key_type - ) -kagome_install(key_file_storage) - -add_library(crypto_store - crypto_store_impl.cpp - crypto_suites.hpp - key_cache.hpp - session_keys.cpp - session_keys.hpp) - -target_link_libraries(crypto_store - key_file_storage - ecdsa_provider - ed25519_provider - sr25519_provider - p2p::p2p_random_generator # generator from libp2p - bip39_provider - crypto_store_key_type - ) -kagome_install(crypto_store) diff --git a/core/crypto/crypto_store/crypto_store_impl.cpp b/core/crypto/crypto_store/crypto_store_impl.cpp deleted file mode 100644 index 820bbaf3ff..0000000000 --- a/core/crypto/crypto_store/crypto_store_impl.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/** - * Copyright Quadrivium LLC - * All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "crypto/crypto_store/crypto_store_impl.hpp" - -#include - -#include "common/bytestr.hpp" -#include "common/visitor.hpp" -#include "utils/read_file.hpp" - -OUTCOME_CPP_DEFINE_CATEGORY(kagome::crypto, CryptoStoreError, e) { - using E = kagome::crypto::CryptoStoreError; - switch (e) { - case E::UNSUPPORTED_KEY_TYPE: - return "key type is not supported"; - case E::UNSUPPORTED_CRYPTO_TYPE: - return "cryptographic type is not supported"; - case E::WRONG_SEED_SIZE: - return "wrong seed size"; - case E::KEY_NOT_FOUND: - return "key not found"; - case E::BABE_ALREADY_EXIST: - return "BABE key already exists"; - case E::GRAN_ALREADY_EXIST: - return "GRAN key already exists"; - case E::AUDI_ALREADY_EXIST: - return "AUDI key already exists"; - case E::WRONG_PUBLIC_KEY: - return "Public key doesn't match seed"; - } - return "Unknown CryptoStoreError code"; -} - -namespace kagome::crypto { - - CryptoStoreImpl::CryptoStoreImpl( - std::shared_ptr ecdsa_suite, - std::shared_ptr ed_suite, - std::shared_ptr sr_suite, - std::shared_ptr bip39_provider, - std::shared_ptr csprng, - std::shared_ptr key_fs) - : file_storage_{std::move(key_fs)}, - ecdsa_suite_{std::move(ecdsa_suite)}, - ed_suite_{std::move(ed_suite)}, - sr_suite_{std::move(sr_suite)}, - bip39_provider_{std::move(bip39_provider)}, - csprng_{std::move(csprng)}, - logger_{log::createLogger("CryptoStore", "crypto_store")} { - BOOST_ASSERT(ecdsa_suite_ != nullptr); - BOOST_ASSERT(ed_suite_ != nullptr); - BOOST_ASSERT(sr_suite_ != nullptr); - BOOST_ASSERT(bip39_provider_ != nullptr); - BOOST_ASSERT(file_storage_ != nullptr); - } - - outcome::result CryptoStoreImpl::generateEcdsaKeypair( - KeyType key_type, std::string_view mnemonic_phrase) { - OUTCOME_TRY(kp, generateKeypair(mnemonic_phrase, *ecdsa_suite_)); - getCache(ecdsa_suite_, ecdsa_caches_, key_type) - .insert(kp.public_key, kp.secret_key); - return kp; - } - - outcome::result CryptoStoreImpl::generateEd25519Keypair( - KeyType key_type, std::string_view mnemonic_phrase) { - OUTCOME_TRY(kp, generateKeypair(mnemonic_phrase, *ed_suite_)); - getCache(ed_suite_, ed_caches_, key_type) - .insert(kp.public_key, kp.secret_key); - return kp; - } - - outcome::result CryptoStoreImpl::generateSr25519Keypair( - KeyType key_type, std::string_view mnemonic_phrase) { - OUTCOME_TRY(kp, generateKeypair(mnemonic_phrase, *sr_suite_)); - getCache(sr_suite_, sr_caches_, key_type) - .insert(kp.public_key, kp.secret_key); - return kp; - } - - outcome::result CryptoStoreImpl::generateEcdsaKeypair( - KeyType key_type, const EcdsaSeed &seed) { - OUTCOME_TRY(kp, ecdsa_suite_->generateKeypair(seed, {})); - getCache(ecdsa_suite_, ecdsa_caches_, key_type) - .insert(kp.public_key, kp.secret_key); - return kp; - } - - outcome::result CryptoStoreImpl::generateEd25519Keypair( - KeyType key_type, const Ed25519Seed &seed) { - OUTCOME_TRY(kp, ed_suite_->generateKeypair(seed, {})); - getCache(ed_suite_, ed_caches_, key_type) - .insert(kp.public_key, kp.secret_key); - return kp; - } - - outcome::result CryptoStoreImpl::generateSr25519Keypair( - KeyType key_type, const Sr25519Seed &seed) { - OUTCOME_TRY(kp, sr_suite_->generateKeypair(seed, {})); - getCache(sr_suite_, sr_caches_, key_type) - .insert(kp.public_key, kp.secret_key); - return kp; - } - - outcome::result CryptoStoreImpl::generateEcdsaKeypairOnDisk( - KeyType key_type) { - return generateKeypairOnDisk(key_type, ecdsa_suite_, ecdsa_caches_); - } - - outcome::result CryptoStoreImpl::generateEd25519KeypairOnDisk( - KeyType key_type) { - return generateKeypairOnDisk(key_type, ed_suite_, ed_caches_); - } - - outcome::result CryptoStoreImpl::generateSr25519KeypairOnDisk( - KeyType key_type) { - return generateKeypairOnDisk(key_type, sr_suite_, sr_caches_); - } - - outcome::result CryptoStoreImpl::findEcdsaKeypair( - KeyType key_type, const EcdsaPublicKey &pk) const { - auto kp_opt = - getCache(ecdsa_suite_, ecdsa_caches_, key_type).searchKeypair(pk); - if (kp_opt) { - return kp_opt.value(); - } - OUTCOME_TRY(phrase, file_storage_->searchForPhrase(key_type, pk)); - if (not phrase) { - return CryptoStoreError::KEY_NOT_FOUND; - } - OUTCOME_TRY(bip, bip39_provider_->generateSeed(*phrase)); - return ecdsa_suite_->generateKeypair(bip); - } - - outcome::result CryptoStoreImpl::findEd25519Keypair( - KeyType key_type, const Ed25519PublicKey &pk) const { - auto kp_opt = getCache(ed_suite_, ed_caches_, key_type).searchKeypair(pk); - if (kp_opt) { - return kp_opt.value(); - } - OUTCOME_TRY(phrase, file_storage_->searchForPhrase(key_type, pk)); - if (not phrase) { - return CryptoStoreError::KEY_NOT_FOUND; - } - OUTCOME_TRY(bip, bip39_provider_->generateSeed(*phrase)); - return ed_suite_->generateKeypair(bip); - } - - outcome::result CryptoStoreImpl::findSr25519Keypair( - KeyType key_type, const Sr25519PublicKey &pk) const { - auto kp_opt = getCache(sr_suite_, sr_caches_, key_type).searchKeypair(pk); - if (kp_opt) { - return kp_opt.value(); - } - OUTCOME_TRY(phrase, file_storage_->searchForPhrase(key_type, pk)); - if (not phrase) { - return CryptoStoreError::KEY_NOT_FOUND; - } - OUTCOME_TRY(bip, bip39_provider_->generateSeed(*phrase)); - return sr_suite_->generateKeypair(bip); - } - - outcome::result - CryptoStoreImpl::getEcdsaPublicKeys(KeyType key_type) const { - return getPublicKeys(key_type, - getCache(ecdsa_suite_, ecdsa_caches_, key_type), - *ecdsa_suite_); - } - - outcome::result - CryptoStoreImpl::getEd25519PublicKeys(KeyType key_type) const { - return getPublicKeys( - key_type, getCache(ed_suite_, ed_caches_, key_type), *ed_suite_); - } - - outcome::result - CryptoStoreImpl::getSr25519PublicKeys(KeyType key_type) const { - return getPublicKeys( - key_type, getCache(sr_suite_, sr_caches_, key_type), *sr_suite_); - } - - outcome::result CryptoStoreImpl::loadLibp2pKeypair( - const CryptoStore::Path &key_path) const { - SecureBuffer<> contents; - if (not readFile(contents, key_path.string())) { - return CryptoStoreError::KEY_NOT_FOUND; - } - BOOST_ASSERT(ED25519_SEED_LENGTH == contents.size() - or 2 * ED25519_SEED_LENGTH == contents.size()); // hex - auto seed_res = [&]() -> outcome::result { - if (ED25519_SEED_LENGTH == contents.size()) { - OUTCOME_TRY(_seed, Ed25519Seed::from(std::move(contents))); - return _seed; - } else if (2 * ED25519_SEED_LENGTH == contents.size()) { // hex-encoded - std::span char_content{reinterpret_cast(contents.data()), - contents.size()}; - OUTCOME_TRY(_seed, - Ed25519Seed::fromHex(SecureCleanGuard{char_content})); - return _seed; - } else { - return CryptoStoreError::UNSUPPORTED_CRYPTO_TYPE; - } - }(); - OUTCOME_TRY(seed, seed_res); - OUTCOME_TRY(kp, ed_suite_->generateKeypair(seed, {})); - return ed25519KeyToLibp2pKeypair(kp); - } - - libp2p::crypto::KeyPair ed25519KeyToLibp2pKeypair(const Ed25519Keypair &kp) { - const auto &secret_key = kp.secret_key; - const auto &public_key = kp.public_key; - libp2p::crypto::PublicKey lp2p_public{ - {libp2p::crypto::Key::Type::Ed25519, - std::vector{public_key.cbegin(), public_key.cend()}}}; - auto bytes = secret_key.unsafeBytes(); - // TODO(Harrm): implement secure private key storage in libp2p - libp2p::crypto::PrivateKey lp2p_private{ - {libp2p::crypto::Key::Type::Ed25519, - std::vector{bytes.begin(), bytes.end()}}}; - return libp2p::crypto::KeyPair{ - .publicKey = lp2p_public, - .privateKey = lp2p_private, - }; - } -} // namespace kagome::crypto diff --git a/core/crypto/crypto_store/crypto_store_impl.hpp b/core/crypto/crypto_store/crypto_store_impl.hpp deleted file mode 100644 index ae50565b9f..0000000000 --- a/core/crypto/crypto_store/crypto_store_impl.hpp +++ /dev/null @@ -1,203 +0,0 @@ -/** - * Copyright Quadrivium LLC - * All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include - -#include -#include "filesystem/common.hpp" - -#include "common/blob.hpp" -#include "crypto/bip39/bip39_provider.hpp" -#include "crypto/bip39/mnemonic.hpp" -#include "crypto/crypto_store.hpp" -#include "crypto/crypto_store/crypto_suites.hpp" -#include "crypto/crypto_store/key_cache.hpp" -#include "crypto/crypto_store/key_file_storage.hpp" -#include "log/logger.hpp" - -namespace kagome::crypto { - - enum class CryptoStoreError { - UNSUPPORTED_KEY_TYPE = 1, - UNSUPPORTED_CRYPTO_TYPE, - WRONG_SEED_SIZE, - KEY_NOT_FOUND, - BABE_ALREADY_EXIST, - GRAN_ALREADY_EXIST, - AUDI_ALREADY_EXIST, - WRONG_PUBLIC_KEY, - }; - - libp2p::crypto::KeyPair ed25519KeyToLibp2pKeypair(const Ed25519Keypair &kp); - - /// TODO(Harrm) Add policies to emit a warning when found a keypair - /// with incompatible type and algorithm (e. g. ed25519 BABE keypair, - /// whereas BABE has to be sr25519 only) or when trying to generate more - /// keypair than there should be (e. g. more than one libp2p keypair is a - /// suspicious behaviour) - class CryptoStoreImpl : public CryptoStore { - public: - CryptoStoreImpl(std::shared_ptr ecdsa_suite, - std::shared_ptr ed_suite, - std::shared_ptr sr_suite, - std::shared_ptr bip39_provider, - std::shared_ptr csprng, - std::shared_ptr key_fs); - - outcome::result generateEcdsaKeypair( - KeyType key_type, std::string_view mnemonic_phrase) override; - - outcome::result generateEd25519Keypair( - KeyType key_type, std::string_view mnemonic_phrase) override; - - outcome::result generateSr25519Keypair( - KeyType key_type, std::string_view mnemonic_phrase) override; - - outcome::result generateEcdsaKeypair( - KeyType key_type, const EcdsaSeed &seed) override; - - outcome::result generateEd25519Keypair( - KeyType key_type, const Ed25519Seed &seed) override; - - outcome::result generateSr25519Keypair( - KeyType key_type, const Sr25519Seed &seed) override; - - outcome::result generateEcdsaKeypairOnDisk( - KeyType key_type) override; - - outcome::result generateEd25519KeypairOnDisk( - KeyType key_type) override; - - outcome::result generateSr25519KeypairOnDisk( - KeyType key_type) override; - - outcome::result findEcdsaKeypair( - KeyType key_type, const EcdsaPublicKey &pk) const override; - - outcome::result findEd25519Keypair( - KeyType key_type, const Ed25519PublicKey &pk) const override; - - outcome::result findSr25519Keypair( - KeyType key_type, const Sr25519PublicKey &pk) const override; - - outcome::result getEcdsaPublicKeys( - KeyType key_type) const override; - - outcome::result getEd25519PublicKeys( - KeyType key_type) const override; - - outcome::result getSr25519PublicKeys( - KeyType key_type) const override; - - outcome::result loadLibp2pKeypair( - const Path &key_path) const override; - - private: - template - outcome::result> getPublicKeys( - KeyType key_type, - const KeyCache &cache, - const CryptoSuite &suite) const { - auto cached_keys = cache.getPublicKeys(); - OUTCOME_TRY(keys, file_storage_->collectPublicKeys(key_type)); - - std::vector res; - res.reserve(keys.size()); - for (auto &key : keys) { - OUTCOME_TRY(pk, suite.toPublicKey(key)); - auto erased = cached_keys.erase(pk); - // if we erased pk from cache, it means it was there and thus was a - // valid cached key, which we can collect to our result - if (erased == 1) { - res.emplace_back(std::move(pk)); - - // otherwise, pk was not found in cache and has to be loaded and - // checked - } else { - // need to check if the read key's algorithm belongs to the given - // CryptoSuite - OUTCOME_TRY(phrase, file_storage_->searchForPhrase(key_type, key)); - BOOST_ASSERT_MSG( - phrase, - "The public key has just been scanned, its file has to exist"); - if (not phrase) { - logger_->error("Error reading key seed from key file storage"); - continue; - } - OUTCOME_TRY(bip, bip39_provider_->generateSeed(*phrase)); - auto kp_res = suite.generateKeypair(bip); - if (not kp_res) { - // cannot create a seed from file content; suppose it belongs to a - // different algorithm - continue; - } - SL_TRACE(logger_, "Loaded key {}", pk.toHex()); - OUTCOME_TRY(kp, kp_res); - auto &&[pub, priv] = suite.decomposeKeypair(std::move(kp)); - if (pub == pk) { - SL_TRACE(logger_, "Key is correct {}", pk.toHex()); - res.emplace_back(std::move(pk)); - } - } - } - std::move( - cached_keys.begin(), cached_keys.end(), std::back_inserter(res)); - return res; - } - - template - outcome::result generateKeypair( - std::string_view mnemonic_phrase, const CryptoSuite &suite) { - OUTCOME_TRY(bip, bip39_provider_->generateSeed(mnemonic_phrase)); - return suite.generateKeypair(bip); - } - - template - outcome::result generateKeypairOnDisk( - KeyType key_type, - const std::shared_ptr &suite, - std::unordered_map> &caches) { - SecureBuffer<> seed_buf(CryptoSuite::Seed::size()); - csprng_->fillRandomly(seed_buf); - OUTCOME_TRY(seed, CryptoSuite::Seed::from(std::move(seed_buf))); - OUTCOME_TRY(kp, suite->generateKeypair(seed, {})); - getCache(suite, caches, key_type).insert(kp.public_key, kp.secret_key); - OUTCOME_TRY(file_storage_->saveKeyPair( - key_type, kp.public_key, seed.unsafeBytes())); - return kp; - } - - template - KeyCache &getCache( - std::shared_ptr suite, - std::unordered_map> &caches, - KeyType type) const { - auto it = caches.find(type); - if (it == caches.end()) { - auto &&[new_it, success] = caches.insert({type, KeyCache{type, suite}}); - BOOST_ASSERT(success); - it = new_it; - } - return it->second; - } - - mutable std::unordered_map> ecdsa_caches_; - mutable std::unordered_map> ed_caches_; - mutable std::unordered_map> sr_caches_; - std::shared_ptr file_storage_; - std::shared_ptr ecdsa_suite_; - std::shared_ptr ed_suite_; - std::shared_ptr sr_suite_; - std::shared_ptr bip39_provider_; - std::shared_ptr csprng_; - log::Logger logger_; - }; - -} // namespace kagome::crypto - -OUTCOME_HPP_DECLARE_ERROR(kagome::crypto, CryptoStoreError); diff --git a/core/crypto/crypto_store/crypto_suites.hpp b/core/crypto/crypto_store/crypto_suites.hpp deleted file mode 100644 index 5e112e0d3b..0000000000 --- a/core/crypto/crypto_store/crypto_suites.hpp +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Copyright Quadrivium LLC - * All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "crypto/ecdsa_provider.hpp" -#include "crypto/ed25519_provider.hpp" -#include "crypto/random_generator.hpp" -#include "crypto/sr25519_provider.hpp" - -namespace kagome::crypto { - - /** - * Combination of several crypto primitives belonging to one algorithm - */ - template - struct CryptoSuite { - using PublicKey = PublicKeyT; - using PrivateKey = PrivateKeyT; - using Keypair = KeypairT; - using KeypairAndSeed = KeypairAndSeedT; - using Seed = SeedT; - using Junctions = std::span; - - virtual ~CryptoSuite() = default; - - /** - * Genereate a keypair from seed and junctions - */ - virtual outcome::result generateKeypair( - const Seed &seed, Junctions junctions) const noexcept = 0; - - /** - * Generate a random keypair from seed and junctions - */ - outcome::result generateKeypair( - const bip39::Bip39SeedAndJunctions &bip) const { - return generateKeypair(Seed::from(bip.seed), bip.junctions); - } - - /** - * Create a keypair from a public key and a private key - * @note Although it is typically just a structure with two fields, from the - * compiler point of view they all are different types, thus this - * convenience method emerges - */ - virtual Keypair composeKeypair(PublicKey pub, - PrivateKey priv) const noexcept = 0; - /** - * Extrace the private key and the public key from a keypair - * @see composeKeypair() - */ - virtual std::pair decomposeKeypair( - Keypair &&kp) const noexcept = 0; - - /** - * Create a public key from its bytes - */ - virtual outcome::result toPublicKey( - common::BufferView bytes) const noexcept = 0; - - /** - * Create a seed from its bytes - */ - virtual outcome::result toSeed( - SecureCleanGuard bytes) const noexcept = 0; - }; - - class EcdsaSuite : public CryptoSuite { - public: - explicit EcdsaSuite(std::shared_ptr ecdsa_provider) - : ecdsa_provider_{std::move(ecdsa_provider)} { - BOOST_ASSERT(ecdsa_provider_ != nullptr); - } - - using CryptoSuite::generateKeypair; - outcome::result generateKeypair( - const EcdsaSeed &seed, Junctions junctions) const noexcept override { - return ecdsa_provider_->generateKeypair(seed, junctions); - } - - EcdsaKeypair composeKeypair(PublicKey pub, - PrivateKey priv) const noexcept override { - return EcdsaKeypair{.secret_key = std::move(priv), - .public_key = std::move(pub)}; - } - - std::pair decomposeKeypair( - EcdsaKeypair &&kp) const noexcept override { - return {kp.public_key, kp.secret_key}; - } - - outcome::result toPublicKey( - common::BufferView bytes) const noexcept override { - OUTCOME_TRY(blob, EcdsaPublicKey::fromSpan(bytes)); - return EcdsaPublicKey{blob}; - } - - outcome::result toSeed( - SecureCleanGuard bytes) const noexcept override { - return EcdsaSeed::from(std::move(bytes)); - } - - private: - std::shared_ptr ecdsa_provider_; - }; - - class Ed25519Suite : public CryptoSuite { - public: - explicit Ed25519Suite(std::shared_ptr ed_provider) - : ed_provider_{std::move(ed_provider)} { - BOOST_ASSERT(ed_provider_ != nullptr); - } - - using CryptoSuite::generateKeypair; - outcome::result generateKeypair( - const Ed25519Seed &seed, Junctions junctions) const noexcept override { - return ed_provider_->generateKeypair(seed, junctions); - } - - Ed25519Keypair composeKeypair(PublicKey pub, - PrivateKey priv) const noexcept override { - return Ed25519Keypair{.secret_key = std::move(priv), - .public_key = std::move(pub)}; - } - - std::pair decomposeKeypair( - Ed25519Keypair &&kp) const noexcept override { - return {kp.public_key, std::move(kp.secret_key)}; - } - - outcome::result toPublicKey( - common::BufferView bytes) const noexcept override { - OUTCOME_TRY(blob, Ed25519PublicKey::fromSpan(bytes)); - return Ed25519PublicKey{blob}; - } - - outcome::result toSeed( - SecureCleanGuard bytes) const noexcept override { - return Ed25519Seed::from(std::move(bytes)); - } - - private: - std::shared_ptr ed_provider_; - }; - - class Sr25519Suite : public CryptoSuite { - public: - explicit Sr25519Suite(std::shared_ptr sr_provider) - : sr_provider_{std::move(sr_provider)} { - BOOST_ASSERT(sr_provider_ != nullptr); - } - - using CryptoSuite::generateKeypair; - outcome::result generateKeypair( - const Sr25519Seed &seed, Junctions junctions) const noexcept override { - return sr_provider_->generateKeypair(seed, junctions); - } - - Sr25519Keypair composeKeypair(PublicKey pub, - PrivateKey priv) const noexcept override { - return Sr25519Keypair{.secret_key = std::move(priv), - .public_key = std::move(pub)}; - } - - std::pair decomposeKeypair( - Sr25519Keypair &&kp) const noexcept override { - return {kp.public_key, kp.secret_key}; - } - - outcome::result toPublicKey( - common::BufferView bytes) const noexcept override { - OUTCOME_TRY(blob, Sr25519PublicKey::fromSpan(bytes)); - return Sr25519PublicKey{std::move(blob)}; - } - - outcome::result toSeed( - SecureCleanGuard bytes) const noexcept override { - return Sr25519Seed::from(std::move(bytes)); - } - - private: - std::shared_ptr sr_provider_; - }; - -} // namespace kagome::crypto diff --git a/core/crypto/crypto_store/key_cache.hpp b/core/crypto/crypto_store/key_cache.hpp deleted file mode 100644 index 6cee976c64..0000000000 --- a/core/crypto/crypto_store/key_cache.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright Quadrivium LLC - * All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include -#include -#include - -#include - -#include "crypto/crypto_store/key_type.hpp" - -namespace kagome::crypto { - - /** - * In-memory cache of keys belonging to the same crypto suite and the same key - * type - * @see crypto_suites.hpp - * @see key_type.hpp - */ - template - class KeyCache { - public: - using PublicKey = typename CryptoSuite::PublicKey; - using PrivateKey = typename CryptoSuite::PrivateKey; - using Keypair = typename CryptoSuite::Keypair; - using Seed = typename CryptoSuite::Seed; - - explicit KeyCache(KeyType type, std::shared_ptr suite) - : type_{type}, suite_{std::move(suite)} { - BOOST_ASSERT(suite_ != nullptr); - } - - void insert(PublicKey pubkey, PrivateKey privkey) { - // this should be refactored in the future, the session key should be - // determined by either node's config or node's internal logic - if (not session_key_) { - session_key_ = suite_->composeKeypair(pubkey, privkey); - } - cache_.emplace(std::move(pubkey), std::move(privkey)); - } - - /** - * Session keys are short-living keys used by the node - */ - const std::optional &getSessionKey() const noexcept { - return session_key_; - } - - std::unordered_set getPublicKeys() const { - std::unordered_set keys; - for (auto &&[k, v] : cache_) { - keys.emplace(k); - } - return keys; - } - - std::optional searchKeypair(const PublicKey &key) const { - auto it = cache_.find(key); - if (it != cache_.end()) { - return suite_->composeKeypair(it->first, it->second); - } - return std::nullopt; - } - - private: - KeyType type_; - std::optional session_key_; - std::unordered_map cache_; - std::shared_ptr suite_; - }; -} // namespace kagome::crypto diff --git a/core/crypto/ecdsa_provider.hpp b/core/crypto/ecdsa_provider.hpp index f2f3d097c7..48f05ead40 100644 --- a/core/crypto/ecdsa_provider.hpp +++ b/core/crypto/ecdsa_provider.hpp @@ -13,6 +13,11 @@ namespace kagome::crypto { class EcdsaProvider { public: + using Keypair = EcdsaKeypair; + using PublicKey = EcdsaPublicKey; + using PrivateKey = EcdsaPrivateKey; + using Seed = EcdsaSeed; + using Junctions = std::span; virtual ~EcdsaProvider() = default; diff --git a/core/crypto/ed25519_provider.hpp b/core/crypto/ed25519_provider.hpp index 021234a76d..69190c3048 100644 --- a/core/crypto/ed25519_provider.hpp +++ b/core/crypto/ed25519_provider.hpp @@ -13,6 +13,11 @@ namespace kagome::crypto { class Ed25519Provider { public: + using Keypair = Ed25519Keypair; + using PublicKey = Ed25519PublicKey; + using PrivateKey = Ed25519PrivateKey; + using Seed = Ed25519Seed; + using Junctions = std::span; virtual ~Ed25519Provider() = default; diff --git a/core/crypto/ed25519_types.hpp b/core/crypto/ed25519_types.hpp index 4f8cc4e4db..8052c60ddf 100644 --- a/core/crypto/ed25519_types.hpp +++ b/core/crypto/ed25519_types.hpp @@ -66,4 +66,5 @@ namespace kagome::crypto { struct Ed25519KeypairAndSeed : Ed25519Keypair { Ed25519Seed seed; }; + } // namespace kagome::crypto diff --git a/core/crypto/key_store.hpp b/core/crypto/key_store.hpp new file mode 100644 index 0000000000..724b6cd9aa --- /dev/null +++ b/core/crypto/key_store.hpp @@ -0,0 +1,165 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include + +#include + +#include "application/app_state_manager.hpp" +#include "common/bytestr.hpp" +#include "common/optref.hpp" +#include "crypto/bip39/bip39_provider.hpp" +#include "crypto/common.hpp" +#include "crypto/ecdsa_provider.hpp" +#include "crypto/ed25519_provider.hpp" +#include "crypto/ed25519_types.hpp" +#include "crypto/key_store/key_type.hpp" +#include "crypto/sr25519_provider.hpp" +#include "filesystem/common.hpp" +#include "log/logger.hpp" +#include "utils/json_unquote.hpp" +#include "utils/read_file.hpp" + +namespace kagome::crypto { + + enum class KeyStoreError { + UNSUPPORTED_KEY_TYPE = 1, + UNSUPPORTED_CRYPTO_TYPE, + WRONG_SEED_SIZE, + KEY_NOT_FOUND, + BABE_ALREADY_EXIST, + GRAN_ALREADY_EXIST, + AUDI_ALREADY_EXIST, + WRONG_PUBLIC_KEY, + FAILED_TO_OPEN_FILE, + INVALID_FILE_FORMAT, + }; +} + +OUTCOME_HPP_DECLARE_ERROR(kagome::crypto, KeyStoreError); + +namespace kagome::crypto { + template + concept Suite = requires() { + typename T::Keypair; + typename T::PrivateKey; + typename T::PublicKey; + typename T::Seed; + }; + + template + class KeySuiteStore { + public: + using Keypair = typename T::Keypair; + using PrivateKey = typename T::PrivateKey; + using PublicKey = typename T::PublicKey; + using Seed = typename T::Seed; + + virtual ~KeySuiteStore() = default; + + /** + * @brief generates a keypair and stores it in memory + * @param key_type key type identifier + * @param mnemonic_phrase mnemonic phrase + * @return generated key pair or error + */ + virtual outcome::result generateKeypair( + KeyType key_type, std::string_view mnemonic_phrase) = 0; + + /** + * @brief generates a keypair and stores it in memory + * @param key_type key type identifier + * @param seed seed for generating keys + * @return generated key pair + */ + virtual outcome::result generateKeypair(KeyType key_type, + const Seed &seed) = 0; + + /** + * @brief generates a keypair and stores it on disk + * @param key_type key type identifier + * @return generated key pair or error + */ + virtual outcome::result generateKeypairOnDisk( + KeyType key_type) = 0; + + /** + * @brief searches for key pair + * @param key_type key category + * @param pk public key to look for + * @return found key pair if exists + */ + virtual OptRef findKeypair(KeyType key_type, + const PublicKey &pk) const = 0; + + /** + * @brief searches for public keys of specified type + * @param key_type key type identifier to look for + * @return vector of found public keys + */ + virtual outcome::result> getPublicKeys( + KeyType key_type) const = 0; + }; + + libp2p::crypto::KeyPair ed25519KeyToLibp2pKeypair(const Ed25519Keypair &kp); + ; + + class KeyStore { + public: + struct Config { + explicit Config(std::filesystem::path key_store_dir) + : key_store_dir{std::move(key_store_dir)} {} + + std::filesystem::path key_store_dir; + }; + + KeyStore(std::unique_ptr> sr25519, + std::unique_ptr> ed25519, + std::unique_ptr> ecdsa, + std::shared_ptr ed25519_provider, + std::shared_ptr app_manager, + Config config); + + bool prepare(); + + KeySuiteStore &sr25519() { + return *sr25519_; + } + + KeySuiteStore &ed25519() { + return *ed25519_; + } + + KeySuiteStore &ecdsa() { + return *ecdsa_; + } + + outcome::result loadLibp2pKeypair( + const std::filesystem::path &file_path) const; + + private: + using SecureString = std:: + basic_string, SecureHeapAllocator>; + + outcome::result readSeed( + const std::filesystem::path &file_path) const; + + outcome::result scanKeyDirectory(const std::filesystem::path &dir); + + Config config_; + std::unique_ptr> sr25519_; + std::unique_ptr> ed25519_; + std::unique_ptr> ecdsa_; + std::shared_ptr ed25519_provider_; + std::shared_ptr app_manager_; + log::Logger logger_; + }; + +} // namespace kagome::crypto diff --git a/core/crypto/key_store/CMakeLists.txt b/core/crypto/key_store/CMakeLists.txt new file mode 100644 index 0000000000..cfed64dd95 --- /dev/null +++ b/core/crypto/key_store/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# Copyright Quadrivium LLC +# All Rights Reserved +# SPDX-License-Identifier: Apache-2.0 +# + +add_library(key_store + key_store_impl.cpp + session_keys.cpp + key_type.cpp + key_file_storage.cpp + ) + +target_link_libraries(key_store + ecdsa_provider + ed25519_provider + sr25519_provider + p2p::p2p_random_generator # generator from libp2p + bip39_provider + ) +kagome_install(key_store) diff --git a/core/crypto/crypto_store/key_file_storage.cpp b/core/crypto/key_store/key_file_storage.cpp similarity index 79% rename from core/crypto/crypto_store/key_file_storage.cpp rename to core/crypto/key_store/key_file_storage.cpp index 97958c830d..23252e166a 100644 --- a/core/crypto/crypto_store/key_file_storage.cpp +++ b/core/crypto/key_store/key_file_storage.cpp @@ -4,12 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "crypto/crypto_store/key_file_storage.hpp" +#include "crypto/key_store/key_file_storage.hpp" #include #include "common/hexutil.hpp" -#include "crypto/crypto_store/key_type.hpp" +#include "crypto/key_store/key_type.hpp" #include "filesystem/common.hpp" #include "utils/json_unquote.hpp" #include "utils/read_file.hpp" @@ -50,7 +50,7 @@ namespace kagome::crypto { KeyFileStorage::KeyFileStorage(Path keystore_path) : keystore_path_{std::move(keystore_path)}, - logger_{log::createLogger("KeyFileStorage", "crypto_store")} {} + logger_{log::createLogger("KeyFileStorage", "key_store")} {} outcome::result> KeyFileStorage::parseKeyFileName( std::string_view file_name) const { @@ -122,57 +122,26 @@ namespace kagome::crypto { return outcome::success(); } - outcome::result> KeyFileStorage::collectPublicKeys( - KeyType type) const { - namespace fs = filesystem; - - std::error_code ec{}; - - std::vector keys; - - fs::directory_iterator it{keystore_path_, ec}, end{}; - if (ec) { - logger_->error("Error scanning keystore: {}", ec); - return Error::FAILED_OPEN_FILE; - } - for (; it != end; ++it) { - if (!fs::is_regular_file(*it)) { - continue; - } - auto info = parseKeyFileName(it->path().filename().string()); - if (!info) { - continue; - } - auto &[id, pk] = info.value(); - - if (id == type) { - keys.push_back(pk); - } - } - return keys; - } - - outcome::result> KeyFileStorage::searchForPhrase( + outcome::result KeyFileStorage::searchForKey( KeyType type, common::BufferView public_key_bytes) const { auto key_path = composeKeyPath(type, public_key_bytes); - namespace fs = filesystem; std::error_code ec{}; - if (not fs::exists(key_path, ec)) { - return std::nullopt; + if (not filesystem::exists(key_path, ec)) { + return false; } std::string content; if (not readFile(content, key_path.string())) { - return std::nullopt; + return false; } if (not content.empty() and content[0] == '"') { if (auto str = jsonUnquote(content)) { - return str; + return true; } return Error::INVALID_FILE_FORMAT; } OUTCOME_TRY(common::unhexWith0x(content)); - return content; + return true; } } // namespace kagome::crypto diff --git a/core/crypto/crypto_store/key_file_storage.hpp b/core/crypto/key_store/key_file_storage.hpp similarity index 87% rename from core/crypto/crypto_store/key_file_storage.hpp rename to core/crypto/key_store/key_file_storage.hpp index a787bfef40..581b4f5362 100644 --- a/core/crypto/crypto_store/key_file_storage.hpp +++ b/core/crypto/key_store/key_file_storage.hpp @@ -11,7 +11,8 @@ #include #include "common/buffer.hpp" -#include "crypto/crypto_store/key_type.hpp" +#include "crypto/common.hpp" +#include "crypto/key_store/key_type.hpp" #include "filesystem/common.hpp" #include "log/logger.hpp" @@ -45,17 +46,12 @@ namespace kagome::crypto { static outcome::result> createAt( Path keystore_path); - /** - * Collects all public keys of the given type from the key storage - */ - outcome::result> collectPublicKeys(KeyType type) const; - /** * Searches for a key file for the corresponding type and public key and * returns its content if it's a valid hex blob or mnemonic phrase json. */ - outcome::result> searchForPhrase( - KeyType type, common::BufferView public_key_bytes) const; + outcome::result searchForKey(KeyType type, + common::BufferView public_key) const; /** * Stores the \param seed that generates the \param public_key to the key diff --git a/core/crypto/key_store/key_store_impl.cpp b/core/crypto/key_store/key_store_impl.cpp new file mode 100644 index 0000000000..6f881806f8 --- /dev/null +++ b/core/crypto/key_store/key_store_impl.cpp @@ -0,0 +1,158 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "crypto/key_store/key_store_impl.hpp" + +#include + +#include "common/bytestr.hpp" +#include "common/visitor.hpp" +#include "crypto/key_store.hpp" +#include "utils/read_file.hpp" + +OUTCOME_CPP_DEFINE_CATEGORY(kagome::crypto, KeyStoreError, e) { + switch (e) { + using enum kagome::crypto::KeyStoreError; + case UNSUPPORTED_KEY_TYPE: + return "Key type is not supported"; + case UNSUPPORTED_CRYPTO_TYPE: + return "Cryptographic type is not supported"; + case WRONG_SEED_SIZE: + return "Wrong seed size"; + case KEY_NOT_FOUND: + return "Key not found"; + case BABE_ALREADY_EXIST: + return "BABE key already exists"; + case GRAN_ALREADY_EXIST: + return "GRAN key already exists"; + case AUDI_ALREADY_EXIST: + return "AUDI key already exists"; + case WRONG_PUBLIC_KEY: + return "Public key doesn't match seed"; + case FAILED_TO_OPEN_FILE: + return "Failed to open the key file"; + case INVALID_FILE_FORMAT: + return "The key file is not valid (should be a BIP39 phrase or a hex-encoded seed)"; + } + return "Unknown KeyStoreError code"; +} + +namespace kagome::crypto { + + libp2p::crypto::KeyPair ed25519KeyToLibp2pKeypair(const Ed25519Keypair &kp) { + const auto &secret_key = kp.secret_key; + const auto &public_key = kp.public_key; + libp2p::crypto::PublicKey lp2p_public{ + {libp2p::crypto::Key::Type::Ed25519, + std::vector{public_key.cbegin(), public_key.cend()}}}; + libp2p::crypto::PrivateKey lp2p_private{ + {libp2p::crypto::Key::Type::Ed25519, + std::vector{secret_key.unsafeBytes().begin(), + secret_key.unsafeBytes().end()}}}; + return libp2p::crypto::KeyPair{ + .publicKey = lp2p_public, + .privateKey = lp2p_private, + }; + } + + KeyStore::KeyStore(std::unique_ptr> sr25519, + std::unique_ptr> ed25519, + std::unique_ptr> ecdsa, + std::shared_ptr ed25519_provider, + std::shared_ptr app_manager, + Config config) + : config_{std::move(config)}, + sr25519_{std::move(sr25519)}, + ed25519_{std::move(ed25519)}, + ecdsa_{std::move(ecdsa)}, + ed25519_provider_{std::move(ed25519_provider)}, + app_manager_{std::move(app_manager)}, + logger_{log::createLogger("KeyStore", "crypto")} { + BOOST_ASSERT(sr25519_); + BOOST_ASSERT(ed25519_); + BOOST_ASSERT(ecdsa_); + BOOST_ASSERT(ed25519_provider_); + BOOST_ASSERT(app_manager_); + app_manager_->takeControl(*this); + } + + bool KeyStore::prepare() { + if (auto res = scanKeyDirectory(config_.key_store_dir); !res) { + SL_ERROR( + logger_, "Failed to fetch keys from filesystem: {}", res.error()); + return false; + } + return true; + } + + outcome::result KeyStore::loadLibp2pKeypair( + const std::filesystem::path &file_path) const { + SecureString content; + if (!readFile(content, file_path)) { + return KeyStoreError::KEY_NOT_FOUND; + } + Ed25519Seed seed; + if (ED25519_SEED_LENGTH == content.size()) { + OUTCOME_TRY(_seed, + Ed25519Seed::from( + SecureCleanGuard(str2byte(std::span(content))))); + seed = _seed; + } else if (2 * ED25519_SEED_LENGTH == content.size()) { // hex-encoded + OUTCOME_TRY(_seed, Ed25519Seed::fromHex(SecureCleanGuard(content))); + seed = _seed; + } else { + return KeyStoreError::UNSUPPORTED_CRYPTO_TYPE; + } + OUTCOME_TRY(kp, ed25519_provider_->generateKeypair(seed, {})); + return ed25519KeyToLibp2pKeypair(kp); + } + + outcome::result KeyStore::readSeed( + const std::filesystem::path &file_path) const { + SecureString content; + if (!readFile(content, file_path)) { + return KeyStoreError::FAILED_TO_OPEN_FILE; + } + if (not content.empty() and content[0] == '"') { + if (auto str = jsonUnquote(content)) { + content = std::move(*str); + } else { + return KeyStoreError::INVALID_FILE_FORMAT; + } + } else { + // check it's a valid hex string + OUTCOME_TRY(common::unhexWith0x(content)); + } + return content; + } + + outcome::result KeyStore::scanKeyDirectory( + const std::filesystem::path &dir) { + // scan directory and collect every type-public key-seed triplet + // for every key type + // for every allowed algorithm for this key type + // try to make a public key from the seed, if it matches the original + // key, add this keypair to the store + std::error_code ec{}; + std::filesystem::directory_iterator iter{dir, ec}; + if (ec) { + return ec; + } + for (auto &file : iter) { + if (file.is_regular_file()) { + OUTCOME_TRY(content, readSeed(file.path())); + OUTCOME_TRY(decoded_parts, + decodeKeyFileName(file.path().filename().string())); + auto [key_type, public_key] = std::move(decoded_parts); + + std::ignore = sr25519_->generateKeypair(key_type, content); + std::ignore = ed25519_->generateKeypair(key_type, content); + std::ignore = ecdsa_->generateKeypair(key_type, content); + } + } + return outcome::success(); + } +} // namespace kagome::crypto diff --git a/core/crypto/key_store/key_store_impl.hpp b/core/crypto/key_store/key_store_impl.hpp new file mode 100644 index 0000000000..55d20410ed --- /dev/null +++ b/core/crypto/key_store/key_store_impl.hpp @@ -0,0 +1,116 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#include "common/blob.hpp" +#include "common/optref.hpp" +#include "crypto/bip39/bip39_provider.hpp" +#include "crypto/bip39/mnemonic.hpp" +#include "crypto/key_store.hpp" +#include "crypto/key_store/key_file_storage.hpp" +#include "crypto/random_generator.hpp" +#include "filesystem/common.hpp" +#include "log/logger.hpp" +#include "outcome/outcome.hpp" +#include "utils/read_file.hpp" + +namespace kagome::crypto { + + /// TODO(Harrm) Add policies to emit a warning when found a keypair + /// with incompatible type and algorithm (e. g. ed25519 BABE keypair, + /// whereas BABE has to be sr25519 only) or when trying to generate more + /// keypair than there should be (e. g. more than one libp2p keypair is a + /// suspicious behaviour) + template + class KeySuiteStoreImpl final : public KeySuiteStore { + public: + using Keypair = typename T::Keypair; + using PrivateKey = typename T::PrivateKey; + using PublicKey = typename T::PublicKey; + using Seed = typename T::Seed; + + KeySuiteStoreImpl(std::shared_ptr suite, + std::shared_ptr bip39_provider, + std::shared_ptr csprng, + std::shared_ptr key_fs) + : suite_{std::move(suite)}, + file_storage_{std::move(key_fs)}, + bip39_provider_{std::move(bip39_provider)}, + csprng_{std::move(csprng)}, + logger_{log::createLogger("KeyStore", "key_store")} { + BOOST_ASSERT(suite_ != nullptr); + BOOST_ASSERT(bip39_provider_ != nullptr); + BOOST_ASSERT(file_storage_ != nullptr); + BOOST_ASSERT(csprng_ != nullptr); + } + + outcome::result generateKeypair( + KeyType key_type, std::string_view mnemonic_phrase) override { + OUTCOME_TRY(bip, bip39_provider_->generateSeed(mnemonic_phrase)); + auto seed = Seed::from(bip.seed); + OUTCOME_TRY(kp, suite_->generateKeypair(seed, bip.junctions)); + keys_[key_type].insert(std::pair{kp.public_key, kp}); + return kp; + } + + outcome::result generateKeypair(KeyType key_type, + const Seed &seed) override { + OUTCOME_TRY(kp, suite_->generateKeypair(seed, {})); + keys_[key_type].insert(std::pair{kp.public_key, kp}); + return kp; + } + + outcome::result generateKeypairOnDisk(KeyType key_type) override { + SecureBuffer<> seed_buf(Seed::size()); + csprng_->fillRandomly(seed_buf); + OUTCOME_TRY(seed, Seed::from(std::move(seed_buf))); + OUTCOME_TRY(kp, suite_->generateKeypair(seed, {})); + keys_[key_type].insert(std::pair{kp.public_key, kp}); + OUTCOME_TRY(file_storage_->saveKeyPair( + key_type, kp.public_key, seed.unsafeBytes())); + return kp; + } + + OptRef findKeypair(KeyType key_type, + const PublicKey &pk) const override { + auto keys_it = keys_.find(key_type); + if (keys_it == keys_.end()) { + return std::nullopt; + } + if (auto it = keys_it->second.find(pk); it != keys_it->second.end()) { + return it->second; + } + return std::nullopt; + } + + outcome::result> getPublicKeys( + KeyType key_type) const override { + auto keys_it = keys_.find(key_type); + if (keys_it == keys_.end()) { + return std::vector{}; + } + auto &keys = keys_it->second; + std::vector res; + res.reserve(keys.size()); + for (auto &[public_key, private_key] : keys) { + res.push_back(public_key); + } + return res; + } + + private: + std::shared_ptr suite_; + std::shared_ptr file_storage_; + std::shared_ptr bip39_provider_; + std::shared_ptr csprng_; + std::unordered_map> keys_; + log::Logger logger_; + }; + +} // namespace kagome::crypto diff --git a/core/crypto/crypto_store/key_type.cpp b/core/crypto/key_store/key_type.cpp similarity index 53% rename from core/crypto/crypto_store/key_type.cpp rename to core/crypto/key_store/key_type.cpp index d31cfd1cc1..5f37610ec1 100644 --- a/core/crypto/crypto_store/key_type.cpp +++ b/core/crypto/key_store/key_type.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "crypto/crypto_store/key_type.hpp" +#include "crypto/key_store/key_type.hpp" #include @@ -17,30 +17,8 @@ namespace kagome::crypto { return KeyTypes::is_supported(*this); } - std::string encodeKeyTypeToStr(const KeyType &key_type) { - const auto *p = reinterpret_cast(&key_type); - return {p, p + sizeof(uint32_t)}; - } - - KeyType decodeKeyTypeFromStr(std::string_view str) { - uint32_t res = 0; - - if (str.size() == sizeof(uint32_t)) { - // string's data is aligned as KeyType - if (reinterpret_cast(str.data()) - % std::alignment_of_v - == 0) { - res = *reinterpret_cast(str.data()); - } else { - memcpy(&res, str.data(), sizeof(uint32_t)); - } - } - - return res; - } - std::string encodeKeyFileName(const KeyType &type, common::BufferView key) { - return common::hex_lower(str2byte(encodeKeyTypeToStr(type))) + key.toHex(); + return common::hex_lower(str2byte(type.toString())) + key.toHex(); } outcome::result> decodeKeyFileName( @@ -53,8 +31,10 @@ namespace kagome::crypto { } OUTCOME_TRY(type_raw, common::Blob<4>::fromHex(type_str)); OUTCOME_TRY(key, common::Buffer::fromHex(key_str)); - return std::make_pair(decodeKeyTypeFromStr(byte2str(type_raw)), - std::move(key)); + if (auto key_type = KeyType::fromString(byte2str(type_raw))) { + return std::make_pair(*key_type, std::move(key)); + } + return KeyTypeError::UNSUPPORTED_KEY_TYPE; } } // namespace kagome::crypto @@ -63,8 +43,6 @@ OUTCOME_CPP_DEFINE_CATEGORY(kagome::crypto, KeyTypeError, e) { switch (e) { case Error::UNSUPPORTED_KEY_TYPE: return "key type is not supported"; - case Error::UNSUPPORTED_KEY_TYPE_ID: - return "key type id is not supported"; } return "Unknown KeyTypeError"; } diff --git a/core/crypto/crypto_store/key_type.hpp b/core/crypto/key_store/key_type.hpp similarity index 86% rename from core/crypto/crypto_store/key_type.hpp rename to core/crypto/key_store/key_type.hpp index 8bc433830f..a583c773b7 100644 --- a/core/crypto/crypto_store/key_type.hpp +++ b/core/crypto/key_store/key_type.hpp @@ -14,24 +14,22 @@ namespace kagome::crypto { enum class KeyTypeError { UNSUPPORTED_KEY_TYPE = 1, - UNSUPPORTED_KEY_TYPE_ID, }; - /** - * Makes 32bit integer which represent encoded 4-char strings - * Little-endian byte order is used - */ - constexpr uint32_t operator""_key(const char *s, std::size_t size) { - return (static_cast(s[0]) << (CHAR_BIT * 0)) - | (static_cast(s[1]) << (CHAR_BIT * 1)) - | (static_cast(s[2]) << (CHAR_BIT * 2)) - | (static_cast(s[3]) << (CHAR_BIT * 3)); - } - struct KeyType { KeyType() = default; constexpr KeyType(uint32_t id) : id_(id){}; + static constexpr std::optional fromString(std::string_view s) { + if (s.size() != 4) { + return std::nullopt; + } + return KeyType((static_cast(s[0]) << (CHAR_BIT * 0)) + | (static_cast(s[1]) << (CHAR_BIT * 1)) + | (static_cast(s[2]) << (CHAR_BIT * 2)) + | (static_cast(s[3]) << (CHAR_BIT * 3))); + } + constexpr operator uint32_t() const { return id_; } @@ -50,10 +48,22 @@ namespace kagome::crypto { return s >> v.id_; } + std::string toString() const { + return {reinterpret_cast(&id_), 4}; + } + private: uint32_t id_{0}; }; + /** + * Makes 32bit integer which represent encoded 4-char strings + * Little-endian byte order is used + */ + consteval uint32_t operator""_key(const char *s, size_t len) { + return *KeyType::fromString(s); + } + struct KeyTypes { /// Key type for Babe module, built-in. static constexpr KeyType BABE = "babe"_key; @@ -105,20 +115,6 @@ namespace kagome::crypto { } }; - /** - * @brief makes string representation of KeyType - * @param key_type KeyType - * @return string representation of KeyType - */ - std::string encodeKeyTypeToStr(const KeyType &key_type); - - /** - * @brief restores KeyType from its string representation - * @param param string representation of key type - * @return KeyType - */ - KeyType decodeKeyTypeFromStr(std::string_view str); - std::string encodeKeyFileName(const KeyType &type, common::BufferView key); outcome::result> decodeKeyFileName( diff --git a/core/crypto/crypto_store/session_keys.cpp b/core/crypto/key_store/session_keys.cpp similarity index 60% rename from core/crypto/crypto_store/session_keys.cpp rename to core/crypto/key_store/session_keys.cpp index 3d868ae868..971ad7c008 100644 --- a/core/crypto/crypto_store/session_keys.cpp +++ b/core/crypto/key_store/session_keys.cpp @@ -4,20 +4,18 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "crypto/crypto_store/session_keys.hpp" +#include "crypto/key_store/session_keys.hpp" #include "application/app_configuration.hpp" -#include "crypto/crypto_store.hpp" +#include "crypto/ed25519_provider.hpp" +#include "crypto/key_store.hpp" namespace kagome::crypto { - template list_public, - SessionKeysImpl::FnGetPrivate get_private, - typename A, - typename Eq> - SessionKeys::KeypairWithIndexOpt SessionKeysImpl::find( - KeypairWithIndexOpt &cache, + template + SessionKeys::KeypairWithIndexOpt SessionKeysImpl::find( + KeypairWithIndexOpt &cache, KeyType type, + const KeySuiteStore &store, const std::vector &authorities, const Eq &eq) { if (not roles_.flags.authority) { @@ -37,57 +35,57 @@ namespace kagome::crypto { return cache; } } - auto keys_res = ((*store_).*list_public)(type); + auto keys_res = store.getPublicKeys(type); if (not keys_res) { return std::nullopt; } auto &keys = keys_res.value(); - for (auto &key : keys) { + for (auto &pubkey : keys) { auto it = std::find_if( authorities.begin(), authorities.end(), [&](const A &authority) { - return eq(key, authority); + return eq(pubkey, authority); }); if (it == authorities.end()) { continue; } - auto keypair_res = ((*store_).*get_private)(type, key); - if (not keypair_res) { + auto keypair_opt = store.findKeypair(type, pubkey); + if (not keypair_opt) { continue; } - auto &keypair = keypair_res.value(); - cache.emplace(std::make_shared(keypair), it - authorities.begin()); + cache.emplace( + std::make_shared(std::move(keypair_opt.value())), + it - authorities.begin()); return cache; } return std::nullopt; } - SessionKeysImpl::SessionKeysImpl(std::shared_ptr store, + SessionKeysImpl::SessionKeysImpl(std::shared_ptr store, const application::AppConfiguration &config) - : roles_(config.roles()), store_(store) { + : roles_(config.roles()), store_(std::move(store)) { if (auto dev = config.devMnemonicPhrase()) { // Ed25519 - store_->generateEd25519Keypair(KeyTypes::GRANDPA, *dev).value(); + store_->ed25519().generateKeypair(KeyTypes::GRANDPA, *dev).value(); // Sr25519 for (auto key_type : {KeyTypes::BABE, KeyTypes::IM_ONLINE, KeyTypes::AUTHORITY_DISCOVERY, KeyTypes::ASSIGNMENT, KeyTypes::PARACHAIN}) { - store_->generateSr25519Keypair(key_type, *dev).value(); + store_->sr25519().generateKeypair(key_type, *dev).value(); } // Ecdsa - store_->generateEcdsaKeypair(KeyTypes::BEEFY, *dev).value(); + store_->ecdsa().generateKeypair(KeyTypes::BEEFY, *dev).value(); } } SessionKeys::KeypairWithIndexOpt SessionKeysImpl::getBabeKeyPair( const consensus::babe::Authorities &authorities) { - return find( + return find( babe_key_pair_, KeyTypes::BABE, + store_->sr25519(), authorities, [](const Sr25519PublicKey &l, const consensus::babe::Authority &r) { return l == r.id; @@ -98,8 +96,8 @@ namespace kagome::crypto { // SessionKeysImpl::getSassafrasKeyPair( // const consensus::sassafras::Authorities &authorities) { // return find( + // &KeyStore::getBandersnatchPublicKeys, + // &KeyStore::findBandersnatchKeypair>( // sass_key_pair_, // KeyTypes::SASSAFRAS, // authorities, @@ -111,11 +109,10 @@ namespace kagome::crypto { std::shared_ptr SessionKeysImpl::getGranKeyPair( const consensus::grandpa::AuthoritySet &authorities) { - if (auto res = find( + if (auto res = find( gran_key_pair_, KeyTypes::GRANDPA, + store_->ed25519(), authorities.authorities, [](const Ed25519PublicKey &l, const consensus::grandpa::Authority &r) { return l == r.id; })) { @@ -127,21 +124,20 @@ namespace kagome::crypto { SessionKeys::KeypairWithIndexOpt SessionKeysImpl::getParaKeyPair( const std::vector &authorities) { - return find( - para_key_pair_, KeyTypes::PARACHAIN, authorities, std::equal_to{}); + return find(para_key_pair_, + KeyTypes::PARACHAIN, + store_->sr25519(), + authorities, + std::equal_to{}); } std::shared_ptr SessionKeysImpl::getAudiKeyPair( const std::vector &authorities) { - if (auto res = find( - audi_key_pair_, - KeyTypes::AUTHORITY_DISCOVERY, - authorities, - std::equal_to{})) { + if (auto res = find(audi_key_pair_, + KeyTypes::AUTHORITY_DISCOVERY, + store_->sr25519(), + authorities, + std::equal_to{})) { return std::move(res->first); } return nullptr; @@ -150,9 +146,10 @@ namespace kagome::crypto { SessionKeys::KeypairWithIndexOpt SessionKeysImpl::getBeefKeyPair( const std::vector &authorities) { - return find( - beef_key_pair_, KeyTypes::BEEFY, authorities, std::equal_to{}); + return find(beef_key_pair_, + KeyTypes::BEEFY, + store_->ecdsa(), + authorities, + std::equal_to{}); } } // namespace kagome::crypto diff --git a/core/crypto/crypto_store/session_keys.hpp b/core/crypto/key_store/session_keys.hpp similarity index 82% rename from core/crypto/crypto_store/session_keys.hpp rename to core/crypto/key_store/session_keys.hpp index b221c01625..8ea4917a2e 100644 --- a/core/crypto/crypto_store/session_keys.hpp +++ b/core/crypto/key_store/session_keys.hpp @@ -10,8 +10,9 @@ #include "consensus/babe/types/authority.hpp" // #include "consensus/sassafras/types/authority.hpp" #include "consensus/grandpa/types/authority.hpp" -#include "crypto/crypto_store/key_type.hpp" #include "crypto/ecdsa_types.hpp" +#include "crypto/key_store.hpp" +#include "crypto/key_store/key_type.hpp" #include "network/types/roles.hpp" #include "primitives/authority_discovery_id.hpp" @@ -21,7 +22,7 @@ namespace kagome::application { namespace kagome::crypto { - class CryptoStore; + class KeyStore; struct Ed25519Keypair; struct Sr25519Keypair; struct Sr25519PublicKey; @@ -91,26 +92,28 @@ namespace kagome::crypto { KeypairWithIndexOpt audi_key_pair_; KeypairWithIndexOpt beef_key_pair_; network::Roles roles_; - std::shared_ptr store_; - - template - using FnListPublic = outcome::result> ( - CryptoStore::*)(KeyType) const; - template - using FnGetPrivate = outcome::result (CryptoStore::*)( - KeyType, const decltype(T::public_key) &) const; - template list_public, - FnGetPrivate get_private, + std::shared_ptr store_; + + template + using FnListPublic = outcome::result> ( + KeySuiteStore::*)(KeyType) const; + + template + using FnGetKeypair = outcome::result ( + KeySuiteStore::*)(KeyType, const typename T::PublicKey &) const; + + template - KeypairWithIndexOpt find(KeypairWithIndexOpt &cache, - KeyType type, - const std::vector &authorities, - const Eq &eq); + KeypairWithIndexOpt find( + KeypairWithIndexOpt &cache, + KeyType type, + const KeySuiteStore &store, + const std::vector &authorities, + const Eq &eq); public: - SessionKeysImpl(std::shared_ptr store, + SessionKeysImpl(std::shared_ptr store, const application::AppConfiguration &config); KeypairWithIndexOpt getBabeKeyPair( diff --git a/core/crypto/sr25519/sr25519_provider_impl.cpp b/core/crypto/sr25519/sr25519_provider_impl.cpp index 73c1e5345d..64137b9fce 100644 --- a/core/crypto/sr25519/sr25519_provider_impl.cpp +++ b/core/crypto/sr25519/sr25519_provider_impl.cpp @@ -9,7 +9,7 @@ #include "crypto/sr25519_types.hpp" namespace kagome::crypto { - Sr25519Keypair Sr25519ProviderImpl::generateKeypair( + outcome::result Sr25519ProviderImpl::generateKeypair( const Sr25519Seed &seed, Junctions junctions) const { std::array kp{}; sr25519_keypair_from_seed(kp.data(), seed.unsafeBytes().data()); diff --git a/core/crypto/sr25519/sr25519_provider_impl.hpp b/core/crypto/sr25519/sr25519_provider_impl.hpp index 2f5f5161bf..785f308e9f 100644 --- a/core/crypto/sr25519/sr25519_provider_impl.hpp +++ b/core/crypto/sr25519/sr25519_provider_impl.hpp @@ -12,8 +12,8 @@ namespace kagome::crypto { class Sr25519ProviderImpl : public Sr25519Provider { public: - Sr25519Keypair generateKeypair(const Sr25519Seed &seed, - Junctions junctions) const override; + outcome::result generateKeypair( + const Sr25519Seed &seed, Junctions junctions) const override; outcome::result sign( const Sr25519Keypair &keypair, diff --git a/core/crypto/sr25519_provider.hpp b/core/crypto/sr25519_provider.hpp index 5d7cb049e5..26f98b2353 100644 --- a/core/crypto/sr25519_provider.hpp +++ b/core/crypto/sr25519_provider.hpp @@ -23,6 +23,11 @@ namespace kagome::crypto { class Sr25519Provider { public: + using Keypair = Sr25519Keypair; + using PublicKey = Sr25519PublicKey; + using PrivateKey = Sr25519SecretKey; + using Seed = Sr25519Seed; + using Junctions = std::span; virtual ~Sr25519Provider() = default; @@ -30,8 +35,8 @@ namespace kagome::crypto { /** * Generate random keypair from seed */ - virtual Sr25519Keypair generateKeypair(const Sr25519Seed &seed, - Junctions junctions) const = 0; + virtual outcome::result generateKeypair( + const Sr25519Seed &seed, Junctions junctions) const = 0; /** * Sign message \param msg using \param keypair. If computed value is less diff --git a/core/dispute_coordinator/impl/dispute_coordinator_impl.hpp b/core/dispute_coordinator/impl/dispute_coordinator_impl.hpp index c26e088d2b..4714f9db8a 100644 --- a/core/dispute_coordinator/impl/dispute_coordinator_impl.hpp +++ b/core/dispute_coordinator/impl/dispute_coordinator_impl.hpp @@ -14,7 +14,7 @@ #include #include "clock/impl/basic_waitable_timer.hpp" -#include "crypto/crypto_store/session_keys.hpp" +#include "crypto/key_store/session_keys.hpp" #include "crypto/sr25519_provider.hpp" #include "dispute_coordinator/chain_scraper.hpp" #include "dispute_coordinator/impl/batches.hpp" diff --git a/core/dispute_coordinator/impl/runtime_info.cpp b/core/dispute_coordinator/impl/runtime_info.cpp index 985095d00e..315e6348ea 100644 --- a/core/dispute_coordinator/impl/runtime_info.cpp +++ b/core/dispute_coordinator/impl/runtime_info.cpp @@ -6,7 +6,7 @@ #include "dispute_coordinator/impl/runtime_info.hpp" -#include "crypto/crypto_store/session_keys.hpp" +#include "crypto/key_store/session_keys.hpp" #include "dispute_coordinator/impl/errors.hpp" #include "runtime/runtime_api/parachain_host.hpp" diff --git a/core/dispute_coordinator/impl/runtime_info.hpp b/core/dispute_coordinator/impl/runtime_info.hpp index c7745837e2..2475898319 100644 --- a/core/dispute_coordinator/impl/runtime_info.hpp +++ b/core/dispute_coordinator/impl/runtime_info.hpp @@ -19,7 +19,7 @@ namespace kagome::crypto { namespace kagome::dispute { - struct SyncCryptoStorePtr {}; + struct SyncKeyStorePtr {}; /// Information about ourselves, in case we are an `Authority`. /// diff --git a/core/host_api/impl/CMakeLists.txt b/core/host_api/impl/CMakeLists.txt index 17e5666377..10f0901714 100644 --- a/core/host_api/impl/CMakeLists.txt +++ b/core/host_api/impl/CMakeLists.txt @@ -24,7 +24,7 @@ target_link_libraries(crypto_extension secp256k1_provider ed25519_provider scale::scale - crypto_store + key_store ) kagome_install(crypto_extension) @@ -51,7 +51,6 @@ add_library(misc_extension target_link_libraries(misc_extension scale::scale logger - constant_code_provider outcome blob ) diff --git a/core/host_api/impl/crypto_extension.cpp b/core/host_api/impl/crypto_extension.cpp index 2804c76ce8..f167998707 100644 --- a/core/host_api/impl/crypto_extension.cpp +++ b/core/host_api/impl/crypto_extension.cpp @@ -13,11 +13,11 @@ #include #include -#include "crypto/crypto_store.hpp" -#include "crypto/crypto_store/key_type.hpp" #include "crypto/ecdsa_provider.hpp" #include "crypto/ed25519_provider.hpp" #include "crypto/hasher.hpp" +#include "crypto/key_store.hpp" +#include "crypto/key_store/key_type.hpp" #include "crypto/secp256k1/secp256k1_provider_impl.hpp" #include "crypto/sr25519_provider.hpp" #include "log/trace_macros.hpp" @@ -65,14 +65,14 @@ namespace kagome::host_api { std::shared_ptr ed25519_provider, std::shared_ptr secp256k1_provider, std::shared_ptr hasher, - std::shared_ptr crypto_store) + std::shared_ptr key_store) : memory_provider_(std::move(memory_provider)), sr25519_provider_(std::move(sr25519_provider)), ecdsa_provider_(std::move(ecdsa_provider)), ed25519_provider_(std::move(ed25519_provider)), secp256k1_provider_(std::move(secp256k1_provider)), hasher_(std::move(hasher)), - crypto_store_(std::move(crypto_store)), + key_store_(std::move(key_store)), logger_{log::createLogger("CryptoExtension", "crypto_extension")} { BOOST_ASSERT(memory_provider_ != nullptr); BOOST_ASSERT(sr25519_provider_ != nullptr); @@ -81,6 +81,7 @@ namespace kagome::host_api { BOOST_ASSERT(secp256k1_provider_ != nullptr); BOOST_ASSERT(hasher_ != nullptr); BOOST_ASSERT(logger_ != nullptr); + BOOST_ASSERT(key_store_ != nullptr); } // ---------------------- hashing ---------------------- @@ -181,7 +182,7 @@ namespace kagome::host_api { crypto::KeyType key_type = loadKeyType(key_type_ptr); checkIfKeyIsSupported(key_type, logger_); - auto public_keys = crypto_store_->getEd25519PublicKeys(key_type); + auto public_keys = key_store_->ed25519().getPublicKeys(key_type); if (not public_keys) { throw_with_error( logger_, "error loading public keys: {}", public_keys.error()); @@ -207,10 +208,10 @@ namespace kagome::host_api { outcome::result kp_res = [&] { if (seed_opt.has_value()) { - return crypto_store_->generateEd25519Keypair(key_type, + return key_store_->ed25519().generateKeypair(key_type, seed_opt.value()); } else { - return crypto_store_->generateEd25519KeypairOnDisk(key_type); + return key_store_->ed25519().generateKeypairOnDisk(key_type); } }(); if (!kp_res) { @@ -240,20 +241,20 @@ namespace kagome::host_api { if (!pk) { BOOST_UNREACHABLE_RETURN({}); } - auto key_pair = crypto_store_->findEd25519Keypair(key_type, pk.value()); - if (!key_pair) { + auto key_pair_opt = key_store_->ed25519().findKeypair(key_type, pk.value()); + if (!key_pair_opt) { logger_->error("failed to find required key"); auto error_result = scale::encode(ResultType(std::nullopt)).value(); return getMemory().storeBuffer(error_result); } - auto sign = ed25519_provider_->sign(key_pair.value(), msg_buffer); + auto sign = ed25519_provider_->sign(key_pair_opt.value(), msg_buffer); if (!sign) { throw_with_error( logger_, "failed to sign message, error = {}", sign.error()); } SL_TRACE_FUNC_CALL( - logger_, sign.value(), key_pair.value().public_key, msg_buffer); + logger_, sign.value(), key_pair_opt.value().public_key, msg_buffer); auto buffer = scale::encode(ResultType(sign.value())).value(); return getMemory().storeBuffer(buffer); } @@ -308,7 +309,7 @@ namespace kagome::host_api { crypto::KeyType key_type = loadKeyType(key_type_ptr); checkIfKeyIsSupported(key_type, logger_); - auto public_keys = crypto_store_->getSr25519PublicKeys(key_type); + auto public_keys = key_store_->sr25519().getPublicKeys(key_type); if (not public_keys) { throw_with_error( logger_, "error loading public keys: {}", public_keys.error()); @@ -335,10 +336,10 @@ namespace kagome::host_api { outcome::result kp_res = [&]() { auto bip39_seed = seed_res.value(); if (bip39_seed.has_value()) { - return crypto_store_->generateSr25519Keypair(key_type, + return key_store_->sr25519().generateKeypair(key_type, bip39_seed.value()); } else { - return crypto_store_->generateSr25519KeypairOnDisk(key_type); + return key_store_->sr25519().generateKeypairOnDisk(key_type); } }(); if (!kp_res) { @@ -375,9 +376,10 @@ namespace kagome::host_api { // error is not possible, since we loaded correct number of bytes BOOST_UNREACHABLE_RETURN({}); } - auto key_pair = crypto_store_->findSr25519Keypair(key_type, pk.value()); + auto key_pair = key_store_->sr25519().findKeypair(key_type, pk.value()); if (!key_pair) { - logger_->error("failed to find required key: {}", key_pair.error()); + logger_->error( + "failed to find required key: {} {}", key_type, pk.value()); return getMemory().storeBuffer(error_result); } @@ -579,7 +581,7 @@ namespace kagome::host_api { crypto::KeyType key_type = loadKeyType(key_type_ptr); checkIfKeyIsSupported(key_type, logger_); - auto public_keys = crypto_store_->getEcdsaPublicKeys(key_type); + auto public_keys = key_store_->ecdsa().getPublicKeys(key_type); if (not public_keys) { throw_with_error( logger_, "error loading public keys: {}", public_keys.error()); @@ -606,7 +608,7 @@ namespace kagome::host_api { crypto::EcdsaPublicKey pk; std::copy(public_buffer.begin(), public_buffer.end(), pk.begin()); - auto key_pair = crypto_store_->findEcdsaKeypair(key_type, pk); + auto key_pair = key_store_->ecdsa().findKeypair(key_type, pk); if (!key_pair) { logger_->error("failed to find required key"); auto error_result = scale::encode(ResultType(std::nullopt)).value(); @@ -639,7 +641,7 @@ namespace kagome::host_api { crypto::EcdsaPublicKey pk; std::copy(public_buffer.begin(), public_buffer.end(), pk.begin()); - auto key_pair = crypto_store_->findEcdsaKeypair(key_type, pk); + auto key_pair = key_store_->ecdsa().findKeypair(key_type, pk); if (!key_pair) { logger_->error("failed to find required key"); auto error_result = scale::encode(ResultType(std::nullopt)).value(); @@ -675,10 +677,10 @@ namespace kagome::host_api { outcome::result kp_res = [&]() { auto bip39_seed = seed_res.value(); if (bip39_seed.has_value()) { - return crypto_store_->generateEcdsaKeypair(key_type, + return key_store_->ecdsa().generateKeypair(key_type, bip39_seed.value()); } else { - return crypto_store_->generateEcdsaKeypairOnDisk(key_type); + return key_store_->ecdsa().generateKeypairOnDisk(key_type); } }(); if (!kp_res) { diff --git a/core/host_api/impl/crypto_extension.hpp b/core/host_api/impl/crypto_extension.hpp index 6b557b2e9a..620026eb09 100644 --- a/core/host_api/impl/crypto_extension.hpp +++ b/core/host_api/impl/crypto_extension.hpp @@ -10,7 +10,7 @@ #include #include -#include "crypto/crypto_store.hpp" +#include "crypto/key_store.hpp" #include "log/logger.hpp" #include "runtime/memory_provider.hpp" #include "runtime/types.hpp" @@ -21,7 +21,7 @@ namespace kagome::crypto { class Ed25519Provider; class Secp256k1Provider; class Hasher; - class CryptoStore; + class KeyStore; struct KeyType; } // namespace kagome::crypto @@ -41,7 +41,7 @@ namespace kagome::host_api { std::shared_ptr ed25519_provider, std::shared_ptr secp256k1_provider, std::shared_ptr hasher, - std::shared_ptr crypto_store); + std::shared_ptr key_store); void reset(); @@ -270,7 +270,7 @@ namespace kagome::host_api { std::shared_ptr ed25519_provider_; std::shared_ptr secp256k1_provider_; std::shared_ptr hasher_; - std::shared_ptr crypto_store_; + std::shared_ptr key_store_; log::Logger logger_; std::optional batch_verify_; }; diff --git a/core/host_api/impl/host_api_factory_impl.cpp b/core/host_api/impl/host_api_factory_impl.cpp index 4d524b529e..77c7ef81e9 100644 --- a/core/host_api/impl/host_api_factory_impl.cpp +++ b/core/host_api/impl/host_api_factory_impl.cpp @@ -17,7 +17,7 @@ namespace kagome::host_api { std::shared_ptr ed25519_provider, std::shared_ptr secp256k1_provider, std::shared_ptr hasher, - std::shared_ptr crypto_store, + std::shared_ptr key_store, std::shared_ptr offchain_persistent_storage, std::shared_ptr offchain_worker_pool) @@ -27,13 +27,14 @@ namespace kagome::host_api { ed25519_provider_(std::move(ed25519_provider)), secp256k1_provider_(std::move(secp256k1_provider)), hasher_(std::move(hasher)), - crypto_store_(std::move(crypto_store)), + key_store_(std::move(key_store)), offchain_persistent_storage_(std::move(offchain_persistent_storage)), offchain_worker_pool_(std::move(offchain_worker_pool)) { BOOST_ASSERT(sr25519_provider_ != nullptr); BOOST_ASSERT(ed25519_provider_ != nullptr); BOOST_ASSERT(secp256k1_provider_ != nullptr); BOOST_ASSERT(hasher_ != nullptr); + BOOST_ASSERT(key_store_ != nullptr); } std::unique_ptr HostApiFactoryImpl::make( @@ -49,7 +50,7 @@ namespace kagome::host_api { ed25519_provider_, secp256k1_provider_, hasher_, - crypto_store_, + key_store_, offchain_persistent_storage_, offchain_worker_pool_); } diff --git a/core/host_api/impl/host_api_factory_impl.hpp b/core/host_api/impl/host_api_factory_impl.hpp index 44b245cd95..791ee94a59 100644 --- a/core/host_api/impl/host_api_factory_impl.hpp +++ b/core/host_api/impl/host_api_factory_impl.hpp @@ -8,7 +8,7 @@ #include "host_api/host_api_factory.hpp" -#include "crypto/crypto_store.hpp" +#include "crypto/key_store.hpp" #include "crypto/ecdsa_provider.hpp" #include "crypto/ed25519_provider.hpp" #include "crypto/hasher.hpp" @@ -34,7 +34,7 @@ namespace kagome::host_api { std::shared_ptr ed25519_provider, std::shared_ptr secp256k1_provider, std::shared_ptr hasher, - std::shared_ptr crypto_store, + std::shared_ptr key_store, std::shared_ptr offchain_persistent_storage, std::shared_ptr offchain_worker_pool); @@ -52,7 +52,7 @@ namespace kagome::host_api { std::shared_ptr ed25519_provider_; std::shared_ptr secp256k1_provider_; std::shared_ptr hasher_; - std::shared_ptr crypto_store_; + std::shared_ptr key_store_; std::shared_ptr offchain_persistent_storage_; std::shared_ptr offchain_worker_pool_; diff --git a/core/host_api/impl/host_api_impl.cpp b/core/host_api/impl/host_api_impl.cpp index 5c977747ab..0d64240e4d 100644 --- a/core/host_api/impl/host_api_impl.cpp +++ b/core/host_api/impl/host_api_impl.cpp @@ -29,7 +29,7 @@ namespace kagome::host_api { std::shared_ptr ed25519_provider, std::shared_ptr secp256k1_provider, std::shared_ptr hasher, - std::shared_ptr crypto_store, + std::shared_ptr key_store, std::shared_ptr offchain_persistent_storage, std::shared_ptr offchain_worker_pool) @@ -47,7 +47,7 @@ namespace kagome::host_api { std::move(ed25519_provider), std::move(secp256k1_provider), hasher, - std::move(crypto_store)), + std::move(key_store)), io_ext_(memory_provider_), memory_ext_(memory_provider_), misc_ext_{DEFAULT_CHAIN_ID, diff --git a/core/host_api/impl/host_api_impl.hpp b/core/host_api/impl/host_api_impl.hpp index f3d6a1da70..60de93ce50 100644 --- a/core/host_api/impl/host_api_impl.hpp +++ b/core/host_api/impl/host_api_impl.hpp @@ -43,7 +43,7 @@ namespace kagome::host_api { std::shared_ptr ed25519_provider, std::shared_ptr secp256k1_provider, std::shared_ptr hasher, - std::shared_ptr crypto_store, + std::shared_ptr key_store, std::shared_ptr offchain_persistent_storage, std::shared_ptr offchain_worker_pool); diff --git a/core/injector/CMakeLists.txt b/core/injector/CMakeLists.txt index 095aa9ae8d..5164a64881 100644 --- a/core/injector/CMakeLists.txt +++ b/core/injector/CMakeLists.txt @@ -32,7 +32,7 @@ target_link_libraries(application_injector clock consensus core_api - crypto_store + key_store dispute_coordinator ecdsa_provider ed25519_provider @@ -42,7 +42,6 @@ target_link_libraries(application_injector grandpa_api host_api_factory kagome_benchmarks - key_file_storage log_configurator metadata_api metrics diff --git a/core/injector/application_injector.cpp b/core/injector/application_injector.cpp index a445d4bc17..881cced0b3 100644 --- a/core/injector/application_injector.cpp +++ b/core/injector/application_injector.cpp @@ -5,6 +5,7 @@ */ #include "injector/application_injector.hpp" +#include "crypto/key_store.hpp" #define BOOST_DI_CFG_DIAGNOSTICS_LEVEL 2 #define BOOST_DI_CFG_CTOR_LIMIT_SIZE \ @@ -85,11 +86,11 @@ #include "consensus/timeline/impl/slots_util_impl.hpp" #include "consensus/timeline/impl/timeline_impl.hpp" #include "crypto/bip39/impl/bip39_provider_impl.hpp" -#include "crypto/crypto_store/crypto_store_impl.hpp" -#include "crypto/crypto_store/session_keys.hpp" #include "crypto/ecdsa/ecdsa_provider_impl.hpp" #include "crypto/ed25519/ed25519_provider_impl.hpp" #include "crypto/hasher/hasher_impl.hpp" +#include "crypto/key_store/key_store_impl.hpp" +#include "crypto/key_store/session_keys.hpp" #include "crypto/pbkdf2/impl/pbkdf2_provider_impl.hpp" #include "crypto/random_generator/boost_generator.hpp" #include "crypto/secp256k1/secp256k1_provider_impl.hpp" @@ -181,6 +182,7 @@ #include "runtime/runtime_api/impl/session_keys_api.hpp" #include "runtime/runtime_api/impl/tagged_transaction_queue.hpp" #include "runtime/runtime_api/impl/transaction_payment_api.hpp" +#include "runtime/wabt/instrument.hpp" #if KAGOME_WASM_COMPILER_WASM_EDGE == 1 @@ -404,7 +406,6 @@ namespace { injector.template create>(), injector.template create>(), injector.template create>(), - injector.template create>(), module_cache_opt, injector.template create>()); }), @@ -560,7 +561,6 @@ namespace { di::bind.template to(), di::bind.template to(), di::bind.template to(), - di::bind.template to(), di::bind.template to(), std::forward(args)...); } @@ -625,7 +625,15 @@ namespace { #if KAGOME_WASM_COMPILER_WASM_EDGE == 1 useConfig(wasmedge_config), #endif - + di::bind.to([](const auto &injector) { + const auto &config = + injector + .template create(); + auto chain_spec = + injector.template create>(); + return crypto::KeyStore::Config{config.keystorePath(chain_spec->id())}; + }), + // inherit host injector libp2p::injector::makeHostInjector( libp2p::injector::useWssPem(config->nodeWssPem()), @@ -663,7 +671,7 @@ namespace { injector.template create(); auto &csprng = injector.template create(); auto &crypto_store = - injector.template create(); + injector.template create(); return injector::get_peer_keypair( app_config, chain, crypto_provider, csprng, crypto_store); })[boost::di::override], @@ -765,7 +773,7 @@ namespace { di::bind.template to(), di::bind.template to(), bind_by_lambda([](const auto &injector) { - const application::AppConfiguration &config = + const auto &config = injector .template create(); auto chain_spec = @@ -773,7 +781,9 @@ namespace { return get_key_file_storage(config, chain_spec); }), - di::bind.template to(), + di::bind>.template to>(), + di::bind>.template to>(), + di::bind>.template to>(), di::bind.template to(), makeRuntimeInjector(config->runtimeExecMethod(), config->runtimeInterpreter()), di::bind.template to(), diff --git a/core/injector/get_peer_keypair.hpp b/core/injector/get_peer_keypair.hpp index dce5c61d49..56ede33f01 100644 --- a/core/injector/get_peer_keypair.hpp +++ b/core/injector/get_peer_keypair.hpp @@ -11,7 +11,7 @@ #include "application/app_configuration.hpp" #include "common/bytestr.hpp" #include "common/outcome_throw.hpp" -#include "crypto/crypto_store/crypto_store_impl.hpp" +#include "crypto/key_store/key_store_impl.hpp" #include "crypto/ed25519_provider.hpp" namespace kagome::injector { @@ -20,7 +20,7 @@ namespace kagome::injector { const application::ChainSpec &chain, const crypto::Ed25519Provider &crypto_provider, crypto::CSPRNG &csprng, - crypto::CryptoStore &crypto_store) { + crypto::KeyStore &key_store) { auto log = log::createLogger("Injector", "injector"); if (app_config.nodeKey()) { @@ -40,7 +40,7 @@ namespace kagome::injector { const auto &path = app_config.nodeKeyFile().value(); log->info( "Will use LibP2P keypair from config or 'node-key-file' CLI arg"); - auto key = crypto_store.loadLibp2pKeypair(path); + auto key = key_store.loadLibp2pKeypair(path); if (key.has_error()) { log->error("Unable to load user provided key from {}. Error: {}", path, @@ -54,7 +54,7 @@ namespace kagome::injector { } auto path = app_config.chainPath(chain.id()) / "network/secret_ed25519"; - if (auto r = crypto_store.loadLibp2pKeypair(path)) { + if (auto r = key_store.loadLibp2pKeypair(path)) { log->info( "Will use LibP2P keypair from config or args (loading from base " "path)"); diff --git a/core/log/configurator.cpp b/core/log/configurator.cpp index aeb0271f36..c8a818e8dc 100644 --- a/core/log/configurator.cpp +++ b/core/log/configurator.cpp @@ -48,7 +48,7 @@ namespace kagome::log { - name: crypto children: - name: bip39 - - name: crypto_store + - name: key_store - name: ed25519 - name: ecdsa - name: consensus diff --git a/core/log/trace_macros.hpp b/core/log/trace_macros.hpp index 47a22b9ae6..3301a0b6a0 100644 --- a/core/log/trace_macros.hpp +++ b/core/log/trace_macros.hpp @@ -65,12 +65,9 @@ namespace kagome::log { #else -#define SL_TRACE_FUNC_CALL(logger, ret, ...) \ - ::kagome::log::trace_function_call((logger), \ - reinterpret_cast(this), \ - __FUNCTION__, \ - (ret), \ - ##__VA_ARGS__) +#define SL_TRACE_FUNC_CALL(logger, ret, ...) \ + ::kagome::log::trace_function_call( \ + (logger), fmt::ptr(this), __FUNCTION__, (ret), ##__VA_ARGS__) #define SL_TRACE_VOID_FUNC_CALL(logger, ...) \ ::kagome::log::trace_void_function_call( \ diff --git a/core/network/types/own_peer_info.hpp b/core/network/types/own_peer_info.hpp index 0aee04578a..4ddf57cf08 100644 --- a/core/network/types/own_peer_info.hpp +++ b/core/network/types/own_peer_info.hpp @@ -11,7 +11,7 @@ #include #include "application/app_configuration.hpp" -#include "crypto/crypto_store.hpp" +#include "crypto/key_store.hpp" #include "scale/libp2p_types.hpp" namespace kagome::network { diff --git a/core/parachain/CMakeLists.txt b/core/parachain/CMakeLists.txt index 1b8eab9538..9d93a98629 100644 --- a/core/parachain/CMakeLists.txt +++ b/core/parachain/CMakeLists.txt @@ -27,7 +27,7 @@ add_library(validator_parachain ) target_link_libraries(validator_parachain - crypto_store + key_store dispute_coordinator module_repository network diff --git a/core/parachain/approval/approval_distribution.cpp b/core/parachain/approval/approval_distribution.cpp index c7bc42693b..0ba8d74820 100644 --- a/core/parachain/approval/approval_distribution.cpp +++ b/core/parachain/approval/approval_distribution.cpp @@ -16,8 +16,8 @@ #include "common/worker_thread_pool.hpp" #include "consensus/babe/babe_config_repository.hpp" #include "consensus/babe/impl/babe_digests_util.hpp" -#include "crypto/crypto_store.hpp" #include "crypto/hasher.hpp" +#include "crypto/key_store.hpp" #include "crypto/sr25519_provider.hpp" #include "network/impl/protocols/parachain_protocols.hpp" #include "network/impl/stream_engine.hpp" @@ -446,7 +446,7 @@ namespace kagome::parachain { common::WorkerThreadPool &worker_thread_pool, std::shared_ptr parachain_host, LazySPtr slots_util, - std::shared_ptr keystore, + std::shared_ptr keystore, std::shared_ptr hasher, std::shared_ptr peer_view, std::shared_ptr parachain_processor, @@ -617,11 +617,11 @@ namespace kagome::parachain { std::optional> ApprovalDistribution::findAssignmentKey( - const std::shared_ptr &keystore, + const std::shared_ptr &keystore, const runtime::SessionInfo &config) { for (size_t ix = 0; ix < config.assignment_keys.size(); ++ix) { const auto &pk = config.assignment_keys[ix]; - if (auto res = keystore->findSr25519Keypair( + if (auto res = keystore->sr25519().findKeypair( crypto::KeyTypes::ASSIGNMENT, crypto::Sr25519PublicKey::fromSpan(pk).value()); res.has_value()) { @@ -633,7 +633,7 @@ namespace kagome::parachain { ApprovalDistribution::AssignmentsList ApprovalDistribution::compute_assignments( - const std::shared_ptr &keystore, + const std::shared_ptr &keystore, const runtime::SessionInfo &config, const RelayVRFStory &relay_vrf_story, const CandidateIncludedList &leaving_cores) { @@ -642,13 +642,13 @@ namespace kagome::parachain { return {}; } - std::optional> - founded_key = findAssignmentKey(keystore, config); - if (!founded_key) { + std::optional> found_key = + findAssignmentKey(keystore, config); + if (!found_key) { return {}; } - const auto &[validator_ix, assignments_key] = *founded_key; + const auto &[validator_ix, assignments_key] = *found_key; std::vector lc; for (const auto &[hashed_candidate_receipt, core_ix, group_ix] : leaving_cores) { @@ -2352,8 +2352,8 @@ namespace kagome::parachain { SessionIndex session_index, const CandidateHash &candidate_hash) { auto key_pair = - keystore_->findSr25519Keypair(crypto::KeyTypes::PARACHAIN, pubkey); - if (key_pair.has_error()) { + keystore_->sr25519().findKeypair(crypto::KeyTypes::PARACHAIN, pubkey); + if (!key_pair) { logger_->warn("No key pair in store for {}", pubkey); return std::nullopt; } @@ -2448,10 +2448,9 @@ namespace kagome::parachain { }; return approval::min_or_some( e.next_no_show, - (e.last_assignment_tick - ? filter(*e.last_assignment_tick + kApprovalDelay, - tick_now) - : std::optional{})); + (e.last_assignment_tick ? filter( + *e.last_assignment_tick + kApprovalDelay, tick_now) + : std::optional{})); }, [&](const approval::PendingRequiredTranche &e) { std::optional next_announced{}; diff --git a/core/parachain/approval/approval_distribution.hpp b/core/parachain/approval/approval_distribution.hpp index 36d18bf1f6..8602963c38 100644 --- a/core/parachain/approval/approval_distribution.hpp +++ b/core/parachain/approval/approval_distribution.hpp @@ -21,8 +21,8 @@ #include "consensus/babe/types/babe_block_header.hpp" #include "consensus/timeline/slots_util.hpp" #include "consensus/timeline/types.hpp" -#include "crypto/crypto_store/key_file_storage.hpp" -#include "crypto/crypto_store/session_keys.hpp" +#include "crypto/key_store/key_file_storage.hpp" +#include "crypto/key_store/session_keys.hpp" #include "crypto/type_hasher.hpp" #include "dispute_coordinator/dispute_coordinator.hpp" #include "injector/lazy.hpp" @@ -273,7 +273,7 @@ namespace kagome::parachain { common::WorkerThreadPool &worker_thread_pool, std::shared_ptr parachain_host, LazySPtr slots_util, - std::shared_ptr keystore, + std::shared_ptr keystore, std::shared_ptr hasher, std::shared_ptr peer_view, std::shared_ptr parachain_processor, @@ -296,7 +296,7 @@ namespace kagome::parachain { using AssignmentsList = std::unordered_map; static AssignmentsList compute_assignments( - const std::shared_ptr &keystore, + const std::shared_ptr &keystore, const runtime::SessionInfo &config, const RelayVRFStory &relay_vrf_story, const CandidateIncludedList &leaving_cores); @@ -583,7 +583,7 @@ namespace kagome::parachain { const runtime::SessionInfo &session_info); static std::optional> - findAssignmentKey(const std::shared_ptr &keystore, + findAssignmentKey(const std::shared_ptr &keystore, const runtime::SessionInfo &config); void unify_with_peer(StoreUnit> &entries, @@ -714,7 +714,7 @@ namespace kagome::parachain { std::shared_ptr parachain_host_; LazySPtr slots_util_; - std::shared_ptr keystore_; + std::shared_ptr keystore_; std::shared_ptr hasher_; const ApprovalVotingSubsystem config_; std::shared_ptr peer_view_; diff --git a/core/parachain/pvf/kagome_pvf_worker_injector.hpp b/core/parachain/pvf/kagome_pvf_worker_injector.hpp index 4ee7f58834..9b538193d2 100644 --- a/core/parachain/pvf/kagome_pvf_worker_injector.hpp +++ b/core/parachain/pvf/kagome_pvf_worker_injector.hpp @@ -65,7 +65,7 @@ namespace kagome::parachain { di::bind.to(), di::bind.to(), - bind_null(), + bind_null(), bind_null(), bind_null(), di::bind.to(), @@ -107,7 +107,6 @@ namespace kagome::parachain { injector.template create>(), injector.template create>(), injector.template create>(), - injector.template create>(), module_cache_opt, injector.template create>()); }), diff --git a/core/parachain/pvf/session_params.hpp b/core/parachain/pvf/session_params.hpp index 99fe78590b..94281ac572 100644 --- a/core/parachain/pvf/session_params.hpp +++ b/core/parachain/pvf/session_params.hpp @@ -12,18 +12,24 @@ namespace kagome::parachain { inline outcome::result sessionParams( runtime::ParachainHost &api, const primitives::BlockHash &relay_parent) { + // https://github.com/paritytech/polkadot-sdk/blob/e0c081dbd46c1e6edca1ce2c62298f5f3622afdd/polkadot/node/core/pvf/common/src/executor_interface.rs#L46-L47 + constexpr uint32_t kDefaultHeapPagesEstimate = 32; + constexpr uint32_t kExtraHeapPages = 2048; OUTCOME_TRY(session_index, api.session_index_for_child(relay_parent)); OUTCOME_TRY(session_params, api.session_executor_params(relay_parent, session_index)); runtime::RuntimeContext::ContextParams config; config.memory_limits.max_stack_values_num = runtime::RuntimeContext::DEFAULT_STACK_MAX; + config.memory_limits.heap_alloc_strategy = + HeapAllocStrategyDynamic{kDefaultHeapPagesEstimate + kExtraHeapPages}; if (session_params) { for (auto ¶m : *session_params) { if (auto *stack_max = get_if(¶m)) { config.memory_limits.max_stack_values_num = stack_max->max_values_num; } else if (auto *pages_max = get_if(¶m)) { - config.memory_limits.max_memory_pages_num = pages_max->limit; + config.memory_limits.heap_alloc_strategy = HeapAllocStrategyDynamic{ + kDefaultHeapPagesEstimate + pages_max->limit}; } } } diff --git a/core/parachain/validator/signer.hpp b/core/parachain/validator/signer.hpp index 5c431ac669..92de39f27e 100644 --- a/core/parachain/validator/signer.hpp +++ b/core/parachain/validator/signer.hpp @@ -8,7 +8,7 @@ #include -#include "crypto/crypto_store/session_keys.hpp" +#include "crypto/key_store/session_keys.hpp" #include "crypto/sr25519_provider.hpp" #include "network/types/collator_messages.hpp" #include "runtime/runtime_api/parachain_host.hpp" diff --git a/core/runtime/CMakeLists.txt b/core/runtime/CMakeLists.txt index 1d16cc1192..410617169a 100644 --- a/core/runtime/CMakeLists.txt +++ b/core/runtime/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(common) add_subdirectory(binaryen) +add_subdirectory(wabt) add_library(wasm_compiler INTERFACE) diff --git a/core/runtime/binaryen/memory_impl.cpp b/core/runtime/binaryen/memory_impl.cpp index 824b0b4f0d..06f8cdd05a 100644 --- a/core/runtime/binaryen/memory_impl.cpp +++ b/core/runtime/binaryen/memory_impl.cpp @@ -23,6 +23,10 @@ namespace kagome::runtime::binaryen { memory_->resize(kInitialMemorySize); } + std::optional MemoryImpl::pagesMax() const { + return memory_->pagesMax(); + } + WasmPointer MemoryImpl::allocate(WasmSize size) { return allocator_->allocate(size); } diff --git a/core/runtime/binaryen/memory_impl.hpp b/core/runtime/binaryen/memory_impl.hpp index 40bb22dba7..2db2b0f9b9 100644 --- a/core/runtime/binaryen/memory_impl.hpp +++ b/core/runtime/binaryen/memory_impl.hpp @@ -64,6 +64,8 @@ namespace kagome::runtime::binaryen { return memory_->getSize(); } + std::optional pagesMax() const override; + outcome::result view(WasmPointer ptr, WasmSize size) const override; diff --git a/core/runtime/binaryen/runtime_external_interface.cpp b/core/runtime/binaryen/runtime_external_interface.cpp index 753e8717c9..f42f1121fd 100644 --- a/core/runtime/binaryen/runtime_external_interface.cpp +++ b/core/runtime/binaryen/runtime_external_interface.cpp @@ -196,6 +196,9 @@ namespace kagome::runtime::binaryen { void RuntimeExternalInterface::init(wasm::Module &wasm, wasm::ModuleInstance &instance) { memory.resize(wasm.memory.initial * wasm::Memory::kPageSize); + if (wasm.memory.hasMax()) { + memory.pages_max = wasm.memory.max; + } // apply memory segments for (auto &segment : wasm.memory.segments) { wasm::Address offset = diff --git a/core/runtime/binaryen/runtime_external_interface.hpp b/core/runtime/binaryen/runtime_external_interface.hpp index 529d3494f4..345d1e07e0 100644 --- a/core/runtime/binaryen/runtime_external_interface.hpp +++ b/core/runtime/binaryen/runtime_external_interface.hpp @@ -37,8 +37,11 @@ namespace kagome::runtime::binaryen { class RuntimeExternalInterface : public wasm::ModuleInstance::ExternalInterface { class Memory { + friend class RuntimeExternalInterface; + using Mem = std::vector; Mem memory; + std::optional pages_max; template static bool aligned(const char *address) { static_assert(!(sizeof(T) & (sizeof(T) - 1)), "must be a power of 2"); @@ -66,6 +69,9 @@ namespace kagome::runtime::binaryen { auto getSize() const { return memory.size(); } + std::optional pagesMax() const { + return pages_max; + } template void set(size_t address, T value) { check(address, sizeof(T)); @@ -169,8 +175,7 @@ namespace kagome::runtime::binaryen { memory.resize(newSize); } - [[noreturn]] - void trap(const char *why) override { + [[noreturn]] void trap(const char *why) override { logger_->error("Trap: {}", why); throw wasm::TrapException{}; } diff --git a/core/runtime/common/CMakeLists.txt b/core/runtime/common/CMakeLists.txt index 269f75b8a4..34a13ebc69 100644 --- a/core/runtime/common/CMakeLists.txt +++ b/core/runtime/common/CMakeLists.txt @@ -5,14 +5,9 @@ # add_library(runtime_common - stack_limiter.cpp memory_error.cpp ) target_link_libraries(runtime_common - wabt::wabt - blob - logger - uncompress_if_needed outcome ) kagome_install(runtime_common) @@ -27,14 +22,6 @@ target_link_libraries(storage_code_provider ) kagome_install(storage_code_provider) -add_library(constant_code_provider - constant_code_provider.cpp - ) -target_link_libraries(constant_code_provider - uncompress_if_needed - ) -kagome_install(constant_code_provider) - add_library(uncompress_if_needed uncompress_code_if_needed.cpp ) @@ -76,6 +63,7 @@ add_library(module_repository target_link_libraries(module_repository outcome uncompress_if_needed + wasm_instrument blob executor runtime_common @@ -90,6 +78,7 @@ add_library(executor target_link_libraries(executor logger uncompress_if_needed + wasm_instrument storage mp_utils runtime_common diff --git a/core/runtime/common/constant_code_provider.cpp b/core/runtime/common/constant_code_provider.cpp deleted file mode 100644 index 9dece14d69..0000000000 --- a/core/runtime/common/constant_code_provider.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright Quadrivium LLC - * All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "runtime/common/constant_code_provider.hpp" - -namespace kagome::runtime { - - ConstantCodeProvider::ConstantCodeProvider(common::Buffer code) - : code_{std::move(code)} {} - - outcome::result ConstantCodeProvider::getCodeAt( - const storage::trie::RootHash &) const { - return code_; - } - -} // namespace kagome::runtime diff --git a/core/runtime/common/constant_code_provider.hpp b/core/runtime/common/constant_code_provider.hpp deleted file mode 100644 index 5b436eeff1..0000000000 --- a/core/runtime/common/constant_code_provider.hpp +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright Quadrivium LLC - * All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "runtime/runtime_code_provider.hpp" - -namespace kagome::runtime { - - /** - * A code provider that serves only one fixed blob of code for any state - */ - class ConstantCodeProvider final : public RuntimeCodeProvider { - public: - explicit ConstantCodeProvider(common::Buffer code); - - outcome::result getCodeAt( - const storage::trie::RootHash &at) const override; - - private: - common::Buffer code_; - }; - -} // namespace kagome::runtime diff --git a/core/runtime/common/core_api_factory_impl.hpp b/core/runtime/common/core_api_factory_impl.hpp index c1f45d2f03..d89141bdea 100644 --- a/core/runtime/common/core_api_factory_impl.hpp +++ b/core/runtime/common/core_api_factory_impl.hpp @@ -20,7 +20,6 @@ namespace kagome::blockchain { namespace kagome::runtime { class ModuleFactory; - class SingleModuleCache; } // namespace kagome::runtime namespace kagome::runtime { @@ -29,7 +28,8 @@ namespace kagome::runtime { : public runtime::CoreApiFactory, public std::enable_shared_from_this { public: - explicit CoreApiFactoryImpl(std::shared_ptr module_factory); + explicit CoreApiFactoryImpl( + std::shared_ptr module_factory); ~CoreApiFactoryImpl() = default; outcome::result> make( diff --git a/core/runtime/common/memory_allocator.cpp b/core/runtime/common/memory_allocator.cpp index 0111ec56a6..c7449f77a4 100644 --- a/core/runtime/common/memory_allocator.cpp +++ b/core/runtime/common/memory_allocator.cpp @@ -33,8 +33,7 @@ namespace kagome::runtime { MemoryAllocator::MemoryAllocator(Memory &memory, const MemoryConfig &config) : memory_{memory}, offset_{roundUpAlign(config.heap_base)}, - max_memory_pages_num_{ - config.limits.max_memory_pages_num.value_or(kMaxPages)} { + max_memory_pages_num_{memory_.pagesMax().value_or(kMaxPages)} { BOOST_ASSERT(max_memory_pages_num_ > 0); } diff --git a/core/runtime/common/module_instance.cpp b/core/runtime/common/module_instance.cpp index 2e7a47ef5b..250f9606ff 100644 --- a/core/runtime/common/module_instance.cpp +++ b/core/runtime/common/module_instance.cpp @@ -43,29 +43,6 @@ namespace kagome::runtime { .resetMemory(MemoryConfig{heap_base, limits})); auto &memory = memory_provider->getCurrentMemory()->get(); - // TODO: https://github.com/qdrvm/kagome/issues/1962 limit max memory - if (auto &storage = getEnvironment().storage_provider) { - static const auto heappages_key = ":heappages"_buf; - auto batch = storage->getCurrentBatch(); - OUTCOME_TRY(heappages, batch->tryGet(heappages_key)); - if (heappages) { - if (sizeof(uint64_t) != heappages->size()) { - SL_ERROR(log, - "Unable to read :heappages value. Type size mismatch. " - "Required {} bytes, but {} available", - sizeof(uint64_t), - heappages->size()); - } else { - uint64_t pages = common::le_bytes_to_uint64(heappages->view()); - memory.resize(pages * kMemoryPageSize); - SL_TRACE(log, - "Creating wasm module with non-default :heappages value set " - "to {}", - pages); - } - } - } - size_t max_data_segment_end = 0; size_t segments_num = 0; forDataSegment([&](ModuleInstance::SegmentOffset offset, diff --git a/core/runtime/common/module_repository_impl.cpp b/core/runtime/common/module_repository_impl.cpp index b38cea94af..a42c26366e 100644 --- a/core/runtime/common/module_repository_impl.cpp +++ b/core/runtime/common/module_repository_impl.cpp @@ -8,12 +8,14 @@ #include "log/profiling_logger.hpp" #include "runtime/common/runtime_instances_pool.hpp" +#include "runtime/heap_alloc_strategy_heappages.hpp" #include "runtime/instance_environment.hpp" #include "runtime/module.hpp" #include "runtime/module_factory.hpp" #include "runtime/module_instance.hpp" #include "runtime/runtime_code_provider.hpp" #include "runtime/runtime_upgrade_tracker.hpp" +#include "storage/trie/trie_storage.hpp" namespace kagome::runtime { using kagome::primitives::ThreadNumber; @@ -21,20 +23,22 @@ namespace kagome::runtime { ModuleRepositoryImpl::ModuleRepositoryImpl( std::shared_ptr runtime_instances_pool, + std::shared_ptr hasher, std::shared_ptr runtime_upgrade_tracker, + std::shared_ptr trie_storage, std::shared_ptr module_factory, - std::shared_ptr last_compiled_module, std::shared_ptr code_provider) : runtime_instances_pool_{std::move(runtime_instances_pool)}, + hasher_{std::move(hasher)}, runtime_upgrade_tracker_{std::move(runtime_upgrade_tracker)}, + trie_storage_{std::move(trie_storage)}, module_factory_{std::move(module_factory)}, - last_compiled_module_{std::move(last_compiled_module)}, code_provider_{code_provider}, + cache_{4}, logger_{log::createLogger("Module Repository", "runtime")} { BOOST_ASSERT(runtime_instances_pool_); BOOST_ASSERT(runtime_upgrade_tracker_); BOOST_ASSERT(module_factory_); - BOOST_ASSERT(last_compiled_module_); } outcome::result> @@ -45,33 +49,34 @@ namespace kagome::runtime { OUTCOME_TRY(state, runtime_upgrade_tracker_->getLastCodeUpdateState(block)); KAGOME_PROFILE_END(code_retrieval) - KAGOME_PROFILE_START(module_retrieval) { - // Add compiled module if any - if (auto module = last_compiled_module_->try_extract(); - module.has_value()) { - runtime_instances_pool_->putModule(state, module.value()); - } - - // Compile new module if required - if (auto opt_module = runtime_instances_pool_->getModule(state); - !opt_module.has_value()) { - SL_DEBUG(logger_, "Runtime module cache miss for state {}", state); + KAGOME_PROFILE_START(module_retrieval) + constexpr uint32_t kDefaultHeapAllocPages = 2048; + MemoryLimits config; + config.heap_alloc_strategy = + HeapAllocStrategyStatic{kDefaultHeapAllocPages}; + Item item; + OUTCOME_TRY(SAFE_UNIQUE(cache_)->outcome::result { + if (auto r = cache_.get(state)) { + item = r->get(); + } else { auto code = code_provider_->getCodeAt(state); if (not code.has_value()) { code = code_provider_->getCodeAt(storage_state); } - if (not code.has_value()) { - return code.as_failure(); + BOOST_OUTCOME_TRY(item.code, std::move(code)); + item.hash = hasher_->blake2b_256(*item.code); + OUTCOME_TRY(batch, trie_storage_->getEphemeralBatchAt(storage_state)); + OUTCOME_TRY(heappages, heapAllocStrategyHeappages(*batch)); + if (heappages) { + item.config.heap_alloc_strategy = *heappages; } - OUTCOME_TRY(new_module, module_factory_->make(code.value())); - runtime_instances_pool_->putModule(state, std::move(new_module)); + cache_.put(state, item); } - } - - // Try to acquire an instance (instantiate if needed) + return outcome::success(); + }); OUTCOME_TRY(runtime_instance, - runtime_instances_pool_->instantiateFromState( - state, RuntimeContext::ContextParams{})); + runtime_instances_pool_->instantiateFromCode( + item.hash, *item.code, {config})); KAGOME_PROFILE_END(module_retrieval) return runtime_instance; diff --git a/core/runtime/common/module_repository_impl.hpp b/core/runtime/common/module_repository_impl.hpp index 70bf2fbd14..d663314e3a 100644 --- a/core/runtime/common/module_repository_impl.hpp +++ b/core/runtime/common/module_repository_impl.hpp @@ -13,20 +13,30 @@ #include "log/logger.hpp" #include "runtime/instance_environment.hpp" +#include "utils/lru.hpp" +#include "utils/safe_object.hpp" + +namespace kagome::crypto { + class Hasher; +} // namespace kagome::crypto + +namespace kagome::storage::trie { + class TrieStorage; +} // namespace kagome::storage::trie namespace kagome::runtime { class RuntimeUpgradeTracker; class ModuleFactory; - class SingleModuleCache; class RuntimeInstancesPool; class ModuleRepositoryImpl final : public ModuleRepository { public: ModuleRepositoryImpl( std::shared_ptr runtime_instances_pool, + std::shared_ptr hasher, std::shared_ptr runtime_upgrade_tracker, + std::shared_ptr trie_storage, std::shared_ptr module_factory, - std::shared_ptr last_compiled_module, std::shared_ptr code_provider); outcome::result> getInstanceAt( @@ -34,11 +44,18 @@ namespace kagome::runtime { const storage::trie::RootHash &state) override; private: + struct Item { + common::Hash256 hash; + std::shared_ptr code; + MemoryLimits config; + }; std::shared_ptr runtime_instances_pool_; + std::shared_ptr hasher_; std::shared_ptr runtime_upgrade_tracker_; + std::shared_ptr trie_storage_; std::shared_ptr module_factory_; - std::shared_ptr last_compiled_module_; std::shared_ptr code_provider_; + SafeObject> cache_; log::Logger logger_; }; diff --git a/core/runtime/common/runtime_context.cpp b/core/runtime/common/runtime_context.cpp index e68d6d74cc..187ccb077d 100644 --- a/core/runtime/common/runtime_context.cpp +++ b/core/runtime/common/runtime_context.cpp @@ -9,7 +9,6 @@ #include "runtime/runtime_context.hpp" #include "blockchain/block_header_repository.hpp" -#include "runtime/common/stack_limiter.hpp" #include "runtime/common/uncompress_code_if_needed.hpp" #include "runtime/instance_environment.hpp" #include "runtime/memory_provider.hpp" @@ -18,6 +17,7 @@ #include "runtime/module_instance.hpp" #include "runtime/module_repository.hpp" #include "runtime/trie_storage_provider.hpp" +#include "runtime/wabt/instrument.hpp" #include "storage/trie/polkadot_trie/trie_error.hpp" OUTCOME_CPP_DEFINE_CATEGORY(kagome::runtime, Error, e) { @@ -54,17 +54,8 @@ namespace kagome::runtime { ContextParams params) { common::Buffer code; OUTCOME_TRY(runtime::uncompressCodeIfNeeded(code_zstd, code)); - if (params.memory_limits.max_stack_values_num) { - auto res = instrumentWithStackLimiter( - code, *params.memory_limits.max_stack_values_num); - if (!res) { - log::createLogger("RuntimeContextFactory", "runtime") - ->error("Failed to instrument wasm code with stack limiter: {}", - res.error().message()); - return Error::INSTRUMENTATION_FAILED; - } - code = std::move(res.value()); - } + BOOST_OUTCOME_TRY(code, + prepareBlobForCompilation(code, params.memory_limits)); auto runtime_module_res = module_factory.make(code); if (!runtime_module_res) { return Error::COMPILATION_FAILED; diff --git a/core/runtime/common/runtime_instances_pool.cpp b/core/runtime/common/runtime_instances_pool.cpp index d28b25c597..ef2f9e31ed 100644 --- a/core/runtime/common/runtime_instances_pool.cpp +++ b/core/runtime/common/runtime_instances_pool.cpp @@ -7,12 +7,12 @@ #include "runtime/common/runtime_instances_pool.hpp" #include "common/monadic_utils.hpp" -#include "runtime/common/stack_limiter.hpp" #include "runtime/common/uncompress_code_if_needed.hpp" #include "runtime/instance_environment.hpp" #include "runtime/module.hpp" #include "runtime/module_factory.hpp" #include "runtime/module_instance.hpp" +#include "runtime/wabt/instrument.hpp" namespace kagome::runtime { /** @@ -24,11 +24,15 @@ namespace kagome::runtime { public: BorrowedInstance(std::weak_ptr pool, const common::Hash256 &hash, + const RuntimeContext::ContextParams &config, std::shared_ptr instance) - : pool_{std::move(pool)}, hash_{hash}, instance_{std::move(instance)} {} + : pool_{std::move(pool)}, + hash_{hash}, + config_{config}, + instance_{std::move(instance)} {} ~BorrowedInstance() { if (auto pool = pool_.lock()) { - pool->release(hash_, std::move(instance_)); + pool->release(hash_, config_, std::move(instance_)); } } @@ -66,7 +70,8 @@ namespace kagome::runtime { private: std::weak_ptr pool_; - common::Hash256 hash_; // either trie hash or code hash + common::Hash256 hash_; + RuntimeContext::ContextParams config_; std::shared_ptr instance_; }; @@ -86,22 +91,23 @@ namespace kagome::runtime { common::BufferView code_zstd, const RuntimeContext::ContextParams &config) { std::unique_lock lock{pools_mtx_}; - auto pool_opt = pools_.get(code_hash); + Key key{code_hash, config}; + auto pool_opt = pools_.get(key); if (!pool_opt) { lock.unlock(); OUTCOME_TRY(module, tryCompileModule(code_hash, code_zstd, config)); lock.lock(); - pool_opt = pools_.get(code_hash); + pool_opt = pools_.get(key); if (!pool_opt) { - pool_opt = std::ref(pools_.put(code_hash, InstancePool{module, {}})); + pool_opt = std::ref(pools_.put(key, InstancePool{module, {}})); } } BOOST_ASSERT(pool_opt); OUTCOME_TRY(instance, pool_opt->get().instantiate(lock)); BOOST_ASSERT(shared_from_this()); return std::make_shared( - weak_from_this(), code_hash, std::move(instance)); + weak_from_this(), code_hash, config, std::move(instance)); } RuntimeInstancesPoolImpl::CompilationResult @@ -110,7 +116,8 @@ namespace kagome::runtime { common::BufferView code_zstd, const RuntimeContext::ContextParams &config) { std::unique_lock l{compiling_modules_mtx_}; - if (auto iter = compiling_modules_.find(code_hash); + Key key{code_hash, config}; + if (auto iter = compiling_modules_.find(key); iter != compiling_modules_.end()) { std::shared_future future = iter->second; l.unlock(); @@ -118,7 +125,7 @@ namespace kagome::runtime { } std::promise promise; auto [iter, is_inserted] = - compiling_modules_.insert({code_hash, promise.get_future()}); + compiling_modules_.insert({key, promise.get_future()}); BOOST_ASSERT(is_inserted); BOOST_ASSERT(iter != compiling_modules_.end()); l.unlock(); @@ -148,49 +155,19 @@ namespace kagome::runtime { return *res; } - outcome::result> - RuntimeInstancesPoolImpl::instantiateFromState( - const RuntimeInstancesPoolImpl::TrieHash &state, - const RuntimeContext::ContextParams &config) { - std::unique_lock lock{pools_mtx_}; - auto entry = pools_.get(state); - BOOST_ASSERT(entry); - OUTCOME_TRY(instance, entry->get().instantiate(lock)); - BOOST_ASSERT(shared_from_this()); - return std::make_shared( - weak_from_this(), state, std::move(instance)); - } - void RuntimeInstancesPoolImpl::release( - const RuntimeInstancesPoolImpl::TrieHash &state, + const CodeHash &code_hash, + const RuntimeContext::ContextParams &config, std::shared_ptr &&instance) { std::unique_lock guard{pools_mtx_}; - auto entry = pools_.get(state); + Key key{code_hash, config}; + auto entry = pools_.get(key); if (not entry) { - entry = pools_.put(state, {instance->getModule(), {}}); + entry = pools_.put(key, {instance->getModule(), {}}); } entry->get().instances.emplace_back(std::move(instance)); } - std::optional> - RuntimeInstancesPoolImpl::getModule( - const RuntimeInstancesPoolImpl::TrieHash &state) { - std::unique_lock guard{pools_mtx_}; - if (auto entry = pools_.get(state)) { - return entry->get().module; - } - return std::nullopt; - } - - void RuntimeInstancesPoolImpl::putModule( - const RuntimeInstancesPoolImpl::TrieHash &state, - std::shared_ptr module) { - std::unique_lock guard{pools_mtx_}; - if (not pools_.get(state)) { - pools_.put(state, {std::move(module), {}}); - } - } - outcome::result> RuntimeInstancesPoolImpl::InstancePool::instantiate( std::unique_lock &lock) { diff --git a/core/runtime/common/runtime_instances_pool.hpp b/core/runtime/common/runtime_instances_pool.hpp index 1ccdb7ccdf..44906ad9c0 100644 --- a/core/runtime/common/runtime_instances_pool.hpp +++ b/core/runtime/common/runtime_instances_pool.hpp @@ -14,7 +14,6 @@ #include #include -#include "runtime/common/stack_limiter.hpp" #include "runtime/module_factory.hpp" #include "utils/lru.hpp" @@ -38,18 +37,6 @@ namespace kagome::runtime { common::BufferView code_zstd, const RuntimeContext::ContextParams &config) override; - /** - * @brief Instantiate new or reuse existing ModuleInstance for the provided - * state. - * - * @param state - the merkle trie root of the state containing the code of - * the runtime module we are acquiring an instance of. - * @return pointer to the acquired ModuleInstance if success. Error - * otherwise. - */ - outcome::result> instantiateFromState( - const TrieHash &state, - const RuntimeContext::ContextParams &config) override; /** * @brief Releases the module instance (returns it to the pool) * @@ -57,29 +44,12 @@ namespace kagome::runtime { * module code we are releasing an instance of. * @param instance - instance to be released. */ - void release(const TrieHash &state, - std::shared_ptr &&instance) override; - - /** - * @brief Get the module for state from internal cache - * - * @param state - the state containing the module's code. - * @return Module if any, nullopt otherwise - */ - std::optional> getModule( - const TrieHash &state) override; - - /** - * @brief Puts new module into internal cache - * - * @param state - storage hash of the block containing the code of the - * module - * @param module - new module pointer - */ - void putModule(const TrieHash &state, - std::shared_ptr module) override; + void release(const CodeHash &code_hash, + const RuntimeContext::ContextParams &config, + std::shared_ptr &&instance); private: + using Key = std::tuple; struct InstancePool { std::shared_ptr module; std::vector> instances; @@ -99,10 +69,10 @@ namespace kagome::runtime { std::shared_ptr instrument_; std::mutex pools_mtx_; - Lru pools_; + Lru pools_; mutable std::mutex compiling_modules_mtx_; - std::unordered_map> + std::unordered_map> compiling_modules_; }; diff --git a/core/runtime/common/storage_code_provider.cpp b/core/runtime/common/storage_code_provider.cpp index 1d786517b1..28b1055e87 100644 --- a/core/runtime/common/storage_code_provider.cpp +++ b/core/runtime/common/storage_code_provider.cpp @@ -31,7 +31,7 @@ namespace kagome::runtime { BOOST_ASSERT(runtime_upgrade_tracker_ != nullptr); } - outcome::result StorageCodeProvider::getCodeAt( + RuntimeCodeProvider::Result StorageCodeProvider::getCodeAt( const storage::trie::RootHash &state) const { std::unique_lock lock{mutex_}; if (last_state_root_ != state) { @@ -42,13 +42,14 @@ namespace kagome::runtime { OUTCOME_TRY( code, chain_spec_->fetchCodeSubstituteByBlockInfo(block_info.value())); - OUTCOME_TRY(uncompressCodeIfNeeded(code, cached_code_)); - return cached_code_; + common::Buffer code2; + OUTCOME_TRY(uncompressCodeIfNeeded(code, code2)); + return std::make_shared(std::move(code2)); } } OUTCOME_TRY(batch, storage_->getEphemeralBatchAt(state)); OUTCOME_TRY(code, setCodeFromBatch(*batch.get())); - cached_code_ = std::move(code); + cached_code_ = std::make_shared(std::move(code)); last_state_root_ = state; } return cached_code_; diff --git a/core/runtime/common/storage_code_provider.hpp b/core/runtime/common/storage_code_provider.hpp index 5d8095dc12..c7416d244f 100644 --- a/core/runtime/common/storage_code_provider.hpp +++ b/core/runtime/common/storage_code_provider.hpp @@ -31,8 +31,7 @@ namespace kagome::runtime { std::shared_ptr code_substitutes, std::shared_ptr chain_spec); - outcome::result getCodeAt( - const storage::trie::RootHash &state) const override; + Result getCodeAt(const storage::trie::RootHash &state) const override; private: outcome::result setCodeFromBatch( @@ -41,7 +40,7 @@ namespace kagome::runtime { std::shared_ptr runtime_upgrade_tracker_; std::shared_ptr known_code_substitutes_; std::shared_ptr chain_spec_; - mutable common::Buffer cached_code_; + mutable Code cached_code_; mutable storage::trie::RootHash last_state_root_; log::Logger logger_; mutable std::mutex mutex_; diff --git a/core/runtime/heap_alloc_strategy.hpp b/core/runtime/heap_alloc_strategy.hpp new file mode 100644 index 0000000000..096c9ce77d --- /dev/null +++ b/core/runtime/heap_alloc_strategy.hpp @@ -0,0 +1,54 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include + +#include "scale/tie.hpp" +#include "scale/tie_hash.hpp" + +namespace kagome { + /** + * Allocate the initial heap pages as requested by the wasm file and then + * allow it to grow dynamically. + */ + struct HeapAllocStrategyDynamic { + SCALE_TIE(1); + SCALE_TIE_HASH_BOOST(HeapAllocStrategyDynamic); + + /** + * The absolute maximum size of the linear memory (in pages). + * When `Some(_)` the linear memory will be allowed to grow up to this + * limit. When `None` the linear memory will be allowed to grow up to the + * maximum limit supported by WASM (4GB). + */ + std::optional maximum_pages; + }; + /** + * Allocate a static number of heap pages. + * The total number of allocated heap pages is the initial number of heap + * pages requested by the wasm file plus the `extra_pages`. + */ + struct HeapAllocStrategyStatic { + SCALE_TIE(1); + SCALE_TIE_HASH_BOOST(HeapAllocStrategyStatic); + + /** + * The number of pages that will be added on top of the initial heap pages + * requested by the wasm file. + */ + uint32_t extra_pages; + }; + /** + * Defines the heap pages allocation strategy the wasm runtime should use. + * A heap page is defined as 64KiB of memory. + */ + using HeapAllocStrategy = + boost::variant; +} // namespace kagome diff --git a/core/runtime/heap_alloc_strategy_heappages.hpp b/core/runtime/heap_alloc_strategy_heappages.hpp new file mode 100644 index 0000000000..537901a1ca --- /dev/null +++ b/core/runtime/heap_alloc_strategy_heappages.hpp @@ -0,0 +1,25 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "runtime/heap_alloc_strategy.hpp" +#include "storage/predefined_keys.hpp" +#include "storage/trie/trie_batches.hpp" + +namespace kagome { + /// Convert ":heappages" from state trie to `HeapAllocStrategy`. + inline outcome::result> + heapAllocStrategyHeappages(const storage::trie::TrieBatch &trie) { + OUTCOME_TRY(raw, trie.tryGet(storage::kRuntimeHeappagesKey)); + if (raw) { + if (auto r = scale::decode(*raw)) { + return HeapAllocStrategyStatic{static_cast(r.value())}; + } + } + return std::nullopt; + } +} // namespace kagome diff --git a/core/runtime/memory.hpp b/core/runtime/memory.hpp index f226a5b344..0128719eca 100644 --- a/core/runtime/memory.hpp +++ b/core/runtime/memory.hpp @@ -52,6 +52,8 @@ namespace kagome::runtime { */ virtual WasmSize size() const = 0; + virtual std::optional pagesMax() const = 0; + /** * Resizes memory to the given size * @param new_size diff --git a/core/runtime/module.hpp b/core/runtime/module.hpp index 103bb6c461..60727a00f5 100644 --- a/core/runtime/module.hpp +++ b/core/runtime/module.hpp @@ -25,36 +25,7 @@ namespace kagome::runtime { public: virtual ~Module() = default; - virtual outcome::result> instantiate() const = 0; + virtual outcome::result> instantiate() + const = 0; }; - - /** - * A wrapper for compiled module. Used when we update WAVM runtime in order to - * skip double compilation which takes significant time (see issue #1104). - * Currently it's shared through DI. - */ - class SingleModuleCache { - public: - /** - * @brief Sets new cached value, scrapping previous if any - * @param module New compiled module to store - */ - void set(std::shared_ptr module) { - module_ = module; - } - - /** - * Pops stored module (if any), clears cache in process. - * @return Value if any, std::nullopt otherwise. - */ - std::optional> try_extract() { - auto module = module_; - module_.reset(); - return module; - } - - private: - std::optional> module_; - }; - } // namespace kagome::runtime diff --git a/core/runtime/runtime_api/impl/lru.hpp b/core/runtime/runtime_api/impl/lru.hpp index ee1a8c05bd..3bc0b26c91 100644 --- a/core/runtime/runtime_api/impl/lru.hpp +++ b/core/runtime/runtime_api/impl/lru.hpp @@ -11,6 +11,7 @@ #include "runtime/runtime_upgrade_tracker.hpp" #include "utils/lru_encoded.hpp" #include "utils/safe_object.hpp" +#include "utils/tuple_hash.hpp" namespace kagome::runtime { constexpr auto DISABLE_RUNTIME_LRU = false; @@ -163,6 +164,7 @@ template struct std::hash> { size_t operator()( const kagome::runtime::RuntimeApiLruBlockArgKey &x) const { - return boost::hash_value(std::tie(x.first, x.second)); + auto t = std::tie(x.first, x.second); + return std::hash{}(t); } }; diff --git a/core/runtime/runtime_api/session_keys_api.hpp b/core/runtime/runtime_api/session_keys_api.hpp index f637e3f66d..adcf99ceb5 100644 --- a/core/runtime/runtime_api/session_keys_api.hpp +++ b/core/runtime/runtime_api/session_keys_api.hpp @@ -10,7 +10,7 @@ #include -#include "crypto/crypto_store/key_type.hpp" +#include "crypto/key_store/key_type.hpp" #include "primitives/common.hpp" #include "primitives/metadata.hpp" diff --git a/core/runtime/runtime_code_provider.hpp b/core/runtime/runtime_code_provider.hpp index c3cde37a05..9ef92ec391 100644 --- a/core/runtime/runtime_code_provider.hpp +++ b/core/runtime/runtime_code_provider.hpp @@ -6,13 +6,11 @@ #pragma once -#include -#include - -#include "common/buffer_view.hpp" -#include "primitives/block_id.hpp" +#include "common/buffer.hpp" #include "storage/trie/types.hpp" +#include + namespace kagome::runtime { /** * @class RuntimeCodeProvider keeps and provides wasm state code @@ -21,8 +19,10 @@ namespace kagome::runtime { public: virtual ~RuntimeCodeProvider() = default; - virtual outcome::result getCodeAt( - const storage::trie::RootHash &state) const = 0; + using Code = std::shared_ptr; + using Result = outcome::result; + + virtual Result getCodeAt(const storage::trie::RootHash &state) const = 0; }; } // namespace kagome::runtime diff --git a/core/runtime/runtime_context.hpp b/core/runtime/runtime_context.hpp index beac171705..2093e4644a 100644 --- a/core/runtime/runtime_context.hpp +++ b/core/runtime/runtime_context.hpp @@ -159,3 +159,5 @@ namespace kagome::runtime { }; } // namespace kagome::runtime + +SCALE_TIE_HASH_STD(kagome::runtime::RuntimeContext::ContextParams); diff --git a/core/runtime/runtime_instances_pool.hpp b/core/runtime/runtime_instances_pool.hpp index 2ee68fc893..4d922e1ae8 100644 --- a/core/runtime/runtime_instances_pool.hpp +++ b/core/runtime/runtime_instances_pool.hpp @@ -19,7 +19,6 @@ namespace kagome::runtime { public: static constexpr size_t DEFAULT_MODULES_CACHE_SIZE = 2; - using TrieHash = storage::trie::RootHash; using CodeHash = storage::trie::RootHash; virtual ~RuntimeInstancesPool() = default; @@ -28,47 +27,6 @@ namespace kagome::runtime { instantiateFromCode(const CodeHash &code_hash, common::BufferView code_zstd, const RuntimeContext::ContextParams &config) = 0; - - /** - * @brief Instantiate new or reuse existing ModuleInstance for the provided - * state. - * - * @param state - the merkle trie root of the state containing the code of - * the runtime module we are acquiring an instance of. - * @return pointer to the acquired ModuleInstance if success. Error - * otherwise. - */ - virtual outcome::result> - instantiateFromState(const TrieHash &state, - const RuntimeContext::ContextParams &config) = 0; - /** - * @brief Releases the module instance (returns it to the pool) - * - * @param state - the merkle trie root of the state containing the runtime - * module code we are releasing an instance of. - * @param instance - instance to be released. - */ - virtual void release(const TrieHash &state, - std::shared_ptr &&instance) = 0; - - /** - * @brief Get the module for state from internal cache - * - * @param state - the state containing the module's code. - * @return Module if any, nullopt otherwise - */ - virtual std::optional> getModule( - const TrieHash &state) = 0; - - /** - * @brief Puts new module into internal cache - * - * @param state - storage hash of the block containing the code of the - * module - * @param module - new module pointer - */ - virtual void putModule(const TrieHash &state, - std::shared_ptr module) = 0; }; } // namespace kagome::runtime diff --git a/core/runtime/types.hpp b/core/runtime/types.hpp index 68d659da88..659f30ff13 100644 --- a/core/runtime/types.hpp +++ b/core/runtime/types.hpp @@ -11,6 +11,7 @@ #include #include "outcome/outcome.hpp" +#include "runtime/heap_alloc_strategy.hpp" #include "scale/tie.hpp" namespace kagome::runtime { @@ -53,7 +54,7 @@ namespace kagome::runtime { SCALE_TIE(2); std::optional max_stack_values_num{}; - std::optional max_memory_pages_num{}; + HeapAllocStrategy heap_alloc_strategy; }; struct MemoryConfig { @@ -77,9 +78,11 @@ namespace kagome::runtime { enum class Error { COMPILATION_FAILED = 1, - INSTRUMENTATION_FAILED + INSTRUMENTATION_FAILED, }; } // namespace kagome::runtime OUTCOME_HPP_DECLARE_ERROR(kagome::runtime, Error); + +SCALE_TIE_HASH_STD(kagome::runtime::MemoryLimits); diff --git a/core/runtime/wabt/CMakeLists.txt b/core/runtime/wabt/CMakeLists.txt new file mode 100644 index 0000000000..2e5a248393 --- /dev/null +++ b/core/runtime/wabt/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# Copyright Quadrivium LLC +# All Rights Reserved +# SPDX-License-Identifier: Apache-2.0 +# + +add_library(wasm_instrument + instrument.cpp + stack_limiter.cpp + ) +target_link_libraries(wasm_instrument + logger + outcome + wabt::wabt + ) +kagome_install(wasm_instrument) diff --git a/core/runtime/wabt/error.hpp b/core/runtime/wabt/error.hpp new file mode 100644 index 0000000000..c1cac23d3e --- /dev/null +++ b/core/runtime/wabt/error.hpp @@ -0,0 +1,29 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "runtime/types.hpp" + +namespace kagome::runtime { + struct WabtError { + [[nodiscard]] const std::string &message() const { + return msg; + } + std::string msg; + }; + + inline std::error_code make_error_code(const WabtError &) { + return Error::INSTRUMENTATION_FAILED; + } + + inline void outcome_throw_as_system_error_with_payload(WabtError e) { + throw e; + } + + template + using WabtOutcome = outcome::result; +} // namespace kagome::runtime diff --git a/core/runtime/wabt/instrument.cpp b/core/runtime/wabt/instrument.cpp new file mode 100644 index 0000000000..f226185372 --- /dev/null +++ b/core/runtime/wabt/instrument.cpp @@ -0,0 +1,101 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "runtime/wabt/instrument.hpp" + +#include "runtime/wabt/stack_limiter.hpp" +#include "runtime/wabt/util.hpp" + +namespace kagome::runtime { + WabtOutcome convertMemoryImportIntoExport(wabt::Module &module) { + for (auto it = module.fields.begin(); it != module.fields.end(); ++it) { + auto import = dynamic_cast(&*it); + if (not import) { + continue; + } + auto memory = dynamic_cast(import->import.get()); + if (not memory) { + continue; + } + if (std::any_of(module.fields.begin(), + module.fields.end(), + [&](const wabt::ModuleField &field) { + return field.type() == wabt::ModuleFieldType::Memory; + })) { + return WabtError{"unexpected MemoryModuleField"}; + } + auto import_it = std::find( + module.imports.begin(), module.imports.end(), import->import.get()); + if (import_it == module.imports.end()) { + return WabtError{"inconsistent Module.imports"}; + } + auto memory_it = std::find( + module.memories.begin(), module.memories.end(), &memory->memory); + if (memory_it == module.memories.end()) { + return WabtError{"inconsistent Module.memories"}; + } + auto memory2 = std::make_unique(); + memory2->memory.page_limits = memory->memory.page_limits; + auto export_ = std::make_unique(); + export_->export_ = { + import->import->field_name, + wabt::ExternalKind::Memory, + wabt::Var{0, {}}, + }; + module.imports.erase(import_it); + module.memories.erase(memory_it); + module.fields.erase(it); + --module.num_memory_imports; + module.AppendField(std::move(memory2)); + module.AppendField(std::move(export_)); + break; + } + return outcome::success(); + } + + WabtOutcome setupMemoryAccordingToHeapAllocStrategy( + wabt::Module &module, const HeapAllocStrategy &config) { + for (auto it = module.fields.begin(); it != module.fields.end(); ++it) { + auto memory = dynamic_cast(&*it); + if (not memory) { + continue; + } + auto &limit = memory->memory.page_limits; + auto init = limit.initial; + if (auto v = boost::get(&config)) { + if (auto &max = v->maximum_pages) { + limit = {std::min(init, *max), *max}; + } else { + limit = wabt::Limits{init}; + } + } else { + auto max = + init + boost::get(config).extra_pages; + limit = {max, max}; + } + } + return outcome::success(); + } + + WabtOutcome prepareBlobForCompilation( + common::BufferView code, const MemoryLimits &config) { + OUTCOME_TRY(module, wabtDecode(code)); + if (config.max_stack_values_num) { + OUTCOME_TRY( + instrumentWithStackLimiter(module, *config.max_stack_values_num)); + } + OUTCOME_TRY(convertMemoryImportIntoExport(module)); + OUTCOME_TRY(setupMemoryAccordingToHeapAllocStrategy( + module, config.heap_alloc_strategy)); + OUTCOME_TRY(wabtValidate(module)); + return wabtEncode(module); + } + + WabtOutcome InstrumentWasm::instrument( + common::BufferView code, const MemoryLimits &config) const { + return prepareBlobForCompilation(code, config); + } +} // namespace kagome::runtime diff --git a/core/runtime/wabt/instrument.hpp b/core/runtime/wabt/instrument.hpp new file mode 100644 index 0000000000..eaf56c971d --- /dev/null +++ b/core/runtime/wabt/instrument.hpp @@ -0,0 +1,41 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "common/buffer.hpp" +#include "runtime/wabt/error.hpp" + +namespace wabt { + struct Module; +} // namespace wabt + +namespace kagome::runtime { + struct MemoryLimits; + + WabtOutcome convertMemoryImportIntoExport(wabt::Module &module); + + WabtOutcome setupMemoryAccordingToHeapAllocStrategy( + wabt::Module &module, const HeapAllocStrategy &config); + + /** + * Instrument wasm code: + * - add stack limiting + * - convert imported memory (if any) to exported memory + * - set memory limit + * https://github.com/paritytech/polkadot-sdk/blob/11831df8e709061e9c6b3292facb5d7d9709f151/substrate/client/executor/wasmtime/src/runtime.rs#L651 + */ + WabtOutcome prepareBlobForCompilation( + common::BufferView code, const MemoryLimits &config); + + class InstrumentWasm { + public: + virtual ~InstrumentWasm() = default; + + virtual WabtOutcome instrument( + common::BufferView code, const MemoryLimits &config) const; + }; +} // namespace kagome::runtime diff --git a/core/runtime/common/stack_limiter.cpp b/core/runtime/wabt/stack_limiter.cpp similarity index 88% rename from core/runtime/common/stack_limiter.cpp rename to core/runtime/wabt/stack_limiter.cpp index 0684dcc08b..d37d38d6b9 100644 --- a/core/runtime/common/stack_limiter.cpp +++ b/core/runtime/wabt/stack_limiter.cpp @@ -4,20 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "runtime/common/stack_limiter.hpp" +#include "runtime/wabt/stack_limiter.hpp" #include "common/visitor.hpp" #include "log/logger.hpp" #include "log/profiling_logger.hpp" - -#include -#include -#include -#include -#include +#include "runtime/wabt/util.hpp" namespace kagome::runtime { - namespace detail { template @@ -119,9 +113,9 @@ namespace kagome::runtime { frames_{}, logger_{std::move(logger)} {} - outcome::result unreachable() { + WabtOutcome unreachable() { if (frames_.empty()) { - return StackLimiterError{"Stack must not be empty"}; + return WabtError{"Stack must not be empty"}; } frames_.back().is_polymorphic = true; return outcome::success(); @@ -148,8 +142,8 @@ namespace kagome::runtime { }); } - outcome::result push_frame( - MaybeConst branch, bool check_frame_boundary) { + WabtOutcome push_frame(MaybeConst branch, + bool check_frame_boundary) { uint32_t end_arity = branch.true_.decl.GetNumResults() != 0; uint32_t branch_arity = end_arity; auto res = pop_values(1); @@ -178,9 +172,9 @@ namespace kagome::runtime { }); } - outcome::result pop_frame() { + WabtOutcome pop_frame() { if (frames_.empty()) { - return StackLimiterError{"Stack is empty"}; + return WabtError{"Stack is empty"}; } height_ = frames_.back().start_height; push_values(frames_.back().end_value_num); @@ -202,24 +196,23 @@ namespace kagome::runtime { SL_TRACE(logger_, "push {}, now height_ {}", num, height_); } - outcome::result pop_values(uint32_t num) { + WabtOutcome pop_values(uint32_t num) { if (num == 0) { return outcome::success(); } if (frames_.empty()) { - return StackLimiterError{"Stack is empty"}; + return WabtError{"Stack is empty"}; } SL_TRACE(logger_, "pop {}, now height_ {}", num, height_ - num); if (height_ - num < frames_.back().start_height) { if (!frames_.back().is_polymorphic) { - return StackLimiterError{ - "Popping values not pushed in the current frame"}; + return WabtError{"Popping values not pushed in the current frame"}; } else { return outcome::success(); } } if (height_ < num) { - return StackLimiterError{"Stack underflow"}; + return WabtError{"Stack underflow"}; } height_ -= num; return outcome::success(); @@ -229,7 +222,7 @@ namespace kagome::runtime { return frames_.empty(); } - outcome::result advance() { + WabtOutcome advance() { bool is_over = false; do { auto &frame = frames_.back(); @@ -273,11 +266,10 @@ namespace kagome::runtime { return &frames_.back(); } - [[nodiscard]] outcome::result, - StackLimiterError> + [[nodiscard]] WabtOutcome> get_frame(size_t idx_from_top) const { if (frames_.size() <= idx_from_top) { - return StackLimiterError{"Stack frame underflow"}; + return WabtError{"Stack frame underflow"}; } return frames_.at(frames_.size() - idx_from_top - 1); } @@ -291,10 +283,9 @@ namespace kagome::runtime { using ConstStack = Stack; using MutStack = Stack; - outcome::result compute_stack_cost( - const log::Logger &logger, - const wabt::Func &func, - const wabt::Module &module) { + WabtOutcome compute_stack_cost(const log::Logger &logger, + const wabt::Func &func, + const wabt::Module &module) { uint32_t locals_num = func.GetNumLocals(); ConstStack stack{logger}; @@ -374,7 +365,7 @@ namespace kagome::runtime { OUTCOME_TRY(frame, stack.get_frame(v.index())); uint32_t arity = frame.get().branch_value_num; if (arity != target_arity) { - return StackLimiterError{ + return WabtError{ "All jump-targets should have equal frame arities"}; } } @@ -491,9 +482,8 @@ namespace kagome::runtime { break; } default: - return StackLimiterError{ - fmt::format("Unsupported instruction: {}", - wabt::GetExprTypeName(expr.type()))}; + return WabtError{fmt::format("Unsupported instruction: {}", + wabt::GetExprTypeName(expr.type()))}; } if (!pushed_frame) { if (auto expr_opt = stack.advance(); !expr_opt.has_value()) { @@ -555,7 +545,7 @@ namespace kagome::runtime { return next_it; } - outcome::result instrument_func( + WabtOutcome instrument_func( wabt::Func &func, const wabt::Var &stack_height, uint32_t stack_limit, @@ -628,7 +618,7 @@ namespace kagome::runtime { return outcome::success(); } - outcome::result generate_thunks( + WabtOutcome generate_thunks( const log::Logger &logger, wabt::Module &module, const wabt::Var &stack_height, @@ -666,7 +656,7 @@ namespace kagome::runtime { break; } default: - return StackLimiterError{ + return WabtError{ fmt::format("Unsupported element expression of type {}", GetExprTypeName(expr.type()))}; } @@ -730,7 +720,7 @@ namespace kagome::runtime { break; } default: - return StackLimiterError{ + return WabtError{ fmt::format("Invalid element expression of type {}", GetExprTypeName(expr.type()))}; } @@ -743,27 +733,15 @@ namespace kagome::runtime { return outcome::success(); } } // namespace detail - outcome::result instrumentWithStackLimiter( - common::BufferView uncompressed_wasm, const size_t stack_limit) { - auto logger = log::createLogger("StackLimiter", "runtime"); - KAGOME_PROFILE_START_L(logger, read_ir); - wabt::Errors errors; - wabt::Module module; - wabt::ReadBinaryIr("", - uncompressed_wasm.data(), - uncompressed_wasm.size(), - wabt::ReadBinaryOptions({}, nullptr, true, false, false), - &errors, - &module); - if (!errors.empty()) { - std::stringstream ss; - for (auto &e : errors) { - ss << e.message << "\n"; - } - return StackLimiterError{ss.str()}; - } - KAGOME_PROFILE_END_L(logger, read_ir); + auto &stackLimiterLog() { + static auto log = log::createLogger("StackLimiter", "runtime"); + return log; + } + + WabtOutcome instrumentWithStackLimiter(wabt::Module &module, + size_t stack_limit) { + auto logger = stackLimiterLog(); KAGOME_PROFILE_START_L(logger, count_costs); std::unordered_map func_costs; for (size_t i = 0; i < module.num_func_imports; i++) { @@ -802,32 +780,20 @@ namespace kagome::runtime { KAGOME_PROFILE_END_L(logger, instrument_wasm); - if (wabt::Failed( - wabt::ValidateModule(&module, &errors, wabt::ValidateOptions{}))) { - std::stringstream ss; - for (auto &err : errors) { - ss << err.message; - } - return StackLimiterError{ss.str()}; - } - - KAGOME_PROFILE_START_L(logger, serialize_wasm); - wabt::MemoryStream s; - if (wabt::WriteBinaryModule( - &s, &module, wabt::WriteBinaryOptions({}, false, false, true)) - != wabt::Result::Ok) { - return StackLimiterError{"Failed to serialize WASM module"}; - } - KAGOME_PROFILE_END_L(logger, serialize_wasm); - return common::Buffer{std::move(s.output_buffer().data)}; + OUTCOME_TRY(wabtValidate(module)); + return outcome::success(); } - WabtOutcome InstrumentWasm::instrument( - common::BufferView code, const MemoryLimits &config) const { - // TODO(turuslan): https://github.com/qdrvm/kagome/pull/2009 - if (config.max_stack_values_num) { - return instrumentWithStackLimiter(code, *config.max_stack_values_num); - } - return common::Buffer{code}; + WabtOutcome instrumentWithStackLimiter( + common::BufferView uncompressed_wasm, size_t stack_limit) { + auto logger = stackLimiterLog(); + KAGOME_PROFILE_START_L(logger, read_ir); + OUTCOME_TRY(module, wabtDecode(uncompressed_wasm)); + KAGOME_PROFILE_END_L(logger, read_ir); + + OUTCOME_TRY(instrumentWithStackLimiter(module, stack_limit)); + + KAGOME_PROFILE_START_L(logger, serialize_wasm); + return wabtEncode(module); } } // namespace kagome::runtime diff --git a/core/runtime/common/stack_limiter.hpp b/core/runtime/wabt/stack_limiter.hpp similarity index 51% rename from core/runtime/common/stack_limiter.hpp rename to core/runtime/wabt/stack_limiter.hpp index 40403b7ad4..d745b31f9f 100644 --- a/core/runtime/common/stack_limiter.hpp +++ b/core/runtime/wabt/stack_limiter.hpp @@ -6,12 +6,9 @@ #pragma once -#include - #include "common/buffer.hpp" #include "log/logger.hpp" -#include "outcome/outcome.hpp" -#include "runtime/types.hpp" +#include "runtime/wabt/error.hpp" namespace wabt { struct Module; @@ -19,27 +16,11 @@ namespace wabt { } // namespace wabt namespace kagome::runtime { - - struct StackLimiterError { - [[nodiscard]] const std::string &message() const { - return msg; - } - std::string msg; - }; - - template - using WabtOutcome = outcome::result; - // for tests namespace detail { - outcome::result compute_stack_cost( - const log::Logger &logger, - const wabt::Func &func, - const wabt::Module &module); - } - - inline boost::exception_ptr make_exception_ptr(const StackLimiterError &e) { - return std::make_exception_ptr(std::runtime_error{e.msg}); + WabtOutcome compute_stack_cost(const log::Logger &logger, + const wabt::Func &func, + const wabt::Module &module); } /** @@ -54,11 +35,6 @@ namespace kagome::runtime { [[nodiscard]] WabtOutcome instrumentWithStackLimiter( common::BufferView uncompressed_wasm, size_t stack_limit); - class InstrumentWasm { - public: - virtual ~InstrumentWasm() = default; - - virtual WabtOutcome instrument( - common::BufferView code, const MemoryLimits &config) const; - }; + WabtOutcome instrumentWithStackLimiter(wabt::Module &module, + size_t stack_limit); } // namespace kagome::runtime diff --git a/core/runtime/wabt/util.hpp b/core/runtime/wabt/util.hpp new file mode 100644 index 0000000000..3e5c7e63c8 --- /dev/null +++ b/core/runtime/wabt/util.hpp @@ -0,0 +1,53 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "common/buffer.hpp" +#include "runtime/wabt/error.hpp" + +namespace kagome::runtime { + WabtOutcome wabtTry(auto &&f) { + wabt::Errors errors; + if (wabt::Failed(f(errors))) { + return WabtError{ + wabt::FormatErrorsToString(errors, wabt::Location::Type::Binary)}; + } + return outcome::success(); + } + + inline WabtOutcome wabtDecode(common::BufferView code) { + wabt::Module module; + OUTCOME_TRY(wabtTry([&](wabt::Errors &errors) { + return wabt::ReadBinaryIr( + "", + code.data(), + code.size(), + wabt::ReadBinaryOptions({}, nullptr, true, false, false), + &errors, + &module); + })); + return module; + } + + inline WabtOutcome wabtValidate(const wabt::Module &module) { + return wabtTry([&](wabt::Errors &errors) { + return wabt::ValidateModule(&module, &errors, wabt::ValidateOptions{}); + }); + } + + inline WabtOutcome wabtEncode(const wabt::Module &module) { + wabt::MemoryStream s; + if (wabt::Failed(wabt::WriteBinaryModule( + &s, &module, wabt::WriteBinaryOptions({}, false, false, true)))) { + return WabtError{"Failed to serialize WASM module"}; + } + return common::Buffer{std::move(s.output_buffer().data)}; + } +} // namespace kagome::runtime diff --git a/core/runtime/wasm_edge/memory_impl.cpp b/core/runtime/wasm_edge/memory_impl.cpp index 8c330f7ec1..1fcd2317cc 100644 --- a/core/runtime/wasm_edge/memory_impl.cpp +++ b/core/runtime/wasm_edge/memory_impl.cpp @@ -20,6 +20,16 @@ namespace kagome::runtime::wasm_edge { fmt::ptr(mem_instance_)); } + std::optional MemoryImpl::pagesMax() const { + auto type = WasmEdge_MemoryInstanceGetMemoryType(mem_instance_); + if (type == nullptr) { + throw std::runtime_error{ + "WasmEdge_MemoryInstanceGetMemoryType returned nullptr"}; + } + auto limit = WasmEdge_MemoryTypeGetLimit(type); + return limit.HasMax ? std::make_optional(limit.Max) : std::nullopt; + } + void MemoryImpl::resize(WasmSize new_size) { if (new_size > size()) { auto old_page_num = WasmEdge_MemoryInstanceGetPageSize(mem_instance_); diff --git a/core/runtime/wasm_edge/memory_impl.hpp b/core/runtime/wasm_edge/memory_impl.hpp index d1be855ebd..943ab109d8 100644 --- a/core/runtime/wasm_edge/memory_impl.hpp +++ b/core/runtime/wasm_edge/memory_impl.hpp @@ -29,6 +29,8 @@ namespace kagome::runtime::wasm_edge { * kMemoryPageSize; } + std::optional pagesMax() const override; + /** * Resizes memory to the given size * @param new_size diff --git a/core/runtime/wavm/CMakeLists.txt b/core/runtime/wavm/CMakeLists.txt index 59874229fd..726d2f1fc3 100644 --- a/core/runtime/wavm/CMakeLists.txt +++ b/core/runtime/wavm/CMakeLists.txt @@ -24,7 +24,6 @@ target_link_libraries(runtime_wavm runtime_common ${LLVM_LIBS} WAVM::libWAVM - constant_code_provider core_api_factory executor Boost::boost diff --git a/core/runtime/wavm/instance_environment_factory.hpp b/core/runtime/wavm/instance_environment_factory.hpp index 0b2b19511c..bec26db93d 100644 --- a/core/runtime/wavm/instance_environment_factory.hpp +++ b/core/runtime/wavm/instance_environment_factory.hpp @@ -26,7 +26,6 @@ namespace WAVM::Runtime { } namespace kagome::runtime { - class SingleModuleCache; class ModuleFactory; } // namespace kagome::runtime @@ -53,7 +52,6 @@ namespace kagome::runtime::wavm { std::shared_ptr serializer_; std::shared_ptr host_api_factory_; std::shared_ptr module_factory_; - }; } // namespace kagome::runtime::wavm diff --git a/core/runtime/wavm/memory_impl.cpp b/core/runtime/wavm/memory_impl.cpp index 2decdfe5a8..e5a23e21e2 100644 --- a/core/runtime/wavm/memory_impl.cpp +++ b/core/runtime/wavm/memory_impl.cpp @@ -23,6 +23,11 @@ namespace kagome::runtime::wavm { resize(kInitialMemorySize); } + std::optional MemoryImpl::pagesMax() const { + auto max = WAVM::Runtime::getMemoryType(memory_).size.max; + return max != UINT64_MAX ? std::make_optional(max) : std::nullopt; + } + WasmPointer MemoryImpl::allocate(WasmSize size) { return allocator_->allocate(size); } diff --git a/core/runtime/wavm/memory_impl.hpp b/core/runtime/wavm/memory_impl.hpp index 27883f2e5f..24f5d21e68 100644 --- a/core/runtime/wavm/memory_impl.hpp +++ b/core/runtime/wavm/memory_impl.hpp @@ -42,6 +42,8 @@ namespace kagome::runtime::wavm { return WAVM::Runtime::getMemoryNumPages(memory_) * kMemoryPageSize; } + std::optional pagesMax() const override; + void resize(WasmSize new_size) override { /** * We use this condition to avoid deallocated_ pointers fixup diff --git a/core/runtime/wavm/module_factory_impl.cpp b/core/runtime/wavm/module_factory_impl.cpp index 0e8ff45fd2..bf7dddf89a 100644 --- a/core/runtime/wavm/module_factory_impl.cpp +++ b/core/runtime/wavm/module_factory_impl.cpp @@ -21,7 +21,6 @@ namespace kagome::runtime::wavm { std::shared_ptr storage, std::shared_ptr serializer, std::shared_ptr intrinsic_module, - std::shared_ptr last_compiled_module, std::optional> module_cache, std::shared_ptr hasher) : compartment_{std::move(compartment)}, @@ -29,13 +28,11 @@ namespace kagome::runtime::wavm { host_api_factory_{host_api_factory}, storage_{storage}, serializer_{serializer}, - last_compiled_module_{last_compiled_module}, intrinsic_module_{std::move(intrinsic_module)}, hasher_(std::move(hasher)) { BOOST_ASSERT(compartment_ != nullptr); BOOST_ASSERT(module_params_ != nullptr); BOOST_ASSERT(host_api_factory_ != nullptr); - BOOST_ASSERT(last_compiled_module_ != nullptr); BOOST_ASSERT(intrinsic_module_ != nullptr); BOOST_ASSERT(hasher_ != nullptr); diff --git a/core/runtime/wavm/module_factory_impl.hpp b/core/runtime/wavm/module_factory_impl.hpp index 2e31cd86d1..242951d3f8 100644 --- a/core/runtime/wavm/module_factory_impl.hpp +++ b/core/runtime/wavm/module_factory_impl.hpp @@ -27,10 +27,6 @@ namespace kagome::storage::trie { class TrieSerializer; } // namespace kagome::storage::trie -namespace kagome::runtime { - class SingleModuleCache; -} - namespace kagome::runtime::wavm { class CompartmentWrapper; @@ -50,7 +46,6 @@ namespace kagome::runtime::wavm { std::shared_ptr storage, std::shared_ptr serializer, std::shared_ptr intrinsic_module, - std::shared_ptr last_compiled_module, std::optional> module_cache, std::shared_ptr hasher); @@ -63,7 +58,6 @@ namespace kagome::runtime::wavm { std::shared_ptr host_api_factory_; std::shared_ptr storage_; std::shared_ptr serializer_; - std::shared_ptr last_compiled_module_; std::shared_ptr intrinsic_module_; std::shared_ptr hasher_; }; diff --git a/core/scale/tie_hash.hpp b/core/scale/tie_hash.hpp new file mode 100644 index 0000000000..894afd27ab --- /dev/null +++ b/core/scale/tie_hash.hpp @@ -0,0 +1,28 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "scale/tie.hpp" +#include "utils/tuple_hash.hpp" + +namespace scale { + auto tieHash(const auto &v) { + return ::scale::as_tie(v, + [](auto t) { return std::hash{}(t); }); + } +} // namespace scale + +#define SCALE_TIE_HASH_BOOST(type) \ + friend auto hash_value(const type &v) { return ::scale::tieHash(v); } + +#define SCALE_TIE_HASH_STD(type) \ + template <> \ + struct std::hash { \ + inline size_t operator()(const type &v) const { \ + return ::scale::tieHash(v); \ + } \ + } diff --git a/core/storage/changes_trie/impl/storage_changes_tracker_impl.cpp b/core/storage/changes_trie/impl/storage_changes_tracker_impl.cpp index 2dbca67624..9d18be020d 100644 --- a/core/storage/changes_trie/impl/storage_changes_tracker_impl.cpp +++ b/core/storage/changes_trie/impl/storage_changes_tracker_impl.cpp @@ -14,7 +14,8 @@ namespace kagome::storage::changes_trie { const primitives::events::StorageSubscriptionEnginePtr &storage_sub_engine, const primitives::events::ChainSubscriptionEnginePtr &chain_sub_engine) { - if (actual_val_.find(storage::kRuntimeCodeKey) != actual_val_.cend()) { + if (actual_val_.contains(storage::kRuntimeCodeKey) + or actual_val_.contains(storage::kRuntimeHeappagesKey)) { chain_sub_engine->notify(primitives::events::ChainEventType::kNewRuntime, hash); } diff --git a/core/storage/predefined_keys.hpp b/core/storage/predefined_keys.hpp index f4680fa184..d837ef2f41 100644 --- a/core/storage/predefined_keys.hpp +++ b/core/storage/predefined_keys.hpp @@ -14,6 +14,7 @@ namespace kagome::storage { using namespace common::literals; inline const common::Buffer kRuntimeCodeKey = ":code"_buf; + inline const common::Buffer kRuntimeHeappagesKey = ":heappages"_buf; inline const common::Buffer kExtrinsicIndexKey = ":extrinsic_index"_buf; diff --git a/core/utils/json_unquote.hpp b/core/utils/json_unquote.hpp index ecc92708f8..9e59dd23cd 100644 --- a/core/utils/json_unquote.hpp +++ b/core/utils/json_unquote.hpp @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -19,17 +20,21 @@ namespace rapidjson { #include namespace kagome { - inline std::optional jsonUnquote(std::string_view json) { + + // Remove outer quotes and parse escape sequences in a JSON string + template + inline std::optional jsonUnquote(std::string_view json) { struct Handler : rapidjson::BaseReaderHandler, Handler> { bool Default() const { return false; } bool String(const char *ptr, size_t size, bool) { - str.assign(ptr, size); + str.resize(size); + std::copy_n(ptr, size, std::begin(str)); return true; } - std::string str; + StringType str; }; rapidjson::MemoryStream stream{json.data(), json.size()}; rapidjson::Reader reader; diff --git a/core/utils/optref.hpp b/core/utils/optref.hpp deleted file mode 100644 index e5b324411c..0000000000 --- a/core/utils/optref.hpp +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright Quadrivium LLC - * All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -namespace kagome { - template - using OptRef = T *; -} // namespace kagome diff --git a/core/utils/read_file.hpp b/core/utils/read_file.hpp index 14bc5b7cef..1ae540bf30 100644 --- a/core/utils/read_file.hpp +++ b/core/utils/read_file.hpp @@ -6,14 +6,27 @@ #pragma once +#include #include #include "common/buffer.hpp" namespace kagome { - template - bool readFile(Out &out, const std::string &path) { - static_assert(sizeof(*out.data()) == 1); + + template + concept StandardLayoutPointer = + std::is_standard_layout_v>; + + template + concept ByteContainer = requires(T t, std::streampos pos) { + { t.data() } -> StandardLayoutPointer; + { t.size() } -> std::convertible_to; + { t.resize(pos) }; + { t.clear() }; + }; + + template + bool readFile(Out &out, const std::filesystem::path &path) { std::ifstream file{path, std::ios::binary | std::ios::ate}; if (not file.good()) { out.clear(); diff --git a/core/utils/tuple_hash.hpp b/core/utils/tuple_hash.hpp index 1b43dbd22a..3d75f63608 100644 --- a/core/utils/tuple_hash.hpp +++ b/core/utils/tuple_hash.hpp @@ -16,8 +16,9 @@ struct std::hash> { template void hash_element_of_tuple(size_t &result, const std::tuple &v) const { - auto item = std::get(v); - boost::hash_combine(result, std::hash()(item)); + auto &item = std::get(v); + boost::hash_combine(result, + std::hash>()(item)); if constexpr (sizeof...(Args) > I + 1) { hash_element_of_tuple(result, v); } diff --git a/housekeeping/clang-tidy-diff.sh b/housekeeping/clang-tidy-diff.sh index 63516f2099..f23217baf3 100755 --- a/housekeeping/clang-tidy-diff.sh +++ b/housekeeping/clang-tidy-diff.sh @@ -8,4 +8,5 @@ BUILD_DIR="${BUILD_DIR:-build}" cd $(dirname $0)/.. -git diff -U0 HEAD^ | clang-tidy-diff.py -p1 -path $BUILD_DIR -regex "\.(hpp|h)" +git diff -U0 origin/master | clang-tidy-diff.py -p1 -path $BUILD_DIR -iregex '(core|node)\/.*\.(h|c|hpp|cpp)' | tee clang-tidy.log +! grep ': error:' clang-tidy.log diff --git a/test/core/api/service/author/author_api_test.cpp b/test/core/api/service/author/author_api_test.cpp index 9e3864ff36..3f6b285d6c 100644 --- a/test/core/api/service/author/author_api_test.cpp +++ b/test/core/api/service/author/author_api_test.cpp @@ -13,15 +13,16 @@ #include "common/blob.hpp" #include "common/hexutil.hpp" -#include "crypto/crypto_store/crypto_store_impl.hpp" -#include "crypto/crypto_store/key_file_storage.hpp" -#include "crypto/crypto_store/session_keys.hpp" +#include "common/optref.hpp" #include "crypto/ed25519_types.hpp" +#include "crypto/key_store/key_file_storage.hpp" +#include "crypto/key_store/key_store_impl.hpp" +#include "crypto/key_store/session_keys.hpp" #include "crypto/sr25519_types.hpp" #include "mock/core/api/service/api_service_mock.hpp" #include "mock/core/application/app_configuration_mock.hpp" #include "mock/core/blockchain/block_tree_mock.hpp" -#include "mock/core/crypto/crypto_store_mock.hpp" +#include "mock/core/crypto/key_store_mock.hpp" #include "mock/core/network/transactions_transmitter_mock.hpp" #include "mock/core/runtime/session_keys_api_mock.hpp" #include "mock/core/transaction_pool/transaction_pool_mock.hpp" @@ -43,6 +44,7 @@ using namespace kagome::crypto; using namespace kagome::transaction_pool; using namespace kagome::runtime; +using kagome::OptRef; using kagome::application::AppConfigurationMock; using kagome::blockchain::BlockTree; using kagome::blockchain::BlockTreeMock; @@ -105,7 +107,7 @@ struct AuthorApiTest : public ::testing::Test { using sptr = std::shared_ptr; kagome::network::Roles role; - sptr store; + sptr store; sptr keys; sptr key_store; Sr25519Keypair key_pair; @@ -140,7 +142,7 @@ struct AuthorApiTest : public ::testing::Test { event_receiver->receive(set_id, session, id, event); }); - store = std::make_shared(); + store = std::make_shared(); key_store = KeyFileStorage::createAt("test_chain_43/keystore").value(); key_pair = generateSr25519Keypair(); ASSERT_OUTCOME_SUCCESS_TRY( @@ -210,8 +212,8 @@ MATCHER_P(eventsAreEqual, n, "") { TEST_F(AuthorApiTest, InsertKeyUnsupported) { EXPECT_OUTCOME_ERROR( res, - author_api->insertKey(decodeKeyTypeFromStr("unkn"), {}, {}), - CryptoStoreError::UNSUPPORTED_KEY_TYPE); + author_api->insertKey(KeyType::fromString("unkn").value(), {}, {}), + KeyStoreError::UNSUPPORTED_KEY_TYPE); } /** @@ -222,7 +224,7 @@ TEST_F(AuthorApiTest, InsertKeyUnsupported) { TEST_F(AuthorApiTest, InsertKeyBabe) { Sr25519Seed seed; Sr25519PublicKey public_key; - EXPECT_CALL(*store, generateSr25519Keypair(KeyTypes::BABE, seed)) + EXPECT_CALL(store->sr25519(), generateKeypair(KeyTypes::BABE, seed)) .WillOnce(Return(Sr25519Keypair{{}, public_key})); EXPECT_OUTCOME_SUCCESS( res, @@ -238,8 +240,8 @@ TEST_F(AuthorApiTest, InsertKeyBabe) { TEST_F(AuthorApiTest, InsertKeyAudi) { Sr25519Seed seed; Sr25519PublicKey public_key; - EXPECT_CALL(*store, - generateSr25519Keypair(KeyTypes::AUTHORITY_DISCOVERY, seed)) + EXPECT_CALL(store->sr25519(), + generateKeypair(KeyTypes::AUTHORITY_DISCOVERY, seed)) .WillOnce(Return(Sr25519Keypair{{}, public_key})); EXPECT_OUTCOME_SUCCESS( res, @@ -256,7 +258,7 @@ TEST_F(AuthorApiTest, InsertKeyAudi) { TEST_F(AuthorApiTest, InsertKeyGran) { Ed25519Seed seed; Ed25519PublicKey public_key; - EXPECT_CALL(*store, generateEd25519Keypair(KeyTypes::GRANDPA, seed)) + EXPECT_CALL(store->ed25519(), generateKeypair(KeyTypes::GRANDPA, seed)) .WillOnce(Return(Ed25519Keypair{{}, public_key})); EXPECT_OUTCOME_SUCCESS( res, @@ -323,27 +325,27 @@ TEST_F(AuthorApiTest, HasSessionKeysNotEqualKeys) { TEST_F(AuthorApiTest, HasSessionKeysSuccess6Keys) { Buffer keys; keys.resize(32 * 6); - outcome::result edOk = Ed25519Keypair{}; - outcome::result srOk = Sr25519Keypair{}; + const Ed25519Keypair edOk{}; + const Sr25519Keypair srOk{}; InSequence s; - EXPECT_CALL(*store, findEd25519Keypair(KeyTypes::GRANDPA, _)) + EXPECT_CALL(store->ed25519(), findKeypair(KeyTypes::GRANDPA, _)) .Times(1) - .WillOnce(Return(edOk)); - EXPECT_CALL(*store, findSr25519Keypair(KeyTypes::BABE, _)) + .WillOnce(Return(OptRef(edOk))); + EXPECT_CALL(store->sr25519(), findKeypair(KeyTypes::BABE, _)) .Times(1) - .WillOnce(Return(srOk)); - EXPECT_CALL(*store, findSr25519Keypair(KeyTypes::IM_ONLINE, _)) + .WillOnce(Return(OptRef(srOk))); + EXPECT_CALL(store->sr25519(), findKeypair(KeyTypes::IM_ONLINE, _)) .Times(1) - .WillOnce(Return(srOk)); - EXPECT_CALL(*store, findSr25519Keypair(KeyTypes::PARACHAIN, _)) + .WillOnce(Return(OptRef(srOk))); + EXPECT_CALL(store->sr25519(), findKeypair(KeyTypes::PARACHAIN, _)) .Times(1) - .WillOnce(Return(srOk)); - EXPECT_CALL(*store, findSr25519Keypair(KeyTypes::ASSIGNMENT, _)) + .WillOnce(Return(OptRef(srOk))); + EXPECT_CALL(store->sr25519(), findKeypair(KeyTypes::ASSIGNMENT, _)) .Times(1) - .WillOnce(Return(srOk)); - EXPECT_CALL(*store, findSr25519Keypair(KeyTypes::AUTHORITY_DISCOVERY, _)) + .WillOnce(Return(OptRef(srOk))); + EXPECT_CALL(store->sr25519(), findKeypair(KeyTypes::AUTHORITY_DISCOVERY, _)) .Times(1) - .WillOnce(Return(srOk)); + .WillOnce(Return(OptRef(srOk))); EXPECT_OUTCOME_SUCCESS(res, author_api->hasSessionKeys(keys)); EXPECT_EQ(res.value(), true); } @@ -356,8 +358,8 @@ TEST_F(AuthorApiTest, HasSessionKeysSuccess6Keys) { TEST_F(AuthorApiTest, HasSessionKeysSuccess1Keys) { Buffer keys; keys.resize(32); - outcome::result edOk = Ed25519Keypair{}; - EXPECT_CALL(*store, findEd25519Keypair(KeyTypes::GRANDPA, _)) + Ed25519Keypair edOk{}; + EXPECT_CALL(store->ed25519(), findKeypair(KeyTypes::GRANDPA, _)) .Times(1) .WillOnce(Return(edOk)); EXPECT_OUTCOME_SUCCESS(res, author_api->hasSessionKeys(keys)); @@ -372,10 +374,12 @@ TEST_F(AuthorApiTest, HasSessionKeysSuccess1Keys) { TEST_F(AuthorApiTest, HasSessionKeysFailureNotFound) { Buffer keys; keys.resize(32 * 6); - outcome::result edOk = Ed25519Keypair{}; - outcome::result srErr = CryptoStoreError::KEY_NOT_FOUND; - EXPECT_CALL(*store, findEd25519Keypair(_, _)).Times(1).WillOnce(Return(edOk)); - EXPECT_CALL(*store, findSr25519Keypair(_, _)) + Ed25519Keypair edOk{}; + auto srErr = std::nullopt; + EXPECT_CALL(store->ed25519(), findKeypair(_, _)) + .Times(1) + .WillOnce(Return(edOk)); + EXPECT_CALL(store->sr25519(), findKeypair(_, _)) .Times(1) .WillOnce(Return(srErr)); EXPECT_OUTCOME_SUCCESS(res, author_api->hasSessionKeys(keys)); diff --git a/test/core/authority_discovery/CMakeLists.txt b/test/core/authority_discovery/CMakeLists.txt index 5a7c08e8eb..13d98cd749 100644 --- a/test/core/authority_discovery/CMakeLists.txt +++ b/test/core/authority_discovery/CMakeLists.txt @@ -9,7 +9,7 @@ addtest(address_publisher_test ) target_link_libraries(address_publisher_test address_publisher - crypto_store + key_store logger_for_tests network ) diff --git a/test/core/authority_discovery/address_publisher_test.cpp b/test/core/authority_discovery/address_publisher_test.cpp index 7aff2698b6..dcbba3f10a 100644 --- a/test/core/authority_discovery/address_publisher_test.cpp +++ b/test/core/authority_discovery/address_publisher_test.cpp @@ -14,8 +14,8 @@ #include "mock/core/application/app_configuration_mock.hpp" #include "mock/core/application/app_state_manager_mock.hpp" #include "mock/core/blockchain/block_tree_mock.hpp" -#include "mock/core/crypto/crypto_store_mock.hpp" #include "mock/core/crypto/ed25519_provider_mock.hpp" +#include "mock/core/crypto/key_store_mock.hpp" #include "mock/core/crypto/sr25519_provider_mock.hpp" #include "mock/core/runtime/authority_discovery_api_mock.hpp" #include "mock/libp2p/protocol/kademlia/kademlia_mock.hpp" @@ -25,10 +25,10 @@ using kagome::application::AppConfigurationMock; using kagome::application::AppStateManagerMock; using kagome::authority_discovery::AddressPublisher; using kagome::blockchain::BlockTreeMock; -using kagome::crypto::CryptoStoreMock; using kagome::crypto::Ed25519PrivateKey; using kagome::crypto::Ed25519ProviderMock; using kagome::crypto::Ed25519PublicKey; +using kagome::crypto::KeyStoreMock; using kagome::crypto::SecureBuffer; using kagome::crypto::SessionKeysImpl; using kagome::crypto::Sr25519Keypair; @@ -100,8 +100,8 @@ struct AddressPublisherTest : public testing::Test { std::shared_ptr host_ = std::make_shared(); std::shared_ptr kademlia_ = std::make_shared(); std::shared_ptr scheduler_ = std::make_shared(); - std::shared_ptr crypto_store_ = - std::make_shared(); + std::shared_ptr crypto_store_ = + std::make_shared(); PeerInfo peer_info_{ PeerId::fromBase58("12D3KooWGYLoNGrZn2nwewBiPFZuKHZebPDL9QAF26cVgLxwuiTZ") .value(), @@ -118,9 +118,9 @@ struct AddressPublisherTest : public testing::Test { */ TEST_F(AddressPublisherTest, Success) { EXPECT_CALL(*host_, getPeerInfo()).WillOnce(Return(peer_info_)); - EXPECT_CALL(*crypto_store_, getSr25519PublicKeys(_)) + EXPECT_CALL(crypto_store_->sr25519(), getPublicKeys(_)) .WillOnce(Return(std::vector{audi_key_})); - EXPECT_CALL(*crypto_store_, findSr25519Keypair(_, _)) + EXPECT_CALL(crypto_store_->sr25519(), findKeypair(_, _)) .WillOnce(Return(Sr25519Keypair{})); EXPECT_CALL(*block_tree_, bestBlock()); EXPECT_CALL(*authority_discovery_api_, authorities(_)) diff --git a/test/core/crypto/crypto_store/CMakeLists.txt b/test/core/crypto/crypto_store/CMakeLists.txt index 63b9db4076..77dc305f84 100644 --- a/test/core/crypto/crypto_store/CMakeLists.txt +++ b/test/core/crypto/crypto_store/CMakeLists.txt @@ -8,14 +8,14 @@ addtest(key_type_test key_type_test.cpp ) target_link_libraries(key_type_test - crypto_store_key_type + key_store ) addtest(crypto_store_test crypto_store_test.cpp ) target_link_libraries(crypto_store_test - crypto_store + key_store base_fs_test ) @@ -24,6 +24,6 @@ addtest(session_keys_test ) target_link_libraries(session_keys_test - crypto_store + key_store log_configurator ) diff --git a/test/core/crypto/crypto_store/crypto_store_test.cpp b/test/core/crypto/crypto_store/crypto_store_test.cpp index 41b75097b5..4a1264b97f 100644 --- a/test/core/crypto/crypto_store/crypto_store_test.cpp +++ b/test/core/crypto/crypto_store/crypto_store_test.cpp @@ -4,9 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "crypto/crypto_store/crypto_store_impl.hpp" +#include "crypto/key_store/key_store_impl.hpp" #include +#include #include "crypto/bip39/impl/bip39_provider_impl.hpp" #include "crypto/ecdsa/ecdsa_provider_impl.hpp" @@ -16,6 +17,8 @@ #include "crypto/random_generator/boost_generator.hpp" #include "crypto/sr25519/sr25519_provider_impl.hpp" +#include "mock/core/application/app_state_manager_mock.hpp" + #include "testutil/outcome.hpp" #include "testutil/prepare_loggers.hpp" #include "testutil/storage/base_fs_test.hpp" @@ -25,23 +28,21 @@ using kagome::common::Buffer; using kagome::crypto::Bip39Provider; using kagome::crypto::Bip39ProviderImpl; using kagome::crypto::BoostRandomGenerator; -using kagome::crypto::CryptoStore; -using kagome::crypto::CryptoStoreError; -using kagome::crypto::CryptoStoreImpl; using kagome::crypto::EcdsaKeypair; using kagome::crypto::EcdsaPrivateKey; using kagome::crypto::EcdsaProvider; using kagome::crypto::EcdsaProviderImpl; using kagome::crypto::EcdsaPublicKey; -using kagome::crypto::EcdsaSuite; using kagome::crypto::Ed25519Keypair; using kagome::crypto::Ed25519PrivateKey; using kagome::crypto::Ed25519Provider; using kagome::crypto::Ed25519ProviderImpl; using kagome::crypto::Ed25519PublicKey; using kagome::crypto::Ed25519Seed; -using kagome::crypto::Ed25519Suite; using kagome::crypto::HasherImpl; +using kagome::crypto::KeyStore; +using kagome::crypto::KeyStoreError; +using kagome::crypto::KeySuiteStoreImpl; using kagome::crypto::KeyType; using kagome::crypto::KeyTypes; using kagome::crypto::Pbkdf2Provider; @@ -53,18 +54,17 @@ using kagome::crypto::Sr25519ProviderImpl; using kagome::crypto::Sr25519PublicKey; using kagome::crypto::Sr25519SecretKey; using kagome::crypto::Sr25519Seed; -using kagome::crypto::Sr25519Suite; using std::string_literals::operator""s; -static CryptoStoreImpl::Path crypto_store_test_directory = +static auto crypto_store_test_directory = kagome::filesystem::temp_directory_path() / "crypto_store_test"; -struct CryptoStoreTest : public test::BaseFS_Test { +struct KeyStoreTest : public test::BaseFS_Test { static void SetUpTestCase() { testutil::prepareLoggers(); } - CryptoStoreTest() + KeyStoreTest() : BaseFS_Test(crypto_store_test_directory), ed_pair{ .secret_key = Ed25519PrivateKey::fromHex( @@ -87,14 +87,26 @@ struct CryptoStoreTest : public test::BaseFS_Test { auto pbkdf2_provider = std::make_shared(); bip39_provider = std::make_shared(std::move(pbkdf2_provider), hasher); - crypto_store = std::make_shared( - std::make_shared(std::move(ecdsa_provider)), - std::make_shared(std::move(ed25519_provider)), - std::make_shared(std::move(sr25519_provider)), - bip39_provider, - csprng, + std::shared_ptr key_file_storage = kagome::crypto::KeyFileStorage::createAt(crypto_store_test_directory) - .value()); + .value(); + KeyStore::Config config{crypto_store_test_directory}; + key_store = std::make_shared( + std::make_unique>( + std::move(sr25519_provider), + bip39_provider, + csprng, + key_file_storage), + std::make_unique>( + ed25519_provider, bip39_provider, csprng, key_file_storage), + std::make_unique>( + std::move(ecdsa_provider), + bip39_provider, + csprng, + key_file_storage), + ed25519_provider, + std::make_shared(), + config); mnemonic = "ozone drill grab fiber curtain grace pudding thank cruise elder eight " @@ -126,7 +138,7 @@ struct CryptoStoreTest : public test::BaseFS_Test { } std::shared_ptr bip39_provider; - std::shared_ptr crypto_store; + std::shared_ptr key_store; std::string mnemonic; Buffer entropy; Blob<32> seed; @@ -137,23 +149,21 @@ struct CryptoStoreTest : public test::BaseFS_Test { }; /** - * @given cryptostore instance, type, mnemonic and predefined key pair + * @given KeyStore instance, type, mnemonic and predefined key pair * @when generateEd25519Keypair is called * @then method call succeeds and result matches predefined key pair * @and generated key pair is stored in memory */ -TEST_F(CryptoStoreTest, generateEd25519KeypairMnemonicSuccess) { - EXPECT_OUTCOME_FALSE( - err, crypto_store->findEd25519Keypair(key_type, ed_pair.public_key)); - ASSERT_EQ(err, CryptoStoreError::KEY_NOT_FOUND); +TEST_F(KeyStoreTest, generateEd25519KeypairMnemonicSuccess) { + auto res = key_store->ed25519().findKeypair(key_type, ed_pair.public_key); + ASSERT_EQ(res, std::nullopt); EXPECT_OUTCOME_TRUE(pair, - crypto_store->generateEd25519Keypair(key_type, mnemonic)); + key_store->ed25519().generateKeypair(key_type, mnemonic)); ASSERT_EQ(pair, ed_pair); // check that created pair is now contained in memory - EXPECT_OUTCOME_TRUE( - found, crypto_store->findEd25519Keypair(key_type, pair.public_key)); + auto found = key_store->ed25519().findKeypair(key_type, pair.public_key); ASSERT_EQ(found, pair); // not stored on disk @@ -161,67 +171,62 @@ TEST_F(CryptoStoreTest, generateEd25519KeypairMnemonicSuccess) { } /** - * @given cryptostore instance, type, mnemonic and predefined key pair + * @given KeyStore instance, type, mnemonic and predefined key pair * @when generateSr25519Keypair is called * @then method call succeeds and result matches predefined key pair * @and generated key pair is stored in memory */ -TEST_F(CryptoStoreTest, generateSr25519KeypairMnemonicSuccess) { +TEST_F(KeyStoreTest, generateSr25519KeypairMnemonicSuccess) { EXPECT_OUTCOME_TRUE(pair, - crypto_store->generateSr25519Keypair(key_type, mnemonic)); + key_store->sr25519().generateKeypair(key_type, mnemonic)); ASSERT_EQ(pair, sr_pair); // check that created pair is now contained in memory - EXPECT_OUTCOME_TRUE( - found, crypto_store->findSr25519Keypair(key_type, pair.public_key)); + auto found = key_store->sr25519().findKeypair(key_type, pair.public_key); ASSERT_EQ(found, pair); // not stored on disk ASSERT_FALSE(isStoredOnDisk(key_type, pair.public_key)); } /** - * @given cryptostore instance, type, seed and predefined key pair + * @given KeyStore instance, type, seed and predefined key pair * @when generateEd25519Keypair is called * @then method call succeeds and result matches predefined key pair * @and generated key pair is stored in memory */ -TEST_F(CryptoStoreTest, generateEd25519KeypairSeedSuccess) { - EXPECT_OUTCOME_FALSE( - err, crypto_store->findEd25519Keypair(key_type, ed_pair.public_key)); - ASSERT_EQ(err, CryptoStoreError::KEY_NOT_FOUND); +TEST_F(KeyStoreTest, generateEd25519KeypairSeedSuccess) { + auto res = key_store->ed25519().findKeypair(key_type, ed_pair.public_key); + ASSERT_EQ(res, std::nullopt); EXPECT_OUTCOME_TRUE(pair, - crypto_store->generateEd25519Keypair( + key_store->ed25519().generateKeypair( key_type, Ed25519Seed::from(SecureCleanGuard{seed}))); ASSERT_EQ(pair, ed_pair); // check that created pair is now contained in memory - EXPECT_OUTCOME_TRUE( - found, crypto_store->findEd25519Keypair(key_type, pair.public_key)); + auto found = key_store->ed25519().findKeypair(key_type, pair.public_key); ASSERT_EQ(found, pair); // not stored on disk ASSERT_FALSE(isStoredOnDisk(key_type, pair.public_key)); } /** - * @given cryptostore instance, type, seed and predefined key pair + * @given KeyStore instance, type, seed and predefined key pair * @when generateSr25519Keypair is called * @then method call succeeds and result matches predefined key pair * @and key generated pair is stored in memory */ -TEST_F(CryptoStoreTest, generateSr25519KeypairSeedSuccess) { - EXPECT_OUTCOME_FALSE( - err, crypto_store->findSr25519Keypair(key_type, sr_pair.public_key)); - ASSERT_EQ(err, CryptoStoreError::KEY_NOT_FOUND); +TEST_F(KeyStoreTest, generateSr25519KeypairSeedSuccess) { + auto res = key_store->sr25519().findKeypair(key_type, sr_pair.public_key); + ASSERT_EQ(res, std::nullopt); EXPECT_OUTCOME_TRUE(pair, - crypto_store->generateSr25519Keypair( + key_store->sr25519().generateKeypair( key_type, Sr25519Seed::from(SecureCleanGuard{seed}))); ASSERT_EQ(pair, sr_pair); // check that created pair is now contained in memory - EXPECT_OUTCOME_TRUE( - found, crypto_store->findSr25519Keypair(key_type, pair.public_key)); + auto found = key_store->sr25519().findKeypair(key_type, pair.public_key); ASSERT_EQ(found, pair); // not stored on disk @@ -229,17 +234,16 @@ TEST_F(CryptoStoreTest, generateSr25519KeypairSeedSuccess) { } /** - * @given cryptostore instance, and key type + * @given KeyStore instance, and key type * @when call generateEd25519KeypairOnDisk(key_type) * @then a new ed25519 key pair is generated and stored on disk */ -TEST_F(CryptoStoreTest, generateEd25519KeypairStoreSuccess) { +TEST_F(KeyStoreTest, generateEd25519KeypairStoreSuccess) { EXPECT_OUTCOME_TRUE(pair, - crypto_store->generateEd25519KeypairOnDisk(key_type)); + key_store->ed25519().generateKeypairOnDisk(key_type)); // check that created pair is contained in the storage on disk - EXPECT_OUTCOME_TRUE( - found, crypto_store->findEd25519Keypair(key_type, pair.public_key)); + auto found = key_store->ed25519().findKeypair(key_type, pair.public_key); ASSERT_EQ(found, pair); // stored on disk @@ -247,17 +251,16 @@ TEST_F(CryptoStoreTest, generateEd25519KeypairStoreSuccess) { } /** - * @given cryptostore instance, and key type + * @given KeyStore instance, and key type * @when call generateSr25519KeypairOnDisk(key_type) * @then a new ed25519 key pair is generated and stored on disk */ -TEST_F(CryptoStoreTest, generateSr25519KeypairStoreSuccess) { +TEST_F(KeyStoreTest, generateSr25519KeypairStoreSuccess) { EXPECT_OUTCOME_TRUE(pair, - crypto_store->generateSr25519KeypairOnDisk(key_type)); + key_store->sr25519().generateKeypairOnDisk(key_type)); // check that created pair is contained in the storage on disk - EXPECT_OUTCOME_TRUE( - found, crypto_store->findSr25519Keypair(key_type, pair.public_key)); + auto found = key_store->sr25519().findKeypair(key_type, pair.public_key); ASSERT_EQ(found, pair); // stored on disk @@ -265,75 +268,48 @@ TEST_F(CryptoStoreTest, generateSr25519KeypairStoreSuccess) { } /** - * @given cryptostore instance, and key type + * @given KeyStore instance, and key type * @when call getEd25519PublicKeys * @then collection of all ed25519 public keys of provided type is returned */ -TEST_F(CryptoStoreTest, getEd25519PublicKeysSuccess) { +TEST_F(KeyStoreTest, getEd25519PublicKeysSuccess) { EXPECT_OUTCOME_TRUE( - pair1, crypto_store->generateEd25519KeypairOnDisk(KeyTypes::BABE)); + pair1, key_store->ed25519().generateKeypairOnDisk(KeyTypes::BABE)); EXPECT_OUTCOME_TRUE( - pair2, crypto_store->generateEd25519KeypairOnDisk(KeyTypes::BABE)); + pair2, key_store->ed25519().generateKeypairOnDisk(KeyTypes::BABE)); EXPECT_OUTCOME_SUCCESS( - pair4, crypto_store->generateSr25519KeypairOnDisk(KeyTypes::BABE)); + pair4, key_store->sr25519().generateKeypairOnDisk(KeyTypes::BABE)); EXPECT_OUTCOME_SUCCESS( - pair5, crypto_store->generateSr25519KeypairOnDisk(KeyTypes::ACCOUNT)); + pair5, key_store->sr25519().generateKeypairOnDisk(KeyTypes::ACCOUNT)); std::set ed_babe_keys_set = {pair1.public_key, pair2.public_key}; std::vector ed_babe_keys(ed_babe_keys_set.begin(), ed_babe_keys_set.end()); - auto keys = crypto_store->getEd25519PublicKeys(KeyTypes::BABE).value(); + auto keys = key_store->ed25519().getPublicKeys(KeyTypes::BABE).value(); ASSERT_THAT(keys, testing::UnorderedElementsAreArray(ed_babe_keys)); } /** - * @given cryptostore instance, and key type + * @given KeyStore instance, and key type * @when call getSr25519PublicKeys * @then collection of all sr25519 public keys of provided type is returned */ -TEST_F(CryptoStoreTest, getSr25519PublicKeysSuccess) { +TEST_F(KeyStoreTest, getSr25519PublicKeysSuccess) { EXPECT_OUTCOME_TRUE( - pair1, crypto_store->generateSr25519KeypairOnDisk(KeyTypes::BABE)); + pair1, key_store->sr25519().generateKeypairOnDisk(KeyTypes::BABE)); EXPECT_OUTCOME_TRUE( - pair2, crypto_store->generateSr25519KeypairOnDisk(KeyTypes::BABE)); + pair2, key_store->sr25519().generateKeypairOnDisk(KeyTypes::BABE)); EXPECT_OUTCOME_SUCCESS( - pair4, crypto_store->generateEd25519KeypairOnDisk(KeyTypes::BABE)); + pair4, key_store->ed25519().generateKeypairOnDisk(KeyTypes::BABE)); EXPECT_OUTCOME_SUCCESS( - pair5, crypto_store->generateEd25519KeypairOnDisk(KeyTypes::ACCOUNT)); + pair5, key_store->ed25519().generateKeypairOnDisk(KeyTypes::ACCOUNT)); std::set sr_babe_keys_set = {pair1.public_key, pair2.public_key}; std::vector sr_babe_keys(sr_babe_keys_set.begin(), sr_babe_keys_set.end()); - auto keys = crypto_store->getSr25519PublicKeys(KeyTypes::BABE).value(); + auto keys = key_store->sr25519().getPublicKeys(KeyTypes::BABE).value(); ASSERT_THAT(keys, testing::UnorderedElementsAreArray(sr_babe_keys)); } - -/** - * Currently incompatible with subkey because subkey doesn't append key type to - * filename - */ -TEST(CryptoStoreCompatibilityTest, DISABLED_SubkeyCompat) { - auto hasher = std::make_shared(); - auto csprng = std::make_shared(); - auto ecdsa_provider = std::make_shared(hasher); - auto ed25519_provider = std::make_shared(hasher); - auto sr25519_provider = std::make_shared(); - - auto pbkdf2_provider = std::make_shared(); - auto bip39_provider = - std::make_shared(std::move(pbkdf2_provider), hasher); - auto keystore_path = kagome::filesystem::path(__FILE__).parent_path() - / "subkey_keys" / "keystore"; - auto crypto_store = std::make_shared( - std::make_shared(std::move(ecdsa_provider)), - std::make_shared(std::move(ed25519_provider)), - std::make_shared(std::move(sr25519_provider)), - bip39_provider, - csprng, - kagome::crypto::KeyFileStorage::createAt(keystore_path).value()); - EXPECT_OUTCOME_TRUE(keys, crypto_store->getEd25519PublicKeys(KeyTypes::BABE)); - ASSERT_EQ(keys.size(), 1); -} diff --git a/test/core/crypto/crypto_store/key_type_test.cpp b/test/core/crypto/crypto_store/key_type_test.cpp index 2c130c261d..1c6e711bbd 100644 --- a/test/core/crypto/crypto_store/key_type_test.cpp +++ b/test/core/crypto/crypto_store/key_type_test.cpp @@ -8,10 +8,8 @@ #include -#include "crypto/crypto_store/key_type.hpp" +#include "crypto/key_store/key_type.hpp" -using kagome::crypto::decodeKeyTypeFromStr; -using kagome::crypto::encodeKeyTypeToStr; using kagome::crypto::KeyType; using kagome::crypto::KeyTypes; @@ -33,7 +31,7 @@ struct KeyTypeTest : public ::testing::TestWithParam< TEST_P(KeyTypeTest, DecodeSuccess) { auto [key_type, repr, should_succeed] = GetParam(); - auto &&key_type_str = encodeKeyTypeToStr(key_type); + auto &&key_type_str = key_type.toString(); if (should_succeed) { ASSERT_EQ(key_type_str, repr); @@ -44,7 +42,7 @@ TEST_P(KeyTypeTest, DecodeSuccess) { TEST_P(KeyTypeTest, EncodeSuccess) { auto [repr, key_type_str, should_succeed] = GetParam(); - auto key_type = decodeKeyTypeFromStr(std::string(key_type_str)); + auto key_type = KeyType::fromString(std::string(key_type_str)); if (should_succeed) { ASSERT_EQ(key_type, repr); diff --git a/test/core/crypto/crypto_store/session_keys_test.cpp b/test/core/crypto/crypto_store/session_keys_test.cpp index 6fb62deb1e..1667457322 100644 --- a/test/core/crypto/crypto_store/session_keys_test.cpp +++ b/test/core/crypto/crypto_store/session_keys_test.cpp @@ -6,9 +6,9 @@ #include -#include "crypto/crypto_store/session_keys.hpp" +#include "crypto/key_store/session_keys.hpp" #include "mock/core/application/app_configuration_mock.hpp" -#include "mock/core/crypto/crypto_store_mock.hpp" +#include "mock/core/crypto/key_store_mock.hpp" #include "testutil/prepare_loggers.hpp" using kagome::application::AppConfigurationMock; @@ -27,7 +27,7 @@ struct SessionKeysTest : public ::testing::Test { } void SetUp() override { - store = std::make_shared(); + store = std::make_shared(); role.flags.authority = 1; EXPECT_CALL(*config, roles()).WillOnce(Return(role)); session_keys = std::make_shared(store, *config); @@ -36,7 +36,7 @@ struct SessionKeysTest : public ::testing::Test { std::shared_ptr config = std::make_shared(); network::Roles role; - std::shared_ptr store; + std::shared_ptr store; std::shared_ptr session_keys; }; @@ -49,10 +49,10 @@ struct SessionKeysTest : public ::testing::Test { TEST_F(SessionKeysTest, SessionKeys) { outcome::result ed_keys_empty = Ed25519Keys{}; outcome::result sr_keys_empty = Sr25519Keys{}; - EXPECT_CALL(*store, getSr25519PublicKeys(KeyType(KeyTypes::BABE))) + EXPECT_CALL(store->sr25519(), getPublicKeys(KeyType(KeyTypes::BABE))) .Times(1) .WillOnce(Return(sr_keys_empty)); - EXPECT_CALL(*store, getEd25519PublicKeys(KeyType(KeyTypes::GRANDPA))) + EXPECT_CALL(store->ed25519(), getPublicKeys(KeyType(KeyTypes::GRANDPA))) .Times(1) .WillOnce(Return(ed_keys_empty)); ASSERT_FALSE(session_keys->getBabeKeyPair({})); @@ -71,10 +71,10 @@ TEST_F(SessionKeysTest, SessionKeys) { outcome::result ed_keys = Ed25519Keys{ed_key}; outcome::result sr_keys = Sr25519Keys{sr_key}; - EXPECT_CALL(*store, getSr25519PublicKeys(KeyType(KeyTypes::BABE))) + EXPECT_CALL(store->sr25519(), getPublicKeys(KeyType(KeyTypes::BABE))) .Times(1) .WillOnce(Return(sr_keys)); - EXPECT_CALL(*store, getEd25519PublicKeys(KeyType(KeyTypes::GRANDPA))) + EXPECT_CALL(store->ed25519(), getPublicKeys(KeyType(KeyTypes::GRANDPA))) .Times(1) .WillOnce(Return(ed_keys)); @@ -91,15 +91,15 @@ TEST_F(SessionKeysTest, SessionKeys) { "35b6d6196f33169334e36a05d624d9996d07243f9f71e638e3bc29a5330ec9"s}) .value(); - outcome::result ed_pair = Ed25519Keypair{ed_priv, ed_key}; - outcome::result sr_pair = Sr25519Keypair{sr_priv, sr_key}; + Ed25519Keypair ed_pair{ed_priv, ed_key}; + Sr25519Keypair sr_pair{sr_priv, sr_key}; - EXPECT_CALL(*store, findSr25519Keypair(KeyType(KeyTypes::BABE), _)) + EXPECT_CALL(store->sr25519(), findKeypair(KeyType(KeyTypes::BABE), _)) .Times(1) - .WillOnce(Return(sr_pair)); - EXPECT_CALL(*store, findEd25519Keypair(KeyType(KeyTypes::GRANDPA), _)) + .WillOnce(Return(OptRef(sr_pair))); + EXPECT_CALL(store->ed25519(), findKeypair(KeyType(KeyTypes::GRANDPA), _)) .Times(1) - .WillOnce(Return(ed_pair)); + .WillOnce(Return(OptRef(ed_pair))); ASSERT_TRUE(session_keys->getBabeKeyPair({{{sr_key}, {}}})); ASSERT_TRUE(session_keys->getGranKeyPair({{}, {{{ed_key}, {}}}})); diff --git a/test/core/crypto/sr25519/sr25519_provider_test.cpp b/test/core/crypto/sr25519/sr25519_provider_test.cpp index 9dcfa03021..79d740f0da 100644 --- a/test/core/crypto/sr25519/sr25519_provider_test.cpp +++ b/test/core/crypto/sr25519/sr25519_provider_test.cpp @@ -75,8 +75,8 @@ struct Sr25519ProviderTest : public ::testing::Test { */ TEST_F(Sr25519ProviderTest, GenerateKeysNotEqual) { for (auto i = 0; i < 10; ++i) { - auto kp1 = generate(); - auto kp2 = generate(); + EXPECT_OUTCOME_TRUE(kp1, generate()); + EXPECT_OUTCOME_TRUE(kp2, generate()); ASSERT_NE(kp1.public_key, kp2.public_key); ASSERT_NE(kp1.secret_key, kp2.secret_key); } @@ -90,7 +90,7 @@ TEST_F(Sr25519ProviderTest, GenerateKeysNotEqual) { * @then verification succeeds */ TEST_F(Sr25519ProviderTest, SignVerifySuccess) { - auto kp = generate(); + EXPECT_OUTCOME_TRUE(kp, generate()); EXPECT_OUTCOME_TRUE(signature, sr25519_provider->sign(kp, message_span)); EXPECT_OUTCOME_TRUE( res, sr25519_provider->verify(signature, message_span, kp.public_key)); @@ -107,7 +107,7 @@ TEST_F(Sr25519ProviderTest, SignVerifySuccess) { * @then sign fails */ TEST_F(Sr25519ProviderTest, DISABLED_SignWithInvalidKeyFails) { - auto kp = generate(); + EXPECT_OUTCOME_TRUE(kp, generate()); kp.public_key.fill(1); EXPECT_OUTCOME_FALSE_1(sr25519_provider->sign(kp, message_span)); } @@ -120,10 +120,10 @@ TEST_F(Sr25519ProviderTest, DISABLED_SignWithInvalidKeyFails) { * @then verification succeeds, but verification result is false */ TEST_F(Sr25519ProviderTest, VerifyWrongKeyFail) { - auto kp = generate(); + EXPECT_OUTCOME_TRUE(kp, generate()); EXPECT_OUTCOME_TRUE(signature, sr25519_provider->sign(kp, message_span)); // generate another valid key pair and take public one - auto kp1 = generate(); + EXPECT_OUTCOME_TRUE(kp1, generate()); EXPECT_OUTCOME_TRUE( ver_res, sr25519_provider->verify(signature, message_span, kp1.public_key)); @@ -143,7 +143,7 @@ TEST_F(Sr25519ProviderTest, VerifyWrongKeyFail) { * @then verification fails */ TEST_F(Sr25519ProviderTest, DISABLED_VerifyInvalidKeyFail) { - auto kp = generate(); + EXPECT_OUTCOME_TRUE(kp, generate()); EXPECT_OUTCOME_TRUE(signature, sr25519_provider->sign(kp, message_span)); // make public key invalid kp.public_key.fill(1); @@ -166,7 +166,7 @@ TEST_F(Sr25519ProviderTest, GenerateBySeedSuccess) { secret_key, Sr25519SecretKey::fromHex(SecureCleanGuard{std::string{hex_sk}})); - auto &&kp = sr25519_provider->generateKeypair(seed, {}); + EXPECT_OUTCOME_TRUE(kp, sr25519_provider->generateKeypair(seed, {})); ASSERT_EQ(kp.secret_key, secret_key); ASSERT_EQ(kp.public_key, public_key); @@ -180,8 +180,10 @@ TEST_F(Sr25519ProviderTest, Junctions) { }; auto f = [&](std::string_view phrase, std::string_view pub_str) { auto bip = bip_provider.generateSeed(phrase).value(); - auto keys = sr25519_provider->generateKeypair(Sr25519Seed::from(bip.seed), - bip.junctions); + auto keys = + sr25519_provider + ->generateKeypair(Sr25519Seed::from(bip.seed), bip.junctions) + .value(); EXPECT_EQ(keys.public_key.toHex(), pub_str); }; f("//Alice", diff --git a/test/core/host_api/crypto_extension_test.cpp b/test/core/host_api/crypto_extension_test.cpp index b57b4e37f1..96713ea2f4 100644 --- a/test/core/host_api/crypto_extension_test.cpp +++ b/test/core/host_api/crypto_extension_test.cpp @@ -11,14 +11,14 @@ #include #include -#include "crypto/crypto_store/crypto_store_impl.hpp" #include "crypto/ecdsa/ecdsa_provider_impl.hpp" #include "crypto/ed25519/ed25519_provider_impl.hpp" #include "crypto/hasher/hasher_impl.hpp" +#include "crypto/key_store/key_store_impl.hpp" #include "crypto/random_generator/boost_generator.hpp" #include "crypto/secp256k1/secp256k1_provider_impl.hpp" #include "crypto/sr25519/sr25519_provider_impl.hpp" -#include "mock/core/crypto/crypto_store_mock.hpp" +#include "mock/core/crypto/key_store_mock.hpp" #include "mock/core/runtime/memory_provider_mock.hpp" #include "runtime/ptr_size.hpp" #include "scale/scale.hpp" @@ -32,8 +32,6 @@ using kagome::common::Blob; using kagome::common::Buffer; using kagome::common::BufferView; using kagome::crypto::BoostRandomGenerator; -using kagome::crypto::CryptoStore; -using kagome::crypto::CryptoStoreMock; using kagome::crypto::CSPRNG; using kagome::crypto::EcdsaKeypair; using kagome::crypto::EcdsaPrivateKey; @@ -50,6 +48,9 @@ using kagome::crypto::Ed25519Seed; using kagome::crypto::Ed25519Signature; using kagome::crypto::Hasher; using kagome::crypto::HasherImpl; +using kagome::crypto::KeyStore; +using kagome::crypto::KeyStoreMock; +using kagome::crypto::KeySuiteStoreMock; using kagome::crypto::KeyType; using kagome::crypto::KeyTypes; using kagome::crypto::Secp256k1Provider; @@ -98,14 +99,14 @@ class CryptoExtensionTest : public ::testing::Test { ed25519_provider_ = std::make_shared(hasher_); secp256k1_provider_ = std::make_shared(); - crypto_store_ = std::make_shared(); + key_store_ = std::make_shared(); crypto_ext_ = std::make_shared(memory_provider_, sr25519_provider_, ecdsa_provider_, ed25519_provider_, secp256k1_provider_, hasher_, - crypto_store_); + key_store_); EXPECT_OUTCOME_TRUE(seed_tmp, kagome::common::Blob<32>::fromHexWithPrefix(seed_hex)); @@ -117,8 +118,10 @@ class CryptoExtensionTest : public ::testing::Test { std::optional optional_mnemonic(mnemonic); mnemonic_buffer.put(scale::encode(optional_mnemonic).value()); - sr25519_keypair = sr25519_provider_->generateKeypair( - Sr25519Seed::from(SecureCleanGuard{seed}), {}); + sr25519_keypair = + sr25519_provider_ + ->generateKeypair(Sr25519Seed::from(SecureCleanGuard{seed}), {}) + .value(); sr25519_signature = sr25519_provider_->sign(sr25519_keypair, input).value(); ed25519_keypair = @@ -199,7 +202,7 @@ class CryptoExtensionTest : public ::testing::Test { std::shared_ptr ed25519_provider_; std::shared_ptr secp256k1_provider_; std::shared_ptr hasher_; - std::shared_ptr crypto_store_; + std::shared_ptr key_store_; std::shared_ptr crypto_ext_; KeyType key_type = KeyTypes::BABE; @@ -445,7 +448,7 @@ TEST_F(CryptoExtensionTest, Secp256k1RecoverCompressedFailure) { * @then we get serialized set of existing ed25519 keys */ TEST_F(CryptoExtensionTest, Ed25519GetPublicKeysSuccess) { - EXPECT_CALL(*crypto_store_, getEd25519PublicKeys(key_type)) + EXPECT_CALL(key_store_->ed25519(), getPublicKeys(key_type)) .WillOnce(Return(ed_public_keys)); ASSERT_EQ(memory_[crypto_ext_->ext_crypto_ed25519_public_keys_version_1( @@ -459,7 +462,7 @@ TEST_F(CryptoExtensionTest, Ed25519GetPublicKeysSuccess) { * @then we get serialized set of existing sr25519 keys */ TEST_F(CryptoExtensionTest, Sr25519GetPublicKeysSuccess) { - EXPECT_CALL(*crypto_store_, getSr25519PublicKeys(key_type)) + EXPECT_CALL(key_store_->sr25519(), getPublicKeys(key_type)) .WillOnce(Return(sr_public_keys)); ASSERT_EQ(memory_[crypto_ext_->ext_crypto_sr25519_public_keys_version_1( @@ -473,8 +476,8 @@ TEST_F(CryptoExtensionTest, Sr25519GetPublicKeysSuccess) { * @then we get a valid signature */ TEST_F(CryptoExtensionTest, Ed25519SignSuccess) { - EXPECT_CALL(*crypto_store_, - findEd25519Keypair(key_type, ed25519_keypair.public_key)) + EXPECT_CALL(key_store_->ed25519(), + findKeypair(key_type, ed25519_keypair.public_key)) .WillOnce(Return(ed25519_keypair)); ASSERT_EQ(memory_[crypto_ext_->ext_crypto_ed25519_sign_version_1( @@ -491,10 +494,9 @@ TEST_F(CryptoExtensionTest, Ed25519SignSuccess) { * @then we get a valid serialized error */ TEST_F(CryptoExtensionTest, Ed25519SignFailure) { - EXPECT_CALL(*crypto_store_, - findEd25519Keypair(key_type, ed25519_keypair.public_key)) - .WillOnce(Return( - outcome::failure(kagome::crypto::CryptoStoreError::KEY_NOT_FOUND))); + EXPECT_CALL(key_store_->ed25519(), + findKeypair(key_type, ed25519_keypair.public_key)) + .WillOnce(Return(std::nullopt)); ASSERT_EQ(memory_[crypto_ext_->ext_crypto_ed25519_sign_version_1( memory_.store32u(key_type), @@ -509,8 +511,8 @@ TEST_F(CryptoExtensionTest, Ed25519SignFailure) { * @then we get a valid signature */ TEST_F(CryptoExtensionTest, Sr25519SignSuccess) { - EXPECT_CALL(*crypto_store_, - findSr25519Keypair(key_type, sr25519_keypair.public_key)) + EXPECT_CALL(key_store_->sr25519(), + findKeypair(key_type, sr25519_keypair.public_key)) .WillOnce(Return(sr25519_keypair)); auto sig = memory_ @@ -531,10 +533,9 @@ TEST_F(CryptoExtensionTest, Sr25519SignSuccess) { * @then we get a valid serialized error */ TEST_F(CryptoExtensionTest, Sr25519SignFailure) { - EXPECT_CALL(*crypto_store_, - findSr25519Keypair(key_type, sr25519_keypair.public_key)) - .WillOnce(Return( - outcome::failure(kagome::crypto::CryptoStoreError::KEY_NOT_FOUND))); + EXPECT_CALL(key_store_->sr25519(), + findKeypair(key_type, sr25519_keypair.public_key)) + .WillOnce(Return(std::nullopt)); ASSERT_EQ(memory_[crypto_ext_->ext_crypto_sr25519_sign_version_1( memory_.store32u(key_type), @@ -549,8 +550,8 @@ TEST_F(CryptoExtensionTest, Sr25519SignFailure) { * @then a new ed25519 keypair is successfully generated and stored */ TEST_F(CryptoExtensionTest, Ed25519GenerateByHexSeedSuccess) { - EXPECT_CALL(*crypto_store_, - generateEd25519Keypair(key_type, std::string_view(mnemonic))) + EXPECT_CALL(key_store_->ed25519(), + generateKeypair(key_type, std::string_view(mnemonic))) .WillOnce(Return(ed25519_keypair)); bytesN(crypto_ext_->ext_crypto_ed25519_generate_version_1( memory_.store32u(key_type), memory_[mnemonic_buffer]), @@ -563,8 +564,8 @@ TEST_F(CryptoExtensionTest, Ed25519GenerateByHexSeedSuccess) { * @then a new ed25519 keypair is successfully generated and stored */ TEST_F(CryptoExtensionTest, Ed25519GenerateByMnemonicSuccess) { - EXPECT_CALL(*crypto_store_, - generateEd25519Keypair(key_type, std::string_view(mnemonic))) + EXPECT_CALL(key_store_->ed25519(), + generateKeypair(key_type, std::string_view(mnemonic))) .WillOnce(Return(ed25519_keypair)); bytesN(crypto_ext_->ext_crypto_ed25519_generate_version_1( memory_.store32u(key_type), memory_[mnemonic_buffer]), @@ -577,8 +578,8 @@ TEST_F(CryptoExtensionTest, Ed25519GenerateByMnemonicSuccess) { * @then a new sr25519 keypair is successfully generated and stored */ TEST_F(CryptoExtensionTest, Sr25519GenerateByHexSeedSuccess) { - EXPECT_CALL(*crypto_store_, - generateSr25519Keypair(key_type, std::string_view(mnemonic))) + EXPECT_CALL(key_store_->sr25519(), + generateKeypair(key_type, std::string_view(mnemonic))) .WillOnce(Return(sr25519_keypair)); bytesN(crypto_ext_->ext_crypto_sr25519_generate_version_1( memory_.store32u(key_type), memory_[mnemonic_buffer]), @@ -591,8 +592,8 @@ TEST_F(CryptoExtensionTest, Sr25519GenerateByHexSeedSuccess) { * @then a new sr25519 keypair is successfully generated and stored */ TEST_F(CryptoExtensionTest, Sr25519GenerateByMnemonicSuccess) { - EXPECT_CALL(*crypto_store_, - generateSr25519Keypair(key_type, std::string_view(mnemonic))) + EXPECT_CALL(key_store_->sr25519(), + generateKeypair(key_type, std::string_view(mnemonic))) .WillOnce(Return(sr25519_keypair)); bytesN(crypto_ext_->ext_crypto_sr25519_generate_version_1( memory_.store32u(key_type), memory_[mnemonic_buffer]), diff --git a/test/core/injector/application_injector_test.cpp b/test/core/injector/application_injector_test.cpp index 1aa519fa22..3ef88a4201 100644 --- a/test/core/injector/application_injector_test.cpp +++ b/test/core/injector/application_injector_test.cpp @@ -42,7 +42,7 @@ namespace { kagome::crypto::SecureCleanGuard{random_generator->randomBytes( kagome::crypto::constants::sr25519::SEED_SIZE)}) .value(); - auto babe = sr25519_provider->generateKeypair(seed, {}); + auto babe = sr25519_provider->generateKeypair(seed, {}).value(); auto babe_path = (keystore_dir / fmt::format("babe{}", babe.public_key.toHex())) .native(); @@ -69,7 +69,7 @@ namespace { kagome::crypto::SecureCleanGuard{random_generator->randomBytes( kagome::crypto::constants::sr25519::SEED_SIZE)}) .value(); - auto libp2p = sr25519_provider->generateKeypair(seed, {}); + auto libp2p = sr25519_provider->generateKeypair(seed, {}).value(); auto libp2p_path = (keystore_dir / fmt::format("lp2p{}", libp2p.public_key.toHex())) .native(); diff --git a/test/core/parachain/CMakeLists.txt b/test/core/parachain/CMakeLists.txt index 341048212b..02a5957dd7 100644 --- a/test/core/parachain/CMakeLists.txt +++ b/test/core/parachain/CMakeLists.txt @@ -17,7 +17,7 @@ addtest(assignments_test assignments.cpp ) target_link_libraries(assignments_test - crypto_store + key_store base_fs_test validator_parachain ) diff --git a/test/core/parachain/assignments.cpp b/test/core/parachain/assignments.cpp index fccc4181a0..140ca36e34 100644 --- a/test/core/parachain/assignments.cpp +++ b/test/core/parachain/assignments.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "crypto/crypto_store/crypto_store_impl.hpp" +#include "crypto/key_store/key_store_impl.hpp" #include @@ -15,6 +15,8 @@ #include "crypto/pbkdf2/impl/pbkdf2_provider_impl.hpp" #include "crypto/random_generator/boost_generator.hpp" #include "crypto/sr25519/sr25519_provider_impl.hpp" +#include "crypto/sr25519_types.hpp" +#include "mock/core/application/app_state_manager_mock.hpp" #include #include @@ -30,7 +32,7 @@ using kagome::common::Blob; using kagome::common::Buffer; using namespace kagome::crypto; -static CryptoStoreImpl::Path assignments_directory = +static auto assignments_directory = kagome::filesystem::temp_directory_path() / "assignments_test"; struct AssignmentsTest : public test::BaseFS_Test { @@ -43,21 +45,26 @@ struct AssignmentsTest : public test::BaseFS_Test { void SetUp() override {} template - auto assignment_keys_plus_random(std::shared_ptr &cs, + auto assignment_keys_plus_random(std::shared_ptr &cs, const char *const (&accounts)[N], size_t random) { + std::vector keys; for (const auto &acc : accounts) { - std::ignore = cs->generateSr25519Keypair(KeyTypes::ASSIGNMENT, - std::string_view{acc}) - .value(); + auto keypair = + cs->sr25519() + .generateKeypair(KeyTypes::ASSIGNMENT, std::string_view{acc}) + .value(); + keys.push_back(keypair.public_key); } for (size_t ix = 0ull; ix < random; ++ix) { auto seed = std::to_string(ix); - std::ignore = cs->generateSr25519Keypair(KeyTypes::ASSIGNMENT, - std::string_view{seed}) - .value(); + auto keypair = + cs->sr25519() + .generateKeypair(KeyTypes::ASSIGNMENT, std::string_view{seed}) + .value(); + keys.push_back(keypair.public_key); } - return cs->getSr25519PublicKeys(KeyTypes::ASSIGNMENT).value(); + return keys; } auto create_crypto_store() { @@ -73,14 +80,25 @@ struct AssignmentsTest : public test::BaseFS_Test { auto keystore_path = kagome::filesystem::path(__FILE__).parent_path() / "subkey_keys" / "keystore"; - - return std::make_shared( - std::make_shared(std::move(ecdsa_provider)), - std::make_shared(std::move(ed25519_provider)), - std::make_shared(std::move(sr25519_provider)), - bip39_provider, - csprng, - kagome::crypto::KeyFileStorage::createAt(keystore_path).value()); + std::shared_ptr key_file_storage = + kagome::crypto::KeyFileStorage::createAt(keystore_path).value(); + KeyStore::Config config{keystore_path}; + return std::make_shared( + std::make_unique>( + std::move(sr25519_provider), + bip39_provider, + csprng, + key_file_storage), + std::make_unique>( + ed25519_provider, bip39_provider, csprng, key_file_storage), + std::make_unique>( + std::move(ecdsa_provider), + bip39_provider, + csprng, + key_file_storage), + ed25519_provider, + std::make_shared(), + config); } }; @@ -102,7 +120,7 @@ TEST_F(AssignmentsTest, succeeds_empty_for_0_cores) { si.n_cores = 0; si.zeroth_delay_tranche_width = 10; - si.relay_vrf_modulo_samples = 3; + si.relay_vrf_modulo_samples = 10; si.n_delay_tranches = 40; kagome::parachain::ApprovalDistribution::CandidateIncludedList @@ -137,20 +155,20 @@ TEST_F(AssignmentsTest, assign_to_nonzero_core) { std::vector{1, 2}); si.n_cores = 2; si.zeroth_delay_tranche_width = 10; - si.relay_vrf_modulo_samples = 3; + si.relay_vrf_modulo_samples = 10; si.n_delay_tranches = 40; kagome::parachain::ApprovalDistribution::CandidateIncludedList leaving_cores = {std::make_tuple( kagome::parachain::ApprovalDistribution::HashedCandidateReceipt{ kagome::network::CandidateReceipt{}}, - (kagome::parachain::CoreIndex)0, - (kagome::parachain::GroupIndex)0), + static_cast(0), + static_cast(0)), std::make_tuple( kagome::parachain::ApprovalDistribution::HashedCandidateReceipt{ kagome::network::CandidateReceipt{}}, - (kagome::parachain::CoreIndex)1, - (kagome::parachain::GroupIndex)1)}; + static_cast(1), + static_cast(1))}; auto assignments = kagome::parachain::ApprovalDistribution::compute_assignments( cs, si, vrf_story, leaving_cores); @@ -208,7 +226,7 @@ TEST_F(AssignmentsTest, assignments_produced_for_non_backing) { std::vector{1, 2}); si.n_cores = 2; si.zeroth_delay_tranche_width = 10; - si.relay_vrf_modulo_samples = 3; + si.relay_vrf_modulo_samples = 10; si.n_delay_tranches = 40; kagome::parachain::ApprovalDistribution::CandidateIncludedList leaving_cores = diff --git a/test/core/runtime/CMakeLists.txt b/test/core/runtime/CMakeLists.txt index 1b31de72a7..442339ce3d 100644 --- a/test/core/runtime/CMakeLists.txt +++ b/test/core/runtime/CMakeLists.txt @@ -81,7 +81,7 @@ target_link_libraries(instance_pool_test addtest(stack_limiter_test stack_limiter_test.cpp) target_link_libraries(stack_limiter_test - runtime_common logger log_configurator + wasm_instrument ) diff --git a/test/core/runtime/binaryen/CMakeLists.txt b/test/core/runtime/binaryen/CMakeLists.txt index 76986e9c5b..cc988c1445 100644 --- a/test/core/runtime/binaryen/CMakeLists.txt +++ b/test/core/runtime/binaryen/CMakeLists.txt @@ -7,7 +7,6 @@ add_library(binaryen_runtime_test INTERFACE) target_link_libraries(binaryen_runtime_test INTERFACE filesystem - key_file_storage sr25519_provider ecdsa_provider ed25519_provider @@ -15,7 +14,7 @@ target_link_libraries(binaryen_runtime_test INTERFACE bip39_provider secp256k1_provider hasher - crypto_store + key_store host_api host_api_factory core_api @@ -86,7 +85,6 @@ addtest(runtime_external_interface_test target_link_libraries(runtime_external_interface_test binaryen_runtime_external_interface executor - constant_code_provider blob logger_for_tests ) diff --git a/test/core/runtime/binaryen/block_builder_api_test.cpp b/test/core/runtime/binaryen/block_builder_api_test.cpp index 2ce37dc100..c3ab1d339c 100644 --- a/test/core/runtime/binaryen/block_builder_api_test.cpp +++ b/test/core/runtime/binaryen/block_builder_api_test.cpp @@ -64,6 +64,7 @@ TEST_F(BlockBuilderApiTest, CheckInherents) { */ TEST_F(BlockBuilderApiTest, ApplyExtrinsic) { preparePersistentStorageExpects(); + prepareEphemeralStorageExpects(); createBlock("block_hash_43"_hash256, 43); auto ctx = ctx_factory_->persistentAt("block_hash_43"_hash256, std::nullopt).value(); @@ -88,6 +89,7 @@ TEST_F(BlockBuilderApiTest, DISABLED_RandomSeed){ */ TEST_F(BlockBuilderApiTest, InherentExtrinsics) { preparePersistentStorageExpects(); + prepareEphemeralStorageExpects(); createBlock("block_hash_44"_hash256, 44); auto ctx = ctx_factory_->persistentAt("block_hash_44"_hash256, std::nullopt).value(); diff --git a/test/core/runtime/binaryen/runtime_external_interface_test.cpp b/test/core/runtime/binaryen/runtime_external_interface_test.cpp index 242e9225e5..5c4ceb40fc 100644 --- a/test/core/runtime/binaryen/runtime_external_interface_test.cpp +++ b/test/core/runtime/binaryen/runtime_external_interface_test.cpp @@ -9,7 +9,7 @@ #include #include -#include "crypto/crypto_store/key_type.hpp" +#include "crypto/key_store/key_type.hpp" #include "mock/core/blockchain/block_header_repository_mock.hpp" #include "mock/core/host_api/host_api_factory_mock.hpp" #include "mock/core/host_api/host_api_mock.hpp" @@ -19,7 +19,6 @@ #include "mock/core/runtime/module_repository_mock.hpp" #include "mock/core/runtime/runtime_context_factory_mock.hpp" #include "mock/core/runtime/trie_storage_provider_mock.hpp" -#include "runtime/common/constant_code_provider.hpp" #include "runtime/common/memory_allocator.hpp" #include "runtime/ptr_size.hpp" #include "testutil/prepare_loggers.hpp" @@ -34,7 +33,6 @@ using kagome::crypto::KeyTypes; using kagome::host_api::HostApi; using kagome::host_api::HostApiFactoryMock; using kagome::host_api::HostApiMock; -using kagome::runtime::ConstantCodeProvider; using kagome::runtime::CoreApiFactoryMock; using kagome::runtime::MemoryProviderMock; using kagome::runtime::ModuleRepositoryMock; @@ -89,8 +87,6 @@ class REITest : public ::testing::Test { storage_provider_ = std::make_shared(); core_api_factory_ = std::make_shared(); memory_provider_ = std::make_shared(); - auto code_provider = - std::make_shared(kagome::common::Buffer{}); auto module_repo = std::make_shared(); auto header_repo = std::make_shared(); } diff --git a/test/core/runtime/binaryen/wasm_memory_test.cpp b/test/core/runtime/binaryen/wasm_memory_test.cpp index 4f3881ab7f..c05ed1df0b 100644 --- a/test/core/runtime/binaryen/wasm_memory_test.cpp +++ b/test/core/runtime/binaryen/wasm_memory_test.cpp @@ -35,10 +35,7 @@ class BinaryenMemoryHeapTest : public ::testing::Test { std::make_unique(host_api); memory_ = std::make_unique( - rei_->getMemory(), - runtime::MemoryConfig{ - kDefaultHeapBase, - runtime::MemoryLimits{.max_memory_pages_num = memory_page_limit_}}); + rei_->getMemory(), runtime::MemoryConfig{kDefaultHeapBase, {}}); } void TearDown() override { diff --git a/test/core/runtime/executor_test.cpp b/test/core/runtime/executor_test.cpp index 255c8632fd..c0a5b5bc6b 100644 --- a/test/core/runtime/executor_test.cpp +++ b/test/core/runtime/executor_test.cpp @@ -119,11 +119,6 @@ class ExecutorTest : public testing::Test { EXPECT_CALL(*storage_provider, setToEphemeralAt(storage_state)) .WillOnce(Return(outcome::success())); } - auto batch = std::make_shared(); - EXPECT_CALL(*storage_provider, getCurrentBatch()).WillOnce(Return(batch)); - static const auto heappages = ":heappages"_buf; - EXPECT_CALL(*batch, tryGetMock(heappages.view())) - .WillOnce(Return(kagome::common::Buffer{})); auto env = std::make_shared( memory_provider, storage_provider, nullptr, nullptr); diff --git a/test/core/runtime/instance_pool_test.cpp b/test/core/runtime/instance_pool_test.cpp index d3ca8d6f5e..a584573a9b 100644 --- a/test/core/runtime/instance_pool_test.cpp +++ b/test/core/runtime/instance_pool_test.cpp @@ -28,6 +28,7 @@ using kagome::runtime::ModuleMock; using kagome::runtime::RuntimeContext; using kagome::runtime::RuntimeInstancesPool; using kagome::runtime::RuntimeInstancesPoolImpl; +using testing::Return; RuntimeInstancesPool::CodeHash make_code_hash(int i) { return RuntimeInstancesPool::CodeHash::fromString( diff --git a/test/core/runtime/runtime_test_base.hpp b/test/core/runtime/runtime_test_base.hpp index 429c4337b7..db4437aa3d 100644 --- a/test/core/runtime/runtime_test_base.hpp +++ b/test/core/runtime/runtime_test_base.hpp @@ -12,10 +12,10 @@ #include #include "crypto/bip39/impl/bip39_provider_impl.hpp" -#include "crypto/crypto_store/crypto_store_impl.hpp" #include "crypto/ecdsa/ecdsa_provider_impl.hpp" #include "crypto/ed25519/ed25519_provider_impl.hpp" #include "crypto/hasher/hasher_impl.hpp" +#include "crypto/key_store/key_store_impl.hpp" #include "crypto/pbkdf2/impl/pbkdf2_provider_impl.hpp" #include "crypto/random_generator/boost_generator.hpp" #include "crypto/secp256k1/secp256k1_provider_impl.hpp" @@ -23,9 +23,9 @@ #include "filesystem/common.hpp" #include "host_api/impl/host_api_factory_impl.hpp" #include "mock/core/application/app_configuration_mock.hpp" +#include "mock/core/application/app_state_manager_mock.hpp" #include "mock/core/blockchain/block_header_repository_mock.hpp" #include "mock/core/blockchain/block_storage_mock.hpp" -#include "mock/core/crypto/hasher_mock.hpp" #include "mock/core/offchain/offchain_persistent_storage_mock.hpp" #include "mock/core/offchain/offchain_worker_pool_mock.hpp" #include "mock/core/runtime/runtime_properties_cache_mock.hpp" @@ -46,6 +46,7 @@ #include "runtime/executor.hpp" #include "runtime/module.hpp" #include "runtime/runtime_context.hpp" +#include "runtime/wabt/instrument.hpp" #include "storage/in_memory/in_memory_storage.hpp" #include "testutil/literals.hpp" #include "testutil/outcome.hpp" @@ -82,13 +83,25 @@ class RuntimeTestBase : public ::testing::Test { std::make_shared(pbkdf2_provider, hasher_); auto keystore_path = filesystem::temp_directory_path() / filesystem::unique_path(); - auto crypto_store = std::make_shared( - std::make_shared(ecdsa_provider), - std::make_shared(ed25519_provider), - std::make_shared(sr25519_provider), - bip39_provider, - random_generator, - crypto::KeyFileStorage::createAt(keystore_path).value()); + std::shared_ptr key_file_storage = + kagome::crypto::KeyFileStorage::createAt(keystore_path).value(); + crypto::KeyStore::Config config{keystore_path}; + auto key_store = std::make_shared( + std::make_unique>( + sr25519_provider, + bip39_provider, + random_generator, + key_file_storage), + std::make_unique>( + ed25519_provider, + bip39_provider, + random_generator, + key_file_storage), + std::make_unique>( + ecdsa_provider, bip39_provider, random_generator, key_file_storage), + ed25519_provider, + std::make_shared(), + config); offchain_storage_ = std::make_shared(); offchain_worker_pool_ = @@ -101,7 +114,7 @@ class RuntimeTestBase : public ::testing::Test { ed25519_provider, secp256k1_provider, hasher_, - crypto_store, + key_store, offchain_storage_, offchain_worker_pool_); @@ -126,7 +139,6 @@ class RuntimeTestBase : public ::testing::Test { initStorage(); trie_storage_ = std::make_shared(); serializer_ = std::make_shared(); - hasher_ = std::make_shared(); auto buffer_storage = std::make_shared(); auto spaced_storage = std::make_shared(); @@ -158,9 +170,10 @@ class RuntimeTestBase : public ::testing::Test { auto module_repo = std::make_shared( std::make_shared( module_factory, std::make_shared()), + hasher_, upgrade_tracker, + trie_storage_, module_factory, - std::make_shared(), wasm_provider_); ctx_factory_ = std::make_shared( @@ -204,7 +217,8 @@ class RuntimeTestBase : public ::testing::Test { return cursor; })); static auto heappages_key = ":heappages"_buf; - EXPECT_CALL(batch, tryGetMock(heappages_key.view())); + EXPECT_CALL(batch, tryGetMock(heappages_key.view())) + .Times(testing::AnyNumber()); } primitives::BlockHeader createBlockHeader(const primitives::BlockHash &hash, @@ -249,6 +263,6 @@ class RuntimeTestBase : public ::testing::Test { std::shared_ptr ctx_factory_; std::shared_ptr offchain_storage_; std::shared_ptr offchain_worker_pool_; - std::shared_ptr hasher_; + std::shared_ptr hasher_; std::shared_ptr host_api_factory_; }; diff --git a/test/core/runtime/stack_limiter_test.cpp b/test/core/runtime/stack_limiter_test.cpp index 4b33771c46..c94407bd6e 100644 --- a/test/core/runtime/stack_limiter_test.cpp +++ b/test/core/runtime/stack_limiter_test.cpp @@ -9,18 +9,32 @@ #include #include #include +#include #include #include #include #include +#include "common/bytestr.hpp" #include "log/logger.hpp" -#include "runtime/common/stack_limiter.hpp" +#include "runtime/wabt/instrument.hpp" +#include "runtime/wabt/stack_limiter.hpp" +#include "runtime/wabt/util.hpp" #include "testutil/outcome.hpp" #include "testutil/prepare_loggers.hpp" static constexpr uint32_t ACTIVATION_FRAME_COST = 2; +using kagome::byte2str; +using kagome::HeapAllocStrategy; +using kagome::HeapAllocStrategyDynamic; +using kagome::HeapAllocStrategyStatic; +using kagome::str2byte; +using kagome::runtime::convertMemoryImportIntoExport; +using kagome::runtime::setupMemoryAccordingToHeapAllocStrategy; +using kagome::runtime::wabtDecode; +using kagome::runtime::wabtEncode; + std::unique_ptr wat_to_module(std::span wat) { wabt::Result result; wabt::Errors errors; @@ -52,9 +66,26 @@ std::vector wat_to_wasm(std::span wat) { return std::move(stream.output_buffer().data); } +auto fromWat(std::string_view wat) { + return wat_to_module(str2byte(wat)); +} + +std::string toWat(const wabt::Module &module) { + wabt::MemoryStream s; + EXPECT_TRUE( + wabt::Succeeded(wabt::WriteWat(&s, &module, wabt::WriteWatOptions{}))); + return std::string{byte2str(s.output_buffer().data)}; +} + +void expectWasm(const wabt::Module &actual, std::string_view expected) { + auto expected_fmt = toWat(*fromWat(expected)); + EXPECT_EQ(toWat(actual), expected_fmt); + auto actual2 = wabtDecode(wabtEncode(actual).value()).value(); + EXPECT_EQ(toWat(actual2), expected_fmt); +} + uint32_t compute_cost(std::string_view data) { - auto module = wat_to_module( - std::span{reinterpret_cast(data.data()), data.size()}); + auto module = fromWat(data); EXPECT_OUTCOME_TRUE(cost, kagome::runtime::detail::compute_stack_cost( kagome::log::createLogger("StackLimiterTest"), @@ -213,15 +244,7 @@ TEST_P(StackLimiterCompareTest, output_matches_expected) { throw std::runtime_error{"Failed to read binary module"}; } - wabt::MemoryStream result_stream; - wabt::WriteWat(&result_stream, &result_module, wabt::WriteWatOptions{}); - - wabt::MemoryStream expected_stream; - wabt::WriteWat( - &expected_stream, expected_module.get(), wabt::WriteWatOptions{}); - - if (result_stream.output_buffer().data - != expected_stream.output_buffer().data) { + if (toWat(result_module) != toWat(*expected_module)) { std::filesystem::create_directories(std::filesystem::temp_directory_path() / "kagome_test"); auto base_path = std::filesystem::temp_directory_path() / "kagome_test"; @@ -250,3 +273,52 @@ INSTANTIATE_TEST_SUITE_P(SuiteFromSubstrate, "simple", "start", "table")); + +auto wat_memory_import = R"( + (module + (import "env" "mem" (memory (;0;) 100))) +)"; +auto wat_memory_export = R"( + (module + (memory (;0;) 100) + (export "mem" (memory 0))) +)"; +auto memory_limit_static = std::make_pair(HeapAllocStrategyStatic{100}, R"( + (module + (memory (;0;) 200 200) + (export "mem" (memory 0))) +)"); + +/// Check `convertMemoryImportIntoExport`. +TEST(WasmInstrumentTest, memory_import) { + auto module = fromWat(wat_memory_import); + convertMemoryImportIntoExport(*module).value(); + expectWasm(*module, wat_memory_export); +} + +/// Check `setupMemoryAccordingToHeapAllocStrategy`. +TEST(WasmInstrumentTest, memory_limit) { + auto test = [](HeapAllocStrategy config, std::string_view expected) { + auto module = fromWat(wat_memory_export); + setupMemoryAccordingToHeapAllocStrategy(*module, config).value(); + expectWasm(*module, expected); + }; + test(HeapAllocStrategyDynamic{}, wat_memory_export); + test(HeapAllocStrategyDynamic{200}, R"( + (module + (memory (;0;) 100 200) + (export "mem" (memory 0))) + )"); + test(memory_limit_static.first, memory_limit_static.second); +} + +/// Check both `convertMemoryImportIntoExport` and +/// `setupMemoryAccordingToHeapAllocStrategy` to check wabt encoding +/// consistency. +TEST(WasmInstrumentTest, memory_import_limit) { + auto module = fromWat(wat_memory_import); + convertMemoryImportIntoExport(*module).value(); + setupMemoryAccordingToHeapAllocStrategy(*module, memory_limit_static.first) + .value(); + expectWasm(*module, memory_limit_static.second); +} diff --git a/test/core/runtime/storage_code_provider_test.cpp b/test/core/runtime/storage_code_provider_test.cpp index 34a14e61e8..b644f4c65c 100644 --- a/test/core/runtime/storage_code_provider_test.cpp +++ b/test/core/runtime/storage_code_provider_test.cpp @@ -73,7 +73,7 @@ TEST_F(StorageCodeProviderTest, GetCodeWhenNoStorageUpdates) { wasm_provider->getCodeAt(first_state_root)); // then - ASSERT_TRUE(obtained_state_code == common::BufferView(state_code_)); + EXPECT_EQ(*obtained_state_code, state_code_); } /** @@ -120,5 +120,5 @@ TEST_F(StorageCodeProviderTest, DISABLED_GetCodeWhenStorageUpdates) { wasm_provider->getCodeAt(second_state_root)); // then - ASSERT_EQ(obtained_state_code, common::BufferView(state_code_)); + ASSERT_EQ(*obtained_state_code, state_code_); } diff --git a/test/core/runtime/wavm/CMakeLists.txt b/test/core/runtime/wavm/CMakeLists.txt index a391f98832..0dc9449fbf 100644 --- a/test/core/runtime/wavm/CMakeLists.txt +++ b/test/core/runtime/wavm/CMakeLists.txt @@ -6,7 +6,6 @@ add_library(wavm_runtime_test INTERFACE) target_link_libraries(wavm_runtime_test INTERFACE - key_file_storage sr25519_provider ecdsa_provider ed25519_provider @@ -14,7 +13,7 @@ target_link_libraries(wavm_runtime_test INTERFACE bip39_provider secp256k1_provider hasher - crypto_store + key_store host_api host_api_factory core_api diff --git a/test/core/runtime/wavm/wavm_module_init_test.cpp b/test/core/runtime/wavm/wavm_module_init_test.cpp index 5c9f33b02d..ed6773d752 100644 --- a/test/core/runtime/wavm/wavm_module_init_test.cpp +++ b/test/core/runtime/wavm/wavm_module_init_test.cpp @@ -104,7 +104,7 @@ class WavmModuleInitTest : public ::testing::TestWithParam { .value(); auto csprng = std::make_shared(); - auto crypto_store = std::make_shared( + auto crypto_store = std::make_shared( ecdsa_suite, ed_suite, sr_suite, bip39_provider, csprng, key_fs); rocksdb::Options db_options{}; @@ -134,7 +134,6 @@ class WavmModuleInitTest : public ::testing::TestWithParam { offchain_persistent_storage, offchain_worker_pool); - auto smc = std::make_shared(); auto cache = std::make_shared(); diff --git a/test/core/runtime/wavm/wavm_runtime_test.hpp b/test/core/runtime/wavm/wavm_runtime_test.hpp index 959be259bd..8cd61ae8c6 100644 --- a/test/core/runtime/wavm/wavm_runtime_test.hpp +++ b/test/core/runtime/wavm/wavm_runtime_test.hpp @@ -49,7 +49,6 @@ class WavmRuntimeTest : public RuntimeTestBase { trie_storage_, serializer_, intrinsic_module, - std::make_shared(), std::nullopt, hasher_); diff --git a/test/external-project-test/link_libraries.cmake b/test/external-project-test/link_libraries.cmake index 6827038ee6..d821953d7c 100644 --- a/test/external-project-test/link_libraries.cmake +++ b/test/external-project-test/link_libraries.cmake @@ -21,8 +21,7 @@ function(external_project_link_libraries target prefix) log_configurator host_api_factory chain_spec - crypto_store - key_file_storage + key_store sr25519_provider ed25519_provider pbkdf2_provider diff --git a/test/external-project-test/src/main.cpp b/test/external-project-test/src/main.cpp index 8fefb3a532..0c6af20345 100644 --- a/test/external-project-test/src/main.cpp +++ b/test/external-project-test/src/main.cpp @@ -10,10 +10,10 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -145,19 +146,24 @@ int main() { auto bip39_provider = std::make_shared( pbkdf2_provider, hasher); - auto ecdsa_suite = - std::make_shared(ecdsa_provider); - auto ed_suite = - std::make_shared(ed25519_provider); - auto sr_suite = - std::make_shared(sr25519_provider); + auto key_store_dir = "/tmp/kagome_tmp_key_storage"; std::shared_ptr key_fs = - kagome::crypto::KeyFileStorage::createAt("/tmp/kagome_tmp_key_storage") - .value(); + kagome::crypto::KeyFileStorage::createAt(key_store_dir).value(); auto csprng = std::make_shared(); - auto crypto_store = std::make_shared( - ecdsa_suite, ed_suite, sr_suite, bip39_provider, csprng, key_fs); + auto crypto_store = std::make_shared( + std::make_unique< + kagome::crypto::KeySuiteStoreImpl>( + sr25519_provider, bip39_provider, csprng, key_fs), + std::make_unique< + kagome::crypto::KeySuiteStoreImpl>( + ed25519_provider, bip39_provider, csprng, key_fs), + std::make_unique< + kagome::crypto::KeySuiteStoreImpl>( + ecdsa_provider, bip39_provider, csprng, key_fs), + ed25519_provider, + app_state_manager, + kagome::crypto::KeyStore::Config{key_store_dir}); auto offchain_persistent_storage = std::make_shared( @@ -180,8 +186,6 @@ int main() { auto cache = std::make_shared(); - auto smc = std::make_shared(); - auto instance_env_factory = std::make_shared( trie_storage, serializer, host_api_factory); @@ -195,9 +199,10 @@ int main() { module_factory, std::make_shared()); auto module_repo = std::make_shared( runtime_instances_pool, + hasher, runtime_upgrade_tracker, + trie_storage, module_factory, - smc, code_provider); [[maybe_unused]] auto ctx_factory = diff --git a/test/mock/core/crypto/crypto_store_mock.hpp b/test/mock/core/crypto/crypto_store_mock.hpp deleted file mode 100644 index 4b35b979af..0000000000 --- a/test/mock/core/crypto/crypto_store_mock.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Copyright Quadrivium LLC - * All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "crypto/crypto_store.hpp" - -#include - -namespace kagome::crypto { - class CryptoStoreMock : public CryptoStore { - public: - ~CryptoStoreMock() override = default; - - MOCK_METHOD(outcome::result, - generateEcdsaKeypair, - (KeyType, std::string_view), - (override)); - - MOCK_METHOD(outcome::result, - generateEcdsaKeypair, - (KeyType, const EcdsaSeed &), - (override)); - - MOCK_METHOD(outcome::result, - generateEcdsaKeypairOnDisk, - (KeyType), - (override)); - - MOCK_METHOD(outcome::result, - findEcdsaKeypair, - (KeyType, const EcdsaPublicKey &), - (const, override)); - - MOCK_METHOD(outcome::result, - getEcdsaPublicKeys, - (KeyType), - (const, override)); - - MOCK_METHOD(outcome::result, - generateEd25519Keypair, - (KeyType, std::string_view), - (override)); - - MOCK_METHOD(outcome::result, - generateSr25519Keypair, - (KeyType, std::string_view), - (override)); - - MOCK_METHOD(outcome::result, - generateEd25519Keypair, - (KeyType, const Ed25519Seed &), - (override)); - - MOCK_METHOD(outcome::result, - generateSr25519Keypair, - (KeyType, const Sr25519Seed &), - (override)); - - MOCK_METHOD(outcome::result, - generateEd25519KeypairOnDisk, - (KeyType), - (override)); - - MOCK_METHOD(outcome::result, - generateSr25519KeypairOnDisk, - (KeyType), - (override)); - - MOCK_METHOD(outcome::result, - findEd25519Keypair, - (KeyType, const Ed25519PublicKey &), - (const, override)); - - MOCK_METHOD(outcome::result, - findSr25519Keypair, - (KeyType, const Sr25519PublicKey &), - (const, override)); - - MOCK_METHOD(outcome::result, - getEd25519PublicKeys, - (KeyType), - (const, override)); - - MOCK_METHOD(outcome::result, - getSr25519PublicKeys, - (KeyType), - (const, override)); - - MOCK_METHOD(outcome::result, - loadLibp2pKeypair, - (const Path &), - (const, override)); - }; -} // namespace kagome::crypto diff --git a/test/mock/core/crypto/key_store_mock.hpp b/test/mock/core/crypto/key_store_mock.hpp new file mode 100644 index 0000000000..0dedd5feba --- /dev/null +++ b/test/mock/core/crypto/key_store_mock.hpp @@ -0,0 +1,87 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "crypto/ed25519_provider.hpp" +#include "crypto/key_store.hpp" +#include "mock/core/application/app_state_manager_mock.hpp" +#include "mock/core/crypto/ed25519_provider_mock.hpp" + +#include +#include + +namespace kagome::crypto { + + template + class KeySuiteStoreMock : public KeySuiteStore { + public: + using Keypair = typename T::Keypair; + using PrivateKey = typename T::PrivateKey; + using PublicKey = typename T::PublicKey; + using Seed = typename T::Seed; + + MOCK_METHOD(outcome::result, + generateKeypair, + (KeyType, std::string_view), + (override)); + + MOCK_METHOD(outcome::result, + generateKeypair, + (KeyType, const Seed &seed), + (override)); + + MOCK_METHOD(outcome::result, + generateKeypairOnDisk, + (KeyType), + (override)); + + MOCK_METHOD(OptRef, + findKeypair, + (KeyType, const PublicKey &), + (const, override)); + + MOCK_METHOD(outcome::result>, + getPublicKeys, + (KeyType), + (const, override)); + }; + + class KeyStoreMock : public KeyStore { + public: + KeyStoreMock() + : KeyStore{std::make_unique>(), + std::make_unique>(), + std::make_unique>(), + std::make_shared(), + std::make_shared(), + KeyStore::Config{{}}}, + sr25519_{dynamic_cast &>( + KeyStore ::sr25519())}, + ed25519_{dynamic_cast &>( + KeyStore ::ed25519())}, + ecdsa_{dynamic_cast &>( + KeyStore ::ecdsa())} {} + ~KeyStoreMock() = default; + + KeySuiteStoreMock &sr25519() { + return sr25519_; + } + + KeySuiteStoreMock &ed25519() { + return ed25519_; + } + + KeySuiteStoreMock &ecdsa() { + return ecdsa_; + } + + private: + KeySuiteStoreMock &sr25519_; + KeySuiteStoreMock &ed25519_; + KeySuiteStoreMock &ecdsa_; + }; +} // namespace kagome::crypto diff --git a/test/mock/core/crypto/session_keys_mock.hpp b/test/mock/core/crypto/session_keys_mock.hpp index 42e76c91ec..c3a7345c99 100644 --- a/test/mock/core/crypto/session_keys_mock.hpp +++ b/test/mock/core/crypto/session_keys_mock.hpp @@ -9,7 +9,7 @@ #include #include -#include "crypto/crypto_store/session_keys.hpp" +#include "crypto/key_store/session_keys.hpp" namespace kagome::application { class AppConfiguration; diff --git a/test/mock/core/crypto/sr25519_provider_mock.hpp b/test/mock/core/crypto/sr25519_provider_mock.hpp index d7e7384e2b..fe06fe41a4 100644 --- a/test/mock/core/crypto/sr25519_provider_mock.hpp +++ b/test/mock/core/crypto/sr25519_provider_mock.hpp @@ -11,7 +11,7 @@ namespace kagome::crypto { struct Sr25519ProviderMock : public Sr25519Provider { - MOCK_METHOD(Sr25519Keypair, + MOCK_METHOD(outcome::result, generateKeypair, (const Sr25519Seed &, Junctions), (const, override)); diff --git a/test/mock/core/runtime/instrument_wasm.hpp b/test/mock/core/runtime/instrument_wasm.hpp index 3ceb6e9019..cb297f39a4 100644 --- a/test/mock/core/runtime/instrument_wasm.hpp +++ b/test/mock/core/runtime/instrument_wasm.hpp @@ -6,7 +6,7 @@ #pragma once -#include "runtime/common/stack_limiter.hpp" +#include "runtime/wabt/instrument.hpp" #include diff --git a/test/mock/core/runtime/runtime_instances_pool_mock.hpp b/test/mock/core/runtime/runtime_instances_pool_mock.hpp index e1f5d47637..d60268b47d 100644 --- a/test/mock/core/runtime/runtime_instances_pool_mock.hpp +++ b/test/mock/core/runtime/runtime_instances_pool_mock.hpp @@ -20,23 +20,10 @@ namespace kagome::runtime { common::BufferView code_zstd, const RuntimeContext::ContextParams &config)); - MOCK_METHOD(outcome::result>, - instantiateFromState, - (const TrieHash &state, - const RuntimeContext::ContextParams &config)); - MOCK_METHOD(void, release, (const TrieHash &state, std::shared_ptr &&instance)); - - MOCK_METHOD(std::optional>, - getModule, - (const TrieHash &state)); - - MOCK_METHOD(void, - putModule, - (const TrieHash &state, std::shared_ptr module)); }; } // namespace kagome::runtime diff --git a/test/testutil/runtime/common/basic_code_provider.cpp b/test/testutil/runtime/common/basic_code_provider.cpp index 765ea4e515..8e80c3cff7 100644 --- a/test/testutil/runtime/common/basic_code_provider.cpp +++ b/test/testutil/runtime/common/basic_code_provider.cpp @@ -9,21 +9,21 @@ #include "utils/read_file.hpp" namespace kagome::runtime { - using kagome::common::Buffer; - BasicCodeProvider::BasicCodeProvider(std::string_view path) { initialize(path); } - outcome::result BasicCodeProvider::getCodeAt( + RuntimeCodeProvider::Result BasicCodeProvider::getCodeAt( const storage::trie::RootHash &at) const { return buffer_; } void BasicCodeProvider::initialize(std::string_view path) { - if (not readFile(buffer_, std::string{path})) { + common::Buffer code; + if (not readFile(code, std::string{path})) { throw std::runtime_error("File with test code " + std::string(path) + " not found"); } + buffer_ = std::make_shared(std::move(code)); } } // namespace kagome::runtime diff --git a/test/testutil/runtime/common/basic_code_provider.hpp b/test/testutil/runtime/common/basic_code_provider.hpp index 2b747b3897..2f458c4f00 100644 --- a/test/testutil/runtime/common/basic_code_provider.hpp +++ b/test/testutil/runtime/common/basic_code_provider.hpp @@ -14,15 +14,12 @@ namespace kagome::runtime { public: explicit BasicCodeProvider(std::string_view path); - ~BasicCodeProvider() override = default; - - outcome::result getCodeAt( - const storage::trie::RootHash &state) const override; + Result getCodeAt(const storage::trie::RootHash &state) const override; private: void initialize(std::string_view path); - kagome::common::Buffer buffer_; + Code buffer_; }; } // namespace kagome::runtime diff --git a/test/testutil/runtime/memory.hpp b/test/testutil/runtime/memory.hpp index ee38ce1f72..e88210ac64 100644 --- a/test/testutil/runtime/memory.hpp +++ b/test/testutil/runtime/memory.hpp @@ -14,11 +14,16 @@ namespace kagome::runtime { struct TestMemory : Memory { mutable common::Buffer m; + std::optional pages_max; WasmSize size() const override { return m.size(); } + std::optional pagesMax() const override { + return pages_max; + } + void resize(WasmSize size) override { m.resize(size); }