2016-01-18 15:33:29 +00:00
|
|
|
// Copyright (c) 2011-2016 The Cryptonote developers
|
2015-09-18 11:55:31 +00:00
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
#include "CryptoNoteCore/Account.h"
|
|
|
|
#include "CryptoNoteCore/CoreConfig.h"
|
|
|
|
#include "CryptoNoteCore/Core.h"
|
|
|
|
#include "CryptoNoteCore/Currency.h"
|
2015-07-15 12:23:00 +00:00
|
|
|
#include "Logging/LoggerManager.h"
|
2015-07-30 15:22:07 +00:00
|
|
|
#include "P2p/NetNodeConfig.h"
|
2015-07-15 12:23:00 +00:00
|
|
|
#include "System/Dispatcher.h"
|
|
|
|
#include "System/InterruptedException.h"
|
2015-07-30 15:22:07 +00:00
|
|
|
#include "WalletLegacy/WalletLegacy.h"
|
2015-07-15 12:23:00 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
#include "../IntegrationTestLib/BaseFunctionalTests.h"
|
|
|
|
#include "../IntegrationTestLib/TestWalletLegacy.h"
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
using namespace CryptoNote;
|
2015-07-30 15:22:07 +00:00
|
|
|
using namespace Tests::Common;
|
|
|
|
using namespace Crypto;
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
extern System::Dispatcher globalSystem;
|
2015-07-30 15:22:07 +00:00
|
|
|
extern Tests::Common::BaseFunctionalTestsConfig config;
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
namespace {
|
2015-07-30 15:22:07 +00:00
|
|
|
class NodeTxPoolSyncTest : public Tests::Common::BaseFunctionalTests, public ::testing::Test {
|
2015-07-15 12:23:00 +00:00
|
|
|
public:
|
|
|
|
NodeTxPoolSyncTest() :
|
2015-07-30 15:22:07 +00:00
|
|
|
BaseFunctionalTests(m_currency, globalSystem, config),
|
2015-07-15 12:23:00 +00:00
|
|
|
m_dispatcher(globalSystem),
|
|
|
|
m_currency(CurrencyBuilder(m_logManager).testnet(true).currency()) {
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
Logging::LoggerManager m_logManager;
|
|
|
|
System::Dispatcher& m_dispatcher;
|
|
|
|
CryptoNote::Currency m_currency;
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST_F(NodeTxPoolSyncTest, TxPoolsAreRequestedRightAfterANodeIsConnectedToAnotherIfTheirBlockchainsAreSynchronized) {
|
|
|
|
//System::Timer timer(m_dispatcher);
|
|
|
|
//m_dispatcher.spawn([&m_dispatcher, &timer] {
|
|
|
|
// try {
|
|
|
|
// timer.sleep(std::chrono::minutes(5));
|
|
|
|
// m_dispatcher.
|
|
|
|
// } catch (System::InterruptedException&) {
|
|
|
|
// }
|
|
|
|
//});
|
|
|
|
|
|
|
|
const size_t NODE_0 = 0;
|
|
|
|
const size_t NODE_1 = 1;
|
|
|
|
const size_t NODE_2 = 2;
|
|
|
|
const size_t NODE_3 = 3;
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
launchTestnet(4, Tests::Common::BaseFunctionalTests::Line);
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
std::unique_ptr<CryptoNote::INode> node0;
|
|
|
|
std::unique_ptr<CryptoNote::INode> node1;
|
|
|
|
std::unique_ptr<CryptoNote::INode> node2;
|
|
|
|
std::unique_ptr<CryptoNote::INode> node3;
|
|
|
|
|
|
|
|
nodeDaemons[NODE_0]->makeINode(node0);
|
|
|
|
nodeDaemons[NODE_1]->makeINode(node1);
|
|
|
|
nodeDaemons[NODE_2]->makeINode(node2);
|
|
|
|
nodeDaemons[NODE_3]->makeINode(node3);
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
CryptoNote::AccountBase minerAccount;
|
2015-07-15 12:23:00 +00:00
|
|
|
minerAccount.generate();
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
TestWalletLegacy wallet1(m_dispatcher, m_currency, *node1);
|
|
|
|
TestWalletLegacy wallet2(m_dispatcher, m_currency, *node2);
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet1.init()));
|
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet2.init()));
|
|
|
|
|
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_0], wallet1.address(), 1));
|
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_0], wallet2.address(), 1));
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_0], minerAccount.getAccountKeys().address, m_currency.minedMoneyUnlockWindow()));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
wallet1.waitForSynchronizationToHeight(static_cast<uint32_t>(m_currency.minedMoneyUnlockWindow()) + 3);
|
|
|
|
wallet2.waitForSynchronizationToHeight(static_cast<uint32_t>(m_currency.minedMoneyUnlockWindow()) + 3);
|
|
|
|
|
|
|
|
stopNode(NODE_2);
|
|
|
|
// To make sure new transaction won't be received by NODE_2 and NODE_3
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitForPeerCount(*node1, 1));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash1;
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet1.sendTransaction(m_currency.accountAddressAsString(minerAccount), m_currency.coin(), txHash1)));
|
|
|
|
|
|
|
|
stopNode(NODE_1);
|
|
|
|
// Don't start NODE_2, while NODE_1 doesn't close its connections
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitForPeerCount(*node0, 0));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
startNode(NODE_2);
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitDaemonReady(NODE_2));
|
|
|
|
ASSERT_TRUE(waitForPeerCount(*node3, 1));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash2;
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet2.sendTransaction(m_currency.accountAddressAsString(minerAccount), m_currency.coin(), txHash2)));
|
|
|
|
|
|
|
|
startNode(NODE_1);
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitDaemonReady(NODE_1));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
std::vector<std::unique_ptr<CryptoNote::ITransactionReader>> poolTxs1;
|
|
|
|
std::vector<std::unique_ptr<CryptoNote::ITransactionReader>> poolTxs2;
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_TRUE(waitForPoolSize(NODE_1, *node1, 2, poolTxs1));
|
|
|
|
ASSERT_TRUE(waitForPoolSize(NODE_2, *node2, 2, poolTxs2));
|
|
|
|
|
|
|
|
//timer.stop();
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
std::vector<Hash> poolTxsIds1;
|
|
|
|
std::vector<Hash> poolTxsIds2;
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
for (auto& tx : poolTxs1) {
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash = tx->getTransactionHash();
|
2015-07-15 12:23:00 +00:00
|
|
|
poolTxsIds1.emplace_back(std::move(txHash));
|
|
|
|
}
|
|
|
|
for (auto& tx : poolTxs2) {
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash = tx->getTransactionHash();
|
2015-07-15 12:23:00 +00:00
|
|
|
poolTxsIds2.emplace_back(std::move(txHash));
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::find(poolTxsIds1.begin(), poolTxsIds1.end(), txHash1) != poolTxsIds1.end());
|
|
|
|
ASSERT_TRUE(std::find(poolTxsIds1.begin(), poolTxsIds1.end(), txHash2) != poolTxsIds1.end());
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::find(poolTxsIds2.begin(), poolTxsIds2.end(), txHash1) != poolTxsIds2.end());
|
|
|
|
ASSERT_TRUE(std::find(poolTxsIds2.begin(), poolTxsIds2.end(), txHash2) != poolTxsIds2.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(NodeTxPoolSyncTest, TxPoolsAreRequestedRightAfterInitialBlockchainsSynchronization) {
|
|
|
|
//System::Timer timer(m_dispatcher);
|
|
|
|
//m_dispatcher.spawn([&m_dispatcher, &timer] {
|
|
|
|
// try {
|
|
|
|
// timer.sleep(std::chrono::minutes(5));
|
|
|
|
// m_dispatcher.
|
|
|
|
// } catch (System::InterruptedException&) {
|
|
|
|
// }
|
|
|
|
//});
|
|
|
|
|
|
|
|
const size_t NODE_0 = 0;
|
|
|
|
const size_t NODE_1 = 1;
|
|
|
|
const size_t NODE_2 = 2;
|
|
|
|
const size_t NODE_3 = 3;
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
launchTestnet(4, Tests::Common::BaseFunctionalTests::Line);
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
std::unique_ptr<CryptoNote::INode> node0;
|
|
|
|
std::unique_ptr<CryptoNote::INode> node1;
|
|
|
|
std::unique_ptr<CryptoNote::INode> node2;
|
|
|
|
std::unique_ptr<CryptoNote::INode> node3;
|
|
|
|
|
|
|
|
nodeDaemons[NODE_0]->makeINode(node0);
|
|
|
|
nodeDaemons[NODE_1]->makeINode(node1);
|
|
|
|
nodeDaemons[NODE_2]->makeINode(node2);
|
|
|
|
nodeDaemons[NODE_3]->makeINode(node3);
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
CryptoNote::AccountBase minerAccount;
|
2015-07-15 12:23:00 +00:00
|
|
|
minerAccount.generate();
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
TestWalletLegacy wallet1(m_dispatcher, m_currency, *node1);
|
|
|
|
TestWalletLegacy wallet2(m_dispatcher, m_currency, *node2);
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet1.init()));
|
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet2.init()));
|
|
|
|
|
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_0], wallet1.address(), 1));
|
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_0], wallet2.address(), 1));
|
|
|
|
|
|
|
|
wallet1.waitForSynchronizationToHeight(static_cast<uint32_t>(3));
|
|
|
|
wallet2.waitForSynchronizationToHeight(static_cast<uint32_t>(3));
|
|
|
|
|
|
|
|
stopNode(NODE_2);
|
|
|
|
// To make sure new transaction won't be received by NODE_2 and NODE_3
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitForPeerCount(*node1, 1));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_0], minerAccount.getAccountKeys().address, m_currency.minedMoneyUnlockWindow()));
|
2015-07-15 12:23:00 +00:00
|
|
|
wallet1.waitForSynchronizationToHeight(static_cast<uint32_t>(m_currency.minedMoneyUnlockWindow()) + 3);
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash1;
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet1.sendTransaction(m_currency.accountAddressAsString(minerAccount), m_currency.coin(), txHash1)));
|
|
|
|
|
|
|
|
stopNode(NODE_1);
|
|
|
|
// Don't start NODE_2, while NODE_1 doesn't close its connections
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitForPeerCount(*node0, 0));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
startNode(NODE_2);
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitDaemonReady(NODE_2));
|
|
|
|
ASSERT_TRUE(waitForPeerCount(*node3, 1));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_3], minerAccount.getAccountKeys().address, m_currency.minedMoneyUnlockWindow()));
|
2015-07-15 12:23:00 +00:00
|
|
|
wallet2.waitForSynchronizationToHeight(static_cast<uint32_t>(m_currency.minedMoneyUnlockWindow()) + 3);
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash2;
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet2.sendTransaction(m_currency.accountAddressAsString(minerAccount), m_currency.coin(), txHash2)));
|
|
|
|
|
|
|
|
startNode(NODE_1);
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitDaemonReady(NODE_1));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
std::vector<std::unique_ptr<CryptoNote::ITransactionReader>> poolTxs1;
|
|
|
|
std::vector<std::unique_ptr<CryptoNote::ITransactionReader>> poolTxs2;
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_TRUE(waitForPoolSize(NODE_1, *node1, 2, poolTxs1));
|
|
|
|
ASSERT_TRUE(waitForPoolSize(NODE_2, *node2, 2, poolTxs2));
|
|
|
|
|
|
|
|
//timer.stop();
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
std::vector<Hash> poolTxsIds1;
|
|
|
|
std::vector<Hash> poolTxsIds2;
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
for (auto& tx : poolTxs1) {
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash = tx->getTransactionHash();
|
2015-07-15 12:23:00 +00:00
|
|
|
poolTxsIds1.emplace_back(std::move(txHash));
|
|
|
|
}
|
|
|
|
for (auto& tx : poolTxs2) {
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash = tx->getTransactionHash();
|
2015-07-15 12:23:00 +00:00
|
|
|
poolTxsIds2.emplace_back(std::move(txHash));
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::find(poolTxsIds1.begin(), poolTxsIds1.end(), txHash1) != poolTxsIds1.end());
|
|
|
|
ASSERT_TRUE(std::find(poolTxsIds1.begin(), poolTxsIds1.end(), txHash2) != poolTxsIds1.end());
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::find(poolTxsIds2.begin(), poolTxsIds2.end(), txHash1) != poolTxsIds2.end());
|
|
|
|
ASSERT_TRUE(std::find(poolTxsIds2.begin(), poolTxsIds2.end(), txHash2) != poolTxsIds2.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(NodeTxPoolSyncTest, TxPoolsAreRequestedRightAfterTimedBlockchainsSynchronization) {
|
|
|
|
//System::Timer timer(m_dispatcher);
|
|
|
|
//m_dispatcher.spawn([&m_dispatcher, &timer] {
|
|
|
|
// try {
|
|
|
|
// timer.sleep(std::chrono::minutes(5));
|
|
|
|
// m_dispatcher.
|
|
|
|
// } catch (System::InterruptedException&) {
|
|
|
|
// }
|
|
|
|
//});
|
|
|
|
|
|
|
|
const size_t NODE_0 = 0;
|
|
|
|
const size_t NODE_1 = 1;
|
|
|
|
const size_t NODE_2 = 2;
|
|
|
|
const size_t NODE_3 = 3;
|
|
|
|
const size_t NODE_4 = 4;
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
launchTestnet(5, Tests::Common::BaseFunctionalTests::Line);
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
std::unique_ptr<CryptoNote::INode> node0;
|
|
|
|
std::unique_ptr<CryptoNote::INode> node1;
|
|
|
|
std::unique_ptr<CryptoNote::INode> node2;
|
|
|
|
std::unique_ptr<CryptoNote::INode> node3;
|
|
|
|
std::unique_ptr<CryptoNote::INode> node4;
|
|
|
|
|
|
|
|
nodeDaemons[NODE_0]->makeINode(node0);
|
|
|
|
nodeDaemons[NODE_1]->makeINode(node1);
|
|
|
|
nodeDaemons[NODE_2]->makeINode(node2);
|
|
|
|
nodeDaemons[NODE_3]->makeINode(node3);
|
|
|
|
nodeDaemons[NODE_4]->makeINode(node4);
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
CryptoNote::AccountBase minerAccount;
|
2015-07-15 12:23:00 +00:00
|
|
|
minerAccount.generate();
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
TestWalletLegacy wallet1(m_dispatcher, m_currency, *node1);
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet1.init()));
|
|
|
|
|
|
|
|
stopNode(NODE_4);
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitForPeerCount(*node3, 1));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
stopNode(NODE_3);
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitForPeerCount(*node2, 1));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
stopNode(NODE_2);
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitForPeerCount(*node1, 1));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_0], wallet1.address(), 1));
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_0], minerAccount.getAccountKeys().address, m_currency.minedMoneyUnlockWindow()));
|
2015-07-15 12:23:00 +00:00
|
|
|
wallet1.waitForSynchronizationToHeight(static_cast<uint32_t>(m_currency.minedMoneyUnlockWindow()) + 2);
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash1;
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet1.sendTransaction(m_currency.accountAddressAsString(minerAccount), m_currency.coin(), txHash1)));
|
|
|
|
|
|
|
|
// Start nodes simultaneously due to them connect each other and decided that they are connected to network
|
|
|
|
startNode(NODE_4);
|
|
|
|
startNode(NODE_3);
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitDaemonReady(NODE_4));
|
|
|
|
ASSERT_TRUE(waitDaemonReady(NODE_3));
|
|
|
|
ASSERT_TRUE(waitForPeerCount(*node4, 1));
|
|
|
|
ASSERT_TRUE(waitForPeerCount(*node3, 1));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
//std::this_thread::sleep_for(std::chrono::seconds(5));
|
|
|
|
|
|
|
|
startNode(NODE_2);
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitDaemonReady(NODE_2));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
// NODE_3 and NODE_4 are synchronized by timer
|
2015-07-30 15:22:07 +00:00
|
|
|
std::vector<std::unique_ptr<CryptoNote::ITransactionReader>> poolTxs2;
|
|
|
|
std::vector<std::unique_ptr<CryptoNote::ITransactionReader>> poolTxs3;
|
|
|
|
std::vector<std::unique_ptr<CryptoNote::ITransactionReader>> poolTxs4;
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_TRUE(waitForPoolSize(NODE_2, *node2, 1, poolTxs2));
|
|
|
|
ASSERT_TRUE(waitForPoolSize(NODE_3, *node3, 1, poolTxs3));
|
|
|
|
ASSERT_TRUE(waitForPoolSize(NODE_4, *node4, 1, poolTxs4));
|
|
|
|
|
|
|
|
//timer.stop();
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash poolTxId2 = poolTxs2.front()->getTransactionHash();
|
|
|
|
Hash poolTxId3 = poolTxs3.front()->getTransactionHash();
|
|
|
|
Hash poolTxId4 = poolTxs4.front()->getTransactionHash();
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
ASSERT_EQ(txHash1, poolTxId2);
|
|
|
|
ASSERT_EQ(txHash1, poolTxId3);
|
|
|
|
ASSERT_EQ(txHash1, poolTxId4);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(NodeTxPoolSyncTest, TxPoolsAreRequestedRightAfterSwitchingToAlternativeChain) {
|
|
|
|
// If this condition isn't true, then test must be rewritten a bit
|
|
|
|
ASSERT_GT(m_currency.difficultyLag() + m_currency.difficultyCut(), m_currency.minedMoneyUnlockWindow());
|
|
|
|
|
|
|
|
//System::Timer timer(m_dispatcher);
|
|
|
|
//m_dispatcher.spawn([&m_dispatcher, &timer] {
|
|
|
|
// try {
|
|
|
|
// timer.sleep(std::chrono::minutes(5));
|
|
|
|
// m_dispatcher.
|
|
|
|
// } catch (System::InterruptedException&) {
|
|
|
|
// }
|
|
|
|
//});
|
|
|
|
|
|
|
|
const size_t NODE_0 = 0;
|
|
|
|
const size_t NODE_1 = 1;
|
|
|
|
const size_t NODE_2 = 2;
|
|
|
|
const size_t NODE_3 = 3;
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
launchTestnet(4, Tests::Common::BaseFunctionalTests::Line);
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
std::unique_ptr<CryptoNote::INode> node0;
|
|
|
|
std::unique_ptr<CryptoNote::INode> node1;
|
|
|
|
std::unique_ptr<CryptoNote::INode> node2;
|
|
|
|
std::unique_ptr<CryptoNote::INode> node3;
|
|
|
|
|
|
|
|
nodeDaemons[NODE_0]->makeINode(node0);
|
|
|
|
nodeDaemons[NODE_1]->makeINode(node1);
|
|
|
|
nodeDaemons[NODE_2]->makeINode(node2);
|
|
|
|
nodeDaemons[NODE_3]->makeINode(node3);
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
TestWalletLegacy wallet0(m_dispatcher, m_currency, *node1);
|
|
|
|
TestWalletLegacy wallet1(m_dispatcher, m_currency, *node1);
|
|
|
|
TestWalletLegacy wallet2(m_dispatcher, m_currency, *node2);
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet0.init()));
|
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet1.init()));
|
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet2.init()));
|
|
|
|
|
|
|
|
uint32_t blockchainLenght = 1;
|
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_0], wallet0.address(), m_currency.difficultyBlocksCount()));
|
|
|
|
blockchainLenght += static_cast<uint32_t>(m_currency.difficultyBlocksCount());
|
|
|
|
|
|
|
|
wallet1.waitForSynchronizationToHeight(blockchainLenght);
|
|
|
|
wallet2.waitForSynchronizationToHeight(blockchainLenght);
|
|
|
|
|
|
|
|
stopNode(NODE_2);
|
|
|
|
// To make sure new blocks won't be received by NODE_2
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitForPeerCount(*node1, 1));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
// Generate alternative chain for NODE_1
|
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_0], wallet1.address(), 1));
|
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_0], wallet2.address(), m_currency.minedMoneyUnlockWindow()));
|
|
|
|
blockchainLenght += 1 + static_cast<uint32_t>(m_currency.minedMoneyUnlockWindow());
|
|
|
|
|
|
|
|
wallet1.waitForSynchronizationToHeight(blockchainLenght);
|
|
|
|
|
|
|
|
// This transaction is valid in both alternative chains, it is just an indicator, that shows when NODE_1 and NODE_2 are synchronized
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash0;
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet0.sendTransaction(wallet0.wallet()->getAddress(), m_currency.coin(), txHash0)));
|
|
|
|
|
|
|
|
// This transaction is valid only in alternative chain 1
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash1;
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet1.sendTransaction(wallet0.wallet()->getAddress(), m_currency.coin(), txHash1)));
|
|
|
|
|
|
|
|
stopNode(NODE_1);
|
|
|
|
// Don't start NODE_2, while NODE_1 doesn't close its connections
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitForPeerCount(*node0, 0));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
startNode(NODE_2);
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitDaemonReady(NODE_2));
|
|
|
|
ASSERT_TRUE(waitForPeerCount(*node3, 1));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
// Generate alternative chain for NODE_2.
|
|
|
|
// After that it is expected that alternative chains 1 and 2 have the same difficulty, because
|
|
|
|
// m_currency.minedMoneyUnlockWindow() < m_currency.difficultyLag() + m_currency.difficultyCut()
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_2], wallet2.address(), 1));
|
|
|
|
ASSERT_TRUE(mineBlocks(*nodeDaemons[NODE_2], wallet1.address(), m_currency.minedMoneyUnlockWindow()));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
wallet2.waitForSynchronizationToHeight(blockchainLenght);
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
// This block template doesn't contain txHash2, as it is not created yet
|
|
|
|
CryptoNote::Block blockTemplate2;
|
|
|
|
uint64_t difficulty2;
|
|
|
|
ASSERT_TRUE(nodeDaemons[NODE_2]->getBlockTemplate(wallet1.wallet()->getAddress(), blockTemplate2, difficulty2));
|
|
|
|
ASSERT_EQ(1, difficulty2);
|
|
|
|
ASSERT_TRUE(blockTemplate2.transactionHashes.empty());
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
// This transaction is valid only in alternative chain 2
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash2;
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_FALSE(static_cast<bool>(wallet2.sendTransaction(wallet0.wallet()->getAddress(), m_currency.coin(), txHash2)));
|
|
|
|
|
|
|
|
startNode(NODE_1);
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(waitDaemonReady(NODE_1));
|
|
|
|
ASSERT_TRUE(waitForPeerCount(*node2, 2));
|
2015-07-15 12:23:00 +00:00
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
std::vector<std::unique_ptr<CryptoNote::ITransactionReader>> poolTxs2;
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_TRUE(waitForPoolSize(NODE_2, *node2, 2, poolTxs2));
|
|
|
|
|
|
|
|
// Now NODE_1 and NODE_2 are synchronized, but both are on its own alternative chains
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash tailId1;
|
|
|
|
Hash tailId2;
|
|
|
|
ASSERT_TRUE(nodeDaemons[NODE_1]->getTailBlockId(tailId1));
|
|
|
|
ASSERT_TRUE(nodeDaemons[NODE_2]->getTailBlockId(tailId2));
|
|
|
|
ASSERT_NE(tailId1, tailId2);
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
// Add block to alternative chain 2, and wait for when NODE_1 switches to alternative chain 2.
|
2015-07-30 15:22:07 +00:00
|
|
|
ASSERT_TRUE(prepareAndSubmitBlock(*nodeDaemons[NODE_2], std::move(blockTemplate2)));
|
2015-07-15 12:23:00 +00:00
|
|
|
blockchainLenght += 1;
|
|
|
|
|
|
|
|
wallet1.waitForSynchronizationToHeight(blockchainLenght);
|
|
|
|
wallet2.waitForSynchronizationToHeight(blockchainLenght);
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
std::vector<std::unique_ptr<CryptoNote::ITransactionReader>> poolTxs1;
|
2015-07-15 12:23:00 +00:00
|
|
|
ASSERT_TRUE(waitForPoolSize(NODE_1, *node1, 2, poolTxs1));
|
|
|
|
ASSERT_TRUE(waitForPoolSize(NODE_2, *node2, 2, poolTxs2));
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
// Now NODE_1 and NODE_2 are on the same chain
|
|
|
|
ASSERT_TRUE(nodeDaemons[NODE_1]->getTailBlockId(tailId1));
|
|
|
|
ASSERT_TRUE(nodeDaemons[NODE_2]->getTailBlockId(tailId2));
|
|
|
|
ASSERT_EQ(tailId1, tailId2);
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
//timer.stop();
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
std::vector<Hash> poolTxsIds1;
|
|
|
|
std::vector<Hash> poolTxsIds2;
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
for (auto& tx : poolTxs1) {
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash = tx->getTransactionHash();
|
2015-07-15 12:23:00 +00:00
|
|
|
poolTxsIds1.emplace_back(std::move(txHash));
|
|
|
|
}
|
|
|
|
for (auto& tx : poolTxs2) {
|
2015-07-30 15:22:07 +00:00
|
|
|
Hash txHash = tx->getTransactionHash();
|
2015-07-15 12:23:00 +00:00
|
|
|
poolTxsIds2.emplace_back(std::move(txHash));
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::find(poolTxsIds1.begin(), poolTxsIds1.end(), txHash0) != poolTxsIds1.end());
|
|
|
|
ASSERT_TRUE(std::find(poolTxsIds1.begin(), poolTxsIds1.end(), txHash2) != poolTxsIds1.end());
|
|
|
|
|
|
|
|
ASSERT_TRUE(std::find(poolTxsIds2.begin(), poolTxsIds2.end(), txHash0) != poolTxsIds2.end());
|
|
|
|
ASSERT_TRUE(std::find(poolTxsIds2.begin(), poolTxsIds2.end(), txHash2) != poolTxsIds2.end());
|
|
|
|
}
|
|
|
|
}
|