Skip to content

Commit

Permalink
Get wallet outputs and ability to manually select them for sending (s…
Browse files Browse the repository at this point in the history
…eredat#27)

(cherry picked from commit dee0ef30f8b66689a74532d5a6837e9bec708665)
  • Loading branch information
aivve committed Mar 22, 2021
1 parent 4ad68e1 commit b9b60fa
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 9 deletions.
7 changes: 7 additions & 0 deletions include/IWalletLegacy.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,17 @@ class IWalletLegacy {
virtual void getAccountKeys(AccountKeys& keys) = 0;
virtual bool getSeed(std::string& electrum_words) = 0;

virtual std::vector<TransactionOutputInformation> getOutputs() = 0;
virtual std::vector<TransactionOutputInformation> getLockedOutputs() = 0;
virtual std::vector<TransactionOutputInformation> getUnlockedOutputs() = 0;
virtual std::vector<TransactionSpentOutputInformation> getSpentOutputs() = 0;

virtual TransactionId sendTransaction(const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) = 0;
virtual TransactionId sendTransaction(const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) = 0;
virtual TransactionId sendTransaction(const std::vector<WalletLegacyTransfer>& transfers, const std::list<TransactionOutputInformation>& selectedOuts, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) = 0;
virtual TransactionId sendFusionTransaction(const std::list<TransactionOutputInformation>& fusionInputs, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) = 0;
virtual std::string prepareRawTransaction(TransactionId& transactionId, const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) = 0;
virtual std::string prepareRawTransaction(TransactionId& transactionId, const std::vector<WalletLegacyTransfer>& transfers, const std::list<TransactionOutputInformation>& selectedOuts, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) = 0;
virtual std::string prepareRawTransaction(TransactionId& transactionId, const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) = 0;
virtual std::error_code cancelTransaction(size_t transferId) = 0;

Expand Down
68 changes: 65 additions & 3 deletions src/WalletLegacy/WalletLegacy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,28 @@ size_t WalletLegacy::getUnlockedOutputsCount() {
return outputs.size();
}

std::vector<TransactionOutputInformation> WalletLegacy::getOutputs() {
std::vector<TransactionOutputInformation> outputs;
m_transferDetails->getOutputs(outputs, ITransfersContainer::IncludeAll);
return outputs;
}

std::vector<TransactionOutputInformation> WalletLegacy::getLockedOutputs() {
std::vector<TransactionOutputInformation> outputs;
m_transferDetails->getOutputs(outputs, ITransfersContainer::IncludeAllLocked);
return outputs;
}

std::vector<TransactionOutputInformation> WalletLegacy::getUnlockedOutputs() {
std::vector<TransactionOutputInformation> outputs;
m_transferDetails->getOutputs(outputs, ITransfersContainer::IncludeAllUnlocked);
return outputs;
}

std::vector<TransactionSpentOutputInformation> WalletLegacy::getSpentOutputs() {
return m_transferDetails->getSpentOutputs();
}

size_t WalletLegacy::estimateFusion(const uint64_t& threshold) {
size_t fusionReadyCount = 0;
std::vector<TransactionOutputInformation> outputs;
Expand Down Expand Up @@ -747,9 +769,11 @@ TransactionId WalletLegacy::sendTransaction(const std::vector<WalletLegacyTransf
std::deque<std::shared_ptr<WalletLegacyEvent>> events;
throwIfNotInitialised();

std::list<CryptoNote::TransactionOutputInformation> _selectedOuts = {};

{
std::unique_lock<std::mutex> lock(m_cacheMutex);
request = m_sender->makeSendRequest(txId, events, transfers, fee, extra, mixIn, unlockTimestamp);
request = m_sender->makeSendRequest(txId, events, transfers, _selectedOuts, fee, extra, mixIn, unlockTimestamp);
}

notifyClients(events);
Expand All @@ -762,16 +786,54 @@ TransactionId WalletLegacy::sendTransaction(const std::vector<WalletLegacyTransf
return txId;
}

std::string WalletLegacy::prepareRawTransaction(TransactionId& transactionId, const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) {
TransactionId WalletLegacy::sendTransaction(const std::vector<WalletLegacyTransfer>& transfers, const std::list<TransactionOutputInformation>& selectedOuts, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) {
TransactionId txId = 0;
std::shared_ptr<WalletRequest> request;
std::deque<std::shared_ptr<WalletLegacyEvent>> events;
throwIfNotInitialised();

{
std::unique_lock<std::mutex> lock(m_cacheMutex);
request = m_sender->makeSendRequest(txId, events, transfers, selectedOuts, fee, extra, mixIn, unlockTimestamp);
}

notifyClients(events);

if (request) {
m_asyncContextCounter.addAsyncContext();
request->perform(m_node, std::bind(&WalletLegacy::sendTransactionCallback, this, std::placeholders::_1, std::placeholders::_2));
}

return txId;
}

std::string WalletLegacy::prepareRawTransaction(TransactionId& transactionId, const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) {
std::deque<std::shared_ptr<WalletLegacyEvent>> events;
throwIfNotInitialised();

std::list<CryptoNote::TransactionOutputInformation> _selectedOuts = {};

std::string tx_as_hex;

{
std::unique_lock<std::mutex> lock(m_cacheMutex);
tx_as_hex = m_sender->makeRawTransaction(transactionId, events, transfers, _selectedOuts, fee, extra, mixIn, unlockTimestamp);
}

notifyClients(events);

return tx_as_hex;
}

std::string WalletLegacy::prepareRawTransaction(TransactionId& transactionId, const std::vector<WalletLegacyTransfer>& transfers, const std::list<CryptoNote::TransactionOutputInformation>& selectedOuts, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) {
std::deque<std::shared_ptr<WalletLegacyEvent>> events;
throwIfNotInitialised();

std::string tx_as_hex;

{
std::unique_lock<std::mutex> lock(m_cacheMutex);
tx_as_hex = m_sender->makeRawTransaction(transactionId, events, transfers, fee, extra, mixIn, unlockTimestamp);
tx_as_hex = m_sender->makeRawTransaction(transactionId, events, transfers, selectedOuts, fee, extra, mixIn, unlockTimestamp);
}

notifyClients(events);
Expand Down
7 changes: 7 additions & 0 deletions src/WalletLegacy/WalletLegacy.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,17 @@ class WalletLegacy :
virtual void getAccountKeys(AccountKeys& keys) override;
virtual bool getSeed(std::string& electrum_words) override;

virtual std::vector<TransactionOutputInformation> getOutputs() override;
virtual std::vector<TransactionOutputInformation> getLockedOutputs() override;
virtual std::vector<TransactionOutputInformation> getUnlockedOutputs() override;
virtual std::vector<TransactionSpentOutputInformation> getSpentOutputs() override;

virtual TransactionId sendTransaction(const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) override;
virtual TransactionId sendTransaction(const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) override;
virtual TransactionId sendTransaction(const std::vector<WalletLegacyTransfer>& transfers, const std::list<TransactionOutputInformation>& selectedOuts, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) override;
virtual TransactionId sendFusionTransaction(const std::list<TransactionOutputInformation>& fusionInputs, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) override;
virtual std::string prepareRawTransaction(TransactionId& transactionId, const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) override;
virtual std::string prepareRawTransaction(TransactionId& transactionId, const std::vector<WalletLegacyTransfer>& transfers, const std::list<TransactionOutputInformation>& selectedOuts, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) override;
virtual std::string prepareRawTransaction(TransactionId& transactionId, const WalletLegacyTransfer& transfer, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) override;
virtual std::error_code cancelTransaction(size_t transactionId) override;

Expand Down
30 changes: 25 additions & 5 deletions src/WalletLegacy/WalletTransactionSender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ void WalletTransactionSender::validateTransfersAddresses(const std::vector<Walle
}

std::shared_ptr<WalletRequest> WalletTransactionSender::makeSendRequest(TransactionId& transactionId, std::deque<std::shared_ptr<WalletLegacyEvent>>& events,
const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) {
const std::vector<WalletLegacyTransfer>& transfers, const std::list<TransactionOutputInformation>& selectedOuts, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) {

using namespace CryptoNote;

Expand All @@ -117,7 +117,16 @@ std::shared_ptr<WalletRequest> WalletTransactionSender::makeSendRequest(Transact

std::shared_ptr<SendTransactionContext> context = std::make_shared<SendTransactionContext>();

context->foundMoney = selectTransfersToSend(neededMoney, 0 == mixIn, context->dustPolicy.dustThreshold, context->selectedTransfers);
if (selectedOuts.size() > 0) {
for (auto& out : selectedOuts) {
context->foundMoney += out.amount;
}
context->selectedTransfers = selectedOuts;
}
else {
context->foundMoney = selectTransfersToSend(neededMoney, 0 == mixIn, context->dustPolicy.dustThreshold, context->selectedTransfers);
}

throwIf(context->foundMoney < neededMoney, error::WRONG_AMOUNT);

transactionId = m_transactionsCache.addNewTransaction(neededMoney, fee, extra, transfers, unlockTimestamp);
Expand Down Expand Up @@ -162,7 +171,9 @@ std::shared_ptr<WalletRequest> WalletTransactionSender::makeSendFusionRequest(Tr
}

std::string WalletTransactionSender::makeRawTransaction(TransactionId& transactionId, std::deque<std::shared_ptr<WalletLegacyEvent>>& events,
const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp) {
const std::vector<WalletLegacyTransfer>& transfers, const std::list<CryptoNote::TransactionOutputInformation>& selectedOuts,
uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp)
{

std::string raw_tx;

Expand All @@ -174,15 +185,24 @@ std::string WalletTransactionSender::makeRawTransaction(TransactionId& transacti

std::shared_ptr<SendTransactionContext> context = std::make_shared<SendTransactionContext>();

context->foundMoney = selectTransfersToSend(neededMoney, 0 == mixIn, context->dustPolicy.dustThreshold, context->selectedTransfers);
if (selectedOuts.size() > 0) {
for (auto& out : selectedOuts) {
context->foundMoney += out.amount;
}
context->selectedTransfers = selectedOuts;
}
else {
context->foundMoney = selectTransfersToSend(neededMoney, 0 == mixIn, context->dustPolicy.dustThreshold, context->selectedTransfers);
}

throwIf(context->foundMoney < neededMoney, error::WRONG_AMOUNT);

// add tx to wallet cache to prevent reuse of outputs used in this tx
transactionId = m_transactionsCache.addNewTransaction(neededMoney, fee, extra, transfers, unlockTimestamp);
context->transactionId = transactionId;
context->mixIn = mixIn;

if (context->mixIn) {
if (context->mixIn) {
uint64_t outsCount = mixIn + 1; // add one to make possible (if need) to skip real output key
std::vector<uint64_t> amounts;

Expand Down
5 changes: 4 additions & 1 deletion src/WalletLegacy/WalletTransactionSender.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,13 @@ class WalletTransactionSender
std::shared_ptr<WalletRequest> makeSendRequest(TransactionId& transactionId, std::deque<std::shared_ptr<WalletLegacyEvent>>& events,
const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0);

std::shared_ptr<WalletRequest> makeSendRequest(TransactionId& transactionId, std::deque<std::shared_ptr<WalletLegacyEvent>>& events,
const std::vector<WalletLegacyTransfer>& transfers, const std::list<TransactionOutputInformation>& selectedOuts, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0);

std::shared_ptr<WalletRequest> makeSendFusionRequest(TransactionId& transactionId, std::deque<std::shared_ptr<WalletLegacyEvent>>& events,
const std::vector<WalletLegacyTransfer>& transfers, const std::list<TransactionOutputInformation>& fusionInputs, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0);

std::string makeRawTransaction(TransactionId& transactionId, std::deque<std::shared_ptr<WalletLegacyEvent>>& events, const std::vector<WalletLegacyTransfer>& transfers, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp);
std::string makeRawTransaction(TransactionId& transactionId, std::deque<std::shared_ptr<WalletLegacyEvent>>& events, const std::vector<WalletLegacyTransfer>& transfers, const std::list<CryptoNote::TransactionOutputInformation>& _selectedOuts, uint64_t fee, const std::string& extra, uint64_t mixIn, uint64_t unlockTimestamp);

private:
std::shared_ptr<WalletRequest> makeGetRandomOutsRequest(std::shared_ptr<SendTransactionContext> context);
Expand Down

0 comments on commit b9b60fa

Please sign in to comment.