Skip to content

Commit

Permalink
Add state recovery test (hyperledger-iroha#1367)
Browse files Browse the repository at this point in the history
Signed-off-by: Igor Egorov <[email protected]>

Add test that allows us to ensure that Iroha state still can be recovered from existing block store.
  • Loading branch information
igor-egorov authored May 23, 2018
1 parent 97e86f1 commit a6b7333
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ namespace integration_framework {
size_t maximum_proposal_size,
std::function<void(integration_framework::IntegrationTestFramework &)>
deleter,
bool mst_support)
: iroha_instance_(std::make_shared<IrohaInstance>(mst_support)),
bool mst_support,
const std::string &block_store_path)
: iroha_instance_(std::make_shared<IrohaInstance>(mst_support, block_store_path)),
maximum_proposal_size_(maximum_proposal_size),
deleter_(deleter) {}

Expand Down Expand Up @@ -106,16 +107,31 @@ namespace integration_framework {

IntegrationTestFramework &IntegrationTestFramework::setInitialState(
const Keypair &keypair, const shared_model::interface::Block &block) {
initPipeline(keypair);
iroha_instance_->makeGenesis(block);
log_->info("added genesis block");
subscribeQueuesAndRun();
return *this;
}

IntegrationTestFramework &IntegrationTestFramework::recoverState(
const Keypair &keypair) {
initPipeline(keypair);
iroha_instance_->instance_->init();
subscribeQueuesAndRun();
return *this;
}

void IntegrationTestFramework::initPipeline(
const shared_model::crypto::Keypair &keypair) {
log_->info("init state");
// peer initialization
iroha_instance_->initPipeline(keypair, maximum_proposal_size_);
log_->info("created pipeline");
// iroha_instance_->clearLedger();
// log_->info("cleared ledger");
iroha_instance_->instance_->resetOrderingService();
iroha_instance_->makeGenesis(block);
log_->info("added genesis block");
}

void IntegrationTestFramework::subscribeQueuesAndRun() {
// subscribing for components

iroha_instance_->getIrohaInstance()
Expand Down Expand Up @@ -143,7 +159,6 @@ namespace integration_framework {
// start instance
iroha_instance_->run();
log_->info("run iroha");
return *this;
}

shared_model::proto::TransactionResponse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <vector>

#include <tbb/concurrent_queue.h>
#include <boost/filesystem.hpp>
#include "framework/integration_framework/iroha_instance.hpp"
#include "framework/integration_framework/test_irohad.hpp"
#include "logger/logger.hpp"
Expand Down Expand Up @@ -63,12 +64,16 @@ namespace integration_framework {
* receives pointer to constructed instance of Integration Test Framework.
* If specified, then will be called instead of default destructor's code
* @param mst_support enables multisignature tx support
* @param block_store_path specifies path where blocks will be stored
*/
explicit IntegrationTestFramework(
size_t maximum_proposal_size,
std::function<void(IntegrationTestFramework &)> deleter =
[](IntegrationTestFramework &itf) { itf.done(); },
bool mst_support = false);
bool mst_support = false,
const std::string &block_store_path =
(boost::filesystem::temp_directory_path()
/ boost::filesystem::unique_path()).string());

~IntegrationTestFramework();

Expand Down Expand Up @@ -103,6 +108,14 @@ namespace integration_framework {
const shared_model::crypto::Keypair &keypair,
const shared_model::interface::Block &block);

/**
* Initialize Iroha instance using the data left in block store from
* previous launch of Iroha
* @param keypair - signing key used for initialization of previous instance
*/
IntegrationTestFramework &recoverState(
const shared_model::crypto::Keypair &keypair);

/**
* Send transaction to Iroha and validate its status
* @param tx - transaction for sending
Expand Down Expand Up @@ -214,6 +227,9 @@ namespace integration_framework {
tbb::concurrent_queue<BlockType> block_queue_;
std::shared_ptr<IrohaInstance> iroha_instance_;

void initPipeline(const shared_model::crypto::Keypair &keypair);
void subscribeQueuesAndRun();

// config area

/// maximum time of waiting before appearing next proposal
Expand Down
7 changes: 1 addition & 6 deletions test/framework/integration_framework/iroha_instance.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
#include <memory>
#include <string>

#include <boost/filesystem.hpp>

namespace shared_model {
namespace interface {
class Block;
Expand All @@ -41,10 +39,7 @@ namespace integration_framework {
/**
* @param mst_support enables multisignature tx support
*/
IrohaInstance(bool mst_support, const std::string &block_store_path =
(boost::filesystem::temp_directory_path()
/ boost::filesystem::unique_path())
.string());
IrohaInstance(bool mst_support, const std::string &block_store_path);

void makeGenesis(const shared_model::interface::Block &block);

Expand Down
65 changes: 63 additions & 2 deletions test/regression/regression_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/

#include <gtest/gtest.h>
#include "builders/protobuf/queries.hpp"
#include "builders/protobuf/transaction.hpp"
#include "cryptography/crypto_provider/crypto_defaults.hpp"
#include "framework/integration_framework/integration_test_framework.hpp"
Expand Down Expand Up @@ -44,8 +45,9 @@ TEST(RegressionTest, SequentialInitialization) {

auto checkStatelessValid = [](auto &status) {
ASSERT_TRUE(boost::apply_visitor(
shared_model::interface::SpecifiedVisitor<
shared_model::interface::StatelessValidTxResponse>(),
shared_model::interface::
SpecifiedVisitor<shared_model::interface::
StatelessValidTxResponse>(),
status.get()));
};
auto checkProposal = [](auto &proposal) {
Expand All @@ -71,6 +73,65 @@ TEST(RegressionTest, SequentialInitialization) {
}
}

/**
* @given ITF instance
* @when instance is shutdown without blocks erase
* @then another ITF instance can restore WSV from blockstore
*/
TEST(RegressionTest, StateRecovery) {
auto userKeypair =
shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair();
auto tx = shared_model::proto::TransactionBuilder()
.createdTime(iroha::time::now())
.creatorAccountId("admin@test")
.createAccount("user", "test", userKeypair.publicKey())
.addAssetQuantity("admin@test", "coin#test", "133.0")
.transferAsset(
"admin@test", "user@test", "coin#test", "descrs", "97.8")
.quorum(1)
.build()
.signAndAddSignature(kAdminKeypair);
auto hash = tx.hash();
auto makeQuery = [&hash](int query_counter, auto kAdminKeypair) {
return shared_model::proto::QueryBuilder()
.createdTime(iroha::time::now())
.creatorAccountId("admin@test")
.queryCounter(query_counter)
.getTransactions(std::vector<shared_model::crypto::Hash>{hash})
.build()
.signAndAddSignature(kAdminKeypair);
};
auto checkOne = [](auto &res) { ASSERT_EQ(res->transactions().size(), 1); };
auto checkQuery = [&tx](auto &status) {
auto resp = boost::apply_visitor(
shared_model::interface::
SpecifiedVisitor<shared_model::interface::TransactionsResponse>(),
status.get());
ASSERT_TRUE(resp);
ASSERT_EQ(resp.value().transactions().size(), 1);
ASSERT_EQ(*resp.value().transactions()[0].operator->(), tx);
};
auto path =
(boost::filesystem::temp_directory_path() / "iroha-state-recovery-test")
.string();
{
integration_framework::IntegrationTestFramework(
1, [](auto &) {}, false, path)
.setInitialState(kAdminKeypair)
.sendTx(tx)
.checkProposal(checkOne)
.checkBlock(checkOne)
.sendQuery(makeQuery(1, kAdminKeypair), checkQuery);
}
{
integration_framework::IntegrationTestFramework(
1, [](auto &itf) { itf.done(); }, false, path)
.recoverState(kAdminKeypair)
.sendQuery(makeQuery(2, kAdminKeypair), checkQuery)
.done();
}
}

/**
* @given ITF instance with Iroha
* @when done method is called twice
Expand Down

0 comments on commit a6b7333

Please sign in to comment.