// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers
//
// 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 .
#include "gtest/gtest.h"
#include
#include
#include
#include
#include "PaymentGate/WalletService.h"
// test helpers
#include "INodeStubs.h"
#include "TestBlockchainGenerator.h"
using namespace PaymentService;
using namespace CryptoNote;
class PaymentGateTest : public testing::Test {
public:
PaymentGateTest() :
currency(CryptoNote::CurrencyBuilder(logger).currency()),
generator(currency),
nodeStub(generator)
{}
WalletConfiguration createWalletConfiguration(const std::string& walletFile = "pgwalleg.bin") const {
return WalletConfiguration{ walletFile, "pass" };
}
std::unique_ptr createWalletService(const WalletConfiguration& cfg) {
std::unique_ptr service(new WalletService(currency, dispatcher, nodeStub, cfg, logger));
service->init();
return service;
}
void generateWallet(const WalletConfiguration& conf) {
unlink(conf.walletFile.c_str());
generateNewWallet(currency, conf, logger, dispatcher);
}
protected:
Logging::ConsoleLogger logger;
CryptoNote::Currency currency;
TestBlockchainGenerator generator;
INodeTrivialRefreshStub nodeStub;
System::Dispatcher dispatcher;
};
TEST_F(PaymentGateTest, createWallet) {
auto cfg = createWalletConfiguration();
generateWallet(cfg);
auto service = createWalletService(cfg);
}
TEST_F(PaymentGateTest, addTransaction) {
auto cfg = createWalletConfiguration();
generateWallet(cfg);
auto service = createWalletService(cfg);
std::string addressStr;
ASSERT_TRUE(!service->createAddress(addressStr));
AccountPublicAddress address;
ASSERT_TRUE(currency.parseAccountAddressString(addressStr, address));
generator.getBlockRewardForAddress(address);
generator.getBlockRewardForAddress(address);
generator.generateEmptyBlocks(11);
generator.getBlockRewardForAddress(address);
nodeStub.updateObservers();
System::Timer(dispatcher).sleep(std::chrono::seconds(2));
uint64_t txCount = 0;
ASSERT_TRUE(!service->getTransactionsCount(txCount));
ASSERT_EQ(3, txCount);
uint64_t pending = 0, actual = 0;
ASSERT_TRUE(!service->getPendingBalance(pending));
ASSERT_TRUE(!service->getActualBalance(actual));
ASSERT_NE(0, pending);
ASSERT_NE(0, actual);
ASSERT_EQ(pending * 2, actual);
}
TEST_F(PaymentGateTest, DISABLED_sendTransaction) {
auto cfg = createWalletConfiguration();
generateWallet(cfg);
auto service = createWalletService(cfg);
std::string addressStr;
ASSERT_TRUE(!service->createAddress(addressStr));
AccountPublicAddress address;
ASSERT_TRUE(currency.parseAccountAddressString(addressStr, address));
generator.getBlockRewardForAddress(address);
generator.generateEmptyBlocks(11);
nodeStub.updateObservers();
System::Timer(dispatcher).sleep(std::chrono::seconds(5));
auto cfg2 = createWalletConfiguration("pgwallet2.bin");
generateWallet(cfg2);
auto serviceRecv = createWalletService(cfg2);
std::string recvAddress;
serviceRecv->createAddress(recvAddress);
uint64_t TEST_AMOUNT = 0;
currency.parseAmount("100000.0", TEST_AMOUNT);
Crypto::Hash paymentId;
std::iota(reinterpret_cast(&paymentId), reinterpret_cast(&paymentId) + sizeof(paymentId), 0);
std::string paymentIdStr = Common::podToHex(paymentId);
uint64_t txId = 0;
{
SendTransactionRequest req;
SendTransactionResponse res;
req.destinations.push_back(TransferDestination{ TEST_AMOUNT, recvAddress });
req.fee = currency.minimumFee();
req.mixin = 1;
req.unlockTime = 0;
req.paymentId = paymentIdStr;
ASSERT_TRUE(!service->sendTransaction(req, res));
txId = res.transactionId;
}
generator.generateEmptyBlocks(11);
nodeStub.updateObservers();
System::Timer(dispatcher).sleep(std::chrono::seconds(5));
TransactionRpcInfo txInfo;
bool found = false;
ASSERT_TRUE(!service->getTransaction(txId, found, txInfo));
ASSERT_TRUE(found);
uint64_t recvTxCount = 0;
ASSERT_TRUE(!serviceRecv->getTransactionsCount(recvTxCount));
ASSERT_EQ(1, recvTxCount);
uint64_t sendTxCount = 0;
ASSERT_TRUE(!service->getTransactionsCount(sendTxCount));
ASSERT_EQ(2, sendTxCount); // 1 from mining, 1 transfer
TransactionRpcInfo recvTxInfo;
ASSERT_TRUE(!serviceRecv->getTransaction(0, found, recvTxInfo));
ASSERT_TRUE(found);
ASSERT_EQ(txInfo.hash, recvTxInfo.hash);
ASSERT_EQ(txInfo.extra, recvTxInfo.extra);
ASSERT_EQ(-txInfo.totalAmount - currency.minimumFee(), recvTxInfo.totalAmount);
ASSERT_EQ(txInfo.blockHeight, recvTxInfo.blockHeight);
{
// check payments
WalletService::IncomingPayments payments;
ASSERT_TRUE(!serviceRecv->getIncomingPayments({ paymentIdStr }, payments));
ASSERT_EQ(1, payments.size());
ASSERT_EQ(paymentIdStr, payments.begin()->first);
const auto& recvPayment = payments.begin()->second;
ASSERT_EQ(1, recvPayment.size());
ASSERT_EQ(txInfo.hash, recvPayment[0].txHash);
ASSERT_EQ(TEST_AMOUNT, recvPayment[0].amount);
ASSERT_EQ(txInfo.blockHeight, recvPayment[0].blockHeight);
}
// reload services
service->saveWallet();
serviceRecv->saveWallet();
service.reset();
serviceRecv.reset();
service = createWalletService(cfg);
serviceRecv = createWalletService(cfg2);
recvTxInfo = boost::value_initialized();
ASSERT_TRUE(!serviceRecv->getTransaction(0, found, recvTxInfo));
ASSERT_TRUE(found);
ASSERT_EQ(txInfo.hash, recvTxInfo.hash);
ASSERT_EQ(txInfo.extra, recvTxInfo.extra);
ASSERT_EQ(-txInfo.totalAmount - currency.minimumFee(), recvTxInfo.totalAmount);
ASSERT_EQ(txInfo.blockHeight, recvTxInfo.blockHeight);
// send some money back
std::reverse(paymentIdStr.begin(), paymentIdStr.end());
{
std::string recvAddress;
service->createAddress(recvAddress);
SendTransactionRequest req;
SendTransactionResponse res;
req.destinations.push_back(TransferDestination{ TEST_AMOUNT/2, recvAddress });
req.fee = currency.minimumFee();
req.mixin = 1;
req.unlockTime = 0;
req.paymentId = paymentIdStr;
ASSERT_TRUE(!serviceRecv->sendTransaction(req, res));
txId = res.transactionId;
}
generator.generateEmptyBlocks(11);
nodeStub.updateObservers();
System::Timer(dispatcher).sleep(std::chrono::seconds(5));
ASSERT_TRUE(!service->getTransactionsCount(recvTxCount));
ASSERT_EQ(3, recvTxCount);
{
WalletService::IncomingPayments payments;
ASSERT_TRUE(!service->getIncomingPayments({ paymentIdStr }, payments));
ASSERT_EQ(1, payments.size());
ASSERT_EQ(paymentIdStr, payments.begin()->first);
const auto& recvPayment = payments.begin()->second;
ASSERT_EQ(1, recvPayment.size());
ASSERT_EQ(TEST_AMOUNT / 2, recvPayment[0].amount);
}
}