2015-05-27 12:08:46 +00:00
|
|
|
// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers
|
2015-04-06 16:13:07 +00:00
|
|
|
//
|
|
|
|
// This file is part of Bytecoin.
|
|
|
|
//
|
|
|
|
// Bytecoin is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// Bytecoin is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
#include <system_error>
|
|
|
|
|
|
|
|
#include "EventWaiter.h"
|
|
|
|
#include "ICoreStub.h"
|
|
|
|
#include "ICryptonoteProtocolQueryStub.h"
|
2015-05-27 12:08:46 +00:00
|
|
|
#include "InProcessNode/InProcessNode.h"
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
struct CallbackStatus {
|
|
|
|
CallbackStatus() {}
|
|
|
|
|
|
|
|
bool wait() { return waiter.wait_for(std::chrono::milliseconds(3000)); }
|
|
|
|
bool ok() { return waiter.wait_for(std::chrono::milliseconds(3000)) && !static_cast<bool>(code); }
|
|
|
|
void setStatus(const std::error_code& ec) { code = ec; waiter.notify(); }
|
|
|
|
std::error_code getStatus() const { return code; }
|
|
|
|
|
|
|
|
std::error_code code;
|
|
|
|
EventWaiter waiter;
|
|
|
|
};
|
|
|
|
|
|
|
|
class InProcessNode : public ::testing::Test {
|
|
|
|
public:
|
|
|
|
InProcessNode() : node(coreStub, protocolQueryStub) {}
|
|
|
|
void SetUp();
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void initNode();
|
|
|
|
|
|
|
|
ICoreStub coreStub;
|
|
|
|
ICryptonoteProtocolQueryStub protocolQueryStub;
|
|
|
|
CryptoNote::InProcessNode node;
|
|
|
|
};
|
|
|
|
|
|
|
|
void InProcessNode::SetUp() {
|
|
|
|
initNode();
|
|
|
|
}
|
|
|
|
|
|
|
|
void InProcessNode::initNode() {
|
|
|
|
CallbackStatus status;
|
|
|
|
|
|
|
|
node.init([&status] (std::error_code ec) { status.setStatus(ec); });
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, initOk) {
|
|
|
|
CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub);
|
|
|
|
CallbackStatus status;
|
|
|
|
|
|
|
|
newNode.init([&status] (std::error_code ec) { status.setStatus(ec); });
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, doubleInit) {
|
|
|
|
CallbackStatus status;
|
|
|
|
node.init([&status] (std::error_code ec) { status.setStatus(ec); });
|
|
|
|
ASSERT_TRUE(status.wait());
|
|
|
|
|
|
|
|
std::error_code ec = status.getStatus();
|
|
|
|
ASSERT_NE(ec, std::error_code());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, shutdownNotInited) {
|
|
|
|
CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub);
|
|
|
|
ASSERT_FALSE(newNode.shutdown());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, shutdown) {
|
|
|
|
ASSERT_TRUE(node.shutdown());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getPeersCountSuccess) {
|
|
|
|
protocolQueryStub.setPeerCount(1);
|
|
|
|
ASSERT_EQ(1, node.getPeerCount());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getLastLocalBlockHeightSuccess) {
|
|
|
|
crypto::hash ignore;
|
|
|
|
coreStub.set_blockchain_top(10, ignore, true);
|
|
|
|
|
|
|
|
ASSERT_EQ(10, node.getLastLocalBlockHeight());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getLastLocalBlockHeightFailure) {
|
|
|
|
crypto::hash ignore;
|
|
|
|
coreStub.set_blockchain_top(10, ignore, false);
|
|
|
|
|
|
|
|
ASSERT_ANY_THROW(node.getLastLocalBlockHeight());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getLastKnownBlockHeightSuccess) {
|
|
|
|
protocolQueryStub.setObservedHeight(10);
|
2015-05-27 12:08:46 +00:00
|
|
|
ASSERT_EQ(10, node.getLastKnownBlockHeight() + 1);
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getTransactionOutsGlobalIndicesSuccess) {
|
|
|
|
crypto::hash ignore;
|
|
|
|
std::vector<uint64_t> indices;
|
|
|
|
std::vector<uint64_t> expectedIndices;
|
|
|
|
|
|
|
|
uint64_t start = 10;
|
|
|
|
std::generate_n(std::back_inserter(expectedIndices), 5, [&start] () { return start++; });
|
|
|
|
coreStub.set_outputs_gindexs(expectedIndices, true);
|
|
|
|
|
|
|
|
CallbackStatus status;
|
|
|
|
node.getTransactionOutsGlobalIndices(ignore, indices, [&status] (std::error_code ec) { status.setStatus(ec); });
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
|
|
|
|
ASSERT_EQ(expectedIndices.size(), indices.size());
|
|
|
|
std::sort(indices.begin(), indices.end());
|
|
|
|
ASSERT_TRUE(std::equal(indices.begin(), indices.end(), expectedIndices.begin()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getTransactionOutsGlobalIndicesFailure) {
|
|
|
|
crypto::hash ignore;
|
|
|
|
std::vector<uint64_t> indices;
|
|
|
|
coreStub.set_outputs_gindexs(indices, false);
|
|
|
|
|
|
|
|
CallbackStatus status;
|
|
|
|
node.getTransactionOutsGlobalIndices(ignore, indices, [&status] (std::error_code ec) { status.setStatus(ec); });
|
|
|
|
ASSERT_TRUE(status.wait());
|
|
|
|
ASSERT_NE(std::error_code(), status.getStatus());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getRandomOutsByAmountsSuccess) {
|
|
|
|
crypto::public_key ignoredPublicKey;
|
|
|
|
crypto::secret_key ignoredSectetKey;
|
|
|
|
crypto::generate_keys(ignoredPublicKey, ignoredSectetKey);
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response expectedResp;
|
|
|
|
CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_outs_for_amount out;
|
2015-04-06 16:13:07 +00:00
|
|
|
out.amount = 10;
|
|
|
|
out.outs.push_back({ 11, ignoredPublicKey });
|
|
|
|
expectedResp.outs.push_back(out);
|
|
|
|
coreStub.set_random_outs(expectedResp, true);
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
std::vector<CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_outs_for_amount> outs;
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
CallbackStatus status;
|
|
|
|
node.getRandomOutsByAmounts({1,2,3}, 1, outs, [&status] (std::error_code ec) { status.setStatus(ec); });
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
ASSERT_EQ(1, outs.size());
|
|
|
|
|
|
|
|
ASSERT_EQ(10, outs[0].amount);
|
|
|
|
ASSERT_EQ(1, outs[0].outs.size());
|
|
|
|
ASSERT_EQ(11, outs[0].outs.front().global_amount_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getRandomOutsByAmountsFailure) {
|
2015-05-27 12:08:46 +00:00
|
|
|
CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response expectedResp;
|
2015-04-06 16:13:07 +00:00
|
|
|
coreStub.set_random_outs(expectedResp, false);
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
std::vector<CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_outs_for_amount> outs;
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
CallbackStatus status;
|
|
|
|
node.getRandomOutsByAmounts({1,2,3}, 1, outs, [&status] (std::error_code ec) { status.setStatus(ec); });
|
|
|
|
ASSERT_TRUE(status.wait());
|
|
|
|
ASSERT_NE(std::error_code(), status.getStatus());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getPeerCountUninitialized) {
|
|
|
|
CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub);
|
|
|
|
ASSERT_ANY_THROW(newNode.getPeerCount());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getLastLocalBlockHeightUninitialized) {
|
|
|
|
CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub);
|
|
|
|
ASSERT_ANY_THROW(newNode.getLastLocalBlockHeight());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getLastKnownBlockHeightUninitialized) {
|
|
|
|
CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub);
|
|
|
|
ASSERT_ANY_THROW(newNode.getLastKnownBlockHeight());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getNewBlocksUninitialized) {
|
|
|
|
CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub);
|
|
|
|
std::list<crypto::hash> knownBlockIds;
|
2015-05-27 12:08:46 +00:00
|
|
|
std::list<CryptoNote::block_complete_entry> newBlocks;
|
2015-04-06 16:13:07 +00:00
|
|
|
uint64_t startHeight;
|
|
|
|
|
|
|
|
CallbackStatus status;
|
|
|
|
newNode.getNewBlocks(std::move(knownBlockIds), newBlocks, startHeight, [&] (std::error_code ec) { status.setStatus(ec); });
|
|
|
|
ASSERT_TRUE(status.wait());
|
|
|
|
ASSERT_NE(std::error_code(), status.getStatus());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getTransactionOutsGlobalIndicesUninitialized) {
|
|
|
|
CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub);
|
|
|
|
std::vector<uint64_t> outsGlobalIndices;
|
|
|
|
|
|
|
|
CallbackStatus status;
|
|
|
|
newNode.getTransactionOutsGlobalIndices(crypto::hash(), outsGlobalIndices, [&] (std::error_code ec) { status.setStatus(ec); });
|
|
|
|
ASSERT_TRUE(status.wait());
|
|
|
|
ASSERT_NE(std::error_code(), status.getStatus());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getRandomOutsByAmountsUninitialized) {
|
|
|
|
CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub);
|
2015-05-27 12:08:46 +00:00
|
|
|
std::vector<CryptoNote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_outs_for_amount> outs;
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
CallbackStatus status;
|
|
|
|
newNode.getRandomOutsByAmounts({1,2,3}, 1, outs, [&] (std::error_code ec) { status.setStatus(ec); });
|
|
|
|
ASSERT_TRUE(status.wait());
|
|
|
|
ASSERT_NE(std::error_code(), status.getStatus());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, relayTransactionUninitialized) {
|
|
|
|
CryptoNote::InProcessNode newNode(coreStub, protocolQueryStub);
|
|
|
|
|
|
|
|
CallbackStatus status;
|
2015-05-27 12:08:46 +00:00
|
|
|
newNode.relayTransaction(CryptoNote::Transaction(), [&] (std::error_code ec) { status.setStatus(ec); });
|
2015-04-06 16:13:07 +00:00
|
|
|
ASSERT_TRUE(status.wait());
|
|
|
|
ASSERT_NE(std::error_code(), status.getStatus());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getLastLocalBlockTimestamp) {
|
|
|
|
class GetBlockTimestampCore : public ICoreStub {
|
|
|
|
public:
|
|
|
|
GetBlockTimestampCore(uint64_t timestamp) : timestamp(timestamp) {}
|
|
|
|
virtual bool get_blockchain_top(uint64_t& height, crypto::hash& top_id) override {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
virtual bool getBlockByHash(const crypto::hash &h, CryptoNote::Block &blk) override {
|
2015-04-06 16:13:07 +00:00
|
|
|
blk.timestamp = timestamp;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t timestamp;
|
|
|
|
};
|
|
|
|
|
|
|
|
uint64_t expectedTimestamp = 1234567890;
|
|
|
|
GetBlockTimestampCore core(expectedTimestamp);
|
|
|
|
CryptoNote::InProcessNode newNode(core, protocolQueryStub);
|
|
|
|
|
|
|
|
CallbackStatus initStatus;
|
|
|
|
newNode.init([&initStatus] (std::error_code ec) { initStatus.setStatus(ec); });
|
|
|
|
ASSERT_TRUE(initStatus.wait());
|
|
|
|
|
|
|
|
uint64_t timestamp = newNode.getLastLocalBlockTimestamp();
|
|
|
|
|
|
|
|
ASSERT_EQ(expectedTimestamp, timestamp);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(InProcessNode, getLastLocalBlockTimestampError) {
|
|
|
|
class GetBlockTimestampErrorCore : public ICoreStub {
|
|
|
|
public:
|
|
|
|
virtual bool get_blockchain_top(uint64_t& height, crypto::hash& top_id) override {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
virtual bool getBlockByHash(const crypto::hash &h, CryptoNote::Block &blk) override {
|
2015-04-06 16:13:07 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
GetBlockTimestampErrorCore core;
|
|
|
|
CryptoNote::InProcessNode newNode(core, protocolQueryStub);
|
|
|
|
|
|
|
|
CallbackStatus initStatus;
|
|
|
|
newNode.init([&initStatus] (std::error_code ec) { initStatus.setStatus(ec); });
|
|
|
|
ASSERT_TRUE(initStatus.wait());
|
|
|
|
|
|
|
|
ASSERT_THROW(newNode.getLastLocalBlockTimestamp(), std::exception);
|
|
|
|
}
|
|
|
|
|
|
|
|
//TODO: make relayTransaction unit test
|
|
|
|
//TODO: make getNewBlocks unit test
|
|
|
|
//TODO: make queryBlocks unit test
|