852 lines
42 KiB
C++
852 lines
42 KiB
C++
// Copyright (c) 2011-2015 The Cryptonote developers
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <thread>
|
|
#include <chrono>
|
|
#include <mutex>
|
|
#include <functional>
|
|
#include <future>
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <boost/program_options.hpp>
|
|
|
|
#include "CryptoNoteCore/CryptoNoteFormatUtils.h"
|
|
|
|
#include "../IntegrationTestLib/BaseFunctionalTests.h"
|
|
#include "../IntegrationTestLib/Logger.h"
|
|
|
|
#include "Logging/ConsoleLogger.h"
|
|
|
|
#ifndef CHECK_AND_ASSERT_MES
|
|
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message) do{if(!(expr)) {LOG_ERROR(message); return fail_ret_val;};}while(0)
|
|
#endif
|
|
|
|
#ifndef CHECK_AND_ASSERT_MES_NON_FATAL
|
|
#define CHECK_AND_ASSERT_MES_NON_FATAL(expr, fail_ret_val, message) do{if(!(expr)) {LOG_WARNING(message); };}while(0)
|
|
#endif
|
|
|
|
Tests::Common::BaseFunctionalTestsConfig baseCfg;
|
|
// System::Dispatcher globalDispatcher;
|
|
|
|
namespace po = boost::program_options;
|
|
namespace {
|
|
class ConfigurationError : public std::runtime_error {
|
|
public:
|
|
ConfigurationError(const char* desc) : std::runtime_error(desc) {}
|
|
};
|
|
|
|
struct Configuration : public Tests::Common::BaseFunctionalTestsConfig {
|
|
Configuration() : desc("Allowed options") {
|
|
init();
|
|
}
|
|
|
|
bool handleCommandLine(int argc, char **argv) {
|
|
po::variables_map vm;
|
|
po::store(po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(), vm);
|
|
po::notify(vm);
|
|
BaseFunctionalTestsConfig::handleCommandLine(vm);
|
|
if (vm.count("help")) {
|
|
std::cout << desc << std::endl;
|
|
return false;
|
|
}
|
|
|
|
if (vm.count("test-type")) {
|
|
auto testType = vm["test-type"].as<uint16_t>();
|
|
if (testType < 1 || testType >= TESTLAST)
|
|
throw ConfigurationError("Incorrect test type.");
|
|
_testType = (TestType)testType;
|
|
} else
|
|
throw ConfigurationError("Missing test type.");
|
|
return true;
|
|
}
|
|
|
|
enum TestType {
|
|
WALLET2WALLET = 1,
|
|
BLOCKTHRUDAEMONS = 3,
|
|
RELAYBLOCKTHRUDAEMONS = 4,
|
|
TESTPOOLANDINPROCNODE = 5,
|
|
TESTPOOLDELETION = 6,
|
|
TESTMULTIVERSION = 7,
|
|
TESTLAST
|
|
} _testType;
|
|
|
|
po::options_description desc;
|
|
|
|
protected:
|
|
void init() {
|
|
desc.add_options()
|
|
("help,h", "produce this help message and exit")
|
|
("test-type,t", po::value<uint16_t>()->default_value(1),
|
|
"test type:\r\n"
|
|
"1 - wallet to wallet test,\r\n"
|
|
"3 - block thru daemons test\r\n"
|
|
"4 - relay block thru daemons\r\n"
|
|
"5 - test tx pool and inproc node\r\n"
|
|
"6 - deleting tx from pool due to timeout\r\n"
|
|
"7 - multiple daemons interoperability test (use -a option to specify daemons)\r\n");
|
|
BaseFunctionalTestsConfig::init(desc);
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
class SimpleTest : public Tests::Common::BaseFunctionalTests {
|
|
public:
|
|
|
|
SimpleTest(const CryptoNote::Currency& currency, System::Dispatcher& system, const Tests::Common::BaseFunctionalTestsConfig& config) :
|
|
BaseFunctionalTests(currency, system, config) {}
|
|
|
|
class WaitForActualGrowObserver : public CryptoNote::IWalletLegacyObserver {
|
|
Tests::Common::Semaphore& m_GotActual;
|
|
|
|
uint64_t m_lastFunds;
|
|
|
|
public:
|
|
WaitForActualGrowObserver(Tests::Common::Semaphore& GotActual, uint64_t lastFunds) : m_GotActual(GotActual), m_lastFunds(lastFunds) { }
|
|
|
|
virtual void actualBalanceUpdated(uint64_t actualBalance) {
|
|
if (m_lastFunds < actualBalance) {
|
|
m_GotActual.notify();
|
|
}
|
|
m_lastFunds = actualBalance;
|
|
}
|
|
};
|
|
|
|
class WaitForActualDwindleObserver : public CryptoNote::IWalletLegacyObserver {
|
|
Tests::Common::Semaphore& m_GotActual;
|
|
|
|
uint64_t m_lastFunds;
|
|
|
|
public:
|
|
WaitForActualDwindleObserver(Tests::Common::Semaphore& GotActual, uint64_t lastFunds) : m_GotActual(GotActual), m_lastFunds(lastFunds) { }
|
|
|
|
virtual void actualBalanceUpdated(uint64_t actualBalance) {
|
|
if (m_lastFunds > actualBalance) {
|
|
m_GotActual.notify();
|
|
}
|
|
m_lastFunds = actualBalance;
|
|
}
|
|
};
|
|
|
|
class WaitForPendingGrowObserver : public CryptoNote::IWalletLegacyObserver {
|
|
Tests::Common::Semaphore& m_GotActual;
|
|
|
|
uint64_t m_lastFunds;
|
|
|
|
public:
|
|
WaitForPendingGrowObserver(Tests::Common::Semaphore& GotActual, uint64_t lastFunds) : m_GotActual(GotActual), m_lastFunds(lastFunds) { }
|
|
|
|
virtual void pendingBalanceUpdated(uint64_t pendingBalance) {
|
|
if (m_lastFunds < pendingBalance) {
|
|
m_GotActual.notify();
|
|
}
|
|
m_lastFunds = pendingBalance;
|
|
}
|
|
};
|
|
|
|
class WaitForConfirmationObserver : public CryptoNote::IWalletLegacyObserver {
|
|
Tests::Common::Semaphore& m_confirmed;
|
|
|
|
std::function<bool(uint64_t)> m_pred;
|
|
public:
|
|
WaitForConfirmationObserver(Tests::Common::Semaphore& confirmed, std::function<bool(uint64_t)> pred) : m_confirmed(confirmed), m_pred(pred) { }
|
|
|
|
virtual void pendingBalanceUpdated(uint64_t pendingBalance) override {
|
|
if (m_pred(pendingBalance)) m_confirmed.notify();
|
|
}
|
|
};
|
|
|
|
class WaitForSendCompletedObserver : public CryptoNote::IWalletLegacyObserver {
|
|
Tests::Common::Semaphore& m_Sent;
|
|
std::error_code& m_error;
|
|
CryptoNote::TransactionId& m_transactionId;
|
|
|
|
public:
|
|
WaitForSendCompletedObserver(Tests::Common::Semaphore& Sent, CryptoNote::TransactionId& transactionId, std::error_code& error) : m_Sent(Sent), m_transactionId(transactionId), m_error(error) { }
|
|
virtual void sendTransactionCompleted(CryptoNote::TransactionId transactionId, std::error_code result) override {
|
|
m_error = result;
|
|
m_transactionId = transactionId;
|
|
m_Sent.notify();
|
|
}
|
|
};
|
|
|
|
class WaitForExternalTransactionObserver : public CryptoNote::IWalletLegacyObserver {
|
|
public:
|
|
WaitForExternalTransactionObserver() { }
|
|
std::promise<CryptoNote::TransactionId> promise;
|
|
|
|
virtual void externalTransactionCreated(CryptoNote::TransactionId transactionId) override {
|
|
promise.set_value(transactionId);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
class WaitForTransactionUpdated : public CryptoNote::IWalletLegacyObserver {
|
|
public:
|
|
WaitForTransactionUpdated() {}
|
|
std::promise<void> promise;
|
|
|
|
virtual void transactionUpdated(CryptoNote::TransactionId transactionId) override {
|
|
if (expectindTxId == transactionId) {
|
|
promise.set_value();
|
|
}
|
|
}
|
|
|
|
CryptoNote::TransactionId expectindTxId;
|
|
};
|
|
|
|
|
|
bool perform1() {
|
|
using namespace Tests::Common;
|
|
using namespace CryptoNote;
|
|
const uint64_t FEE = 1000000;
|
|
launchTestnet(2);
|
|
LOG_TRACE("STEP 1 PASSED");
|
|
|
|
std::unique_ptr<CryptoNote::INode> node1;
|
|
std::unique_ptr<CryptoNote::INode> node2;
|
|
|
|
nodeDaemons.front()->makeINode(node1);
|
|
nodeDaemons.front()->makeINode(node2);
|
|
|
|
std::unique_ptr<CryptoNote::IWalletLegacy> wallet1;
|
|
std::unique_ptr<CryptoNote::IWalletLegacy> wallet2;
|
|
|
|
makeWallet(wallet1, node1);
|
|
makeWallet(wallet2, node2);
|
|
|
|
CHECK_AND_ASSERT_MES(mineBlock(), false, "can't mine block");
|
|
CHECK_AND_ASSERT_MES(mineBlock(), false, "can't mine block");
|
|
LOG_TRACE("STEP 2 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
CHECK_AND_ASSERT_MES(mineBlock(wallet1), false, "can't mine block on wallet 1");
|
|
CHECK_AND_ASSERT_MES(mineBlock(), false, "can't mine block");
|
|
LOG_TRACE("STEP 3 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
Semaphore wallet1GotActual;
|
|
WaitForConfirmationObserver wallet1ActualGrown(wallet1GotActual, [](uint64_t pending)->bool {return pending == 0; });
|
|
wallet1->addObserver(&wallet1ActualGrown);
|
|
CHECK_AND_ASSERT_MES(startMining(1) , false, "startMining(1) failed");
|
|
wallet1GotActual.wait();
|
|
LOG_TRACE("STEP 4 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
CHECK_AND_ASSERT_MES(stopMining() , false, "stopMining() failed");
|
|
auto wallet1ActualBeforeTransaction = wallet1->actualBalance();
|
|
auto wallet2ActualBeforeTransaction = wallet2->actualBalance();
|
|
auto wallet2PendingBeforeTransaction = wallet2->pendingBalance();
|
|
CryptoNote::WalletLegacyTransfer tr;
|
|
tr.address = wallet2->getAddress();
|
|
tr.amount = wallet1ActualBeforeTransaction / 2;
|
|
TransactionId sendTransaction;
|
|
std::error_code result;
|
|
Semaphore moneySent;
|
|
WaitForSendCompletedObserver sco1(moneySent, sendTransaction, result);
|
|
Semaphore w2GotPending;
|
|
WaitForPendingGrowObserver pgo1(w2GotPending, wallet2PendingBeforeTransaction);
|
|
wallet2->addObserver(&pgo1);
|
|
wallet1->addObserver(&sco1);
|
|
wallet1->sendTransaction(tr, FEE);
|
|
CHECK_AND_ASSERT_MES(startMining(1), false, "startMining(1) failed");
|
|
moneySent.wait();
|
|
w2GotPending.wait();
|
|
CHECK_AND_ASSERT_MES(stopMining(), false, "stopMining() failed");
|
|
auto wallet2PendingAfterTransaction = wallet2->pendingBalance();
|
|
auto wallet1PendingAfterTransaction = wallet1->pendingBalance();
|
|
auto w2PendingDiff = wallet2PendingAfterTransaction - wallet2PendingBeforeTransaction;
|
|
auto wallet1ActualAfterTransaction = wallet1->actualBalance();
|
|
|
|
LOG_TRACE("STEP 5 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
CHECK_AND_ASSERT_MES((tr.amount == w2PendingDiff), false, "STEP 6 ASSERTION 1 FAILED\r\n Transfered amount " + m_currency.formatAmount(tr.amount) + " doesn't match recieved amount " + m_currency.formatAmount(w2PendingDiff));
|
|
CHECK_AND_ASSERT_MES((wallet1ActualBeforeTransaction - wallet1PendingAfterTransaction - wallet1ActualAfterTransaction - tr.amount - FEE == 0), false,
|
|
"STEP 6 ASSERTION 2 FAILED\r\n wallet1 Actual Before Transaction doesn't match wallet1 total After Transaction + Transfered amount + Fee "
|
|
+ m_currency.formatAmount(wallet1ActualBeforeTransaction) + " <> " + m_currency.formatAmount(wallet1PendingAfterTransaction) + " + " + m_currency.formatAmount(wallet1ActualAfterTransaction) + " + " + m_currency.formatAmount(tr.amount) + " + " + m_currency.formatAmount(FEE));
|
|
LOG_TRACE("STEP 6 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
CHECK_AND_ASSERT_MES(startMining(1), false, "startMining(1) failed");
|
|
Semaphore confirmed2;
|
|
Semaphore confirmed1;
|
|
WaitForConfirmationObserver confirmationObserver2(confirmed2, [](uint64_t pending)->bool {return pending == 0; });
|
|
WaitForConfirmationObserver confirmationObserver1(confirmed1, [](uint64_t pending)->bool {return pending == 0; });
|
|
wallet2->addObserver(&confirmationObserver2);
|
|
wallet1->addObserver(&confirmationObserver1);
|
|
if (wallet2->pendingBalance() != 0) confirmed2.wait();
|
|
if (wallet1->pendingBalance() != 0) confirmed1.wait();
|
|
CHECK_AND_ASSERT_MES(stopMining(), false, "stopMining() failed");
|
|
auto wallet1ActualAfterTransactionAndConfirmation = wallet1->actualBalance();
|
|
auto wallet2ActualAfterTransactionAndConfirmation = wallet2->actualBalance();
|
|
auto w2ActualDiff = wallet2ActualAfterTransactionAndConfirmation - wallet2ActualBeforeTransaction;
|
|
auto w1ActualDiff = wallet1ActualBeforeTransaction - wallet1ActualAfterTransactionAndConfirmation;
|
|
CHECK_AND_ASSERT_MES((tr.amount == w2ActualDiff), false, "STEP 7 FAILED\r\n Transfered amount " + m_currency.formatAmount(tr.amount) + " doesn't match confirmed recieved amount " + m_currency.formatAmount(w2ActualDiff));
|
|
CHECK_AND_ASSERT_MES((w1ActualDiff - tr.amount - FEE == 0), false,
|
|
"STEP 7 FAILED\r\n wallet1 Actual Before Transaction doesn't match wallet1 Actual After Transaction + Transfered amount + Fee "
|
|
+ m_currency.formatAmount(wallet1ActualBeforeTransaction) + " <> " + m_currency.formatAmount(wallet1ActualAfterTransactionAndConfirmation) + "+" + m_currency.formatAmount(tr.amount) + "+" + m_currency.formatAmount(FEE));
|
|
LOG_TRACE("STEP 7 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
wallet1->removeObserver(&wallet1ActualGrown);
|
|
wallet2->removeObserver(&pgo1);
|
|
wallet1->removeObserver(&sco1);
|
|
wallet2->removeObserver(&confirmationObserver2);
|
|
wallet1->removeObserver(&confirmationObserver1);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
|
|
return true;
|
|
}
|
|
|
|
class WaitForBlockchainHeightChangeObserver : public CryptoNote::INodeObserver {
|
|
Tests::Common::Semaphore& m_changed;
|
|
public:
|
|
WaitForBlockchainHeightChangeObserver(Tests::Common::Semaphore& changed) : m_changed(changed) { }
|
|
virtual void lastKnownBlockHeightUpdated(uint32_t height) override {
|
|
m_changed.notify();
|
|
}
|
|
};
|
|
|
|
class CallbackHeightChangeObserver : public CryptoNote::INodeObserver {
|
|
std::function<void(uint32_t)> m_callback;
|
|
public:
|
|
CallbackHeightChangeObserver(std::function<void(uint32_t)> callback) : m_callback(callback) {}
|
|
virtual void lastKnownBlockHeightUpdated(uint32_t height) override {
|
|
m_callback(height);
|
|
}
|
|
};
|
|
|
|
bool perform2(size_t blocksCount = 10)
|
|
{
|
|
using namespace Tests::Common;
|
|
launchTestnet(3, Line);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
|
|
LOG_TRACE("STEP 1 PASSED");
|
|
mineBlock();
|
|
mineBlock();
|
|
LOG_TRACE("STEP 2 PASSED");
|
|
std::unique_ptr<CryptoNote::INode> localNode;
|
|
std::unique_ptr<CryptoNote::INode> remoteNode;
|
|
|
|
nodeDaemons.front()->makeINode(localNode);
|
|
nodeDaemons.back()->makeINode(remoteNode);
|
|
|
|
std::unique_ptr<CryptoNote::IWalletLegacy> wallet;
|
|
makeWallet(wallet, localNode);
|
|
|
|
LOG_TRACE("STEP 3 PASSED");
|
|
Semaphore blockMined;
|
|
Semaphore blockArrivedToRemote;
|
|
|
|
WaitForBlockchainHeightChangeObserver localHCO(blockMined);
|
|
WaitForBlockchainHeightChangeObserver remoteHCO(blockArrivedToRemote);
|
|
|
|
localNode->addObserver(&localHCO);
|
|
remoteNode->addObserver(&remoteHCO);
|
|
for (size_t blockNumber = 0; blockNumber < blocksCount; ++blockNumber) {
|
|
nodeDaemons.front()->startMining(1, wallet->getAddress());
|
|
blockMined.wait();
|
|
CHECK_AND_ASSERT_MES(blockArrivedToRemote.wait_for(std::chrono::milliseconds(5000)), false, "block propagation too slow >5000ms.");
|
|
nodeDaemons.front()->stopMining();
|
|
LOG_TRACE("STEP 4 STAGE " + TO_STRING(blockNumber+1) + " of " + TO_STRING(blocksCount)+" PASSED");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool perform4() {
|
|
using namespace CryptoNote;
|
|
using namespace Tests::Common;
|
|
launchTestnet(3, Star);
|
|
LOG_TRACE("STEP 1 PASSED");
|
|
|
|
std::unique_ptr<CryptoNote::INode> hopNode;
|
|
std::unique_ptr<CryptoNote::INode> localNode;
|
|
std::unique_ptr<CryptoNote::INode> remoteNode;
|
|
|
|
nodeDaemons[0]->makeINode(hopNode);
|
|
nodeDaemons[1]->makeINode(localNode);
|
|
nodeDaemons[2]->makeINode(remoteNode);
|
|
|
|
LOG_TRACE("STEP 2 PASSED");
|
|
|
|
|
|
std::string test_block1_hex =
|
|
"0101b392d79f05a742885cb01d11b7b36fb8bf14616d42cd3d8c1429a224df41afa81b86b8a3a84e"
|
|
"d8c33f010b01ff0108c0a62d02cc353782cbe4c6067bd30510f11d1f2993f2c7fed37239f299ffe3"
|
|
"f96f135675c096b102023e8d4b2c22d73f91d0d9f8e0e12c8df24e5917f00d0b2dd99786c5bb0e5b"
|
|
"300580bbb021022764ae61c084db07e7cd83c55e9c833f42b1d422e1008220fdb4acc726b94ea980"
|
|
"88debe01023330c2b7dc4840f478066370ae48b148ce8dd010c59f6ecc08598682d32f07d080a0d9"
|
|
"e61d02bcf35dc40ead54a614174774e60d8f5d0e46272c70bc7e70f205f7ccef25c34980b09dc2df"
|
|
"01026ddcf1aed901f018453fd9352a01d5a44067d271ca403b4cd799d9832076daa280f092cbdd08"
|
|
"021f613eab32b76ed03f6a796de7a5c92009ea9f9b9e3299ec91df7657cd694e5580c089a9a2f50f"
|
|
"02f545046885a297ba63a2c7b305a74fdb741129cc367330661c1363e0bb0f0d0b2101acf052dcbe"
|
|
"407bc34df1b7fffc17f0bfb0ffc23002e2b6de48a210df6f78bf1400";
|
|
std::string test_block2_hex =
|
|
"0101b492d79f05456231a956ed3a8c1ac0bfe8efc1bb5d522d8474e566b051919ddea0ceab478a74"
|
|
"e35210010c01ff0207c0e41202b2d7e697c6e2e894f9e98262c278235720b39f3a149774cb58cb52"
|
|
"e5dde21601c09fab0302abffefad3afab42ca1ce2f7dccfa6942256f31387b307becd43571cfe22a"
|
|
"10688084af5f02e2ab32d9b8fb8ced4bf4a81de0f48c23dc575076e8d233a3532d28f36e79035380"
|
|
"a0d9e61d020c10664fe1ca35418733fa32ae2deadd4bf7ed982bb5d11ba98a7940a73e161580b09d"
|
|
"c2df010266c3bfa27436b480a217a2fe06df714f4d2094ec1a0ced3bac2d96881972e28a80f092cb"
|
|
"dd0802f31e9ac25fb8afd1d9d964331242a94f023c3188db5e532b5a9c800a843a3ebc80c089a9a2"
|
|
"f50f0206244fcc73941c3da62ea6d62d679bedb311fc530d149099bdfd04c59cd507a121019d4b74"
|
|
"f09454ccfdd6ca44b8c5f73c6805ea08dbe6a71769b058e158b2d4df5100";
|
|
std::string test_block3_hex =
|
|
"0101b492d79f051f6fe6d9f7c14c0d5e16ba82d9ea68e4e6d6f30726854d45330aeb2fae5c1cd3fb"
|
|
"7f4352010d01ff0308ffae350220f4c1c7631ecf4247688c376665df2b9dd935af6e4c027c9cddcb"
|
|
"400fefec7380a4e803029e05ef9b3295e178d0f3199fca420f909f04fdab09b97c14290c8a913e42"
|
|
"19c68087a70e02693641fefb1a6da81c2308370f349ef5e4adab792ae06b5da989ae3f1b7a13ca80"
|
|
"d293ad0302c14d721ed8da5c98f108ef17c326737765857ddfa0b705fd4483cfa7ffeaad51808cee"
|
|
"891a02f5a8e2ac24d6a9f789e5514de520c3ac28387788e130e22c4250b7d1be47460380b09dc2df"
|
|
"0102cc3b2f894b416f3e09afae0395fc01cc2ec9763dff72839944e60055049ea37d80f092cbdd08"
|
|
"02772df06a2cd92c174815ae1572799430ea01e903796f6a763648c7b350151ce580c089a9a2f50f"
|
|
"0211c7bea98edba4fad6d3f19b330a676b8fb0391f7a99f45542e7cf52d39d6c632101e0370c5c79"
|
|
"e99d772b41e0569bc41e1ebde2e563cdb7f5bdd23984899fad103200";
|
|
std::string test_block4_hex =
|
|
"0101b492d79f0537da79424e1cc69d16aadf174dcf443947f8027695a5d1e30b2be4f5aa71904194"
|
|
"47fe54010e01ff0407fffc1a0278eb82c9ea2f1e998906cec55caf26e347224c3391fb0aa2213bc1"
|
|
"5eec4dacc580bbb021024ce32a63614269f43f698644c98fd9b7a11694dc69fd5126f6f6735ba6c5"
|
|
"98dd808c8d9e0202d539ead46faf6d786964dd5106004612eb8d64778ad4fe8befa8c63e4d666f92"
|
|
"808cee891a021a6c6669298dcc1c86af887804f128123d95a6d96b5884db97cfc96fa9ad018e80b0"
|
|
"9dc2df0102dd3b9bbfef1eddeef8c406de9c0c4fc469c8069c910541252491df5a482fd5e380f092"
|
|
"cbdd0802176a4cb411309761b7f50b0f495e99cc55cbaae70011d3c901e409a8a938f1b680c089a9"
|
|
"a2f50f02bb232a77911350a1315de0b3de447142390f97e5ef25ecc1bf5837a8972b4b5e2101ef54"
|
|
"5c318e38cfdd92362340fab6ec6630e4134b93cfd01db4d9a42fa945fdef00";
|
|
|
|
Semaphore blockArrivedToRemote;
|
|
|
|
WaitForBlockchainHeightChangeObserver remoteHCO(blockArrivedToRemote);
|
|
|
|
std::chrono::steady_clock::time_point localAdded;
|
|
std::chrono::steady_clock::time_point hoplAdded;
|
|
std::chrono::steady_clock::time_point remoteAdded;
|
|
std::chrono::steady_clock::time_point submitInvokingStart;
|
|
std::chrono::steady_clock::time_point submitInvoked;
|
|
|
|
//auto height = localNode->getLastKnownBlockHeight();
|
|
|
|
CallbackHeightChangeObserver CHCOLocal([&localAdded](uint64_t new_height){localAdded = std::chrono::steady_clock::now(); });
|
|
CallbackHeightChangeObserver CHCOHop([&hoplAdded](uint64_t new_height){hoplAdded = std::chrono::steady_clock::now(); });
|
|
CallbackHeightChangeObserver CHCORemote([&remoteAdded](uint64_t new_height){remoteAdded = std::chrono::steady_clock::now(); });
|
|
|
|
localNode->addObserver(&CHCOLocal);
|
|
hopNode->addObserver(&CHCOHop);
|
|
remoteNode->addObserver(&CHCORemote);
|
|
remoteNode->addObserver(&remoteHCO);
|
|
|
|
LOG_TRACE("test_block1");
|
|
submitInvokingStart = std::chrono::steady_clock::now();
|
|
if (!nodeDaemons[1]->submitBlock(test_block1_hex)) return false;
|
|
submitInvoked = std::chrono::steady_clock::now();
|
|
CHECK_AND_ASSERT_MES(blockArrivedToRemote.wait_for(std::chrono::milliseconds(10000)), false, "block 1 propagation too slow >10000ms.");
|
|
LOG_TRACE("submitBlock() invocation takes: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(submitInvoked - submitInvokingStart).count()) + " ms");
|
|
LOG_TRACE("HeightChangedCallback() since submit : " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(localAdded - submitInvoked).count()) + " ms");
|
|
LOG_TRACE("Local -> HopNode: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(hoplAdded - localAdded).count()) + " ms");
|
|
LOG_TRACE("HopNode -> Remote: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(remoteAdded - hoplAdded).count()) + " ms");
|
|
LOG_TRACE("Local -> Remote: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(remoteAdded - localAdded).count()) + " ms");
|
|
|
|
LOG_TRACE("test_block2");
|
|
submitInvokingStart = std::chrono::steady_clock::now();
|
|
if (!nodeDaemons[1]->submitBlock(test_block2_hex)) return false;
|
|
submitInvoked = std::chrono::steady_clock::now();
|
|
CHECK_AND_ASSERT_MES(blockArrivedToRemote.wait_for(std::chrono::milliseconds(10000)), false, "block 2 propagation too slow >10000ms.");
|
|
LOG_TRACE("submitBlock() invocation takes: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(submitInvoked - submitInvokingStart).count()) + " ms");
|
|
LOG_TRACE("HeightChangedCallback() since submit : " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(localAdded - submitInvoked).count()) + " ms");
|
|
LOG_TRACE("Local -> HopNode: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(hoplAdded - localAdded).count()) + " ms");
|
|
LOG_TRACE("HopNode -> Remote: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(remoteAdded - hoplAdded).count()) + " ms");
|
|
LOG_TRACE("Local -> Remote: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(remoteAdded - localAdded).count()) + " ms");
|
|
|
|
LOG_TRACE("test_block3");
|
|
submitInvokingStart = std::chrono::steady_clock::now();
|
|
if (!nodeDaemons[1]->submitBlock(test_block3_hex)) return false;
|
|
submitInvoked = std::chrono::steady_clock::now();
|
|
CHECK_AND_ASSERT_MES(blockArrivedToRemote.wait_for(std::chrono::milliseconds(10000)), false, "block 3 propagation too slow >10000ms.");
|
|
LOG_TRACE("submitBlock() invocation takes: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(submitInvoked - submitInvokingStart).count()) + " ms");
|
|
LOG_TRACE("HeightChangedCallback() since submit : " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(localAdded - submitInvoked).count()) + " ms");
|
|
LOG_TRACE("Local -> HopNode: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(hoplAdded - localAdded).count()) + " ms");
|
|
LOG_TRACE("HopNode -> Remote: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(remoteAdded - hoplAdded).count()) + " ms");
|
|
LOG_TRACE("Local -> Remote: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(remoteAdded - localAdded).count()) + " ms");
|
|
|
|
LOG_TRACE("test_block4");
|
|
submitInvokingStart = std::chrono::steady_clock::now();
|
|
if (!nodeDaemons[1]->submitBlock(test_block4_hex)) return false;
|
|
submitInvoked = std::chrono::steady_clock::now();
|
|
CHECK_AND_ASSERT_MES(blockArrivedToRemote.wait_for(std::chrono::milliseconds(10000)), false, "block 4 propagation too slow >10000ms.");
|
|
LOG_TRACE("submitBlock() invocation takes: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(submitInvoked - submitInvokingStart).count()) + " ms");
|
|
LOG_TRACE("HeightChangedCallback() since submit : " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(localAdded - submitInvoked).count()) + " ms");
|
|
LOG_TRACE("Local -> HopNode: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(hoplAdded - localAdded).count()) + " ms");
|
|
LOG_TRACE("HopNode -> Remote: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(remoteAdded - hoplAdded).count()) + " ms");
|
|
LOG_TRACE("Local -> Remote: " + TO_STRING(std::chrono::duration_cast<std::chrono::milliseconds>(remoteAdded - localAdded).count()) + " ms");
|
|
|
|
localNode.release();
|
|
remoteNode.release();
|
|
hopNode.release();
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
|
|
return true;
|
|
}
|
|
|
|
|
|
bool perform5() {
|
|
using namespace Tests::Common;
|
|
using namespace CryptoNote;
|
|
const uint64_t FEE = 1000000;
|
|
launchTestnetWithInprocNode(2);
|
|
|
|
std::unique_ptr<CryptoNote::INode> node1;
|
|
std::unique_ptr<CryptoNote::INode> inprocNode;
|
|
|
|
nodeDaemons.front()->makeINode(node1);
|
|
nodeDaemons.back()->makeINode(inprocNode);
|
|
|
|
while (node1->getLastLocalBlockHeight() != inprocNode->getLastLocalBlockHeight()) {
|
|
LOG_TRACE("Syncing...");
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
}
|
|
|
|
LOG_TRACE("STEP 1 PASSED");
|
|
|
|
std::unique_ptr<CryptoNote::IWalletLegacy> wallet1;
|
|
std::unique_ptr<CryptoNote::IWalletLegacy> wallet2;
|
|
|
|
makeWallet(wallet1, node1);
|
|
makeWallet(wallet2, inprocNode);
|
|
|
|
CHECK_AND_ASSERT_MES(mineBlock(), false, "can't mine block");
|
|
CHECK_AND_ASSERT_MES(mineBlock(), false, "can't mine block");
|
|
LOG_TRACE("STEP 2 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
|
|
CHECK_AND_ASSERT_MES(mineBlock(wallet1), false, "can't mine block on wallet 1");
|
|
|
|
LOG_TRACE("STEP 3 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
|
|
Semaphore wallet1GotActual;
|
|
WaitForConfirmationObserver wallet1ActualGrown(wallet1GotActual, [&wallet1](uint64_t actual)->bool {return wallet1->pendingBalance() == actual; });
|
|
wallet1->addObserver(&wallet1ActualGrown);
|
|
CHECK_AND_ASSERT_MES(startMining(1), false, "startMining(1) failed");
|
|
wallet1GotActual.wait();
|
|
|
|
LOG_TRACE("STEP 4 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
|
|
CHECK_AND_ASSERT_MES(stopMining(), false, "stopMining() failed");
|
|
|
|
auto wallet1ActualBeforeTransaction = wallet1->actualBalance();
|
|
auto wallet1PendingBeforeTransaction = wallet1->pendingBalance();
|
|
auto wallet2ActualBeforeTransaction = wallet2->actualBalance();
|
|
auto wallet2PendingBeforeTransaction = wallet2->pendingBalance();
|
|
CryptoNote::WalletLegacyTransfer tr;
|
|
tr.address = wallet2->getAddress();
|
|
tr.amount = wallet1ActualBeforeTransaction / 2;
|
|
std::error_code result;
|
|
Semaphore w2GotPending;
|
|
WaitForPendingGrowObserver pgo1(w2GotPending, wallet2PendingBeforeTransaction);
|
|
wallet2->addObserver(&pgo1);
|
|
|
|
WaitForExternalTransactionObserver poolTxWaiter;
|
|
auto future = poolTxWaiter.promise.get_future();
|
|
wallet2->addObserver(&poolTxWaiter);
|
|
|
|
wallet1->sendTransaction(tr, FEE);
|
|
|
|
auto txId = future.get();
|
|
w2GotPending.wait();
|
|
|
|
wallet2->removeObserver(&poolTxWaiter);
|
|
CryptoNote::WalletLegacyTransaction txInfo;
|
|
wallet2->getTransaction(txId, txInfo);
|
|
|
|
auto wallet2PendingAfterTransaction = wallet2->pendingBalance();
|
|
auto wallet1PendingAfterTransaction = wallet1->pendingBalance();
|
|
auto w2PendingDiff = wallet2PendingAfterTransaction - wallet2PendingBeforeTransaction;
|
|
auto w1PendingDiff = wallet1PendingBeforeTransaction - wallet1PendingAfterTransaction;
|
|
CHECK_AND_ASSERT_MES((txInfo.blockHeight == WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT), false, "STEP 5 ASSERTION 1 FAILED\r\n Transaction blockHeight differs unconfirmed_tx_height");
|
|
CHECK_AND_ASSERT_MES((tr.amount == txInfo.totalAmount), false, "STEP 5 ASSERTION 2 FAILED\r\n Transfered amount " + m_currency.formatAmount(tr.amount) + " doesn't match recieved amount from pool transaction " + m_currency.formatAmount(txInfo.totalAmount));
|
|
CHECK_AND_ASSERT_MES((tr.amount == w2PendingDiff), false, "STEP 5 ASSERTION 3 FAILED\r\n Transfered amount " + m_currency.formatAmount(tr.amount) + " doesn't match recieved amount " + m_currency.formatAmount(w2PendingDiff));
|
|
CHECK_AND_ASSERT_MES((w1PendingDiff - tr.amount - FEE == 0), false,
|
|
"STEP 5 ASSERTION 4 FAILED\r\n wallet1 Pending Before Transaction doesn't match wallet1 Pending After Transaction + Transfered amount + Fee "
|
|
+ m_currency.formatAmount(wallet1PendingBeforeTransaction) + " <> " + m_currency.formatAmount(wallet1PendingAfterTransaction) + "+" + m_currency.formatAmount(tr.amount) + "+" + m_currency.formatAmount(FEE));
|
|
|
|
LOG_TRACE("STEP 5 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
|
|
WaitForTransactionUpdated trasactionConfirmationObserver;
|
|
trasactionConfirmationObserver.expectindTxId = txId;
|
|
|
|
wallet2->addObserver(&trasactionConfirmationObserver);
|
|
auto txUpdated = trasactionConfirmationObserver.promise.get_future();
|
|
|
|
CHECK_AND_ASSERT_MES(mineBlock(), false, "mineBlock() failed");
|
|
CHECK_AND_ASSERT_MES(mineBlock(), false, "mineBlock() failed");
|
|
txUpdated.get();
|
|
wallet2->getTransaction(txId, txInfo);
|
|
wallet2->removeObserver(&trasactionConfirmationObserver);
|
|
|
|
CHECK_AND_ASSERT_MES(txInfo.blockHeight <= inprocNode->getLastLocalBlockHeight(), false, "STEP 6 ASSERTION FAILED tx height confirmation failed");
|
|
LOG_TRACE("STEP 6 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
|
|
|
|
CHECK_AND_ASSERT_MES(startMining(1), false, "startMining(1) failed");
|
|
Semaphore confirmed2;
|
|
Semaphore confirmed1;
|
|
WaitForConfirmationObserver confirmationObserver2(confirmed2, [&wallet2](uint64_t actual)->bool {return wallet2->pendingBalance() == actual; });
|
|
WaitForConfirmationObserver confirmationObserver1(confirmed1, [&wallet1](uint64_t actual)->bool {return wallet1->pendingBalance() == actual; });
|
|
wallet2->addObserver(&confirmationObserver2);
|
|
wallet1->addObserver(&confirmationObserver1);
|
|
if (wallet2->pendingBalance() != wallet2->actualBalance()) confirmed2.wait();
|
|
if (wallet1->pendingBalance() != wallet1->actualBalance()) confirmed1.wait();
|
|
CHECK_AND_ASSERT_MES(stopMining(), false, "stopMining() failed");
|
|
auto wallet1ActualAfterTransactionAndConfirmation = wallet1->actualBalance();
|
|
auto wallet2ActualAfterTransactionAndConfirmation = wallet2->actualBalance();
|
|
auto w2ActualDiff = wallet2ActualAfterTransactionAndConfirmation - wallet2ActualBeforeTransaction;
|
|
auto w1ActualDiff = wallet1ActualBeforeTransaction - wallet1ActualAfterTransactionAndConfirmation;
|
|
CHECK_AND_ASSERT_MES((tr.amount == w2ActualDiff), false, "STEP 7 FAILED\r\n Transfered amount " + m_currency.formatAmount(tr.amount) + " doesn't match confirmed recieved amount " + m_currency.formatAmount(w2ActualDiff));
|
|
CHECK_AND_ASSERT_MES((w1ActualDiff - tr.amount - FEE == 0), false,
|
|
"STEP 7 FAILED\r\n wallet1 Actual Before Transaction doesn't match wallet1 Actual After Transaction + Transfered amount + Fee "
|
|
+ m_currency.formatAmount(wallet1ActualBeforeTransaction) + " <> " + m_currency.formatAmount(wallet1ActualAfterTransactionAndConfirmation) + "+" + m_currency.formatAmount(tr.amount) + "+" + m_currency.formatAmount(FEE));
|
|
LOG_TRACE("STEP 7 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
wallet1->removeObserver(&wallet1ActualGrown);
|
|
wallet2->removeObserver(&pgo1);
|
|
wallet2->removeObserver(&confirmationObserver2);
|
|
wallet1->removeObserver(&confirmationObserver1);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
|
|
return true;
|
|
}
|
|
|
|
|
|
bool perform6() {
|
|
using namespace Tests::Common;
|
|
using namespace CryptoNote;
|
|
const uint64_t FEE = 1000000;
|
|
launchTestnetWithInprocNode(2);
|
|
|
|
std::unique_ptr<CryptoNote::INode> node1;
|
|
std::unique_ptr<CryptoNote::INode> inprocNode;
|
|
|
|
nodeDaemons.front()->makeINode(node1);
|
|
nodeDaemons.back()->makeINode(inprocNode);
|
|
|
|
while (node1->getLastLocalBlockHeight() != inprocNode->getLastLocalBlockHeight()) {
|
|
LOG_TRACE("Syncing...");
|
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
}
|
|
|
|
LOG_TRACE("STEP 1 PASSED");
|
|
|
|
std::unique_ptr<CryptoNote::IWalletLegacy> wallet1;
|
|
std::unique_ptr<CryptoNote::IWalletLegacy> wallet2;
|
|
|
|
makeWallet(wallet1, node1);
|
|
makeWallet(wallet2, inprocNode);
|
|
|
|
CHECK_AND_ASSERT_MES(mineBlock(), false, "can't mine block");
|
|
CHECK_AND_ASSERT_MES(mineBlock(), false, "can't mine block");
|
|
LOG_TRACE("STEP 2 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
|
|
CHECK_AND_ASSERT_MES(mineBlock(wallet1), false, "can't mine block on wallet 1");
|
|
|
|
LOG_TRACE("STEP 3 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
|
|
Semaphore wallet1GotActual;
|
|
WaitForConfirmationObserver wallet1ActualGrown(wallet1GotActual, [&wallet1](uint64_t actual)->bool {return wallet1->pendingBalance() == actual; });
|
|
wallet1->addObserver(&wallet1ActualGrown);
|
|
CHECK_AND_ASSERT_MES(startMining(1), false, "startMining(1) failed");
|
|
wallet1GotActual.wait();
|
|
|
|
LOG_TRACE("STEP 4 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
|
|
CHECK_AND_ASSERT_MES(stopMining(), false, "stopMining() failed");
|
|
|
|
auto wallet1ActualBeforeTransaction = wallet1->actualBalance();
|
|
auto wallet1PendingBeforeTransaction = wallet1->pendingBalance();
|
|
auto wallet2PendingBeforeTransaction = wallet2->pendingBalance();
|
|
CryptoNote::WalletLegacyTransfer tr;
|
|
tr.address = wallet2->getAddress();
|
|
tr.amount = wallet1ActualBeforeTransaction / 2;
|
|
std::error_code result;
|
|
Semaphore w2GotPending;
|
|
WaitForPendingGrowObserver pgo1(w2GotPending, wallet2PendingBeforeTransaction);
|
|
wallet2->addObserver(&pgo1);
|
|
|
|
WaitForExternalTransactionObserver poolTxWaiter;
|
|
auto future = poolTxWaiter.promise.get_future();
|
|
wallet2->addObserver(&poolTxWaiter);
|
|
|
|
wallet1->sendTransaction(tr, FEE);
|
|
|
|
auto txId = future.get();
|
|
w2GotPending.wait();
|
|
|
|
wallet2->removeObserver(&poolTxWaiter);
|
|
CryptoNote::WalletLegacyTransaction txInfo;
|
|
wallet2->getTransaction(txId, txInfo);
|
|
|
|
auto wallet2PendingAfterTransaction = wallet2->pendingBalance();
|
|
auto wallet1PendingAfterTransaction = wallet1->pendingBalance();
|
|
auto w2PendingDiff = wallet2PendingAfterTransaction - wallet2PendingBeforeTransaction;
|
|
auto w1PendingDiff = wallet1PendingBeforeTransaction - wallet1PendingAfterTransaction;
|
|
CHECK_AND_ASSERT_MES((txInfo.blockHeight == WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT), false, "STEP 5 ASSERTION 1 FAILED\r\n Transaction blockHeight differs unconfirmed_tx_height");
|
|
CHECK_AND_ASSERT_MES((tr.amount == txInfo.totalAmount), false, "STEP 5 ASSERTION 2 FAILED\r\n Transfered amount " + m_currency.formatAmount(tr.amount) + " doesn't match recieved amount from pool transaction " + m_currency.formatAmount(txInfo.totalAmount));
|
|
CHECK_AND_ASSERT_MES((tr.amount == w2PendingDiff), false, "STEP 5 ASSERTION 3 FAILED\r\n Transfered amount " + m_currency.formatAmount(tr.amount) + " doesn't match recieved amount " + m_currency.formatAmount(w2PendingDiff));
|
|
CHECK_AND_ASSERT_MES((w1PendingDiff - tr.amount - FEE == 0), false,
|
|
"STEP 5 ASSERTION 4 FAILED\r\n wallet1 Pending Before Transaction doesn't match wallet1 Pending After Transaction + Transfered amount + Fee "
|
|
+ m_currency.formatAmount(wallet1PendingBeforeTransaction) + " <> " + m_currency.formatAmount(wallet1PendingAfterTransaction) + "+" + m_currency.formatAmount(tr.amount) + "+" + m_currency.formatAmount(FEE));
|
|
|
|
LOG_TRACE("STEP 5 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
|
|
|
|
|
|
|
|
|
|
WaitForTransactionUpdated trasactionDeletionObserver;
|
|
trasactionDeletionObserver.expectindTxId = txId;
|
|
|
|
wallet2->addObserver(&trasactionDeletionObserver);
|
|
auto txUpdated = trasactionDeletionObserver.promise.get_future();
|
|
|
|
txUpdated.get();
|
|
wallet2->getTransaction(txId, txInfo);
|
|
wallet2->removeObserver(&trasactionDeletionObserver);
|
|
|
|
|
|
CHECK_AND_ASSERT_MES(txInfo.state == WalletLegacyTransactionState::Deleted, false, "STEP 6 ASSERTION 1 FAILED tx not deleted");
|
|
CHECK_AND_ASSERT_MES(wallet2PendingBeforeTransaction == wallet2->pendingBalance(), false, "STEP 6 ASSERTION 2 FAILED current pending balance <> pending balance before transaction");
|
|
|
|
LOG_TRACE("STEP 6 PASSED");
|
|
LOG_DEBUG("Wallet1 pending: " + m_currency.formatAmount(wallet1->pendingBalance()));
|
|
LOG_DEBUG("Wallet1 actual: " + m_currency.formatAmount(wallet1->actualBalance()));
|
|
LOG_DEBUG("Wallet2 pending: " + m_currency.formatAmount(wallet2->pendingBalance()));
|
|
LOG_DEBUG("Wallet2 actual: " + m_currency.formatAmount(wallet2->actualBalance()));
|
|
|
|
wallet1->removeObserver(&wallet1ActualGrown);
|
|
wallet2->removeObserver(&pgo1);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
|
|
return true;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
void testMultiVersion(const CryptoNote::Currency& currency, System::Dispatcher& d, const Tests::Common::BaseFunctionalTestsConfig& config);
|
|
|
|
|
|
class SimpleTestCase : public ::testing::Test {
|
|
|
|
public:
|
|
|
|
SimpleTestCase() :
|
|
currency(CryptoNote::CurrencyBuilder(logger).testnet(true).currency()),
|
|
test(currency, dispatcher, baseCfg) {
|
|
}
|
|
|
|
System::Dispatcher dispatcher;
|
|
Logging::ConsoleLogger logger;
|
|
CryptoNote::Currency currency;
|
|
SimpleTest test;
|
|
};
|
|
|
|
TEST_F(SimpleTestCase, WALLET2WALLET) {
|
|
ASSERT_TRUE(test.perform1());
|
|
}
|
|
|
|
TEST_F(SimpleTestCase, BLOCKTHRUDAEMONS) {
|
|
ASSERT_TRUE(test.perform2());
|
|
}
|
|
|
|
TEST_F(SimpleTestCase, RELAYBLOCKTHRUDAEMONS) {
|
|
ASSERT_TRUE(test.perform4());
|
|
}
|
|
|
|
TEST_F(SimpleTestCase, TESTPOOLANDINPROCNODE) {
|
|
ASSERT_TRUE(test.perform5());
|
|
}
|
|
|
|
TEST_F(SimpleTestCase, TESTPOOLDELETION) {
|
|
currency = CryptoNote::CurrencyBuilder(logger).testnet(true).mempoolTxLiveTime(60).currency();
|
|
ASSERT_TRUE(test.perform6());
|
|
}
|
|
|
|
TEST_F(SimpleTestCase, MULTIVERSION) {
|
|
ASSERT_NO_THROW(testMultiVersion(currency, dispatcher, baseCfg));
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
CLogger::Instance().init(CLogger::DEBUG);
|
|
|
|
try {
|
|
::Configuration config;
|
|
if (!config.handleCommandLine(argc, argv)) {
|
|
return 0; //help message requested or so
|
|
}
|
|
|
|
baseCfg = config;
|
|
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|
|
catch (::ConfigurationError& ex) {
|
|
std::cerr << "Configuration error: " << ex.what() << std::endl;
|
|
return 1;
|
|
}
|
|
catch (std::exception& ex) {
|
|
LOG_ERROR("Fatal error: " + std::string(ex.what()));
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|