Electroneum
pending_transaction.cpp
Go to the documentation of this file.
1 // Copyrights(c) 2017-2021, The Electroneum Project
2 // Copyrights(c) 2014-2019, The Monero Project
3 //
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without modification, are
7 // permitted provided that the following conditions are met:
8 //
9 // 1. Redistributions of source code must retain the above copyright notice, this list of
10 // conditions and the following disclaimer.
11 //
12 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
13 // of conditions and the following disclaimer in the documentation and/or other
14 // materials provided with the distribution.
15 //
16 // 3. Neither the name of the copyright holder nor the names of its contributors may be
17 // used to endorse or promote products derived from this software without specific
18 // prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
31 
32 #include "pending_transaction.h"
33 #include "wallet.h"
34 #include "common_defines.h"
35 
38 #include "common/base58.h"
39 
40 #include <memory>
41 #include <vector>
42 #include <sstream>
43 #include <boost/format.hpp>
44 
45 using namespace std;
46 
47 namespace Electroneum {
48 
49 PendingTransaction::~PendingTransaction() {}
50 
51 
52 PendingTransactionImpl::PendingTransactionImpl(WalletImpl &wallet)
53  : m_wallet(wallet)
54 {
55  m_status = Status_Ok;
56 }
57 
59 {
60 
61 }
62 
64 {
65  return m_status;
66 }
67 
69 {
70  return m_errorString;
71 }
72 
73 std::vector<std::string> PendingTransactionImpl::txid() const
74 {
75  std::vector<std::string> txid;
76  for (const auto &pt: m_pending_tx)
78  return txid;
79 }
80 
81 bool PendingTransactionImpl::commit(const std::string &filename, bool overwrite)
82 {
83 
84  LOG_PRINT_L3("m_pending_tx size: " << m_pending_tx.size());
85 
86  try {
87  // Save tx to file
88  if (!filename.empty()) {
89  boost::system::error_code ignore;
90  bool tx_file_exists = boost::filesystem::exists(filename, ignore);
91  if(tx_file_exists && !overwrite){
92  m_errorString = string(tr("Attempting to save transaction to file, but specified file(s) exist. Exiting to not risk overwriting. File:")) + filename;
93  m_status = Status_Error;
94  LOG_ERROR(m_errorString);
95  return false;
96  }
97  bool r = m_wallet.m_wallet->save_tx(m_pending_tx, filename);
98  if (!r) {
99  m_errorString = tr("Failed to write transaction(s) to file");
100  m_status = Status_Error;
101  } else {
102  m_status = Status_Ok;
103  }
104  }
105  // Commit tx
106  else {
107  auto multisigState = m_wallet.multisig();
108  if (multisigState.isMultisig && m_signers.size() < multisigState.threshold) {
109  throw runtime_error("Not enough signers to send multisig transaction");
110  }
111 
112  m_wallet.pauseRefresh();
113 
114  const bool tx_cold_signed = m_wallet.m_wallet->get_account().get_device().has_tx_cold_sign();
115  if (tx_cold_signed){
116  std::unordered_set<size_t> selected_transfers;
117  for(const tools::wallet2::pending_tx & ptx : m_pending_tx){
118  for(size_t s : ptx.selected_transfers){
119  selected_transfers.insert(s);
120  }
121  }
122 
123  m_wallet.m_wallet->cold_tx_aux_import(m_pending_tx, m_tx_device_aux);
124  bool r = m_wallet.m_wallet->import_key_images(m_key_images, 0, selected_transfers);
125  if (!r){
126  throw runtime_error("Cold sign transaction submit failed - key image sync fail");
127  }
128  }
129 
130  while (!m_pending_tx.empty()) {
131  auto & ptx = m_pending_tx.back();
132  m_wallet.m_wallet->commit_tx(ptx);
133  // if no exception, remove element from vector
134  m_pending_tx.pop_back();
135  } // TODO: extract method;
136  }
137  } catch (const tools::error::daemon_busy&) {
138  // TODO: make it translatable with "tr"?
139  m_errorString = tr("daemon is busy. Please try again later.");
140  m_status = Status_Error;
141  } catch (const tools::error::no_connection_to_daemon&) {
142  m_errorString = tr("no connection to daemon. Please make sure daemon is running.");
143  m_status = Status_Error;
144  } catch (const tools::error::tx_rejected& e) {
145  std::ostringstream writer(m_errorString);
146  writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status();
147  std::string reason = e.reason();
148  m_status = Status_Error;
149  m_errorString = writer.str();
150  if (!reason.empty())
151  m_errorString += string(tr(". Reason: ")) + reason;
152  } catch (const std::exception &e) {
153  m_errorString = string(tr("Unknown exception: ")) + e.what();
154  m_status = Status_Error;
155  } catch (...) {
156  m_errorString = tr("Unhandled exception");
157  LOG_ERROR(m_errorString);
158  m_status = Status_Error;
159  }
160 
161  m_wallet.startRefresh();
162  return m_status == Status_Ok;
163 }
164 
166 {
167  uint64_t result = 0;
168  for (const auto &ptx : m_pending_tx) {
169  for (const auto &dest : ptx.dests) {
170  result += dest.amount;
171  }
172  }
173  return result;
174 }
175 
177 {
178  uint64_t result = 0;
179  for (const auto & ptx : m_pending_tx) {
180  result += ptx.dust;
181  }
182  return result;
183 }
184 
186 {
187  uint64_t result = 0;
188  for (const auto &ptx : m_pending_tx) {
189  result += ptx.fee;
190  }
191  return result;
192 }
193 
195 {
196  return m_pending_tx.size();
197 }
198 
199 std::vector<uint32_t> PendingTransactionImpl::subaddrAccount() const
200 {
201  std::vector<uint32_t> result;
202  for (const auto& ptx : m_pending_tx)
203  result.push_back(ptx.construction_data.subaddr_account);
204  return result;
205 }
206 
207 std::vector<std::set<uint32_t>> PendingTransactionImpl::subaddrIndices() const
208 {
209  std::vector<std::set<uint32_t>> result;
210  for (const auto& ptx : m_pending_tx)
211  result.push_back(ptx.construction_data.subaddr_indices);
212  return result;
213 }
214 
216  try {
217  if (!m_wallet.multisig().isMultisig) {
218  throw std::runtime_error("wallet is not multisig");
219  }
220 
222  txSet.m_ptx = m_pending_tx;
223  txSet.m_signers = m_signers;
224  auto cipher = m_wallet.m_wallet->save_multisig_tx(txSet);
225 
227  } catch (const std::exception& e) {
228  m_status = Status_Error;
229  m_errorString = std::string(tr("Couldn't multisig sign data: ")) + e.what();
230  }
231 
232  return std::string();
233 }
234 
236  try {
237  std::vector<crypto::hash> ignore;
238 
240  txSet.m_ptx = m_pending_tx;
241  txSet.m_signers = m_signers;
242 
243  if (!m_wallet.m_wallet->sign_multisig_tx(txSet, ignore)) {
244  throw std::runtime_error("couldn't sign multisig transaction");
245  }
246 
247  std::swap(m_pending_tx, txSet.m_ptx);
248  std::swap(m_signers, txSet.m_signers);
249  } catch (const std::exception& e) {
250  m_status = Status_Error;
251  m_errorString = std::string(tr("Couldn't sign multisig transaction: ")) + e.what();
252  }
253 }
254 
255 std::vector<std::string> PendingTransactionImpl::signersKeys() const {
256  std::vector<std::string> keys;
257  keys.reserve(m_signers.size());
258 
259  for (const auto& signer: m_signers) {
261  }
262 
263  return keys;
264 }
265 
266 }
267 
268 namespace Bitelectroneum = Electroneum;
269 
#define tr(x)
Definition: common_defines.h:4
std::string errorString() const override
uint64_t txCount() const override
txCount - number of transactions current transaction will be splitted to
::std::string string
Definition: gtest-port.h:1097
CXA_THROW_INFO_T void(* dest)(void *))
Definition: stack_trace.cpp:91
virtual void startRefresh() override
StartRefresh - Start/resume refresh thread (refresh every 10 seconds)
Definition: wallet.cpp:2140
std::vector< std::string > signersKeys() const override
signersKeys
STL namespace.
std::unordered_set< crypto::public_key > m_signers
Definition: wallet2.h:513
std::string encode(const std::string &data)
Definition: base58.cpp:173
std::vector< uint32_t > subaddrAccount() const override
virtual void pauseRefresh() override
pauseRefresh - pause refresh thread
Definition: wallet.cpp:2161
std::string pod_to_hex(const t_pod_type &s)
Definition: string_tools.h:317
bool commit(const std::string &filename="", bool overwrite=false) override
std::vector< std::set< uint32_t > > subaddrIndices() const override
unsigned __int64 uint64_t
Definition: stdint.h:136
bool t_serializable_object_to_blob(const t_object &to, blobdata &b_blob)
MultisigState multisig() const override
multisig - returns current state of multisig wallet creation process
Definition: wallet.cpp:1248
#define LOG_PRINT_L3(x)
Definition: misc_log_ex.h:102
const std::string & reason() const
#define LOG_ERROR(x)
Definition: misc_log_ex.h:98
const std::string & status() const
std::string buff_to_hex_nodelimer(const std::string &src)
Definition: string_tools.h:87
std::string multisigSignData() override
multisigSignData
crypto::hash get_transaction_hash(const transaction &t)
const cryptonote::transaction & tx() const
std::vector< std::string > txid() const override
std::vector< pending_tx > m_ptx
Definition: wallet2.h:512