Electroneum
Loading...
Searching...
No Matches
unsigned_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
33#include "wallet.h"
34#include "common_defines.h"
35
38
39#include <memory>
40#include <vector>
41#include <sstream>
42#include <boost/format.hpp>
43
44using namespace std;
45
46namespace Electroneum {
47
49
50
52 : m_wallet(wallet)
53{
54 m_status = Status_Ok;
55}
56
61
63{
64 return m_status;
65}
66
68{
69 return m_errorString;
70}
71
72bool UnsignedTransactionImpl::sign(const std::string &signedFileName)
73{
74 if(m_wallet.watchOnly())
75 {
76 m_errorString = tr("This is a watch only wallet");
77 m_status = Status_Error;
78 return false;
79 }
80 std::vector<tools::wallet2::pending_tx> ptx;
81 try
82 {
83 bool r = m_wallet.m_wallet->sign_tx(m_unsigned_tx_set, signedFileName, ptx);
84 if (!r)
85 {
86 m_errorString = tr("Failed to sign transaction");
87 m_status = Status_Error;
88 return false;
89 }
90 }
91 catch (const std::exception &e)
92 {
93 m_errorString = string(tr("Failed to sign transaction")) + e.what();
94 m_status = Status_Error;
95 return false;
96 }
97 return true;
98}
99
100//----------------------------------------------------------------------------------------------------
101bool UnsignedTransactionImpl::checkLoadedTx(const std::function<size_t()> get_num_txes, const std::function<const tools::wallet2::tx_construction_data&(size_t)> &get_tx, const std::string &extra_message)
102{
103 // gather info to ask the user
104 uint64_t amount = 0, amount_to_dests = 0, change = 0;
105 size_t min_ring_size = ~0;
106 std::unordered_map<cryptonote::account_public_address, std::pair<std::string, uint64_t>> dests;
107 int first_known_non_zero_change_index = -1;
108 std::string payment_id_string = "";
109 for (size_t n = 0; n < get_num_txes(); ++n)
110 {
111 const tools::wallet2::tx_construction_data &cd = get_tx(n);
112
113 std::vector<cryptonote::tx_extra_field> tx_extra_fields;
114 bool has_encrypted_payment_id = false;
115 crypto::hash8 payment_id8 = crypto::null_hash8;
116 if (cryptonote::parse_tx_extra(cd.extra, tx_extra_fields))
117 {
118 cryptonote::tx_extra_nonce extra_nonce;
119 if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce))
120 {
121 crypto::hash payment_id;
123 {
124 if (!payment_id_string.empty())
125 payment_id_string += ", ";
126
127 crypto::hash payment_id = crypto::null_hash;
128 memcpy(payment_id.data, payment_id8.data, 8); // convert short pid to regular
129 memset(payment_id.data + 8, 0, 24); // merely a sanity check
130 payment_id_string = std::string("unencrypted payment ID ") + epee::string_tools::pod_to_hex(payment_id);
131
132 }
133 else if (cryptonote::get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
134 {
135 if (!payment_id_string.empty())
136 payment_id_string += ", ";
137 payment_id_string = std::string("unencrypted payment ID ") + epee::string_tools::pod_to_hex(payment_id);
138 }
139 }
140 }
141
142 for (size_t s = 0; s < cd.sources.size(); ++s)
143 {
144 amount += cd.sources[s].amount;
145 size_t ring_size = cd.sources[s].outputs.size();
146 if (ring_size < min_ring_size)
147 min_ring_size = ring_size;
148 }
149 for (size_t d = 0; d < cd.splitted_dsts.size(); ++d)
150 {
151 const cryptonote::tx_destination_entry &entry = cd.splitted_dsts[d];
152 std::string address, standard_address = get_account_address_as_str(m_wallet.m_wallet->nettype(), entry.is_subaddress, entry.addr);
153 if (has_encrypted_payment_id && !entry.is_subaddress)
154 {
155 address = get_account_integrated_address_as_str(m_wallet.m_wallet->nettype(), entry.addr, payment_id8);
156 address += std::string(" (" + standard_address + " with encrypted payment id " + epee::string_tools::pod_to_hex(payment_id8) + ")");
157 }
158 else
159 address = standard_address;
160 auto i = dests.find(entry.addr);
161 if (i == dests.end())
162 dests.insert(std::make_pair(entry.addr, std::make_pair(address, entry.amount)));
163 else
164 i->second.second += entry.amount;
165 amount_to_dests += entry.amount;
166 }
167 if (cd.change_dts.amount > 0)
168 {
169 auto it = dests.find(cd.change_dts.addr);
170 if (it == dests.end())
171 {
172 m_status = Status_Error;
173 m_errorString = tr("Claimed change does not go to a paid address");
174 return false;
175 }
176 if (it->second.second < cd.change_dts.amount)
177 {
178 m_status = Status_Error;
179 m_errorString = tr("Claimed change is larger than payment to the change address");
180 return false;
181 }
182 if (cd.change_dts.amount > 0)
183 {
184 if (first_known_non_zero_change_index == -1)
185 first_known_non_zero_change_index = n;
186 if (memcmp(&cd.change_dts.addr, &get_tx(first_known_non_zero_change_index).change_dts.addr, sizeof(cd.change_dts.addr)))
187 {
188 m_status = Status_Error;
189 m_errorString = tr("Change goes to more than one address");
190 return false;
191 }
192 }
193 change += cd.change_dts.amount;
194 it->second.second -= cd.change_dts.amount;
195 if (it->second.second == 0)
196 dests.erase(cd.change_dts.addr);
197 }
198 }
199 std::string dest_string;
200 for (auto i = dests.begin(); i != dests.end(); )
201 {
202 dest_string += (boost::format(tr("sending %s to %s")) % cryptonote::print_etn(i->second.second) % i->second.first).str();
203 ++i;
204 if (i != dests.end())
205 dest_string += ", ";
206 }
207 if (dest_string.empty())
208 dest_string = tr("with no destinations");
209
210 std::string change_string;
211 if (change > 0)
212 {
213 std::string address = get_account_address_as_str(m_wallet.m_wallet->nettype(), get_tx(0).subaddr_account > 0, get_tx(0).change_dts.addr);
214 change_string += (boost::format(tr("%s change to %s")) % cryptonote::print_etn(change) % address).str();
215 }
216 else
217 change_string += tr("no change");
218 uint64_t fee = amount - amount_to_dests;
219 m_confirmationMessage = (boost::format(tr("Loaded %lu transactions, for %s, fee %s, %s, %s, with min ring size %lu. %s")) % (unsigned long)get_num_txes() % cryptonote::print_etn(amount) % cryptonote::print_etn(fee) % dest_string % change_string % (unsigned long)min_ring_size % extra_message).str();
220 return true;
221}
222
223std::vector<uint64_t> UnsignedTransactionImpl::amount() const
224{
225 std::vector<uint64_t> result;
226 for (const auto &utx : m_unsigned_tx_set.txes) {
227 for (const auto &unsigned_dest : utx.dests) {
228 result.push_back(unsigned_dest.amount);
229 }
230 }
231 return result;
232}
233
234std::vector<uint64_t> UnsignedTransactionImpl::fee() const
235{
236 std::vector<uint64_t> result;
237 for (const auto &utx : m_unsigned_tx_set.txes) {
238 uint64_t fee = 0;
239 for (const auto &i: utx.sources) fee += i.amount;
240 for (const auto &i: utx.splitted_dsts) fee -= i.amount;
241 result.push_back(fee);
242 }
243 return result;
244}
245
246std::vector<uint64_t> UnsignedTransactionImpl::mixin() const
247{
248 std::vector<uint64_t> result;
249 for (const auto &utx: m_unsigned_tx_set.txes) {
250 size_t min_mixin = ~0;
251 // TODO: Is this loop needed or is sources[0] ?
252 for (size_t s = 0; s < utx.sources.size(); ++s) {
253 size_t mixin = utx.sources[s].outputs.size() - 1;
254 if (mixin < min_mixin)
255 min_mixin = mixin;
256 }
257 result.push_back(min_mixin);
258 }
259 return result;
260}
261
263{
264 return m_unsigned_tx_set.txes.size();
265}
266
267std::vector<std::string> UnsignedTransactionImpl::paymentId() const
268{
269 std::vector<string> result;
270 for (const auto &utx: m_unsigned_tx_set.txes) {
271 crypto::hash payment_id = crypto::null_hash;
272 cryptonote::tx_extra_nonce extra_nonce;
273 std::vector<cryptonote::tx_extra_field> tx_extra_fields;
274 cryptonote::parse_tx_extra(utx.extra, tx_extra_fields);
275 if (cryptonote::find_tx_extra_field_by_type(tx_extra_fields, extra_nonce))
276 {
277 crypto::hash8 payment_id8 = crypto::null_hash8;
279 {
280 // We can't decrypt short pid without recipient key.
281 memcpy(payment_id.data, payment_id8.data, 8);
282 }
283 else if (!cryptonote::get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
284 {
285 payment_id = crypto::null_hash;
286 }
287 }
288 if(payment_id != crypto::null_hash)
289 result.push_back(epee::string_tools::pod_to_hex(payment_id));
290 else
291 result.push_back("");
292 }
293 return result;
294}
295
296std::vector<std::string> UnsignedTransactionImpl::recipientAddress() const
297{
298 // TODO: return integrated address if short payment ID exists
299 std::vector<string> result;
300 for (const auto &utx: m_unsigned_tx_set.txes) {
301 if (utx.dests.empty()) {
302 MERROR("empty destinations, skipped");
303 continue;
304 }
305 result.push_back(cryptonote::get_account_address_as_str(m_wallet.m_wallet->nettype(), utx.dests[0].is_subaddress, utx.dests[0].addr));
306 }
307 return result;
308}
309
311{
312 uint64_t min_mixin = ~0;
313 for (const auto &utx: m_unsigned_tx_set.txes) {
314 for (size_t s = 0; s < utx.sources.size(); ++s) {
315 size_t mixin = utx.sources[s].outputs.size() - 1;
316 if (mixin < min_mixin)
317 min_mixin = mixin;
318 }
319 }
320 return min_mixin;
321}
322
323} // namespace
324
325namespace Bitelectroneum = Electroneum;
326
std::vector< uint64_t > amount() const override
std::vector< uint64_t > fee() const override
std::vector< uint64_t > mixin() const override
std::string errorString() const override
bool sign(const std::string &signedFileName) override
sign - Sign txs and saves to file
std::vector< std::string > paymentId() const override
std::vector< std::string > recipientAddress() const override
uint64_t txCount() const override
txCount - number of transactions current transaction will be splitted to
#define tr(x)
void * memcpy(void *a, const void *b, size_t c)
#define MERROR(x)
Definition misc_log_ex.h:73
#define LOG_PRINT_L3(x)
POD_CLASS hash8
Definition hash.h:53
POD_CLASS hash
Definition hash.h:50
bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata &extra_nonce, crypto::hash8 &payment_id)
bool get_payment_id_from_tx_extra_nonce(const blobdata &extra_nonce, crypto::hash &payment_id)
std::string get_account_address_as_str(network_type nettype, bool subaddress, account_public_address const &adr)
bool find_tx_extra_field_by_type(const std::vector< tx_extra_field > &tx_extra_fields, T &field, size_t index=0)
bool parse_tx_extra(const std::vector< uint8_t > &tx_extra, std::vector< tx_extra_field > &tx_extra_fields)
std::string print_etn(uint64_t amount, unsigned int decimal_point)
std::string get_account_integrated_address_as_str(network_type nettype, account_public_address const &adr, crypto::hash8 const &payment_id)
std::string pod_to_hex(const t_pod_type &s)
STL namespace.
unsigned __int64 uint64_t
Definition stdint.h:136
bool is_subaddress
uint64_t amount
account_public_address addr
std::vector< uint8_t > extra
Definition wallet2.h:426
std::vector< cryptonote::tx_source_entry > sources
Definition wallet2.h:422
std::vector< cryptonote::tx_destination_entry > splitted_dsts
Definition wallet2.h:424
cryptonote::tx_destination_entry change_dts
Definition wallet2.h:423
const char * address
Definition multisig.cpp:37