aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/common/boost_serialization_helper.h46
-rw-r--r--src/common/unordered_containers_boost_serialization.h37
-rw-r--r--src/common/util.h2
-rw-r--r--src/cryptonote_core/blockchain_storage.cpp63
-rw-r--r--src/cryptonote_core/checkpoints_create.h3
-rw-r--r--src/cryptonote_core/cryptonote_format_utils.cpp139
-rw-r--r--src/cryptonote_core/cryptonote_format_utils.h21
-rw-r--r--src/cryptonote_core/difficulty.cpp2
-rw-r--r--src/cryptonote_core/tx_extra.h87
-rw-r--r--src/cryptonote_core/tx_pool.h3
-rw-r--r--src/miner/simpleminer.cpp18
-rw-r--r--src/miner/simpleminer_protocol_defs.h4
-rw-r--r--src/rpc/core_rpc_server.cpp4
-rw-r--r--src/serialization/serialization.h2
-rw-r--r--src/simplewallet/simplewallet.cpp163
-rw-r--r--src/simplewallet/simplewallet.h3
-rw-r--r--src/version.h.in4
-rw-r--r--src/wallet/wallet2.cpp119
-rw-r--r--src/wallet/wallet2.h52
-rw-r--r--src/wallet/wallet_errors.h23
-rw-r--r--src/wallet/wallet_rpc_server.cpp49
-rw-r--r--src/wallet/wallet_rpc_server.h10
-rw-r--r--src/wallet/wallet_rpc_server_commans_defs.h35
-rw-r--r--src/wallet/wallet_rpc_server_error_codes.h3
24 files changed, 712 insertions, 180 deletions
diff --git a/src/common/boost_serialization_helper.h b/src/common/boost_serialization_helper.h
index 74016ae75..0bf924802 100644
--- a/src/common/boost_serialization_helper.h
+++ b/src/common/boost_serialization_helper.h
@@ -14,15 +14,55 @@ namespace tools
bool serialize_obj_to_file(t_object& obj, const std::string& file_path)
{
TRY_ENTRY();
+#if defined(_MSC_VER)
+ // Need to know HANDLE of file to call FlushFileBuffers
+ HANDLE data_file_handle = ::CreateFile(file_path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (INVALID_HANDLE_VALUE == data_file_handle)
+ return false;
+
+ int data_file_descriptor = _open_osfhandle((intptr_t)data_file_handle, 0);
+ if (-1 == data_file_descriptor)
+ {
+ ::CloseHandle(data_file_handle);
+ return false;
+ }
+
+ FILE* data_file_file = _fdopen(data_file_descriptor, "wb");
+ if (0 == data_file_file)
+ {
+ // Call CloseHandle is not necessary
+ _close(data_file_descriptor);
+ return false;
+ }
+
+ // HACK: undocumented constructor, this code may not compile
+ std::ofstream data_file(data_file_file);
+ if (data_file.fail())
+ {
+ // Call CloseHandle and _close are not necessary
+ fclose(data_file_file);
+ return false;
+ }
+#else
std::ofstream data_file;
- data_file.open( file_path , std::ios_base::binary | std::ios_base::out| std::ios::trunc);
- if(data_file.fail())
+ data_file.open(file_path , std::ios_base::binary | std::ios_base::out| std::ios::trunc);
+ if (data_file.fail())
return false;
+#endif
boost::archive::binary_oarchive a(data_file);
a << obj;
+ if (data_file.fail())
+ return false;
- return !data_file.fail();
+ data_file.flush();
+#if defined(_MSC_VER)
+ // To make sure the file is fully stored on disk
+ ::FlushFileBuffers(data_file_handle);
+ fclose(data_file_file);
+#endif
+
+ return true;
CATCH_ENTRY_L0("serialize_obj_to_file", false);
}
diff --git a/src/common/unordered_containers_boost_serialization.h b/src/common/unordered_containers_boost_serialization.h
index a29896ee7..84fa73b92 100644
--- a/src/common/unordered_containers_boost_serialization.h
+++ b/src/common/unordered_containers_boost_serialization.h
@@ -2,7 +2,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#pragma once
+#pragma once
#include <boost/serialization/split_free.hpp>
#include <unordered_map>
@@ -41,6 +41,35 @@ namespace boost
}
+ template <class Archive, class h_key, class hval>
+ inline void save(Archive &a, const std::unordered_multimap<h_key, hval> &x, const boost::serialization::version_type ver)
+ {
+ size_t s = x.size();
+ a << s;
+ BOOST_FOREACH(auto& v, x)
+ {
+ a << v.first;
+ a << v.second;
+ }
+ }
+
+ template <class Archive, class h_key, class hval>
+ inline void load(Archive &a, std::unordered_multimap<h_key, hval> &x, const boost::serialization::version_type ver)
+ {
+ x.clear();
+ size_t s = 0;
+ a >> s;
+ for(size_t i = 0; i != s; i++)
+ {
+ h_key k;
+ hval v;
+ a >> k;
+ a >> v;
+ x.emplace(k, v);
+ }
+ }
+
+
template <class Archive, class hval>
inline void save(Archive &a, const std::unordered_set<hval> &x, const boost::serialization::version_type ver)
{
@@ -73,6 +102,12 @@ namespace boost
split_free(a, x, ver);
}
+ template <class Archive, class h_key, class hval>
+ inline void serialize(Archive &a, std::unordered_multimap<h_key, hval> &x, const boost::serialization::version_type ver)
+ {
+ split_free(a, x, ver);
+ }
+
template <class Archive, class hval>
inline void serialize(Archive &a, std::unordered_set<hval> &x, const boost::serialization::version_type ver)
{
diff --git a/src/common/util.h b/src/common/util.h
index af92adf94..8a1f4b041 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -52,7 +52,7 @@ namespace tools
private:
#if defined(WIN32)
- static BOOL win_handler(DWORD type)
+ static BOOL WINAPI win_handler(DWORD type)
{
if (CTRL_C_EVENT == type || CTRL_BREAK_EVENT == type)
{
diff --git a/src/cryptonote_core/blockchain_storage.cpp b/src/cryptonote_core/blockchain_storage.cpp
index c1b9619f2..0e20b454b 100644
--- a/src/cryptonote_core/blockchain_storage.cpp
+++ b/src/cryptonote_core/blockchain_storage.cpp
@@ -582,6 +582,42 @@ bool blockchain_storage::create_block_template(block& b, const account_public_ad
if (!m_tx_pool.fill_block_template(b, median_size, already_generated_coins, txs_size, fee)) {
return false;
}
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ size_t real_txs_size = 0;
+ uint64_t real_fee = 0;
+ CRITICAL_REGION_BEGIN(m_tx_pool.m_transactions_lock);
+ BOOST_FOREACH(crypto::hash &cur_hash, b.tx_hashes) {
+ auto cur_res = m_tx_pool.m_transactions.find(cur_hash);
+ if (cur_res == m_tx_pool.m_transactions.end()) {
+ LOG_ERROR("Creating block template: error: transaction not found");
+ continue;
+ }
+ tx_memory_pool::tx_details &cur_tx = cur_res->second;
+ real_txs_size += cur_tx.blob_size;
+ real_fee += cur_tx.fee;
+ if (cur_tx.blob_size != get_object_blobsize(cur_tx.tx)) {
+ LOG_ERROR("Creating block template: error: invalid transaction size");
+ }
+ uint64_t inputs_amount;
+ if (!get_inputs_money_amount(cur_tx.tx, inputs_amount)) {
+ LOG_ERROR("Creating block template: error: cannot get inputs amount");
+ } else if (cur_tx.fee != inputs_amount - get_outs_money_amount(cur_tx.tx)) {
+ LOG_ERROR("Creating block template: error: invalid fee");
+ }
+ }
+ if (txs_size != real_txs_size) {
+ LOG_ERROR("Creating block template: error: wrongly calculated transaction size");
+ }
+ if (fee != real_fee) {
+ LOG_ERROR("Creating block template: error: wrongly calculated fee");
+ }
+ CRITICAL_REGION_END();
+ LOG_PRINT_L1("Creating block template: height " << height <<
+ ", median size " << median_size <<
+ ", already generated coins " << already_generated_coins <<
+ ", transaction size " << txs_size <<
+ ", fee " << fee);
+#endif
/*
two-phase miner transaction generation: we don't know exact block size until we prepare block, but we don't know reward until we know
@@ -590,27 +626,32 @@ bool blockchain_storage::create_block_template(block& b, const account_public_ad
//make blocks coin-base tx looks close to real coinbase tx to get truthful blob size
bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, 11);
CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance");
-#ifdef _DEBUG
- std::list<size_t> try_val;
- try_val.push_back(get_object_blobsize(b.miner_tx));
-#endif
-
size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx);
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ LOG_PRINT_L1("Creating block template: miner tx size " << get_object_blobsize(b.miner_tx) <<
+ ", cumulative size " << cumulative_size);
+#endif
for (size_t try_count = 0; try_count != 10; ++try_count) {
r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, 11);
-#ifdef _DEBUG
- try_val.push_back(get_object_blobsize(b.miner_tx));
-#endif
CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, second chance");
size_t coinbase_blob_size = get_object_blobsize(b.miner_tx);
if (coinbase_blob_size > cumulative_size - txs_size) {
cumulative_size = txs_size + coinbase_blob_size;
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size <<
+ ", cumulative size " << cumulative_size << " is greater then before");
+#endif
continue;
}
if (coinbase_blob_size < cumulative_size - txs_size) {
size_t delta = cumulative_size - txs_size - coinbase_blob_size;
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size <<
+ ", cumulative size " << txs_size + coinbase_blob_size <<
+ " is less then before, adding " << delta << " zero bytes");
+#endif
b.miner_tx.extra.insert(b.miner_tx.extra.end(), delta, 0);
//here could be 1 byte difference, because of extra field counter is varint, and it can become from 1-byte len to 2-bytes len.
if (cumulative_size != txs_size + get_object_blobsize(b.miner_tx)) {
@@ -626,6 +667,10 @@ bool blockchain_storage::create_block_template(block& b, const account_public_ad
}
}
CHECK_AND_ASSERT_MES(cumulative_size == txs_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " is not equal txs_cumulative_size=" << txs_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx));
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size <<
+ ", cumulative size " << cumulative_size << " is now good");
+#endif
return true;
}
LOG_ERROR("Failed to create_block_template with " << 10 << " tries");
@@ -1603,4 +1648,4 @@ bool blockchain_storage::add_new_block(const block& bl_, block_verification_cont
}
return handle_block_to_main_chain(bl, id, bvc);
-}
+} \ No newline at end of file
diff --git a/src/cryptonote_core/checkpoints_create.h b/src/cryptonote_core/checkpoints_create.h
index 8dff85d84..304096ef2 100644
--- a/src/cryptonote_core/checkpoints_create.h
+++ b/src/cryptonote_core/checkpoints_create.h
@@ -11,7 +11,8 @@
namespace cryptonote {
inline bool create_checkpoints(cryptonote::checkpoints& checkpoints)
- {
+ {
+ ADD_CHECKPOINT(22231, "d69526de16c58b07058bd80a9a8c99389814d17b1935623223b0d6e4a311b80f");
return true;
}
}
diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp
index a231f9c75..aa2c82b2a 100644
--- a/src/cryptonote_core/cryptonote_format_utils.cpp
+++ b/src/cryptonote_core/cryptonote_format_utils.cpp
@@ -61,8 +61,8 @@ namespace cryptonote
keypair txkey = keypair::generate();
add_tx_pub_key_to_extra(tx, txkey.pub);
- if(extra_nonce.size())
- if(!add_tx_extra_nonce(tx, extra_nonce))
+ if(!extra_nonce.empty())
+ if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
return false;
txin_gen in;
@@ -74,6 +74,10 @@ namespace cryptonote
LOG_PRINT_L0("Block is too big");
return false;
}
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ LOG_PRINT_L1("Creating block template: reward " << block_reward <<
+ ", fee " << fee)
+#endif
block_reward += fee;
std::vector<size_t> out_amounts;
@@ -204,53 +208,52 @@ namespace cryptonote
return r;
}
//---------------------------------------------------------------
- crypto::public_key get_tx_pub_key_from_extra(const transaction& tx)
+ bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields)
{
- crypto::public_key pk = null_pkey;
- parse_and_validate_tx_extra(tx, pk);
- return pk;
- }
- //---------------------------------------------------------------
- bool parse_and_validate_tx_extra(const transaction& tx, crypto::public_key& tx_pub_key)
- {
- tx_pub_key = null_pkey;
- bool padding_started = false; //let the padding goes only at the end
- bool tx_extra_tag_pubkey_found = false;
- bool tx_extra_extra_nonce_found = false;
- for(size_t i = 0; i != tx.extra.size();)
+ tx_extra_fields.clear();
+
+ if(tx_extra.empty())
+ return true;
+
+ std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size());
+ std::istringstream iss(extra_str);
+ binary_archive<false> ar(iss);
+
+ bool eof = false;
+ while (!eof)
{
- if(padding_started)
- {
- CHECK_AND_ASSERT_MES(!tx.extra[i], false, "Failed to parse transaction extra (not 0 after padding) in tx " << get_transaction_hash(tx));
- }
- else if(tx.extra[i] == TX_EXTRA_TAG_PUBKEY)
- {
- CHECK_AND_ASSERT_MES(sizeof(crypto::public_key) <= tx.extra.size()-1-i, false, "Failed to parse transaction extra (TX_EXTRA_TAG_PUBKEY have not enough bytes) in tx " << get_transaction_hash(tx));
- CHECK_AND_ASSERT_MES(!tx_extra_tag_pubkey_found, false, "Failed to parse transaction extra (duplicate TX_EXTRA_TAG_PUBKEY entry) in tx " << get_transaction_hash(tx));
- tx_pub_key = *reinterpret_cast<const crypto::public_key*>(&tx.extra[i+1]);
- i += 1 + sizeof(crypto::public_key);
- tx_extra_tag_pubkey_found = true;
- continue;
- }else if(tx.extra[i] == TX_EXTRA_NONCE)
- {
- //CHECK_AND_ASSERT_MES(is_coinbase(tx), false, "Failed to parse transaction extra (TX_EXTRA_NONCE can be only in coinbase) in tx " << get_transaction_hash(tx));
- CHECK_AND_ASSERT_MES(!tx_extra_extra_nonce_found, false, "Failed to parse transaction extra (duplicate TX_EXTRA_NONCE entry) in tx " << get_transaction_hash(tx));
- CHECK_AND_ASSERT_MES(tx.extra.size()-1-i >= 1, false, "Failed to parse transaction extra (TX_EXTRA_NONCE have not enough bytes) in tx " << get_transaction_hash(tx));
- ++i;
- CHECK_AND_ASSERT_MES(tx.extra.size()-1-i >= tx.extra[i], false, "Failed to parse transaction extra (TX_EXTRA_NONCE have wrong bytes counter) in tx " << get_transaction_hash(tx));
- tx_extra_extra_nonce_found = true;
- i += tx.extra[i];//actually don't need to extract it now, just skip
- }
- else if(!tx.extra[i])
- {
- padding_started = true;
- continue;
- }
- ++i;
+ tx_extra_field field;
+ bool r = ::do_serialize(ar, field);
+ CHECK_AND_NO_ASSERT_MES(r, false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
+ tx_extra_fields.push_back(field);
+
+ std::ios_base::iostate state = iss.rdstate();
+ eof = (EOF == iss.peek());
+ iss.clear(state);
}
+ CHECK_AND_NO_ASSERT_MES(::serialization::check_stream_state(ar), false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
+
return true;
}
//---------------------------------------------------------------
+ crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra)
+ {
+ std::vector<tx_extra_field> tx_extra_fields;
+ if (!parse_tx_extra(tx_extra, tx_extra_fields))
+ return null_pkey;
+
+ tx_extra_pub_key pub_key_field;
+ if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field))
+ return null_pkey;
+
+ return pub_key_field.pub_key;
+ }
+ //---------------------------------------------------------------
+ crypto::public_key get_tx_pub_key_from_extra(const transaction& tx)
+ {
+ return get_tx_pub_key_from_extra(tx.extra);
+ }
+ //---------------------------------------------------------------
bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key)
{
tx.extra.resize(tx.extra.size() + 1 + sizeof(crypto::public_key));
@@ -259,32 +262,50 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
- bool add_tx_extra_nonce(transaction& tx, const blobdata& extra_nonce)
+ bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce)
{
- CHECK_AND_ASSERT_MES(extra_nonce.size() <=255, false, "extra nonce could be 255 bytes max");
- size_t start_pos = tx.extra.size();
- tx.extra.resize(tx.extra.size() + 2 + extra_nonce.size());
+ CHECK_AND_ASSERT_MES(extra_nonce.size() <= TX_EXTRA_NONCE_MAX_COUNT, false, "extra nonce could be 255 bytes max");
+ size_t start_pos = tx_extra.size();
+ tx_extra.resize(tx_extra.size() + 2 + extra_nonce.size());
//write tag
- tx.extra[start_pos] = TX_EXTRA_NONCE;
+ tx_extra[start_pos] = TX_EXTRA_NONCE;
//write len
++start_pos;
- tx.extra[start_pos] = static_cast<uint8_t>(extra_nonce.size());
+ tx_extra[start_pos] = static_cast<uint8_t>(extra_nonce.size());
//write data
++start_pos;
- memcpy(&tx.extra[start_pos], extra_nonce.data(), extra_nonce.size());
+ memcpy(&tx_extra[start_pos], extra_nonce.data(), extra_nonce.size());
+ return true;
+ }
+ //---------------------------------------------------------------
+ void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id)
+ {
+ extra_nonce.clear();
+ extra_nonce.push_back(TX_EXTRA_NONCE_PAYMENT_ID);
+ const uint8_t* payment_id_ptr = reinterpret_cast<const uint8_t*>(&payment_id);
+ std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce));
+ }
+ //---------------------------------------------------------------
+ bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id)
+ {
+ if(sizeof(crypto::hash) + 1 != extra_nonce.size())
+ return false;
+ if(TX_EXTRA_NONCE_PAYMENT_ID != extra_nonce[0])
+ return false;
+ payment_id = *reinterpret_cast<const crypto::hash*>(extra_nonce.data() + 1);
return true;
}
//---------------------------------------------------------------
- bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, transaction& tx, uint64_t unlock_time)
+ bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time)
{
tx.vin.clear();
tx.vout.clear();
tx.signatures.clear();
- tx.extra.clear();
tx.version = CURRENT_TRANSACTION_VERSION;
tx.unlock_time = unlock_time;
+ tx.extra = extra;
keypair txkey = keypair::generate();
add_tx_pub_key_to_extra(tx, txkey.pub);
@@ -506,7 +527,10 @@ namespace cryptonote
//---------------------------------------------------------------
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered)
{
- return lookup_acc_outs(acc, tx, get_tx_pub_key_from_extra(tx), outs, money_transfered);
+ crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
+ if(null_pkey == tx_pub_key)
+ return false;
+ return lookup_acc_outs(acc, tx, tx_pub_key, outs, money_transfered);
}
//---------------------------------------------------------------
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered)
@@ -594,6 +618,7 @@ namespace cryptonote
//genesis block
bl = boost::value_initialized<block>();
+
account_public_address ac = boost::value_initialized<account_public_address>();
std::vector<size_t> sz;
construct_miner_tx(0, 0, 0, 0, 0, ac, bl.miner_tx); // zero fee in genesis
@@ -601,16 +626,16 @@ namespace cryptonote
std::string hex_tx_represent = string_tools::buff_to_hex_nodelimer(txb);
//hard code coinbase tx in genesis block, because "tru" generating tx use random, but genesis should be always the same
- std::string genesis_coinbase_tx_hex = "013c01ff0001ffffffffffff03029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121017767aafcde9be00dcfd098715ebcf7f410daebc582fda69d24a28e9d0bc890d1";
+ std::string genesis_coinbase_tx_hex = "010a01ff0001ffffffffffff0f029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121013c086a48c15fb637a96991bc6d53caf77068b5ba6eeb3c82357228c49790584a";
blobdata tx_bl;
string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, tx_bl);
bool r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx);
CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob");
- bl.major_version = 1;
- bl.minor_version = 0;
+ bl.major_version = CURRENT_BLOCK_MAJOR_VERSION;
+ bl.minor_version = CURRENT_BLOCK_MINOR_VERSION;
bl.timestamp = 0;
- bl.nonce = 10000;
+ bl.nonce = 70;
miner::find_nonce_for_given_block(bl, 1, 0);
return true;
}
diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h
index 5873d2943..138fb5224 100644
--- a/src/cryptonote_core/cryptonote_format_utils.h
+++ b/src/cryptonote_core/cryptonote_format_utils.h
@@ -41,11 +41,26 @@ namespace cryptonote
};
//---------------------------------------------------------------
- bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, transaction& tx, uint64_t unlock_time);
- bool parse_and_validate_tx_extra(const transaction& tx, crypto::public_key& tx_pub_key);
+ bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time);
+
+ template<typename T>
+ bool find_tx_extra_field_by_type(const std::vector<tx_extra_field>& tx_extra_fields, T& field)
+ {
+ auto it = std::find_if(tx_extra_fields.begin(), tx_extra_fields.end(), [](const tx_extra_field& f) { return typeid(T) == f.type(); });
+ if(tx_extra_fields.end() == it)
+ return false;
+
+ field = boost::get<T>(*it);
+ return true;
+ }
+
+ bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields);
+ crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra);
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx);
bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key);
- bool add_tx_extra_nonce(transaction& tx, const blobdata& extra_nonce);
+ bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce);
+ void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id);
+ bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id);
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);
diff --git a/src/cryptonote_core/difficulty.cpp b/src/cryptonote_core/difficulty.cpp
index 052f46662..3dde6ad6c 100644
--- a/src/cryptonote_core/difficulty.cpp
+++ b/src/cryptonote_core/difficulty.cpp
@@ -24,7 +24,7 @@ namespace cryptonote {
#include <winnt.h>
static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) {
- low = UnsignedMultiply128(a, b, &high);
+ low = mul128(a, b, &high);
}
#else
diff --git a/src/cryptonote_core/tx_extra.h b/src/cryptonote_core/tx_extra.h
index 7e27cbc7f..8cff085dc 100644
--- a/src/cryptonote_core/tx_extra.h
+++ b/src/cryptonote_core/tx_extra.h
@@ -2,10 +2,93 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#pragma once
+#pragma once
+#define TX_EXTRA_PADDING_MAX_COUNT 255
+#define TX_EXTRA_NONCE_MAX_COUNT 255
-#define TX_EXTRA_PADDING_MAX_COUNT 40
+#define TX_EXTRA_TAG_PADDING 0x00
#define TX_EXTRA_TAG_PUBKEY 0x01
#define TX_EXTRA_NONCE 0x02
+
+#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
+
+namespace cryptonote
+{
+ struct tx_extra_padding
+ {
+ size_t size;
+
+ // load
+ template <template <bool> class Archive>
+ bool do_serialize(Archive<false>& ar)
+ {
+ // size - 1 - because of variant tag
+ for (size = 1; size <= TX_EXTRA_PADDING_MAX_COUNT; ++size)
+ {
+ std::ios_base::iostate state = ar.stream().rdstate();
+ bool eof = EOF == ar.stream().peek();
+ ar.stream().clear(state);
+
+ if (eof)
+ break;
+
+ uint8_t zero;
+ if (!::do_serialize(ar, zero))
+ return false;
+
+ if (0 != zero)
+ return false;
+ }
+
+ return size <= TX_EXTRA_PADDING_MAX_COUNT;
+ }
+
+ // store
+ template <template <bool> class Archive>
+ bool do_serialize(Archive<true>& ar)
+ {
+ if(TX_EXTRA_PADDING_MAX_COUNT < size)
+ return false;
+
+ // i = 1 - because of variant tag
+ for (size_t i = 1; i < size; ++i)
+ {
+ uint8_t zero = 0;
+ if (!::do_serialize(ar, zero))
+ return false;
+ }
+ return true;
+ }
+ };
+
+ struct tx_extra_pub_key
+ {
+ crypto::public_key pub_key;
+
+ BEGIN_SERIALIZE()
+ FIELD(pub_key)
+ END_SERIALIZE()
+ };
+
+ struct tx_extra_nonce
+ {
+ std::string nonce;
+
+ BEGIN_SERIALIZE()
+ FIELD(nonce)
+ if(TX_EXTRA_NONCE_MAX_COUNT < nonce.size()) return false;
+ END_SERIALIZE()
+ };
+
+ // tx_extra_field format, except tx_extra_padding and tx_extra_pub_key:
+ // varint tag;
+ // varint size;
+ // varint data[];
+ typedef boost::variant<tx_extra_padding, tx_extra_pub_key, tx_extra_nonce> tx_extra_field;
+}
+
+VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING);
+VARIANT_TAG(binary_archive, cryptonote::tx_extra_pub_key, TX_EXTRA_TAG_PUBKEY);
+VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE);
diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h
index 3ac1331bd..3978dfb96 100644
--- a/src/cryptonote_core/tx_pool.h
+++ b/src/cryptonote_core/tx_pool.h
@@ -141,6 +141,9 @@ namespace cryptonote
uint64_t operator()(const txin_to_scripthash& tx) const {return 0;}
};
+#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
+ friend class blockchain_storage;
+#endif
};
}
diff --git a/src/miner/simpleminer.cpp b/src/miner/simpleminer.cpp
index a9f0ceab0..3af04954f 100644
--- a/src/miner/simpleminer.cpp
+++ b/src/miner/simpleminer.cpp
@@ -120,6 +120,7 @@ namespace mining
COMMAND_RPC_LOGIN::request req = AUTO_VAL_INIT(req);
req.login = m_login;
req.pass = m_pass;
+ req.agent = "simpleminer/0.1";
COMMAND_RPC_LOGIN::response resp = AUTO_VAL_INIT(resp);
if(!epee::net_utils::invoke_http_json_rpc<mining::COMMAND_RPC_LOGIN>("/", req, resp, m_http_client))
{
@@ -137,7 +138,12 @@ namespace mining
}
pool_session_id = resp.id;
//78
- if(!text_job_details_to_native_job_details(resp.job, job))
+ if (resp.job.blob.empty() && resp.job.target.empty() && resp.job.job_id.empty())
+ {
+ LOG_PRINT_L0("Job didn't change");
+ continue;
+ }
+ else if(!text_job_details_to_native_job_details(resp.job, job))
{
LOG_PRINT_L0("Failed to text_job_details_to_native_job_details(), disconnect and sleep....");
m_http_client.disconnect();
@@ -161,7 +167,8 @@ namespace mining
COMMAND_RPC_SUBMITSHARE::response submit_response = AUTO_VAL_INIT(submit_response);
submit_request.id = pool_session_id;
submit_request.job_id = job.job_id;
- submit_request.nonce = epee::string_tools::pod_to_hex((*((uint32_t*)&job.blob.data()[78])));
+ submit_request.nonce = epee::string_tools::pod_to_hex((*((uint32_t*)&job.blob.data()[39])));
+ submit_request.result = epee::string_tools::pod_to_hex(h);
LOG_PRINT_L0("Share found: nonce=" << submit_request.nonce << " for job=" << job.job_id << ", submitting...");
if(!epee::net_utils::invoke_http_json_rpc<mining::COMMAND_RPC_SUBMITSHARE>("/", submit_request, submit_response, m_http_client))
{
@@ -193,7 +200,12 @@ namespace mining
epee::misc_utils::sleep_no_w(1000);
break;
}
- if(!text_job_details_to_native_job_details(getjob_response, job))
+ if (getjob_response.blob.empty() && getjob_response.target.empty() && getjob_response.job_id.empty())
+ {
+ LOG_PRINT_L0("Job didn't change");
+ continue;
+ }
+ else if(!text_job_details_to_native_job_details(getjob_response, job))
{
LOG_PRINT_L0("Failed to text_job_details_to_native_job_details(), disconnect and sleep....");
m_http_client.disconnect();
diff --git a/src/miner/simpleminer_protocol_defs.h b/src/miner/simpleminer_protocol_defs.h
index 9b70f8cbf..06b6a9053 100644
--- a/src/miner/simpleminer_protocol_defs.h
+++ b/src/miner/simpleminer_protocol_defs.h
@@ -36,10 +36,12 @@ namespace mining
{
std::string login;
std::string pass;
+ std::string agent;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(login)
KV_SERIALIZE(pass)
+ KV_SERIALIZE(agent)
END_KV_SERIALIZE_MAP()
};
@@ -82,11 +84,13 @@ namespace mining
{
std::string id;
std::string nonce;
+ std::string result;
std::string job_id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(id)
KV_SERIALIZE(nonce)
+ KV_SERIALIZE(result)
KV_SERIALIZE(job_id)
END_KV_SERIALIZE_MAP()
};
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 4d78367b6..631fb5cf8 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -2,7 +2,6 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
#include <boost/foreach.hpp>
#include "include_base_utils.h"
using namespace epee;
@@ -359,8 +358,7 @@ namespace cryptonote
return false;
}
blobdata block_blob = t_serializable_object_to_blob(b);
- crypto::public_key tx_pub_key = null_pkey;
- cryptonote::parse_and_validate_tx_extra(b.miner_tx, tx_pub_key);
+ crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(b.miner_tx);
if(tx_pub_key == null_pkey)
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
diff --git a/src/serialization/serialization.h b/src/serialization/serialization.h
index d1c6f7f63..2d78baf3a 100644
--- a/src/serialization/serialization.h
+++ b/src/serialization/serialization.h
@@ -122,7 +122,7 @@ namespace serialization {
{
std::ios_base::iostate state = s.rdstate();
result = EOF == s.peek();
- s.setstate(state);
+ s.clear(state);
}
return result;
}
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index a9c171f6b..919782ab6 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -64,6 +64,19 @@ namespace
return err;
}
+ bool parse_payment_id(const std::string& payment_id_str, crypto::hash& payment_id)
+ {
+ blobdata payment_id_data;
+ if(!string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data))
+ return false;
+
+ if(sizeof(crypto::hash) != payment_id_data.size())
+ return false;
+
+ payment_id = *reinterpret_cast<const crypto::hash*>(payment_id_data.data());
+ return true;
+ }
+
class message_writer
{
public:
@@ -83,7 +96,7 @@ namespace
, m_oss(std::move(rhs.m_oss))
#else
// GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
- , m_oss(rhs.m_oss.str(), ios_base::out | ios_base::ate)
+ , m_oss(rhs.m_oss.str(), ios_base::out | ios_base::ate)
#endif
, m_color(std::move(rhs.m_color))
, m_log_level(std::move(rhs.m_log_level))
@@ -171,8 +184,9 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, _1), "Resynchronize transactions and balance");
m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, _1), "Show current wallet balance");
m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _1), "incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability");
+ m_cmd_binder.set_handler("payments", boost::bind(&simple_wallet::show_payments, this, _1), "payments <payment_id_1> [<payment_id_2> ... <payment_id_N>] - Show payments <payment_id_1>, ... <payment_id_N>");
m_cmd_binder.set_handler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), "Show blockchain height");
- m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer <mixin_count> <addr_1> <amount_1> [<addr_2> <amount_2> ... <addr_N> <amount_N>] - Transfer <amount_1>,... <amount_N> to <address_1>,... <address_N>, respectively. <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available)");
+ m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer <mixin_count> <addr_1> <amount_1> [<addr_2> <amount_2> ... <addr_N> <amount_N>] [payment_id] - Transfer <amount_1>,... <amount_N> to <address_1>,... <address_N>, respectively. <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available)");
m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), "set_log <level> - Change current log detalization level, <level> is a number 0-4");
m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), "Show current wallet public address");
m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data");
@@ -181,7 +195,7 @@ simple_wallet::simple_wallet()
//----------------------------------------------------------------------------------------------------
bool simple_wallet::set_log(const std::vector<std::string> &args)
{
- if(args.size() != 1)
+ if(args.size() != 1)
{
fail_msg_writer() << "use: set_log <log_level_number_0-4>";
return true;
@@ -202,6 +216,43 @@ bool simple_wallet::set_log(const std::vector<std::string> &args)
return true;
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::ask_wallet_create_if_needed()
+{
+ std::string wallet_path;
+
+ std::cout << "Specify wallet file name (e.g., wallet.bin). If the wallet doesn't exist, it will be created.\n";
+ std::cout << "Wallet file name: ";
+
+ std::getline(std::cin, wallet_path);
+
+ wallet_path = string_tools::trim(wallet_path);
+
+ bool keys_file_exists;
+ bool wallet_file_exitst;
+ tools::wallet2::wallet_exists(wallet_path, keys_file_exists, wallet_file_exitst);
+
+ bool r;
+ if(keys_file_exists)
+ {
+ m_wallet_file = wallet_path;
+ r = true;
+ }else
+ {
+ if(!wallet_file_exitst)
+ {
+ std::cout << "The wallet doesn't exist, generating new one" << std::endl;
+ m_generate_new = wallet_path;
+ r = true;
+ }else
+ {
+ fail_msg_writer() << "failed to open wallet \"" << wallet_path << "\". Keys file wasn't found";
+ r = false;
+ }
+ }
+
+ return r;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
handle_command_line(vm);
@@ -212,13 +263,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
- size_t c = 0;
+ size_t c = 0;
if(!m_generate_new.empty()) ++c;
if(!m_wallet_file.empty()) ++c;
if (1 != c)
{
- fail_msg_writer() << "you must specify --wallet-file or --generate-new-wallet params";
- return false;
+ if(!ask_wallet_create_if_needed())
+ return false;
}
if (m_daemon_host.empty())
@@ -463,6 +514,15 @@ void simple_wallet::on_money_spent(uint64_t height, const cryptonote::transactio
m_refresh_progress_reporter.update(height, true);
}
//----------------------------------------------------------------------------------------------------
+void simple_wallet::on_skip_transaction(uint64_t height, const cryptonote::transaction& tx)
+{
+ message_writer(epee::log_space::console_color_red, true) <<
+ "Height " << height <<
+ ", transaction " << get_transaction_hash(tx) <<
+ ", unsupported transaction format";
+ m_refresh_progress_reporter.update(height, true);
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::refresh(const std::vector<std::string>& args)
{
if (!try_connect_to_daemon())
@@ -587,6 +647,55 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
return true;
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::show_payments(const std::vector<std::string> &args)
+{
+ if(args.empty())
+ {
+ fail_msg_writer() << "expected at least one payment_id";
+ return true;
+ }
+
+ message_writer() << " payment \t" <<
+ " transaction \t" <<
+ " height\t amount \tunlock time";
+
+ bool payments_found = false;
+ for(std::string arg : args)
+ {
+ crypto::hash payment_id;
+ if(parse_payment_id(arg, payment_id))
+ {
+ std::list<tools::wallet2::payment_details> payments;
+ m_wallet->get_payments(payment_id, payments);
+ if(payments.empty())
+ {
+ success_msg_writer() << "No payments with id " << payment_id;
+ continue;
+ }
+
+ for (const tools::wallet2::payment_details& pd : payments)
+ {
+ if(!payments_found)
+ {
+ payments_found = true;
+ }
+ success_msg_writer(true) <<
+ payment_id << '\t' <<
+ pd.m_tx_hash << '\t' <<
+ std::setw(8) << pd.m_block_height << '\t' <<
+ std::setw(21) << print_money(pd.m_amount) << '\t' <<
+ pd.m_unlock_time;
+ }
+ }
+ else
+ {
+ fail_msg_writer() << "payment id has invalid format: \"" << arg << "\", expected 64-character string";
+ }
+ }
+
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
uint64_t simple_wallet::get_daemon_blockchain_height(std::string& err)
{
COMMAND_RPC_GET_HEIGHT::request req;
@@ -628,20 +737,37 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
fail_msg_writer() << "mixin_count should be non-negative integer, got " << local_args[0];
return true;
}
+ local_args.erase(local_args.begin());
- vector<cryptonote::tx_destination_entry> dsts;
- for (size_t i = 1; i < local_args.size(); i += 2)
+ std::vector<uint8_t> extra;
+ if (1 == local_args.size() % 2)
{
- cryptonote::tx_destination_entry de;
- if(!get_account_address_from_str(de.addr, local_args[i]))
+ std::string payment_id_str = local_args.back();
+ local_args.pop_back();
+
+ crypto::hash payment_id;
+ bool r = parse_payment_id(payment_id_str, payment_id);
+ if(r)
{
- fail_msg_writer() << "wrong address: " << local_args[i];
+ std::string extra_nonce;
+ set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
+ r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
+ }
+
+ if(!r)
+ {
+ fail_msg_writer() << "payment id has invalid format: \"" << payment_id_str << "\", expected 64-character string";
return true;
}
+ }
- if (local_args.size() <= i + 1)
+ vector<cryptonote::tx_destination_entry> dsts;
+ for (size_t i = 0; i < local_args.size(); i += 2)
+ {
+ cryptonote::tx_destination_entry de;
+ if(!get_account_address_from_str(de.addr, local_args[i]))
{
- fail_msg_writer() << "amount for the last address " << local_args[i] << " is not specified";
+ fail_msg_writer() << "wrong address: " << local_args[i];
return true;
}
@@ -659,7 +785,7 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
try
{
cryptonote::transaction tx;
- m_wallet->transfer(dsts, fake_outs_count, 0, DEFAULT_FEE, tx);
+ m_wallet->transfer(dsts, fake_outs_count, 0, DEFAULT_FEE, extra, tx);
success_msg_writer(true) << "Money successfully sent, transaction " << get_transaction_hash(tx);
}
catch (const tools::error::daemon_busy&)
@@ -801,6 +927,7 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
+ success_msg_writer() << "bytecoin wallet v" << PROJECT_VERSION_LONG;
success_msg_writer() << "Usage: simplewallet [--wallet-file=<file>|--generate-new-wallet=<file>] [--daemon-address=<host>:<port>] [<COMMAND>]";
success_msg_writer() << desc_all << '\n' << w.get_commands_str();
return false;
@@ -833,11 +960,11 @@ int main(int argc, char* argv[])
LOG_PRINT_L0("Setting log level = " << command_line::get_arg(vm, arg_log_level));
log_space::get_set_log_detalisation_level(true, command_line::get_arg(vm, arg_log_level));
}
-
+
if(command_line::has_arg(vm, tools::wallet_rpc_server::arg_rpc_bind_port))
{
log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_2);
- //runs wallet with rpc interface
+ //runs wallet with rpc interface
if(!command_line::has_arg(vm, arg_wallet_file) )
{
LOG_ERROR("Wallet file not set.");
@@ -854,7 +981,7 @@ int main(int argc, char* argv[])
return 1;
}
- std::string wallet_file = command_line::get_arg(vm, arg_wallet_file);
+ std::string wallet_file = command_line::get_arg(vm, arg_wallet_file);
std::string wallet_password = command_line::get_arg(vm, arg_password);
std::string daemon_address = command_line::get_arg(vm, arg_daemon_address);
std::string daemon_host = command_line::get_arg(vm, arg_daemon_host);
@@ -904,7 +1031,7 @@ int main(int argc, char* argv[])
}
}else
{
- //runs wallet with console interface
+ //runs wallet with console interface
r = w.init(vm);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet");
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 002490e89..a6c771804 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -49,6 +49,7 @@ namespace cryptonote
bool refresh(const std::vector<std::string> &args);
bool show_balance(const std::vector<std::string> &args = std::vector<std::string>());
bool show_incoming_transfers(const std::vector<std::string> &args);
+ bool show_payments(const std::vector<std::string> &args);
bool show_blockchain_height(const std::vector<std::string> &args);
bool transfer(const std::vector<std::string> &args);
bool print_address(const std::vector<std::string> &args = std::vector<std::string>());
@@ -57,11 +58,13 @@ namespace cryptonote
uint64_t get_daemon_blockchain_height(std::string& err);
bool try_connect_to_daemon();
+ bool ask_wallet_create_if_needed();
//----------------- i_wallet2_callback ---------------------
virtual void on_new_block(uint64_t height, const cryptonote::block& block);
virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index);
virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, const cryptonote::transaction& spend_tx);
+ virtual void on_skip_transaction(uint64_t height, const cryptonote::transaction& tx);
//----------------------------------------------------------
friend class refresh_progress_reporter_t;
diff --git a/src/version.h.in b/src/version.h.in
index 331657755..2578ea635 100644
--- a/src/version.h.in
+++ b/src/version.h.in
@@ -1,4 +1,4 @@
#define BUILD_COMMIT_ID "@VERSION@"
-#define PROJECT_VERSION "0.8.5"
-#define PROJECT_VERSION_BUILD_NO "294"
+#define PROJECT_VERSION "0.8.6"
+#define PROJECT_VERSION_BUILD_NO "295"
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 9bd487997..e8d67eec2 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -22,6 +22,23 @@ using namespace epee;
using namespace cryptonote;
+namespace
+{
+void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file)
+{
+ keys_file = file_path;
+ wallet_file = file_path;
+ boost::system::error_code e;
+ if(string_tools::get_extension(keys_file) == "keys")
+ {//provided keys file name
+ wallet_file = string_tools::cut_off_extension(wallet_file);
+ }else
+ {//provided wallet file name
+ keys_file += ".keys";
+ }
+}
+} //namespace
+
namespace tools
{
//----------------------------------------------------------------------------------------------------
@@ -36,17 +53,25 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_
process_unconfirmed(tx);
std::vector<size_t> outs;
uint64_t tx_money_got_in_outs = 0;
- crypto::public_key tx_pub_key = null_pkey;
- bool r = parse_and_validate_tx_extra(tx, tx_pub_key);
-
- // Temporarily disabled due to messed up tx_extra from someone
- // screwing around with MMing. 2014-04-30
- // THROW_WALLET_EXCEPTION_IF(!r, error::tx_extra_parse_error, tx);
-
- // We don't know how to handle this weird tx, so return
- if (!r) return;
-
- r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, tx_money_got_in_outs);
+
+ std::vector<tx_extra_field> tx_extra_fields;
+ if(!parse_tx_extra(tx.extra, tx_extra_fields))
+ {
+ // Extra may only be partially parsed, it's OK if tx_extra_fields contains public key
+ LOG_PRINT_L0("Transaction extra has unsupported format: " << get_transaction_hash(tx));
+ }
+
+ tx_extra_pub_key pub_key_field;
+ if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field))
+ {
+ LOG_PRINT_L0("Public key wasn't found in the transaction extra. Skipping transaction " << get_transaction_hash(tx));
+ if(0 != m_callback)
+ m_callback->on_skip_transaction(height, tx);
+ return;
+ }
+
+ crypto::public_key tx_pub_key = pub_key_field.pub_key;
+ bool r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, tx_money_got_in_outs);
THROW_WALLET_EXCEPTION_IF(!r, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys());
if(!outs.empty() && tx_money_got_in_outs)
@@ -87,6 +112,8 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_
m_callback->on_money_received(height, td.m_tx, td.m_internal_output_index);
}
}
+
+ uint64_t tx_money_spent_in_ins = 0;
// check all outputs for spending (compare key images)
BOOST_FOREACH(auto& in, tx.vin)
{
@@ -96,12 +123,33 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_
if(it != m_key_images.end())
{
LOG_PRINT_L0("Spent money: " << print_money(boost::get<cryptonote::txin_to_key>(in).amount) << ", with tx: " << get_transaction_hash(tx));
+ tx_money_spent_in_ins += boost::get<cryptonote::txin_to_key>(in).amount;
transfer_details& td = m_transfers[it->second];
td.m_spent = true;
if (0 != m_callback)
m_callback->on_money_spent(height, td.m_tx, td.m_internal_output_index, tx);
}
}
+
+ tx_extra_nonce extra_nonce;
+ if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce))
+ {
+ crypto::hash payment_id;
+ if(get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
+ {
+ uint64_t received = (tx_money_spent_in_ins < tx_money_got_in_outs) ? tx_money_got_in_outs - tx_money_spent_in_ins : 0;
+ if (0 < received && null_hash != payment_id)
+ {
+ payment_details payment;
+ payment.m_tx_hash = cryptonote::get_transaction_hash(tx);
+ payment.m_amount = received;
+ payment.m_block_height = height;
+ payment.m_unlock_time = tx.unlock_time;
+ m_payments.emplace(payment_id, payment);
+ LOG_PRINT_L2("Payment found: " << payment_id << " / " << payment.m_tx_hash << " / " << payment.m_amount);
+ }
+ }
+ }
}
//----------------------------------------------------------------------------------------------------
void wallet2::process_unconfirmed(const cryptonote::transaction& tx)
@@ -203,7 +251,7 @@ void wallet2::pull_blocks(size_t& blocks_added)
{
//split detected here !!!
THROW_WALLET_EXCEPTION_IF(current_index == res.start_height, error::wallet_internal_error,
- "wrong daemon response: split starts from the first block in response " + string_tools::pod_to_hex(bl_id) +
+ "wrong daemon response: split starts from the first block in response " + string_tools::pod_to_hex(bl_id) +
" (height " + std::to_string(res.start_height) + "), local block id at this height: " +
string_tools::pod_to_hex(m_blockchain[current_index]));
@@ -304,6 +352,14 @@ void wallet2::detach_blockchain(uint64_t height)
m_blockchain.erase(m_blockchain.begin()+height, m_blockchain.end());
m_local_bc_height -= blocks_detached;
+ for (auto it = m_payments.begin(); it != m_payments.end(); )
+ {
+ if(height <= it->second.m_block_height)
+ it = m_payments.erase(it);
+ else
+ ++it;
+ }
+
LOG_PRINT_L0("Detached blockchain on height " << height << ", transfers detached " << transfers_detached << ", blocks detached " << blocks_detached);
}
//----------------------------------------------------------------------------------------------------
@@ -399,18 +455,19 @@ void wallet2::generate(const std::string& wallet_, const std::string& password)
store();
}
//----------------------------------------------------------------------------------------------------
+void wallet2::wallet_exists(const std::string& file_path, bool& keys_file_exists, bool& wallet_file_exitst)
+{
+ std::string keys_file, wallet_file;
+ do_prepare_file_names(file_path, keys_file, wallet_file);
+
+ boost::system::error_code ignore;
+ keys_file_exists = boost::filesystem::exists(keys_file, ignore);
+ wallet_file_exitst = boost::filesystem::exists(wallet_file, ignore);
+}
+//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_file_names(const std::string& file_path)
{
- m_keys_file = file_path;
- m_wallet_file = file_path;
- boost::system::error_code e;
- if(string_tools::get_extension(m_keys_file) == "keys")
- {//provided keys file name
- m_wallet_file = string_tools::cut_off_extension(m_wallet_file);
- }else
- {//provided wallet file name
- m_keys_file += ".keys";
- }
+ do_prepare_file_names(file_path, m_keys_file, m_wallet_file);
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -422,7 +479,7 @@ bool wallet2::check_connection()
net_utils::http::url_content u;
net_utils::parse_url(m_daemon_address, u);
if(!u.port)
- u.port = RPC_DEFAULT_PORT;
+ u.port = RPC_DEFAULT_PORT;
return m_http_client.connect(u.host, std::to_string(u.port), WALLET_RCP_CONNECTION_TIMEOUT);
}
//----------------------------------------------------------------------------------------------------
@@ -497,6 +554,14 @@ void wallet2::get_transfers(wallet2::transfer_container& incoming_transfers) con
incoming_transfers = m_transfers;
}
//----------------------------------------------------------------------------------------------------
+void wallet2::get_payments(const crypto::hash& payment_id, std::list<wallet2::payment_details>& payments) const
+{
+ auto range = m_payments.equal_range(payment_id);
+ std::for_each(range.first, range.second, [&payments](const payment_container::value_type& x) {
+ payments.push_back(x.second);
+ });
+}
+//----------------------------------------------------------------------------------------------------
bool wallet2::is_transfer_unlocked(const transfer_details& td) const
{
if(!is_tx_spendtime_unlocked(td.m_tx.unlock_time))
@@ -596,16 +661,16 @@ void wallet2::add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t cha
}
//----------------------------------------------------------------------------------------------------
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
- uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx)
+ uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx)
{
- transfer(dsts, fake_outputs_count, unlock_time, fee, detail::digit_split_strategy, tx_dust_policy(fee), tx);
+ transfer(dsts, fake_outputs_count, unlock_time, fee, extra, detail::digit_split_strategy, tx_dust_policy(fee), tx);
}
//----------------------------------------------------------------------------------------------------
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
- uint64_t unlock_time, uint64_t fee)
+ uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra)
{
cryptonote::transaction tx;
- transfer(dsts, fake_outputs_count, unlock_time, fee, tx);
+ transfer(dsts, fake_outputs_count, unlock_time, fee, extra, tx);
}
//----------------------------------------------------------------------------------------------------
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 221f3d25c..edbf31f2d 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -34,6 +34,7 @@ namespace tools
virtual void on_new_block(uint64_t height, const cryptonote::block& block) {}
virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index) {}
virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, const cryptonote::transaction& spend_tx) {}
+ virtual void on_skip_transaction(uint64_t height, const cryptonote::transaction& tx) {}
};
struct tx_dust_policy
@@ -67,14 +68,23 @@ namespace tools
uint64_t amount() const { return m_tx.vout[m_internal_output_index].amount; }
};
+ struct payment_details
+ {
+ crypto::hash m_tx_hash;
+ uint64_t m_amount;
+ uint64_t m_block_height;
+ uint64_t m_unlock_time;
+ };
+
struct unconfirmed_transfer_details
{
cryptonote::transaction m_tx;
uint64_t m_change;
- time_t m_sent_time;
+ time_t m_sent_time;
};
typedef std::vector<transfer_details> transfer_container;
+ typedef std::unordered_multimap<crypto::hash, payment_details> payment_container;
struct keys_file_data
{
@@ -108,13 +118,14 @@ namespace tools
uint64_t balance();
uint64_t unlocked_balance();
template<typename T>
- void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy);
+ void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy);
template<typename T>
- void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx);
- void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee);
- void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, cryptonote::transaction& tx);
+ void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx);
+ void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra);
+ void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx);
bool check_connection();
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
+ void get_payments(const crypto::hash& payment_id, std::list<wallet2::payment_details>& payments) const;
uint64_t get_blockchain_current_height() const { return m_local_bc_height; }
template <class t_archive>
inline void serialize(t_archive &a, const unsigned int ver)
@@ -128,8 +139,13 @@ namespace tools
if(ver < 6)
return;
a & m_unconfirmed_txs;
+ if(ver < 7)
+ return;
+ a & m_payments;
}
+ static void wallet_exists(const std::string& file_path, bool& keys_file_exists, bool& wallet_file_exitst);
+
private:
bool store_keys(const std::string& keys_file_name, const std::string& password);
void load_keys(const std::string& keys_file_name, const std::string& password);
@@ -152,10 +168,11 @@ namespace tools
std::string m_keys_file;
epee::net_utils::http::http_simple_client m_http_client;
std::vector<crypto::hash> m_blockchain;
- std::atomic<uint64_t> m_local_bc_height; //temporary workaround
+ std::atomic<uint64_t> m_local_bc_height; //temporary workaround
std::unordered_map<crypto::hash, unconfirmed_transfer_details> m_unconfirmed_txs;
transfer_container m_transfers;
+ payment_container m_payments;
std::unordered_map<crypto::key_image, size_t> m_key_images;
cryptonote::account_public_address m_account_public_address;
uint64_t m_upper_transaction_size_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value
@@ -165,7 +182,7 @@ namespace tools
i_wallet2_callback* m_callback;
};
}
-BOOST_CLASS_VERSION(tools::wallet2, 6)
+BOOST_CLASS_VERSION(tools::wallet2, 7)
namespace boost
{
@@ -190,7 +207,14 @@ namespace boost
a & x.m_tx;
}
-
+ template <class Archive>
+ inline void serialize(Archive& a, tools::wallet2::payment_details& x, const boost::serialization::version_type ver)
+ {
+ a & x.m_tx_hash;
+ a & x.m_amount;
+ a & x.m_block_height;
+ a & x.m_unlock_time;
+ }
}
}
@@ -261,15 +285,15 @@ namespace tools
//----------------------------------------------------------------------------------------------------
template<typename T>
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
- uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy)
+ uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy)
{
cryptonote::transaction tx;
- transfer(dsts, fake_outputs_count, unlock_time, fee, destination_split_strategy, dust_policy, tx);
+ transfer(dsts, fake_outputs_count, unlock_time, fee, extra, destination_split_strategy, dust_policy, tx);
}
template<typename T>
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
- uint64_t unlock_time, uint64_t fee, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx)
+ uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx)
{
using namespace cryptonote;
THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination);
@@ -320,7 +344,7 @@ namespace tools
}
THROW_WALLET_EXCEPTION_IF(!scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count);
}
-
+
//prepare inputs
size_t i = 0;
std::vector<cryptonote::tx_source_entry> sources;
@@ -381,7 +405,7 @@ namespace tools
splitted_dsts.push_back(cryptonote::tx_destination_entry(dust, dust_policy.addr_for_dust));
}
- bool r = cryptonote::construct_tx(m_account.get_keys(), sources, splitted_dsts, tx, unlock_time);
+ bool r = cryptonote::construct_tx(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time);
THROW_WALLET_EXCEPTION_IF(m_upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, m_upper_transaction_size_limit);
@@ -409,7 +433,7 @@ namespace tools
BOOST_FOREACH(transfer_container::iterator it, selected_transfers)
it->m_spent = true;
- LOG_PRINT_L0("Transaction successfully sent. <" << get_transaction_hash(tx) << ">" << ENDL
+ LOG_PRINT_L0("Transaction successfully sent. <" << get_transaction_hash(tx) << ">" << ENDL
<< "Commission: " << print_money(fee+dust) << " (dust: " << print_money(dust) << ")" << ENDL
<< "Balance: " << print_money(balance()) << ENDL
<< "Unlocked: " << print_money(unlocked_balance()) << ENDL
diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h
index b2a863436..0d42dbaf4 100644
--- a/src/wallet/wallet_errors.h
+++ b/src/wallet/wallet_errors.h
@@ -34,7 +34,6 @@ namespace tools
// block_parse_error
// get_blocks_error
// get_out_indexes_error
- // tx_extra_parse_error
// tx_parse_error
// transfer_error *
// get_random_outs_general_error
@@ -248,28 +247,6 @@ namespace tools
//----------------------------------------------------------------------------------------------------
typedef failed_rpc_request<refresh_error, get_out_indices_error_message_index> get_out_indices_error;
//----------------------------------------------------------------------------------------------------
- struct tx_extra_parse_error : public refresh_error
- {
- explicit tx_extra_parse_error(std::string&& loc, const cryptonote::transaction& tx)
- : refresh_error(std::move(loc), "transaction extra parse error")
- , m_tx(tx)
- {
- }
-
- const cryptonote::transaction& tx() const { return m_tx; }
-
- std::string to_string() const
- {
- std::ostringstream ss;
- cryptonote::transaction tx = m_tx;
- ss << refresh_error::to_string() << ", tx: " << cryptonote::obj_to_json_str(tx);
- return ss.str();
- }
-
- private:
- const cryptonote::transaction m_tx;
- };
- //----------------------------------------------------------------------------------------------------
struct tx_parse_error : public refresh_error
{
explicit tx_parse_error(std::string&& loc, const cryptonote::blobdata& tx_blob)
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index a89cc4e72..f1766c3b4 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -11,6 +11,7 @@ using namespace epee;
#include "cryptonote_core/cryptonote_format_utils.h"
#include "cryptonote_core/account.h"
#include "misc_language.h"
+#include "string_tools.h"
#include "crypto/hash.h"
namespace tools
@@ -74,7 +75,7 @@ namespace tools
{
std::vector<cryptonote::tx_destination_entry> dsts;
- for (auto it = req.destinations.begin(); it != req.destinations.end(); it++)
+ for (auto it = req.destinations.begin(); it != req.destinations.end(); it++)
{
cryptonote::tx_destination_entry de;
if(!get_account_address_from_str(de.addr, it->address))
@@ -89,7 +90,7 @@ namespace tools
try
{
cryptonote::transaction tx;
- m_wallet.transfer(dsts, req.mixin, req.unlock_time, req.fee, tx);
+ m_wallet.transfer(dsts, req.mixin, req.unlock_time, req.fee, std::vector<uint8_t>(), tx);
res.tx_hash = boost::lexical_cast<std::string>(cryptonote::get_transaction_hash(tx));
return true;
}
@@ -97,19 +98,19 @@ namespace tools
{
er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY;
er.message = e.what();
- return false;
+ return false;
}
catch (const std::exception& e)
{
er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
er.message = e.what();
- return false;
+ return false;
}
catch (...)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
- return false;
+ return false;
}
return true;
}
@@ -129,4 +130,40 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
-} \ No newline at end of file
+ bool wallet_rpc_server::on_get_payments(const wallet_rpc::COMMAND_RPC_GET_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_PAYMENTS::response& res, epee::json_rpc::error& er, connection_context& cntx)
+ {
+ crypto::hash payment_id;
+ cryptonote::blobdata payment_id_blob;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(req.payment_id, payment_id_blob))
+ {
+ er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
+ er.message = "Payment ID has invald format";
+ return false;
+ }
+
+ if(sizeof(payment_id) != payment_id_blob.size())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
+ er.message = "Payment ID has invalid size";
+ return false;
+ }
+
+ payment_id = *reinterpret_cast<const crypto::hash*>(payment_id_blob.data());
+
+ res.payments.clear();
+ std::list<wallet2::payment_details> payment_list;
+ m_wallet.get_payments(payment_id, payment_list);
+ for (auto payment : payment_list)
+ {
+ wallet_rpc::payment_details rpc_payment;
+ rpc_payment.tx_hash = epee::string_tools::pod_to_hex(payment.m_tx_hash);
+ rpc_payment.amount = payment.m_amount;
+ rpc_payment.block_height = payment.m_block_height;
+ rpc_payment.unlock_time = payment.m_unlock_time;
+ res.payments.push_back(rpc_payment);
+ }
+
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+}
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index 418f055d9..db49df574 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -2,7 +2,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#pragma once
+#pragma once
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
@@ -35,9 +35,10 @@ namespace tools
BEGIN_URI_MAP2()
BEGIN_JSON_RPC_MAP("/json_rpc")
- MAP_JON_RPC_WE("getbalance", on_getbalance, wallet_rpc::COMMAND_RPC_GET_BALANCE)
- MAP_JON_RPC_WE("transfer", on_transfer, wallet_rpc::COMMAND_RPC_TRANSFER)
- MAP_JON_RPC_WE("store", on_store, wallet_rpc::COMMAND_RPC_STORE)
+ MAP_JON_RPC_WE("getbalance", on_getbalance, wallet_rpc::COMMAND_RPC_GET_BALANCE)
+ MAP_JON_RPC_WE("transfer", on_transfer, wallet_rpc::COMMAND_RPC_TRANSFER)
+ MAP_JON_RPC_WE("store", on_store, wallet_rpc::COMMAND_RPC_STORE)
+ MAP_JON_RPC_WE("get_payments", on_get_payments, wallet_rpc::COMMAND_RPC_GET_PAYMENTS)
END_JSON_RPC_MAP()
END_URI_MAP2()
@@ -45,6 +46,7 @@ namespace tools
bool on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_store(const wallet_rpc::COMMAND_RPC_STORE::request& req, wallet_rpc::COMMAND_RPC_STORE::response& res, epee::json_rpc::error& er, connection_context& cntx);
+ bool on_get_payments(const wallet_rpc::COMMAND_RPC_GET_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_PAYMENTS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool handle_command_line(const boost::program_options::variables_map& vm);
diff --git a/src/wallet/wallet_rpc_server_commans_defs.h b/src/wallet/wallet_rpc_server_commans_defs.h
index a94ce36b0..b99d92ca2 100644
--- a/src/wallet/wallet_rpc_server_commans_defs.h
+++ b/src/wallet/wallet_rpc_server_commans_defs.h
@@ -86,6 +86,41 @@ namespace wallet_rpc
};
};
+ struct payment_details
+ {
+ std::string tx_hash;
+ uint64_t amount;
+ uint64_t block_height;
+ uint64_t unlock_time;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(tx_hash)
+ KV_SERIALIZE(amount)
+ KV_SERIALIZE(block_height)
+ KV_SERIALIZE(unlock_time)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct COMMAND_RPC_GET_PAYMENTS
+ {
+ struct request
+ {
+ std::string payment_id;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(payment_id)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::list<payment_details> payments;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(payments)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
}
}
diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h
index 415abf406..7fa536dac 100644
--- a/src/wallet/wallet_rpc_server_error_codes.h
+++ b/src/wallet/wallet_rpc_server_error_codes.h
@@ -2,10 +2,11 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#pragma once
+#pragma once
#define WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR -1
#define WALLET_RPC_ERROR_CODE_WRONG_ADDRESS -2
#define WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY -3
#define WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR -4
+#define WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID -5