danicoin/tests/UnitTests/TestWalletService.cpp
2016-01-18 15:33:29 +00:00

989 lines
34 KiB
C++

// Copyright (c) 2011-2016 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 <algorithm>
#include <queue>
#include <system_error>
#include <IWallet.h>
#include "CryptoNoteCore/Currency.h"
#include "Logging/LoggerGroup.h"
#include "Logging/ConsoleLogger.h"
#include <System/Event.h>
#include "PaymentGate/WalletService.h"
#include "PaymentGate/WalletServiceErrorCategory.h"
#include "INodeStubs.h"
#include "Wallet/WalletErrors.h"
using namespace CryptoNote;
using namespace PaymentService;
namespace CryptoNote {
bool operator== (const WalletOrder& lhs, const WalletOrder& rhs) {
return std::make_tuple(lhs.address, lhs.amount) == std::make_tuple(rhs.address, rhs.amount);
}
bool operator== (const DonationSettings& lhs, const DonationSettings& rhs) {
return std::make_tuple(lhs.address, lhs.threshold) == std::make_tuple(rhs.address, rhs.threshold);
}
} //namespace CryptoNote
struct IWalletBaseStub : public CryptoNote::IWallet {
IWalletBaseStub(System::Dispatcher& dispatcher) : m_eventOccurred(dispatcher) {}
virtual ~IWalletBaseStub() {}
virtual void initialize(const std::string& password) override { }
virtual void initializeWithViewKey(const Crypto::SecretKey& viewSecretKey, const std::string& password) override { }
virtual void load(std::istream& source, const std::string& password) override { }
virtual void shutdown() override { }
virtual void changePassword(const std::string& oldPassword, const std::string& newPassword) override { }
virtual void save(std::ostream& destination, bool saveDetails = true, bool saveCache = true) override { }
virtual size_t getAddressCount() const override { return 0; }
virtual std::string getAddress(size_t index) const override { return ""; }
virtual KeyPair getAddressSpendKey(size_t index) const override { return KeyPair(); }
virtual KeyPair getAddressSpendKey(const std::string& address) const override { return KeyPair(); }
virtual KeyPair getViewKey() const override { return KeyPair(); }
virtual std::string createAddress() override { return ""; }
virtual std::string createAddress(const Crypto::SecretKey& spendSecretKey) override { return ""; }
virtual std::string createAddress(const Crypto::PublicKey& spendPublicKey) override { return ""; }
virtual void deleteAddress(const std::string& address) override { }
virtual uint64_t getActualBalance() const override { return 0; }
virtual uint64_t getActualBalance(const std::string& address) const override { return 0; }
virtual uint64_t getPendingBalance() const override { return 0; }
virtual uint64_t getPendingBalance(const std::string& address) const override { return 0; }
virtual size_t getTransactionCount() const override { return 0; }
virtual WalletTransaction getTransaction(size_t transactionIndex) const override { return WalletTransaction(); }
virtual size_t getTransactionTransferCount(size_t transactionIndex) const override { return 0; }
virtual WalletTransfer getTransactionTransfer(size_t transactionIndex, size_t transferIndex) const override { return WalletTransfer(); }
virtual WalletTransactionWithTransfers getTransaction(const Crypto::Hash& transactionHash) const override { return WalletTransactionWithTransfers(); }
virtual std::vector<TransactionsInBlockInfo> getTransactions(const Crypto::Hash& blockHash, size_t count) const override { return {}; }
virtual std::vector<TransactionsInBlockInfo> getTransactions(uint32_t blockIndex, size_t count) const override { return {}; }
virtual std::vector<Crypto::Hash> getBlockHashes(uint32_t blockIndex, size_t count) const override { return {}; }
virtual uint32_t getBlockCount() const override { return 0; }
virtual std::vector<WalletTransactionWithTransfers> getUnconfirmedTransactions() const override { return {}; }
virtual std::vector<size_t> getDelayedTransactionIds() const override { return {}; }
virtual size_t transfer(const TransactionParameters& sendingTransaction) override { return 0; }
virtual size_t makeTransaction(const TransactionParameters& sendingTransaction) override { return 0; }
virtual void commitTransaction(size_t transactionId) override { }
virtual void rollbackUncommitedTransaction(size_t transactionId) override { }
virtual void start() override { m_stopped = false; }
virtual void stop() override { m_stopped = true; m_eventOccurred.set(); }
//blocks until an event occurred
virtual WalletEvent getEvent() override {
throwIfStopped();
while(m_events.empty()) {
m_eventOccurred.wait();
m_eventOccurred.clear();
throwIfStopped();
}
WalletEvent event = std::move(m_events.front());
m_events.pop();
return event;
}
void pushEvent(const WalletEvent& event) {
m_events.push(event);
m_eventOccurred.set();
}
protected:
void throwIfStopped() {
if (m_stopped) {
throw std::system_error(make_error_code(std::errc::operation_canceled));
}
}
bool m_stopped = false;
System::Event m_eventOccurred;
std::queue<WalletEvent> m_events;
};
class WalletServiceTest: public ::testing::Test {
public:
WalletServiceTest() :
currency(CryptoNote::CurrencyBuilder(logger).currency()),
generator(currency),
nodeStub(generator),
walletBase(dispatcher)
{}
virtual void SetUp() override;
protected:
Logging::ConsoleLogger logger;
Currency currency;
TestBlockchainGenerator generator;
INodeTrivialRefreshStub nodeStub;
WalletConfiguration walletConfig;
System::Dispatcher dispatcher;
IWalletBaseStub walletBase;
std::unique_ptr<WalletService> createWalletService(CryptoNote::IWallet& wallet);
std::unique_ptr<WalletService> createWalletService();
Crypto::Hash generateRandomHash();
};
void WalletServiceTest::SetUp() {
logger.setMaxLevel(Logging::DEBUGGING);
walletConfig.walletFile = "test";
walletConfig.walletPassword = "test";
}
std::unique_ptr<WalletService> WalletServiceTest::createWalletService(CryptoNote::IWallet& wallet) {
return std::unique_ptr<WalletService> (new WalletService(currency, dispatcher, nodeStub, wallet, walletConfig, logger));
}
std::unique_ptr<WalletService> WalletServiceTest::createWalletService() {
return createWalletService(walletBase);
}
Crypto::Hash WalletServiceTest::generateRandomHash() {
Crypto::Hash hash;
std::generate(std::begin(hash.data), std::end(hash.data), std::rand);
return hash;
}
class WalletServiceTest_createAddress : public WalletServiceTest {
};
struct WalletCreateAddressStub: public IWalletBaseStub {
WalletCreateAddressStub(System::Dispatcher& d) : IWalletBaseStub(d) {}
virtual std::string createAddress() override { return address; }
virtual std::string createAddress(const Crypto::SecretKey& spendSecretKey) override { return address; }
virtual std::string createAddress(const Crypto::PublicKey& spendPublicKey) override { return address; }
std::string address = "correctAddress";
};
TEST_F(WalletServiceTest_createAddress, returnsCorrectAddress) {
WalletCreateAddressStub wallet(dispatcher);
std::unique_ptr<WalletService> service = createWalletService(wallet);
std::string address;
std::error_code ec = service->createAddress(address);
ASSERT_FALSE(ec);
ASSERT_EQ(wallet.address, address);
}
TEST_F(WalletServiceTest_createAddress, invalidSecretKey) {
std::unique_ptr<WalletService> service = createWalletService();
std::string address;
std::error_code ec = service->createAddress("wrong key", address);
ASSERT_EQ(make_error_code(CryptoNote::error::WalletServiceErrorCode::WRONG_KEY_FORMAT), ec);
}
TEST_F(WalletServiceTest_createAddress, invalidPublicKey) {
std::unique_ptr<WalletService> service = createWalletService();
std::string address;
std::error_code ec = service->createTrackingAddress("wrong key", address);
ASSERT_EQ(make_error_code(CryptoNote::error::WalletServiceErrorCode::WRONG_KEY_FORMAT), ec);
}
TEST_F(WalletServiceTest_createAddress, correctSecretKey) {
Crypto::PublicKey pub;
Crypto::SecretKey sec;
Crypto::generate_keys(pub, sec);
WalletCreateAddressStub wallet(dispatcher);
std::unique_ptr<WalletService> service = createWalletService(wallet);
std::string address;
std::error_code ec = service->createAddress(Common::podToHex(sec), address);
ASSERT_FALSE(ec);
ASSERT_EQ(wallet.address, address);
}
TEST_F(WalletServiceTest_createAddress, correctPublicKey) {
Crypto::PublicKey pub;
Crypto::SecretKey sec;
Crypto::generate_keys(pub, sec);
WalletCreateAddressStub wallet(dispatcher);
std::unique_ptr<WalletService> service = createWalletService(wallet);
std::string address;
std::error_code ec = service->createTrackingAddress(Common::podToHex(pub), address);
ASSERT_FALSE(ec);
ASSERT_EQ(wallet.address, address);
}
class WalletServiceTest_getSpendKeys : public WalletServiceTest {
};
struct WalletgetSpendKeysStub: public IWalletBaseStub {
WalletgetSpendKeysStub(System::Dispatcher& d) : IWalletBaseStub(d) {
Crypto::generate_keys(keyPair.publicKey, keyPair.secretKey);
}
virtual KeyPair getAddressSpendKey(const std::string& address) const override {
return keyPair;
}
KeyPair keyPair;
};
TEST_F(WalletServiceTest_getSpendKeys, returnsKeysCorrectly) {
WalletgetSpendKeysStub wallet(dispatcher);
std::unique_ptr<WalletService> service = createWalletService(wallet);
std::string publicSpendKey;
std::string secretSpendKey;
auto ec = service->getSpendkeys("address", publicSpendKey, secretSpendKey);
ASSERT_FALSE(ec);
ASSERT_EQ(Common::podToHex(wallet.keyPair.publicKey), publicSpendKey);
ASSERT_EQ(Common::podToHex(wallet.keyPair.secretKey), secretSpendKey);
}
class WalletServiceTest_getBalance : public WalletServiceTest {
};
struct WalletGetBalanceStub: public IWalletBaseStub {
WalletGetBalanceStub(System::Dispatcher& d, bool byAddress) : IWalletBaseStub(d), byAddress(byAddress) {
}
virtual uint64_t getActualBalance() const override {
if (byAddress) {
throw std::runtime_error("wrong overload");
}
return actualBalance;
}
virtual uint64_t getPendingBalance() const override {
if (byAddress) {
throw std::runtime_error("wrong overload");
}
return pendingBalance;
}
virtual uint64_t getActualBalance(const std::string& address) const override {
if (!byAddress) {
throw std::runtime_error("wrong overload");
}
return actualBalance;
}
virtual uint64_t getPendingBalance(const std::string& address) const override {
if (!byAddress) {
throw std::runtime_error("wrong overload");
}
return pendingBalance;
}
bool byAddress;
uint64_t actualBalance = 345466;
uint64_t pendingBalance = 12121;
};
TEST_F(WalletServiceTest_getBalance, returnsCorrectBalance) {
WalletGetBalanceStub wallet(dispatcher, false);
std::unique_ptr<WalletService> service = createWalletService(wallet);
uint64_t actual;
uint64_t pending;
auto ec = service->getBalance(actual, pending);
ASSERT_FALSE(ec);
ASSERT_EQ(wallet.actualBalance, actual);
ASSERT_EQ(wallet.pendingBalance, pending);
}
TEST_F(WalletServiceTest_getBalance, returnsCorrectBalanceByAddress) {
WalletGetBalanceStub wallet(dispatcher, true);
std::unique_ptr<WalletService> service = createWalletService(wallet);
uint64_t actual;
uint64_t pending;
auto ec = service->getBalance("address", actual, pending);
ASSERT_FALSE(ec);
ASSERT_EQ(wallet.actualBalance, actual);
ASSERT_EQ(wallet.pendingBalance, pending);
}
class WalletServiceTest_getBlockHashes : public WalletServiceTest {
protected:
std::vector<Crypto::Hash> convertBlockHashes(const std::vector<std::string>& hashes) {
std::vector<Crypto::Hash> result;
result.reserve(hashes.size());
std::for_each(hashes.begin(), hashes.end(), [&result] (const std::string& str) {
Crypto::Hash hash;
Common::podFromHex(str, hash);
result.push_back(hash);
});
return result;
}
};
struct WalletGetBlockHashesStub: public IWalletBaseStub {
WalletGetBlockHashesStub(System::Dispatcher& d) : IWalletBaseStub(d) {
}
virtual std::vector<Crypto::Hash> getBlockHashes(uint32_t blockIndex, size_t count) const override {
return blockHashes;
}
std::vector<Crypto::Hash> blockHashes;
};
TEST_F(WalletServiceTest_getBlockHashes, returnsEmptyBlockHashes) {
WalletGetBlockHashesStub wallet(dispatcher);
auto service = createWalletService(wallet);
std::vector<std::string> blockHashes;
ASSERT_FALSE(service->getBlockHashes(0, 1, blockHashes));
ASSERT_EQ(wallet.blockHashes, convertBlockHashes(blockHashes));
}
TEST_F(WalletServiceTest_getBlockHashes, returnsBlockHashes) {
WalletGetBlockHashesStub wallet(dispatcher);
std::generate_n(std::back_inserter(wallet.blockHashes), 10, [this] () { return generateRandomHash(); });
auto service = createWalletService(wallet);
std::vector<std::string> blockHashes;
ASSERT_FALSE(service->getBlockHashes(0, 10, blockHashes));
ASSERT_EQ(wallet.blockHashes, convertBlockHashes(blockHashes));
}
class WalletServiceTest_getViewKey : public WalletServiceTest {
};
struct WalletGetViewKeyStub: public IWalletBaseStub {
WalletGetViewKeyStub(System::Dispatcher& d) : IWalletBaseStub(d) {
Crypto::generate_keys(keyPair.publicKey, keyPair.secretKey);
}
virtual KeyPair getViewKey() const override {
return keyPair;
}
KeyPair keyPair;
};
TEST_F(WalletServiceTest_getViewKey, returnsCorrectValue) {
WalletGetViewKeyStub wallet(dispatcher);
auto service = createWalletService(wallet);
std::string viewSecretKey;
ASSERT_FALSE(service->getViewKey(viewSecretKey));
ASSERT_EQ(Common::podToHex(wallet.keyPair.secretKey), viewSecretKey);
}
class WalletTransactionBuilder {
public:
WalletTransactionBuilder& hash(const Crypto::Hash& hash) {
transaction.hash = hash;
return *this;
}
WalletTransactionBuilder& extra(const std::string& extra) {
transaction.extra = Common::asString(Common::fromHex(extra));
return *this;
}
WalletTransactionBuilder& state(WalletTransactionState state) {
transaction.state = state;
return *this;
}
WalletTransaction build() const {
return transaction;
}
WalletTransactionBuilder& timestamp(uint64_t t) {
transaction.timestamp = t;
return *this;
}
WalletTransactionBuilder& blockHeight(uint32_t height) {
transaction.blockHeight = height;
return *this;
}
WalletTransactionBuilder& totalAmount(int64_t amount) {
transaction.totalAmount = amount;
return *this;
}
WalletTransactionBuilder& fee(uint64_t fee) {
transaction.fee = fee;
return *this;
}
WalletTransactionBuilder& creationTime(uint64_t t) {
transaction.creationTime = t;
return *this;
}
WalletTransactionBuilder& unlockTime(uint64_t unlock) {
transaction.unlockTime = unlock;
return *this;
}
WalletTransactionBuilder& isBase(bool base) {
transaction.isBase = base;
return *this;
}
private:
WalletTransaction transaction;
};
class WalletTransactionWithTransfersBuilder {
public:
WalletTransactionWithTransfersBuilder& transaction(const WalletTransaction& transaction) {
tx.transaction = transaction;
return *this;
}
WalletTransactionWithTransfersBuilder& addTransfer(const std::string& address, int64_t amount) {
tx.transfers.push_back(WalletTransfer{WalletTransferType::USUAL, address, amount});
return *this;
}
WalletTransactionWithTransfers build() const {
return tx;
}
private:
WalletTransactionWithTransfers tx;
};
class WalletServiceTest_getTransactions : public WalletServiceTest {
virtual void SetUp() override;
protected:
std::vector<TransactionsInBlockInfo> testTransactions;
const std::string RANDOM_ADDRESS1 = "288DiQfYSxDNQoWpR6cy94i2AWyGnxo1L1MF2ZiXg58h9P52o576CSDcJp7ZceSXSUQ7u8aTF1MigQXzAtqRZ3Uq58Sne8x";
const std::string RANDOM_ADDRESS2 = "29PQ8VbzPi163kG59w5V8PR9A6watydfYAvwFcDS74KhDEyU9CGgqsDH719oeLbpAa4xtPsgfQ6Bv9RmKs1XZWudV6q6cmU";
const std::string RANDOM_ADDRESS3 = "23E4CVgzJok9zXnrKzvHgbKvMXZnAgsB9FA1pkAppR6d42dWMEuJjsfcJp7ZceSXSUQ7u8aTF1MigQXzAtqRZ3Uq5AHHbzZ";
const std::string TRANSACTION_EXTRA = "022100dededededededededededededededededededededededededededededededede";
const std::string PAYMENT_ID = "dededededededededededededededededededededededededededededededede";
};
void WalletServiceTest_getTransactions::SetUp() {
TransactionsInBlockInfo block;
block.blockHash = generateRandomHash();
block.transactions.push_back(
WalletTransactionWithTransfersBuilder().addTransfer(RANDOM_ADDRESS1, 222).addTransfer(RANDOM_ADDRESS2, 33333).transaction(
WalletTransactionBuilder().hash(generateRandomHash()).extra(TRANSACTION_EXTRA).build()
).build()
);
testTransactions.push_back(block);
}
class WalletGetTransactionsStub : public IWalletBaseStub {
public:
WalletGetTransactionsStub(System::Dispatcher& d) : IWalletBaseStub(d) {}
virtual std::vector<TransactionsInBlockInfo> getTransactions(const Crypto::Hash& blockHash, size_t count) const override {
return transactions;
}
virtual std::vector<TransactionsInBlockInfo> getTransactions(uint32_t blockIndex, size_t count) const override {
return transactions;
}
std::vector<TransactionsInBlockInfo> transactions;
};
TEST_F(WalletServiceTest_getTransactions, addressesFilter_emptyReturnsTransaction) {
WalletGetTransactionsStub wallet(dispatcher);
wallet.transactions = testTransactions;
auto service = createWalletService(wallet);
std::vector<TransactionsInBlockRpcInfo> transactions;
auto ec = service->getTransactions({}, 0, 1, "", transactions);
ASSERT_FALSE(ec);
ASSERT_EQ(1, transactions.size());
ASSERT_EQ(Common::podToHex(testTransactions[0].transactions[0].transaction.hash), transactions[0].transactions[0].transactionHash);
}
TEST_F(WalletServiceTest_getTransactions, addressesFilter_existentReturnsTransaction) {
WalletGetTransactionsStub wallet(dispatcher);
wallet.transactions = testTransactions;
auto service = createWalletService(wallet);
std::vector<TransactionsInBlockRpcInfo> transactions;
auto ec = service->getTransactions({RANDOM_ADDRESS1}, 0, 1, "", transactions);
ASSERT_FALSE(ec);
ASSERT_EQ(1, transactions.size());
ASSERT_EQ(Common::podToHex(testTransactions[0].transactions[0].transaction.hash), transactions[0].transactions[0].transactionHash);
}
TEST_F(WalletServiceTest_getTransactions, addressesFilter_nonExistentReturnsNoTransactions) {
WalletGetTransactionsStub wallet(dispatcher);
wallet.transactions = testTransactions;
auto service = createWalletService(wallet);
std::vector<TransactionsInBlockRpcInfo> transactions;
auto ec = service->getTransactions({RANDOM_ADDRESS3}, 0, 1, "", transactions);
ASSERT_FALSE(ec);
ASSERT_EQ(1, transactions.size());
ASSERT_TRUE(transactions[0].transactions.empty());
}
TEST_F(WalletServiceTest_getTransactions, addressesFilter_existentAndNonExistentReturnsTransaction) {
WalletGetTransactionsStub wallet(dispatcher);
wallet.transactions = testTransactions;
auto service = createWalletService(wallet);
std::vector<TransactionsInBlockRpcInfo> transactions;
auto ec = service->getTransactions({RANDOM_ADDRESS1, RANDOM_ADDRESS3}, 0, 1, "", transactions);
ASSERT_FALSE(ec);
ASSERT_EQ(1, transactions.size());
ASSERT_EQ(Common::podToHex(testTransactions[0].transactions[0].transaction.hash), transactions[0].transactions[0].transactionHash);
}
TEST_F(WalletServiceTest_getTransactions, paymentIdFilter_existentReturnsTransaction) {
WalletGetTransactionsStub wallet(dispatcher);
wallet.transactions = testTransactions;
auto service = createWalletService(wallet);
std::vector<TransactionsInBlockRpcInfo> transactions;
auto ec = service->getTransactions({}, 0, 1, PAYMENT_ID, transactions);
ASSERT_FALSE(ec);
ASSERT_EQ(1, transactions.size());
ASSERT_EQ(Common::podToHex(testTransactions[0].transactions[0].transaction.hash), transactions[0].transactions[0].transactionHash);
ASSERT_EQ(PAYMENT_ID, transactions[0].transactions[0].paymentId);
}
TEST_F(WalletServiceTest_getTransactions, paymentIdFilter_nonExistentReturnsNoTransaction) {
WalletGetTransactionsStub wallet(dispatcher);
wallet.transactions = testTransactions;
auto service = createWalletService(wallet);
std::vector<TransactionsInBlockRpcInfo> transactions;
auto ec = service->getTransactions({}, 0, 1, "dfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdfdf", transactions);
ASSERT_FALSE(ec);
ASSERT_EQ(1, transactions.size());
ASSERT_TRUE(transactions[0].transactions.empty());
}
TEST_F(WalletServiceTest_getTransactions, invalidAddress) {
WalletGetTransactionsStub wallet(dispatcher);
wallet.transactions = testTransactions;
auto service = createWalletService(wallet);
std::vector<TransactionsInBlockRpcInfo> transactions;
auto ec = service->getTransactions({"invalid address"}, 0, 1, "", transactions);
ASSERT_EQ(make_error_code(CryptoNote::error::BAD_ADDRESS), ec);
}
TEST_F(WalletServiceTest_getTransactions, invalidPaymentId) {
WalletGetTransactionsStub wallet(dispatcher);
wallet.transactions = testTransactions;
auto service = createWalletService(wallet);
std::vector<TransactionsInBlockRpcInfo> transactions;
auto ec = service->getTransactions({}, 0, 1, "invalid payment id", transactions);
ASSERT_EQ(make_error_code(CryptoNote::error::WalletServiceErrorCode::WRONG_PAYMENT_ID_FORMAT), ec);
}
TEST_F(WalletServiceTest_getTransactions, blockNotFound) {
WalletGetTransactionsStub wallet(dispatcher);
auto service = createWalletService(wallet);
std::vector<TransactionsInBlockRpcInfo> transactions;
auto ec = service->getTransactions({}, 0, 1, "", transactions);
ASSERT_EQ(make_error_code(CryptoNote::error::WalletServiceErrorCode::OBJECT_NOT_FOUND), ec);
}
class WalletServiceTest_getTransaction : public WalletServiceTest_getTransactions {
};
struct WalletGetTransactionStub : public IWalletBaseStub {
WalletGetTransactionStub (System::Dispatcher& dispatcher) : IWalletBaseStub(dispatcher) {
}
virtual WalletTransactionWithTransfers getTransaction(const Crypto::Hash& transactionHash) const override {
return transaction;
}
WalletTransactionWithTransfers transaction;
};
TEST_F(WalletServiceTest_getTransaction, wrongHash) {
auto service = createWalletService();
TransactionRpcInfo transaction;
auto ec = service->getTransaction("wrong hash", transaction);
ASSERT_EQ(make_error_code(CryptoNote::error::WalletServiceErrorCode::WRONG_HASH_FORMAT), ec);
}
TEST_F(WalletServiceTest_getTransaction, returnsCorrectFields) {
WalletGetTransactionStub wallet(dispatcher);
wallet.transaction = WalletTransactionWithTransfersBuilder().transaction(
WalletTransactionBuilder()
.state(WalletTransactionState::FAILED)
.hash(generateRandomHash())
.creationTime(789123)
.extra(TRANSACTION_EXTRA)
.fee(293945)
.isBase(false)
.timestamp(929293847)
.totalAmount(-200000)
.unlockTime(23456)
.build()
).addTransfer("address1", 231).addTransfer("address2", 883).build();
auto service = createWalletService(wallet);
TransactionRpcInfo transaction;
auto ec = service->getTransaction(Common::podToHex(Crypto::Hash()), transaction);
ASSERT_FALSE(ec);
ASSERT_EQ(static_cast<uint8_t>(wallet.transaction.transaction.state), transaction.state);
ASSERT_EQ(wallet.transaction.transaction.blockHeight, transaction.blockIndex);
ASSERT_EQ(Common::toHex(Common::asBinaryArray(wallet.transaction.transaction.extra)), transaction.extra);
ASSERT_EQ(PAYMENT_ID, transaction.paymentId);
ASSERT_EQ(wallet.transaction.transaction.fee, transaction.fee);
ASSERT_EQ(wallet.transaction.transaction.isBase, transaction.isBase);
ASSERT_EQ(wallet.transaction.transaction.timestamp, transaction.timestamp);
ASSERT_EQ(Common::podToHex(wallet.transaction.transaction.hash), transaction.transactionHash);
ASSERT_EQ(wallet.transaction.transaction.unlockTime, transaction.unlockTime);
ASSERT_EQ(wallet.transaction.transfers.size(), transaction.transfers.size());
ASSERT_EQ(wallet.transaction.transfers[0].address, transaction.transfers[0].address);
ASSERT_EQ(wallet.transaction.transfers[0].amount, transaction.transfers[0].amount);
ASSERT_EQ(wallet.transaction.transfers[1].address, transaction.transfers[1].address);
ASSERT_EQ(wallet.transaction.transfers[1].amount, transaction.transfers[1].amount);
}
struct WalletGetTransactionThrowStub : public IWalletBaseStub {
WalletGetTransactionThrowStub (System::Dispatcher& dispatcher) : IWalletBaseStub(dispatcher) {
}
virtual WalletTransactionWithTransfers getTransaction(const Crypto::Hash& transactionHash) const override {
throw std::system_error(make_error_code(error::OBJECT_NOT_FOUND));
}
};
TEST_F(WalletServiceTest_getTransaction, transactionNotFound) {
WalletGetTransactionThrowStub wallet(dispatcher);
auto service = createWalletService(wallet);
TransactionRpcInfo transaction;
auto ec = service->getTransaction(Common::podToHex(Crypto::Hash()), transaction);
ASSERT_EQ(make_error_code(error::OBJECT_NOT_FOUND), ec);
}
class WalletServiceTest_sendTransaction : public WalletServiceTest_getTransactions {
virtual void SetUp() override;
protected:
SendTransaction::Request request;
};
void WalletServiceTest_sendTransaction::SetUp() {
request.sourceAddresses.insert(request.sourceAddresses.end(), {RANDOM_ADDRESS1, RANDOM_ADDRESS2});
request.transfers.push_back(WalletRpcOrder {RANDOM_ADDRESS3, 11111});
request.fee = 2021;
request.anonymity = 4;
request.unlockTime = 848309;
}
struct WalletTransferStub : public IWalletBaseStub {
WalletTransferStub(System::Dispatcher& dispatcher, const Crypto::Hash& hash) : IWalletBaseStub(dispatcher), hash(hash) {
}
virtual size_t transfer(const TransactionParameters& sendingTransaction) override {
params = sendingTransaction;
return 0;
}
virtual WalletTransaction getTransaction(size_t transactionIndex) const override {
return WalletTransactionBuilder().hash(hash).build();
}
Crypto::Hash hash;
TransactionParameters params;
};
bool isEquivalent(const SendTransaction::Request& request, const TransactionParameters& params) {
std::string extra;
if (!request.paymentId.empty()) {
extra = "022100" + request.paymentId;
} else {
extra = request.extra;
}
std::vector<WalletOrder> orders;
std::for_each(request.transfers.begin(), request.transfers.end(), [&orders] (const WalletRpcOrder& order) {
orders.push_back( WalletOrder{order.address, order.amount});
});
return std::make_tuple(request.sourceAddresses, orders, request.fee, request.anonymity, extra, request.unlockTime)
==
std::make_tuple(params.sourceAddresses, params.destinations, params.fee, params.mixIn, Common::toHex(Common::asBinaryArray(params.extra)), params.unlockTimestamp);
}
TEST_F(WalletServiceTest_sendTransaction, passesCorrectParameters) {
WalletTransferStub wallet(dispatcher, generateRandomHash());
auto service = createWalletService(wallet);
std::string hash;
auto ec = service->sendTransaction(request, hash);
ASSERT_FALSE(ec);
ASSERT_EQ(Common::podToHex(wallet.hash), hash);
ASSERT_TRUE(isEquivalent(request, wallet.params));
}
TEST_F(WalletServiceTest_sendTransaction, incorrectSourceAddress) {
auto service = createWalletService();
request.sourceAddresses.push_back("wrong address");
std::string hash;
auto ec = service->sendTransaction(request, hash);
ASSERT_EQ(make_error_code(CryptoNote::error::BAD_ADDRESS), ec);
}
TEST_F(WalletServiceTest_sendTransaction, incorrectTransferAddress) {
auto service = createWalletService();
request.transfers.push_back(WalletRpcOrder{"wrong address", 12131});
std::string hash;
auto ec = service->sendTransaction(request, hash);
ASSERT_EQ(make_error_code(CryptoNote::error::BAD_ADDRESS), ec);
}
class WalletServiceTest_createDelayedTransaction : public WalletServiceTest_getTransactions {
virtual void SetUp() override;
protected:
CreateDelayedTransaction::Request request;
};
void WalletServiceTest_createDelayedTransaction::SetUp() {
request.addresses.insert(request.addresses.end(), {RANDOM_ADDRESS1, RANDOM_ADDRESS2});
request.transfers.push_back(WalletRpcOrder {RANDOM_ADDRESS3, 11111});
request.fee = 2021;
request.anonymity = 4;
request.unlockTime = 848309;
}
struct WalletMakeTransactionStub : public IWalletBaseStub {
WalletMakeTransactionStub(System::Dispatcher& dispatcher, const Crypto::Hash& hash) : IWalletBaseStub(dispatcher), hash(hash) {
}
virtual size_t makeTransaction(const TransactionParameters& sendingTransaction) override {
params = sendingTransaction;
return 0;
}
virtual WalletTransaction getTransaction(size_t transactionIndex) const override {
return WalletTransactionBuilder().hash(hash).build();
}
Crypto::Hash hash;
TransactionParameters params;
};
bool isEquivalent(const CreateDelayedTransaction::Request& request, const TransactionParameters& params) {
std::string extra;
if (!request.paymentId.empty()) {
extra = "022100" + request.paymentId;
} else {
extra = request.extra;
}
std::vector<WalletOrder> orders;
std::for_each(request.transfers.begin(), request.transfers.end(), [&orders] (const WalletRpcOrder& order) {
orders.push_back( WalletOrder{order.address, order.amount});
});
return std::make_tuple(request.addresses, orders, request.fee, request.anonymity, extra, request.unlockTime)
==
std::make_tuple(params.sourceAddresses, params.destinations, params.fee, params.mixIn, Common::toHex(Common::asBinaryArray(params.extra)), params.unlockTimestamp);
}
TEST_F(WalletServiceTest_createDelayedTransaction, passesCorrectParameters) {
WalletMakeTransactionStub wallet(dispatcher, generateRandomHash());
auto service = createWalletService(wallet);
std::string hash;
auto ec = service->createDelayedTransaction(request, hash);
ASSERT_FALSE(ec);
ASSERT_EQ(Common::podToHex(wallet.hash), hash);
ASSERT_TRUE(isEquivalent(request, wallet.params));
}
TEST_F(WalletServiceTest_createDelayedTransaction, incorrectSourceAddress) {
auto service = createWalletService();
request.addresses.push_back("wrong address");
std::string hash;
auto ec = service->createDelayedTransaction(request, hash);
ASSERT_EQ(make_error_code(CryptoNote::error::BAD_ADDRESS), ec);
}
TEST_F(WalletServiceTest_createDelayedTransaction, incorrectTransferAddress) {
auto service = createWalletService();
request.transfers.push_back(WalletRpcOrder{"wrong address", 12131});
std::string hash;
auto ec = service->createDelayedTransaction(request, hash);
ASSERT_EQ(make_error_code(CryptoNote::error::BAD_ADDRESS), ec);
}
class WalletServiceTest_getDelayedTransactionHashes: public WalletServiceTest {
};
struct WalletGetDelayedTransactionIdsStub : public IWalletBaseStub {
WalletGetDelayedTransactionIdsStub(System::Dispatcher& dispatcher, const Crypto::Hash& hash) : IWalletBaseStub(dispatcher), hash(hash) {
}
virtual std::vector<size_t> getDelayedTransactionIds() const override {
return {0};
}
virtual WalletTransaction getTransaction(size_t transactionIndex) const override {
return WalletTransactionBuilder().hash(hash).build();
}
const Crypto::Hash hash;
};
TEST_F(WalletServiceTest_getDelayedTransactionHashes, returnsCorrectResult) {
WalletGetDelayedTransactionIdsStub wallet(dispatcher, generateRandomHash());
auto service = createWalletService(wallet);
std::vector<std::string> hashes;
auto ec = service->getDelayedTransactionHashes(hashes);
ASSERT_FALSE(ec);
ASSERT_EQ(1, hashes.size());
ASSERT_EQ(Common::podToHex(wallet.hash), hashes[0]);
}
class WalletServiceTest_getUnconfirmedTransactionHashes: public WalletServiceTest_getTransactions {
public:
virtual void SetUp() override;
protected:
std::vector<CryptoNote::WalletTransactionWithTransfers> transactions;
};
void WalletServiceTest_getUnconfirmedTransactionHashes::SetUp() {
transactions = { WalletTransactionWithTransfersBuilder().transaction(
WalletTransactionBuilder().hash(generateRandomHash()).build()
).addTransfer(RANDOM_ADDRESS1, 100).addTransfer(RANDOM_ADDRESS2, 333).build()
,
WalletTransactionWithTransfersBuilder().transaction(
WalletTransactionBuilder().hash(generateRandomHash()).build()
).addTransfer(RANDOM_ADDRESS3, 123).addTransfer(RANDOM_ADDRESS2, 4252).build()
};
}
struct WalletGetUnconfirmedTransactionsStub : public IWalletBaseStub {
WalletGetUnconfirmedTransactionsStub(System::Dispatcher& dispatcher) : IWalletBaseStub(dispatcher) {
}
virtual std::vector<WalletTransactionWithTransfers> getUnconfirmedTransactions() const override {
return transactions;
}
std::vector<CryptoNote::WalletTransactionWithTransfers> transactions;
};
TEST_F(WalletServiceTest_getUnconfirmedTransactionHashes, returnsAllHashesWithoutAddresses) {
WalletGetUnconfirmedTransactionsStub wallet(dispatcher);
wallet.transactions = transactions;
auto service = createWalletService(wallet);
std::vector<std::string> hashes;
auto ec = service->getUnconfirmedTransactionHashes({}, hashes);
ASSERT_FALSE(ec);
ASSERT_EQ(2, hashes.size());
ASSERT_EQ(hashes[0], Common::podToHex(transactions[0].transaction.hash));
ASSERT_EQ(hashes[1], Common::podToHex(transactions[1].transaction.hash));
}
TEST_F(WalletServiceTest_getUnconfirmedTransactionHashes, returnsOneTransactionWithAddressFilter) {
WalletGetUnconfirmedTransactionsStub wallet(dispatcher);
wallet.transactions = transactions;
auto service = createWalletService(wallet);
std::vector<std::string> hashes;
auto ec = service->getUnconfirmedTransactionHashes({RANDOM_ADDRESS1}, hashes);
ASSERT_FALSE(ec);
ASSERT_EQ(1, hashes.size());
ASSERT_EQ(hashes[0], Common::podToHex(transactions[0].transaction.hash));
}
TEST_F(WalletServiceTest_getUnconfirmedTransactionHashes, returnsTwoTransactionsWithAddressFilter) {
WalletGetUnconfirmedTransactionsStub wallet(dispatcher);
wallet.transactions = transactions;
auto service = createWalletService(wallet);
std::vector<std::string> hashes;
auto ec = service->getUnconfirmedTransactionHashes({RANDOM_ADDRESS2}, hashes);
ASSERT_FALSE(ec);
ASSERT_EQ(2, hashes.size());
ASSERT_EQ(hashes[0], Common::podToHex(transactions[0].transaction.hash));
ASSERT_EQ(hashes[1], Common::podToHex(transactions[1].transaction.hash));
}
TEST_F(WalletServiceTest_getUnconfirmedTransactionHashes, wrongAddressFilter) {
auto service = createWalletService();
std::vector<std::string> hashes;
auto ec = service->getUnconfirmedTransactionHashes({"wrong address"}, hashes);
ASSERT_EQ(make_error_code(CryptoNote::error::BAD_ADDRESS), ec);
}