Skip to content

Commit

Permalink
Add documentation to authorship module (#1984)
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilsa authored Feb 15, 2024
1 parent c8f1e99 commit 782b5c9
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 20 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ SPDX-License-Identifier: Apache-2.0

[![CodeFactor](https://www.codefactor.io/repository/github/soramitsu/kagome/badge)](https://www.codefactor.io/repository/github/soramitsu/kagome)
[![codecov](https://codecov.io/gh/soramitsu/kagome/branch/master/graph/badge.svg)](https://codecov.io/gh/soramitsu/kagome)
[![](https://img.shields.io/twitter/follow/Soramitsu_co?label=Follow&style=social)](https://twitter.com/Soramitsu_co)
[![](https://img.shields.io/twitter/follow/qdrvm_io?label=Follow&style=social)](https://twitter.com/qdrvm_io)

## Intro

KAGOME is a [Polkadot Host](https://github.com/w3f/polkadot-spec/tree/master/host-spec) (former Polkadot Runtime Environment) developed by [Soramitsu](https://soramitsu.co.jp/) and funded by a Web3 Foundation [grant](https://github.com/w3f/Web3-collaboration/blob/master/grants/grants.md) and Kusama [treasury](https://kusama.polkassembly.io/post/1858).
KAGOME is a [Polkadot Host](https://github.com/w3f/polkadot-spec/tree/master/host-spec) (former Polkadot Runtime Environment) developed by [Quadrivim](https://qdrvm.io) and funded by a Web3 Foundation [grant](https://github.com/w3f/Web3-collaboration/blob/master/grants/grants.md) and Treasury proposals ( [1](https://kusama.polkassembly.io/post/1858), [2](https://polkadot.polkassembly.io/treasury/485)).


## Status
Expand Down Expand Up @@ -47,7 +47,7 @@ KAGOME is a [Polkadot Host](https://github.com/w3f/polkadot-spec/tree/master/hos
- [x] WASM engine
- [x] Binaryen
- [x] WAVM
- [ ] WasmEdge (planned for Q3 2023)
- [x] WasmEdge
- [x] Parachains core
- [x] Non-asynchronous Backing
- [x] Data availability
Expand Down
40 changes: 33 additions & 7 deletions core/authorship/block_builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,57 @@
namespace kagome::authorship {

/**
* BlockBuilder collects extrinsics and creates new block and then should be
* destroyed
* The BlockBuilder class is responsible for collecting extrinsics, creating a
* new block, and should be destroyed after the block is built. It provides
* methods for getting inherent extrinsics, adding extrinsics to a block,
* finalizing the construction of a block, and estimating the size of the
* encoded block. This class is used in the block production process,
* specifically in the propose method of the ProposerImpl class.
*/
class BlockBuilder {
public:
virtual ~BlockBuilder() = default;

/**
* The getInherentExtrinsics method retrieves the inherent extrinsics based
* on the provided inherent data. This method is called in the propose
* method of the ProposerImpl class.
*
* @param data The inherent data used to retrieve the inherent extrinsics.
* @return A result containing a vector of inherent extrinsics if they were
* successfully retrieved, or an error if the extrinsics could not be
* retrieved.
*/
virtual outcome::result<std::vector<primitives::Extrinsic>>
getInherentExtrinsics(const primitives::InherentData &data) const = 0;

/**
* Push extrinsic to wait its inclusion to the block
* Returns result containing success if xt was pushed, error otherwise
* The pushExtrinsic method adds an extrinsic to the block being built.
* This method is called in the propose method of the ProposerImpl class.
*
* @param extrinsic The extrinsic to be added to the block.
* @return A result containing the index of the extrinsic if it was
* successfully added, or an error if the extrinsic could not be added.
*/
virtual outcome::result<primitives::ExtrinsicIndex> pushExtrinsic(
const primitives::Extrinsic &extrinsic) = 0;

/**
* Create a block from extrinsics and header
* The bake method finalizes the construction of the block and returns the
* built block. This method is called in the propose method of the
* ProposerImpl class after all extrinsics have been added to the block.
*
* @return A result containing the built block if the block was successfully
* built, or an error if the block could not be built.
*/
virtual outcome::result<primitives::Block> bake() const = 0;

/**
* Estimate size of encoded block representation
* @return size in bytes
* The estimateBlockSize method estimates the size of the encoded block
* representation. This method can be used to check if the block size limit
* has been reached.
*
* @return The estimated size of the encoded block in bytes.
*/
virtual size_t estimateBlockSize() const = 0;
};
Expand Down
21 changes: 17 additions & 4 deletions core/authorship/block_builder_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,29 @@
namespace kagome::authorship {

/**
* Creates new block builders. Each of them encapsulates the logic for
* creating a single block from provided block information
* The BlockBuilderFactory class is responsible for creating new block
* builders. Each block builder encapsulates the logic for creating a single
* block from provided block information. This class is used in the block
* production process, specifically in the propose method of the ProposerImpl
* class.
*/
class BlockBuilderFactory {
public:
virtual ~BlockBuilderFactory() = default;

/**
* Prepares BlockBuilder for creating block on top of parent block and using
* provided digests. Also initialises the block created in BlockBuilder
* The make method prepares a BlockBuilder for creating a block on top of a
* parent block and using provided digests. It also initializes the block
* created in BlockBuilder. This method is called in the propose method of
* the ProposerImpl class.
*
* @param parent_block The block that the new block will be built on top of.
* @param inherent_digest The digest that will be used in the creation of
* the new block.
* @param changes_tracker Tracks changes to the trie during the block
* production process.
* @return A unique pointer to a BlockBuilder, or an error if the
* BlockBuilder could not be created.
*/
virtual outcome::result<std::unique_ptr<BlockBuilder>> make(
const primitives::BlockInfo &parent_block,
Expand Down
11 changes: 10 additions & 1 deletion core/authorship/impl/block_builder_error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,21 @@

namespace kagome::authorship {

/**
* @enum BlockBuilderError
* @brief Represents errors that can occur while building a block.
*/
enum class BlockBuilderError {
/// @brief Indicates that the application of an extrinsic failed.
EXTRINSIC_APPLICATION_FAILED = 1,
/// @brief Indicates that the block building process has exhausted available
/// resources.
EXHAUSTS_RESOURCES,
/// @brief Indicates that a mandatory extrinsic is bad, i.e., it is not
/// valid or cannot be applied.
BAD_MANDATORY,
};

}
} // namespace kagome::authorship

OUTCOME_HPP_DECLARE_ERROR(kagome::authorship, BlockBuilderError)
4 changes: 4 additions & 0 deletions core/authorship/impl/block_builder_factory_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@ namespace kagome::authorship {
#endif
BOOST_ASSERT(parent_number == parent.number);

// Create a new block header with the incremented number, parent's hash, and
// the inherent digest
auto number = parent.number + 1;
primitives::BlockHeader header{
.number = number,
.parent_hash = parent.hash,
.digest = std::move(inherent_digest),
};

// Try to initialize the block with the created header and changes tracker
if (auto res =
r_core_->initialize_block(header, std::move(changes_tracker));
not res) {
Expand Down
29 changes: 29 additions & 0 deletions core/authorship/impl/block_builder_factory_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,44 @@

namespace kagome::authorship {

/**
* @class BlockBuilderFactoryImpl
* @brief The BlockBuilderFactoryImpl class is responsible for creating
* instances of BlockBuilder.
*
* @see BlockBuilderFactory
* @see BlockBuilder
*/
class BlockBuilderFactoryImpl : public BlockBuilderFactory {
public:
~BlockBuilderFactoryImpl() override = default;

/**
* @brief Constructs a new BlockBuilderFactoryImpl.
*
* @param r_core Shared pointer to the runtime core runtime API that is used
* to initialize the block.
* @param r_block_builder Shared pointer to the runtime block builder
* runtime API that is used to build the block.
* @param header_backend Shared pointer to the block header repository to be
* used to get the block number by its hash.
*/
BlockBuilderFactoryImpl(
std::shared_ptr<runtime::Core> r_core,
std::shared_ptr<runtime::BlockBuilder> r_block_builder,
std::shared_ptr<blockchain::BlockHeaderRepository> header_backend);

/**
* @brief Creates a new BlockBuilder instance.
*
* @param parent The parent block info.
* @param inherent_digest The inherent digest to be used to build the new
* block.
* @param changes_tracker The changes tracker to be used to track trie
* changes.
* @return A result containing a unique pointer to the new BlockBuilder
* instance, or an error if the operation failed.
*/
outcome::result<std::unique_ptr<BlockBuilder>> make(
const kagome::primitives::BlockInfo &parent_block,
primitives::Digest inherent_digest,
Expand Down
53 changes: 53 additions & 0 deletions core/authorship/impl/block_builder_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,78 @@

namespace kagome::authorship {

/**
* @class BlockBuilderImpl
* @file core/authorship/impl/block_builder_impl.hpp
* @brief The BlockBuilderImpl class is responsible for building blocks.
*
* This class implements the BlockBuilder interface. It uses the provided
* block header and other parameters to construct a new block.
*
* @see BlockBuilder
*/
class BlockBuilderImpl : public BlockBuilder {
public:
~BlockBuilderImpl() override = default;

/**
* @brief Constructs a new BlockBuilderImpl.
* @file core/authorship/impl/block_builder_impl.cpp
*
* @param header The block header to be used to build the block.
* @param context The runtime context containing the runtime parameters such
* as memory limits.
* @param block_builder Shared pointer to the block builder runtime API
*/
BlockBuilderImpl(primitives::BlockHeader block_header,
std::unique_ptr<runtime::RuntimeContext> ctx,
std::shared_ptr<runtime::BlockBuilder> block_builder_api);

/**
* Retrieves the inherent extrinsics for the block from provided inherent
* data.
*
* @param data The inherent data to be used.
* @return A vector of inherent extrinsics.
*/
outcome::result<std::vector<primitives::Extrinsic>> getInherentExtrinsics(
const primitives::InherentData &data) const override;

/**
* Pushes an extrinsic into the block.
*
* @param extrinsic The extrinsic to be pushed.
* @return The index of the extrinsic in the block.
*/
outcome::result<primitives::ExtrinsicIndex> pushExtrinsic(
const primitives::Extrinsic &extrinsic) override;

/**
* Finalizes the block construction and returns the built block.
*
* @return The built block.
*/
outcome::result<primitives::Block> bake() const override;

/**
* Estimates the size of the block based on
*
* This function calculates the size of the block by encoding it
* using the ScaleEncoderStream
*
* @return The estimated size of the block.
*/
size_t estimateBlockSize() const override;

private:
/**
* @brief Returns the estimated size of the block header.
*
* This function calculates the size of the block header by encoding it
* using the ScaleEncoderStream
*
* @return The estimated size of the block header.
*/
size_t estimatedBlockHeaderSize() const;

primitives::BlockHeader block_header_;
Expand Down
25 changes: 22 additions & 3 deletions core/authorship/impl/proposer_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ namespace kagome::authorship {
block_builder_factory_->make(
parent_block, inherent_digest, std::move(changes_tracker)));

// Retrieve and add the inherent extrinsics to the block
auto inherent_xts_res = block_builder->getInherentExtrinsics(inherent_data);
if (not inherent_xts_res) {
logger_->error("BlockBuilder->inherent_extrinsics failed with error: {}",
Expand All @@ -58,6 +59,7 @@ namespace kagome::authorship {
}
const auto &inherent_xts = inherent_xts_res.value();

// Add each inherent extrinsic to the block
for (const auto &xt : inherent_xts) {
SL_DEBUG(logger_, "Adding inherent extrinsic: {}", xt.data);
auto inserted_res = block_builder->pushExtrinsic(xt);
Expand All @@ -81,6 +83,7 @@ namespace kagome::authorship {
}
}

// Remove stale transactions from the transaction pool
auto remove_res = transaction_pool_->removeStale(parent_block.number);
if (remove_res.has_error()) {
SL_ERROR(logger_,
Expand All @@ -91,6 +94,8 @@ namespace kagome::authorship {

/// TODO(iceseer): switch to callback case(this case is needed to make tests
/// complete)

// Retrieve ready transactions from the transaction pool
std::vector<std::pair<primitives::Transaction::Hash,
std::shared_ptr<const primitives::Transaction>>>
ready_txs = transaction_pool_->getReadyTransactions();
Expand All @@ -110,15 +115,20 @@ namespace kagome::authorship {

size_t included_tx_count = 0;
std::vector<primitives::Transaction::Hash> included_hashes;

// Iterate through the ready transactions
for (const auto &[hash, tx] : ready_txs) {
// Check if the deadline has been reached
if (deadline && clock_->now() >= deadline) {
break;
}

// Estimate the size of the transaction
scale::ScaleEncoderStream s(true);
s << tx->ext;
auto estimate_tx_size = s.size();

// Check if adding the transaction would exceed the block size limit
if (block_size + estimate_tx_size > block_size_limit) {
if (skipped < kMaxSkippedTransactions) {
++skipped;
Expand All @@ -128,38 +138,45 @@ namespace kagome::authorship {
kMaxSkippedTransactions - skipped);
continue;
}
// Reached the block size limit, stop adding transactions
SL_DEBUG(logger_,
"Reached block size limit, proceeding with proposing.");
hit_block_size_limit = true;
break;
}

// Add the transaction to the block
SL_DEBUG(logger_, "Adding extrinsic: {}", tx->ext.data);
auto inserted_res = block_builder->pushExtrinsic(tx->ext);
if (not inserted_res) {
if (BlockBuilderError::EXHAUSTS_RESOURCES == inserted_res.error()) {
if (skipped < kMaxSkippedTransactions) {
// Skip the transaction and continue with the next one
++skipped;
SL_DEBUG(logger_,
"Block seems full, but will try {} more transactions "
"before quitting.",
kMaxSkippedTransactions - skipped);
} else { // maximum amount of txs is pushed
} else {
// Maximum number of transactions reached, stop adding transactions
SL_DEBUG(logger_, "Block is full, proceed with proposing.");
break;
}
} else { // any other error than exhausted resources
} else {
logger_->warn("Extrinsic {} was not added to the block. Reason: {}",
tx->ext.data,
inserted_res.error());
}
} else { // tx was pushed successfully
} else {
// Transaction was successfully added to the block
block_size += estimate_tx_size;
transaction_pushed = true;
++included_tx_count;
included_hashes.emplace_back(hash);
}
}

// Set the number of included transactions in the block metric
metric_tx_included_in_block_->set(included_tx_count);

if (hit_block_size_limit and not transaction_pushed) {
Expand All @@ -168,8 +185,10 @@ namespace kagome::authorship {
block_size_limit);
}

// Create the block
OUTCOME_TRY(block, block_builder->bake());

// Remove the included transactions from the transaction pool
for (const auto &hash : included_hashes) {
auto removed_res = transaction_pool_->removeOne(hash);
if (not removed_res) {
Expand Down
Loading

0 comments on commit 782b5c9

Please sign in to comment.