2016-01-18 15:33:29 +00:00
|
|
|
// Copyright (c) 2011-2016 The Cryptonote developers
|
2015-04-23 16:07:22 +00:00
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <tuple>
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
#include "CryptoNoteCore/TransactionApi.h"
|
2015-05-27 12:08:46 +00:00
|
|
|
#include "Logging/ConsoleLogger.h"
|
2015-07-30 15:22:07 +00:00
|
|
|
#include "Transfers/TransfersSubscription.h"
|
|
|
|
#include "Transfers/TypeHelpers.h"
|
2015-04-06 16:13:07 +00:00
|
|
|
#include "ITransfersContainer.h"
|
|
|
|
|
|
|
|
#include "TransactionApiHelpers.h"
|
|
|
|
#include "TransfersObserver.h"
|
|
|
|
|
|
|
|
using namespace CryptoNote;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
const uint32_t UNCONFIRMED_TRANSACTION_HEIGHT = std::numeric_limits<uint32_t>::max();
|
|
|
|
const uint32_t UNCONFIRMED = std::numeric_limits<uint32_t>::max();
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
std::error_code createError() {
|
|
|
|
return std::make_error_code(std::errc::invalid_argument);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class TransfersSubscriptionTest : public ::testing::Test {
|
|
|
|
public:
|
|
|
|
|
|
|
|
TransfersSubscriptionTest() :
|
2015-05-27 12:08:46 +00:00
|
|
|
currency(CurrencyBuilder(m_logger).currency()),
|
2015-04-06 16:13:07 +00:00
|
|
|
account(generateAccountKeys()),
|
|
|
|
syncStart(SynchronizationStart{ 0, 0 }),
|
|
|
|
sub(currency, AccountSubscription{ account, syncStart, 10 }) {
|
|
|
|
sub.addObserver(&observer);
|
|
|
|
}
|
|
|
|
|
2015-07-30 15:22:07 +00:00
|
|
|
std::shared_ptr<ITransactionReader> addTransaction(uint64_t amount, uint32_t height, uint32_t outputIndex) {
|
|
|
|
TestTransactionBuilder b1;
|
|
|
|
auto unknownSender = generateAccountKeys();
|
|
|
|
b1.addTestInput(amount, unknownSender);
|
|
|
|
auto outInfo = b1.addTestKeyOutput(amount, outputIndex, account);
|
|
|
|
auto tx = std::shared_ptr<ITransactionReader>(b1.build().release());
|
|
|
|
|
2015-04-06 16:13:07 +00:00
|
|
|
std::vector<TransactionOutputInformationIn> outputs = { outInfo };
|
2015-08-11 14:33:19 +00:00
|
|
|
sub.addTransaction(TransactionBlockInfo{ height, 100000 }, *tx, outputs);
|
2015-04-06 16:13:07 +00:00
|
|
|
return tx;
|
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
Logging::ConsoleLogger m_logger;
|
2015-04-06 16:13:07 +00:00
|
|
|
Currency currency;
|
|
|
|
AccountKeys account;
|
|
|
|
SynchronizationStart syncStart;
|
|
|
|
TransfersSubscription sub;
|
|
|
|
TransfersObserver observer;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(TransfersSubscriptionTest, getInitParameters) {
|
|
|
|
ASSERT_EQ(syncStart.height, sub.getSyncStart().height);
|
|
|
|
ASSERT_EQ(syncStart.timestamp, sub.getSyncStart().timestamp);
|
|
|
|
ASSERT_EQ(account.address, sub.getAddress());
|
|
|
|
ASSERT_EQ(account, sub.getKeys());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TransfersSubscriptionTest, addTransaction) {
|
|
|
|
auto tx1 = addTransaction(10000, 1, 0);
|
|
|
|
auto tx2 = addTransaction(10000, 2, 1);
|
|
|
|
|
|
|
|
// this transaction should not be added, so no notification
|
|
|
|
auto tx = createTransaction();
|
|
|
|
addTestInput(*tx, 20000);
|
2015-08-11 14:33:19 +00:00
|
|
|
sub.addTransaction(TransactionBlockInfo{ 2, 100000 }, *tx, {});
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
ASSERT_EQ(2, sub.getContainer().transactionsCount());
|
|
|
|
ASSERT_EQ(2, observer.updated.size());
|
|
|
|
ASSERT_EQ(tx1->getTransactionHash(), observer.updated[0]);
|
|
|
|
ASSERT_EQ(tx2->getTransactionHash(), observer.updated[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TransfersSubscriptionTest, onBlockchainDetach) {
|
|
|
|
addTransaction(10000, 10, 0);
|
|
|
|
auto txHash = addTransaction(10000, 11, 1)->getTransactionHash();
|
|
|
|
ASSERT_EQ(2, sub.getContainer().transactionsCount());
|
|
|
|
|
|
|
|
sub.onBlockchainDetach(11);
|
|
|
|
|
|
|
|
ASSERT_EQ(1, sub.getContainer().transactionsCount());
|
|
|
|
ASSERT_EQ(1, observer.deleted.size());
|
|
|
|
ASSERT_EQ(txHash, observer.deleted[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TransfersSubscriptionTest, onError) {
|
|
|
|
|
|
|
|
auto err = createError();
|
|
|
|
|
|
|
|
addTransaction(10000, 10, 0);
|
|
|
|
addTransaction(10000, 11, 1);
|
|
|
|
|
|
|
|
ASSERT_EQ(2, sub.getContainer().transactionsCount());
|
|
|
|
|
|
|
|
sub.onError(err, 12);
|
|
|
|
|
|
|
|
ASSERT_EQ(2, sub.getContainer().transactionsCount());
|
|
|
|
ASSERT_EQ(1, observer.errors.size());
|
|
|
|
ASSERT_EQ(std::make_tuple(12, err), observer.errors[0]);
|
|
|
|
|
|
|
|
sub.onError(err, 11);
|
|
|
|
|
|
|
|
ASSERT_EQ(1, sub.getContainer().transactionsCount()); // one transaction should be detached
|
|
|
|
ASSERT_EQ(2, observer.errors.size());
|
|
|
|
|
|
|
|
ASSERT_EQ(std::make_tuple(12, err), observer.errors[0]);
|
|
|
|
ASSERT_EQ(std::make_tuple(11, err), observer.errors[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TransfersSubscriptionTest, advanceHeight) {
|
|
|
|
ASSERT_TRUE(sub.advanceHeight(10));
|
|
|
|
ASSERT_FALSE(sub.advanceHeight(9)); // can't go backwards
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(TransfersSubscriptionTest, markTransactionConfirmed) {
|
2015-07-30 15:22:07 +00:00
|
|
|
auto txHash = addTransaction(10000, UNCONFIRMED_TRANSACTION_HEIGHT, UNCONFIRMED)->getTransactionHash();
|
2015-04-06 16:13:07 +00:00
|
|
|
ASSERT_EQ(1, sub.getContainer().transactionsCount());
|
|
|
|
ASSERT_EQ(1, observer.updated.size()); // added
|
|
|
|
|
2015-08-11 14:33:19 +00:00
|
|
|
sub.markTransactionConfirmed(TransactionBlockInfo{ 10, 100000 }, txHash, { 1 });
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
ASSERT_EQ(2, observer.updated.size()); // added + updated
|
|
|
|
ASSERT_EQ(txHash, observer.updated[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(TransfersSubscriptionTest, deleteUnconfirmedTransaction) {
|
2015-07-30 15:22:07 +00:00
|
|
|
auto txHash = addTransaction(10000, UNCONFIRMED_TRANSACTION_HEIGHT, UNCONFIRMED)->getTransactionHash();
|
2015-04-06 16:13:07 +00:00
|
|
|
ASSERT_EQ(1, sub.getContainer().transactionsCount());
|
|
|
|
|
|
|
|
sub.deleteUnconfirmedTransaction(txHash);
|
|
|
|
|
|
|
|
ASSERT_EQ(0, sub.getContainer().transactionsCount());
|
|
|
|
ASSERT_EQ(1, observer.deleted.size());
|
|
|
|
ASSERT_EQ(txHash, observer.deleted[0]);
|
|
|
|
}
|