initial [broken] update

This commit is contained in:
mydesktop 2014-05-03 12:19:43 -04:00
parent 0f42b2eba6
commit 333f975760
38 changed files with 849 additions and 232 deletions

2
README
View file

@ -29,4 +29,4 @@ cd build
cmake -G "Visual Studio 11 Win64" .. cmake -G "Visual Studio 11 Win64" ..
And then do Build. And then do Build.
Good luck! Good luck!

View file

@ -1,6 +1,12 @@
Release notes -> BMR Bitmonero
- forked for Bitmonero project Release notes 0.8.6
- Simplwallet can set extra for transfers
- Improvements in JSON RPC for wallet
- UX improvements in simplewallet
- Win32 compilation
- Mac OSX compilation
Release notes 0.8.5 Release notes 0.8.5
@ -28,4 +34,4 @@ Release notes 0.8.2
Release notes 0.8.1 Release notes 0.8.1
Bytecoin project is moved to GitHub Bytecoin project is moved to GitHub

View file

@ -856,7 +856,7 @@ using namespace std;
http::url_content u_c; http::url_content u_c;
bool res = parse_url(url, u_c); bool res = parse_url(url, u_c);
if(!tr.is_connected()) if(!tr.is_connected() && !u_c.host.empty())
{ {
CHECK_AND_ASSERT_MES(res, false, "failed to parse url: " << url); CHECK_AND_ASSERT_MES(res, false, "failed to parse url: " << url);

View file

@ -14,15 +14,55 @@ namespace tools
bool serialize_obj_to_file(t_object& obj, const std::string& file_path) bool serialize_obj_to_file(t_object& obj, const std::string& file_path)
{ {
TRY_ENTRY(); TRY_ENTRY();
std::ofstream data_file; #if defined(_MSC_VER)
data_file.open( file_path , std::ios_base::binary | std::ios_base::out| std::ios::trunc); // Need to know HANDLE of file to call FlushFileBuffers
if(data_file.fail()) 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; 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())
return false;
#endif
boost::archive::binary_oarchive a(data_file); boost::archive::binary_oarchive a(data_file);
a << obj; 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); CATCH_ENTRY_L0("serialize_obj_to_file", false);
} }

View file

@ -2,7 +2,7 @@
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once #pragma once
#include <boost/serialization/split_free.hpp> #include <boost/serialization/split_free.hpp>
#include <unordered_map> #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> template <class Archive, class hval>
inline void save(Archive &a, const std::unordered_set<hval> &x, const boost::serialization::version_type ver) 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); 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> template <class Archive, class hval>
inline void serialize(Archive &a, std::unordered_set<hval> &x, const boost::serialization::version_type ver) inline void serialize(Archive &a, std::unordered_set<hval> &x, const boost::serialization::version_type ver)
{ {

View file

@ -52,7 +52,7 @@ namespace tools
private: private:
#if defined(WIN32) #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) if (CTRL_C_EVENT == type || CTRL_BREAK_EVENT == type)
{ {

View file

@ -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)) { if (!m_tx_pool.fill_block_template(b, median_size, already_generated_coins, txs_size, fee)) {
return false; 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 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 //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); 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"); 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); 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) { 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); 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"); CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, second chance");
size_t coinbase_blob_size = get_object_blobsize(b.miner_tx); size_t coinbase_blob_size = get_object_blobsize(b.miner_tx);
if (coinbase_blob_size > cumulative_size - txs_size) { if (coinbase_blob_size > cumulative_size - txs_size) {
cumulative_size = txs_size + coinbase_blob_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; continue;
} }
if (coinbase_blob_size < cumulative_size - txs_size) { if (coinbase_blob_size < cumulative_size - txs_size) {
size_t delta = cumulative_size - txs_size - coinbase_blob_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); 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. //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)) { 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)); 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; return true;
} }
LOG_ERROR("Failed to create_block_template with " << 10 << " tries"); 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); return handle_block_to_main_chain(bl, id, bvc);
} }

View file

@ -11,7 +11,8 @@
namespace cryptonote { namespace cryptonote {
inline bool create_checkpoints(cryptonote::checkpoints& checkpoints) inline bool create_checkpoints(cryptonote::checkpoints& checkpoints)
{ {
ADD_CHECKPOINT(22231, "d69526de16c58b07058bd80a9a8c99389814d17b1935623223b0d6e4a311b80f");
return true; return true;
} }
} }

View file

@ -61,8 +61,8 @@ namespace cryptonote
keypair txkey = keypair::generate(); keypair txkey = keypair::generate();
add_tx_pub_key_to_extra(tx, txkey.pub); add_tx_pub_key_to_extra(tx, txkey.pub);
if(extra_nonce.size()) if(!extra_nonce.empty())
if(!add_tx_extra_nonce(tx, extra_nonce)) if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
return false; return false;
txin_gen in; txin_gen in;
@ -74,6 +74,10 @@ namespace cryptonote
LOG_PRINT_L0("Block is too big"); LOG_PRINT_L0("Block is too big");
return false; return false;
} }
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
LOG_PRINT_L1("Creating block template: reward " << block_reward <<
", fee " << fee)
#endif
block_reward += fee; block_reward += fee;
std::vector<size_t> out_amounts; std::vector<size_t> out_amounts;
@ -204,51 +208,50 @@ namespace cryptonote
return r; 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; tx_extra_fields.clear();
parse_and_validate_tx_extra(tx, pk);
return pk; 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)
{
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;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
bool parse_and_validate_tx_extra(const transaction& tx, crypto::public_key& tx_pub_key) crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra)
{ {
tx_pub_key = null_pkey; std::vector<tx_extra_field> tx_extra_fields;
bool padding_started = false; //let the padding goes only at the end if (!parse_tx_extra(tx_extra, tx_extra_fields))
bool tx_extra_tag_pubkey_found = false; return null_pkey;
bool tx_extra_extra_nonce_found = false;
for(size_t i = 0; i != tx.extra.size();) tx_extra_pub_key pub_key_field;
{ if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field))
if(padding_started) return null_pkey;
{
CHECK_AND_ASSERT_MES(!tx.extra[i], false, "Failed to parse transaction extra (not 0 after padding) in tx " << get_transaction_hash(tx)); return pub_key_field.pub_key;
} }
else if(tx.extra[i] == TX_EXTRA_TAG_PUBKEY) //---------------------------------------------------------------
{ crypto::public_key get_tx_pub_key_from_extra(const transaction& tx)
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)); return get_tx_pub_key_from_extra(tx.extra);
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;
}
return true;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key) bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key)
@ -259,32 +262,50 @@ namespace cryptonote
return true; 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"); 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(); size_t start_pos = tx_extra.size();
tx.extra.resize(tx.extra.size() + 2 + extra_nonce.size()); tx_extra.resize(tx_extra.size() + 2 + extra_nonce.size());
//write tag //write tag
tx.extra[start_pos] = TX_EXTRA_NONCE; tx_extra[start_pos] = TX_EXTRA_NONCE;
//write len //write len
++start_pos; ++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 //write data
++start_pos; ++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; 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) 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, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time)
{ {
tx.vin.clear(); tx.vin.clear();
tx.vout.clear(); tx.vout.clear();
tx.signatures.clear(); tx.signatures.clear();
tx.extra.clear();
tx.version = CURRENT_TRANSACTION_VERSION; tx.version = CURRENT_TRANSACTION_VERSION;
tx.unlock_time = unlock_time; tx.unlock_time = unlock_time;
tx.extra = extra;
keypair txkey = keypair::generate(); keypair txkey = keypair::generate();
add_tx_pub_key_to_extra(tx, txkey.pub); 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) 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) 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 //genesis block
bl = boost::value_initialized<block>(); bl = boost::value_initialized<block>();
account_public_address ac = boost::value_initialized<account_public_address>(); account_public_address ac = boost::value_initialized<account_public_address>();
std::vector<size_t> sz; std::vector<size_t> sz;
construct_miner_tx(0, 0, 0, 0, 0, ac, bl.miner_tx); // zero fee in genesis 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); 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 //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; blobdata tx_bl;
string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, 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); 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"); CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob");
bl.major_version = 1; bl.major_version = CURRENT_BLOCK_MAJOR_VERSION;
bl.minor_version = 0; bl.minor_version = CURRENT_BLOCK_MINOR_VERSION;
bl.timestamp = 0; bl.timestamp = 0;
bl.nonce = 10000; bl.nonce = 70;
miner::find_nonce_for_given_block(bl, 1, 0); miner::find_nonce_for_given_block(bl, 1, 0);
return true; return true;
} }

View file

@ -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 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);
bool parse_and_validate_tx_extra(const transaction& tx, crypto::public_key& tx_pub_key);
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); 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_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 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, 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); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);

View file

@ -24,7 +24,7 @@ namespace cryptonote {
#include <winnt.h> #include <winnt.h>
static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) { 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 #else

View file

@ -2,10 +2,93 @@
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // 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_TAG_PUBKEY 0x01
#define TX_EXTRA_NONCE 0x02 #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);

View file

@ -141,6 +141,9 @@ namespace cryptonote
uint64_t operator()(const txin_to_scripthash& tx) const {return 0;} uint64_t operator()(const txin_to_scripthash& tx) const {return 0;}
}; };
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
friend class blockchain_storage;
#endif
}; };
} }

View file

@ -120,6 +120,7 @@ namespace mining
COMMAND_RPC_LOGIN::request req = AUTO_VAL_INIT(req); COMMAND_RPC_LOGIN::request req = AUTO_VAL_INIT(req);
req.login = m_login; req.login = m_login;
req.pass = m_pass; req.pass = m_pass;
req.agent = "simpleminer/0.1";
COMMAND_RPC_LOGIN::response resp = AUTO_VAL_INIT(resp); 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)) 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; pool_session_id = resp.id;
//78 //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...."); LOG_PRINT_L0("Failed to text_job_details_to_native_job_details(), disconnect and sleep....");
m_http_client.disconnect(); m_http_client.disconnect();
@ -161,7 +167,8 @@ namespace mining
COMMAND_RPC_SUBMITSHARE::response submit_response = AUTO_VAL_INIT(submit_response); COMMAND_RPC_SUBMITSHARE::response submit_response = AUTO_VAL_INIT(submit_response);
submit_request.id = pool_session_id; submit_request.id = pool_session_id;
submit_request.job_id = job.job_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..."); 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)) 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); epee::misc_utils::sleep_no_w(1000);
break; 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...."); LOG_PRINT_L0("Failed to text_job_details_to_native_job_details(), disconnect and sleep....");
m_http_client.disconnect(); m_http_client.disconnect();

View file

@ -36,10 +36,12 @@ namespace mining
{ {
std::string login; std::string login;
std::string pass; std::string pass;
std::string agent;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(login) KV_SERIALIZE(login)
KV_SERIALIZE(pass) KV_SERIALIZE(pass)
KV_SERIALIZE(agent)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
@ -82,11 +84,13 @@ namespace mining
{ {
std::string id; std::string id;
std::string nonce; std::string nonce;
std::string result;
std::string job_id; std::string job_id;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(id) KV_SERIALIZE(id)
KV_SERIALIZE(nonce) KV_SERIALIZE(nonce)
KV_SERIALIZE(result)
KV_SERIALIZE(job_id) KV_SERIALIZE(job_id)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };

View file

@ -2,7 +2,6 @@
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include "include_base_utils.h" #include "include_base_utils.h"
using namespace epee; using namespace epee;
@ -359,8 +358,7 @@ namespace cryptonote
return false; return false;
} }
blobdata block_blob = t_serializable_object_to_blob(b); blobdata block_blob = t_serializable_object_to_blob(b);
crypto::public_key tx_pub_key = null_pkey; crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(b.miner_tx);
cryptonote::parse_and_validate_tx_extra(b.miner_tx, tx_pub_key);
if(tx_pub_key == null_pkey) if(tx_pub_key == null_pkey)
{ {
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;

View file

@ -122,7 +122,7 @@ namespace serialization {
{ {
std::ios_base::iostate state = s.rdstate(); std::ios_base::iostate state = s.rdstate();
result = EOF == s.peek(); result = EOF == s.peek();
s.setstate(state); s.clear(state);
} }
return result; return result;
} }

View file

@ -64,6 +64,19 @@ namespace
return err; 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 class message_writer
{ {
public: public:
@ -83,7 +96,7 @@ namespace
, m_oss(std::move(rhs.m_oss)) , m_oss(std::move(rhs.m_oss))
#else #else
// GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316 // 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 #endif
, m_color(std::move(rhs.m_color)) , m_color(std::move(rhs.m_color))
, m_log_level(std::move(rhs.m_log_level)) , 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("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("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("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("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("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("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"); 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) 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>"; fail_msg_writer() << "use: set_log <log_level_number_0-4>";
return true; return true;
@ -202,6 +216,43 @@ bool simple_wallet::set_log(const std::vector<std::string> &args)
return true; 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) bool simple_wallet::init(const boost::program_options::variables_map& vm)
{ {
handle_command_line(vm); handle_command_line(vm);
@ -212,13 +263,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false; return false;
} }
size_t c = 0; size_t c = 0;
if(!m_generate_new.empty()) ++c; if(!m_generate_new.empty()) ++c;
if(!m_wallet_file.empty()) ++c; if(!m_wallet_file.empty()) ++c;
if (1 != c) if (1 != c)
{ {
fail_msg_writer() << "you must specify --wallet-file or --generate-new-wallet params"; if(!ask_wallet_create_if_needed())
return false; return false;
} }
if (m_daemon_host.empty()) 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); 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) bool simple_wallet::refresh(const std::vector<std::string>& args)
{ {
if (!try_connect_to_daemon()) if (!try_connect_to_daemon())
@ -587,6 +647,55 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
return true; 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) uint64_t simple_wallet::get_daemon_blockchain_height(std::string& err)
{ {
COMMAND_RPC_GET_HEIGHT::request req; COMMAND_RPC_GET_HEIGHT::request req;
@ -628,9 +737,32 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
fail_msg_writer() << "mixin_count should be non-negative integer, got " << local_args[0]; fail_msg_writer() << "mixin_count should be non-negative integer, got " << local_args[0];
return true; return true;
} }
local_args.erase(local_args.begin());
std::vector<uint8_t> extra;
if (1 == local_args.size() % 2)
{
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)
{
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;
}
}
vector<cryptonote::tx_destination_entry> dsts; vector<cryptonote::tx_destination_entry> dsts;
for (size_t i = 1; i < local_args.size(); i += 2) for (size_t i = 0; i < local_args.size(); i += 2)
{ {
cryptonote::tx_destination_entry de; cryptonote::tx_destination_entry de;
if(!get_account_address_from_str(de.addr, local_args[i])) if(!get_account_address_from_str(de.addr, local_args[i]))
@ -639,12 +771,6 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
return true; return true;
} }
if (local_args.size() <= i + 1)
{
fail_msg_writer() << "amount for the last address " << local_args[i] << " is not specified";
return true;
}
bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]); bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]);
if(!ok || 0 == de.amount) if(!ok || 0 == de.amount)
{ {
@ -659,7 +785,7 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
try try
{ {
cryptonote::transaction tx; 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); success_msg_writer(true) << "Money successfully sent, transaction " << get_transaction_hash(tx);
} }
catch (const tools::error::daemon_busy&) 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)) 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() << "Usage: simplewallet [--wallet-file=<file>|--generate-new-wallet=<file>] [--daemon-address=<host>:<port>] [<COMMAND>]";
success_msg_writer() << desc_all << '\n' << w.get_commands_str(); success_msg_writer() << desc_all << '\n' << w.get_commands_str();
return false; 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_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)); 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)) 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); 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) ) if(!command_line::has_arg(vm, arg_wallet_file) )
{ {
LOG_ERROR("Wallet file not set."); LOG_ERROR("Wallet file not set.");
@ -854,7 +981,7 @@ int main(int argc, char* argv[])
return 1; 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 wallet_password = command_line::get_arg(vm, arg_password);
std::string daemon_address = command_line::get_arg(vm, arg_daemon_address); std::string daemon_address = command_line::get_arg(vm, arg_daemon_address);
std::string daemon_host = command_line::get_arg(vm, arg_daemon_host); std::string daemon_host = command_line::get_arg(vm, arg_daemon_host);
@ -904,7 +1031,7 @@ int main(int argc, char* argv[])
} }
}else }else
{ {
//runs wallet with console interface //runs wallet with console interface
r = w.init(vm); r = w.init(vm);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet"); CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet");

View file

@ -49,6 +49,7 @@ namespace cryptonote
bool refresh(const std::vector<std::string> &args); bool refresh(const std::vector<std::string> &args);
bool show_balance(const std::vector<std::string> &args = std::vector<std::string>()); 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_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 show_blockchain_height(const std::vector<std::string> &args);
bool transfer(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>()); 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); uint64_t get_daemon_blockchain_height(std::string& err);
bool try_connect_to_daemon(); bool try_connect_to_daemon();
bool ask_wallet_create_if_needed();
//----------------- i_wallet2_callback --------------------- //----------------- i_wallet2_callback ---------------------
virtual void on_new_block(uint64_t height, const cryptonote::block& block); 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_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_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; friend class refresh_progress_reporter_t;

View file

@ -1,4 +1,4 @@
#define BUILD_COMMIT_ID "@VERSION@" #define BUILD_COMMIT_ID "@VERSION@"
#define PROJECT_VERSION "0.8.5" #define PROJECT_VERSION "0.8.6"
#define PROJECT_VERSION_BUILD_NO "294" #define PROJECT_VERSION_BUILD_NO "295"
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")" #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"

View file

@ -22,6 +22,23 @@ using namespace epee;
using namespace cryptonote; 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 namespace tools
{ {
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@ -36,17 +53,25 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_
process_unconfirmed(tx); process_unconfirmed(tx);
std::vector<size_t> outs; std::vector<size_t> outs;
uint64_t tx_money_got_in_outs = 0; 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()); 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) 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); 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) // check all outputs for spending (compare key images)
BOOST_FOREACH(auto& in, tx.vin) 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()) 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)); 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]; transfer_details& td = m_transfers[it->second];
td.m_spent = true; td.m_spent = true;
if (0 != m_callback) if (0 != m_callback)
m_callback->on_money_spent(height, td.m_tx, td.m_internal_output_index, tx); 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) void wallet2::process_unconfirmed(const cryptonote::transaction& tx)
@ -203,7 +251,7 @@ void wallet2::pull_blocks(size_t& blocks_added)
{ {
//split detected here !!! //split detected here !!!
THROW_WALLET_EXCEPTION_IF(current_index == res.start_height, error::wallet_internal_error, 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: " + " (height " + std::to_string(res.start_height) + "), local block id at this height: " +
string_tools::pod_to_hex(m_blockchain[current_index])); 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_blockchain.erase(m_blockchain.begin()+height, m_blockchain.end());
m_local_bc_height -= blocks_detached; 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); 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(); 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) bool wallet2::prepare_file_names(const std::string& file_path)
{ {
m_keys_file = file_path; do_prepare_file_names(file_path, m_keys_file, m_wallet_file);
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";
}
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
@ -422,7 +479,7 @@ bool wallet2::check_connection()
net_utils::http::url_content u; net_utils::http::url_content u;
net_utils::parse_url(m_daemon_address, u); net_utils::parse_url(m_daemon_address, u);
if(!u.port) 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); 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; 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 bool wallet2::is_transfer_unlocked(const transfer_details& td) const
{ {
if(!is_tx_spendtime_unlocked(td.m_tx.unlock_time)) 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, 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, 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; cryptonote::transaction tx;
transfer(dsts, fake_outputs_count, unlock_time, fee, tx); transfer(dsts, fake_outputs_count, unlock_time, fee, extra, tx);
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
} }

View file

@ -34,6 +34,7 @@ namespace tools
virtual void on_new_block(uint64_t height, const cryptonote::block& block) {} 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_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_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 struct tx_dust_policy
@ -67,14 +68,23 @@ namespace tools
uint64_t amount() const { return m_tx.vout[m_internal_output_index].amount; } 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 struct unconfirmed_transfer_details
{ {
cryptonote::transaction m_tx; cryptonote::transaction m_tx;
uint64_t m_change; uint64_t m_change;
time_t m_sent_time; time_t m_sent_time;
}; };
typedef std::vector<transfer_details> transfer_container; typedef std::vector<transfer_details> transfer_container;
typedef std::unordered_multimap<crypto::hash, payment_details> payment_container;
struct keys_file_data struct keys_file_data
{ {
@ -108,13 +118,14 @@ namespace tools
uint64_t balance(); uint64_t balance();
uint64_t unlocked_balance(); uint64_t unlocked_balance();
template<typename T> 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> 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, 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); 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, 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, cryptonote::transaction& tx);
bool check_connection(); bool check_connection();
void get_transfers(wallet2::transfer_container& incoming_transfers) const; 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; } uint64_t get_blockchain_current_height() const { return m_local_bc_height; }
template <class t_archive> template <class t_archive>
inline void serialize(t_archive &a, const unsigned int ver) inline void serialize(t_archive &a, const unsigned int ver)
@ -128,8 +139,13 @@ namespace tools
if(ver < 6) if(ver < 6)
return; return;
a & m_unconfirmed_txs; 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: private:
bool store_keys(const std::string& keys_file_name, const std::string& password); 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); void load_keys(const std::string& keys_file_name, const std::string& password);
@ -152,10 +168,11 @@ namespace tools
std::string m_keys_file; std::string m_keys_file;
epee::net_utils::http::http_simple_client m_http_client; epee::net_utils::http::http_simple_client m_http_client;
std::vector<crypto::hash> m_blockchain; 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; std::unordered_map<crypto::hash, unconfirmed_transfer_details> m_unconfirmed_txs;
transfer_container m_transfers; transfer_container m_transfers;
payment_container m_payments;
std::unordered_map<crypto::key_image, size_t> m_key_images; std::unordered_map<crypto::key_image, size_t> m_key_images;
cryptonote::account_public_address m_account_public_address; 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 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; i_wallet2_callback* m_callback;
}; };
} }
BOOST_CLASS_VERSION(tools::wallet2, 6) BOOST_CLASS_VERSION(tools::wallet2, 7)
namespace boost namespace boost
{ {
@ -190,7 +207,14 @@ namespace boost
a & x.m_tx; 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> template<typename T>
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, 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; 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> template<typename T>
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, 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; using namespace cryptonote;
THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination); 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); THROW_WALLET_EXCEPTION_IF(!scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count);
} }
//prepare inputs //prepare inputs
size_t i = 0; size_t i = 0;
std::vector<cryptonote::tx_source_entry> sources; 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)); 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(!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); 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) BOOST_FOREACH(transfer_container::iterator it, selected_transfers)
it->m_spent = true; 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 << "Commission: " << print_money(fee+dust) << " (dust: " << print_money(dust) << ")" << ENDL
<< "Balance: " << print_money(balance()) << ENDL << "Balance: " << print_money(balance()) << ENDL
<< "Unlocked: " << print_money(unlocked_balance()) << ENDL << "Unlocked: " << print_money(unlocked_balance()) << ENDL

View file

@ -34,7 +34,6 @@ namespace tools
// block_parse_error // block_parse_error
// get_blocks_error // get_blocks_error
// get_out_indexes_error // get_out_indexes_error
// tx_extra_parse_error
// tx_parse_error // tx_parse_error
// transfer_error * // transfer_error *
// get_random_outs_general_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; 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 struct tx_parse_error : public refresh_error
{ {
explicit tx_parse_error(std::string&& loc, const cryptonote::blobdata& tx_blob) explicit tx_parse_error(std::string&& loc, const cryptonote::blobdata& tx_blob)

View file

@ -11,6 +11,7 @@ using namespace epee;
#include "cryptonote_core/cryptonote_format_utils.h" #include "cryptonote_core/cryptonote_format_utils.h"
#include "cryptonote_core/account.h" #include "cryptonote_core/account.h"
#include "misc_language.h" #include "misc_language.h"
#include "string_tools.h"
#include "crypto/hash.h" #include "crypto/hash.h"
namespace tools namespace tools
@ -74,7 +75,7 @@ namespace tools
{ {
std::vector<cryptonote::tx_destination_entry> dsts; 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; cryptonote::tx_destination_entry de;
if(!get_account_address_from_str(de.addr, it->address)) if(!get_account_address_from_str(de.addr, it->address))
@ -89,7 +90,7 @@ namespace tools
try try
{ {
cryptonote::transaction tx; 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)); res.tx_hash = boost::lexical_cast<std::string>(cryptonote::get_transaction_hash(tx));
return true; return true;
} }
@ -97,19 +98,19 @@ namespace tools
{ {
er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY; er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY;
er.message = e.what(); er.message = e.what();
return false; return false;
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
er.message = e.what(); er.message = e.what();
return false; return false;
} }
catch (...) catch (...)
{ {
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR"; er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
return false; return false;
} }
return true; return true;
} }
@ -129,4 +130,40 @@ namespace tools
return true; return true;
} }
//------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------
} 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;
}
//------------------------------------------------------------------------------------------------------------------------------
}

View file

@ -2,7 +2,7 @@
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // 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/options_description.hpp>
#include <boost/program_options/variables_map.hpp> #include <boost/program_options/variables_map.hpp>
@ -35,9 +35,10 @@ namespace tools
BEGIN_URI_MAP2() BEGIN_URI_MAP2()
BEGIN_JSON_RPC_MAP("/json_rpc") BEGIN_JSON_RPC_MAP("/json_rpc")
MAP_JON_RPC_WE("getbalance", on_getbalance, wallet_rpc::COMMAND_RPC_GET_BALANCE) 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("transfer", on_transfer, wallet_rpc::COMMAND_RPC_TRANSFER)
MAP_JON_RPC_WE("store", on_store, wallet_rpc::COMMAND_RPC_STORE) 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_JSON_RPC_MAP()
END_URI_MAP2() 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_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_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_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); bool handle_command_line(const boost::program_options::variables_map& vm);

View file

@ -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()
};
};
} }
} }

View file

@ -2,10 +2,11 @@
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // 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_UNKNOWN_ERROR -1
#define WALLET_RPC_ERROR_CODE_WRONG_ADDRESS -2 #define WALLET_RPC_ERROR_CODE_WRONG_ADDRESS -2
#define WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY -3 #define WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY -3
#define WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR -4 #define WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR -4
#define WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID -5

View file

@ -323,7 +323,7 @@ bool gen_block_miner_tx_has_2_in::generate(std::vector<test_event_entry>& events
destinations.push_back(de); destinations.push_back(de);
transaction tmp_tx; transaction tmp_tx;
if (!construct_tx(miner_account.get_keys(), sources, destinations, tmp_tx, 0)) if (!construct_tx(miner_account.get_keys(), sources, destinations, std::vector<uint8_t>(), tmp_tx, 0))
return false; return false;
MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); MAKE_MINER_TX_MANUALLY(miner_tx, blk_0);
@ -365,7 +365,7 @@ bool gen_block_miner_tx_with_txin_to_key::generate(std::vector<test_event_entry>
destinations.push_back(de); destinations.push_back(de);
transaction tmp_tx; transaction tmp_tx;
if (!construct_tx(miner_account.get_keys(), sources, destinations, tmp_tx, 0)) if (!construct_tx(miner_account.get_keys(), sources, destinations, std::vector<uint8_t>(), tmp_tx, 0))
return false; return false;
MAKE_MINER_TX_MANUALLY(miner_tx, blk_1); MAKE_MINER_TX_MANUALLY(miner_tx, blk_1);

View file

@ -425,9 +425,12 @@ bool fill_tx_sources(std::vector<tx_source_entry>& sources, const std::vector<te
ts.amount = oi.amount; ts.amount = oi.amount;
ts.real_output_in_tx_index = oi.out_no; ts.real_output_in_tx_index = oi.out_no;
ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // incoming tx public key ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // incoming tx public key
if (!fill_output_entries(outs[o.first], sender_out, nmix, ts.real_output, ts.outputs)) size_t realOutput;
if (!fill_output_entries(outs[o.first], sender_out, nmix, realOutput, ts.outputs))
continue; continue;
ts.real_output = realOutput;
sources.push_back(ts); sources.push_back(ts);
sources_amount += ts.amount; sources_amount += ts.amount;
@ -528,7 +531,7 @@ bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote
vector<tx_destination_entry> destinations; vector<tx_destination_entry> destinations;
fill_tx_sources_and_destinations(events, blk_head, from, to, amount, fee, nmix, sources, destinations); fill_tx_sources_and_destinations(events, blk_head, from, to, amount, fee, nmix, sources, destinations);
return construct_tx(from.get_keys(), sources, destinations, tx, 0); return construct_tx(from.get_keys(), sources, destinations, std::vector<uint8_t>(), tx, 0);
} }
transaction construct_tx_with_fee(std::vector<test_event_entry>& events, const block& blk_head, transaction construct_tx_with_fee(std::vector<test_event_entry>& events, const block& blk_head,

View file

@ -1,4 +1,4 @@
#pragma once #pragma once
//====================================================================================================================== //======================================================================================================================
@ -113,7 +113,7 @@ bool gen_double_spend_in_tx<txs_keeped_by_block>::generate(std::vector<test_even
destinations.push_back(de); destinations.push_back(de);
cryptonote::transaction tx_1; cryptonote::transaction tx_1;
if (!construct_tx(bob_account.get_keys(), sources, destinations, tx_1, 0)) if (!construct_tx(bob_account.get_keys(), sources, destinations, std::vector<uint8_t>(), tx_1, 0))
return false; return false;
SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block); SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block);

View file

@ -72,7 +72,7 @@ bool gen_uint_overflow_base::mark_last_valid_block(cryptonote::core& c, size_t e
bool gen_uint_overflow_1::generate(std::vector<test_event_entry>& events) const bool gen_uint_overflow_1::generate(std::vector<test_event_entry>& events) const
{ {
uint64_t ts_start = 1338224400; uint64_t ts_start = 1338224400;
GENERATE_ACCOUNT(miner_account); GENERATE_ACCOUNT(miner_account);
MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start); MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
@ -116,7 +116,7 @@ bool gen_uint_overflow_1::generate(std::vector<test_event_entry>& events) const
bool gen_uint_overflow_2::generate(std::vector<test_event_entry>& events) const bool gen_uint_overflow_2::generate(std::vector<test_event_entry>& events) const
{ {
uint64_t ts_start = 1338224400; uint64_t ts_start = 1338224400;
GENERATE_ACCOUNT(miner_account); GENERATE_ACCOUNT(miner_account);
MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start); MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
@ -148,7 +148,7 @@ bool gen_uint_overflow_2::generate(std::vector<test_event_entry>& events) const
destinations.push_back(tx_destination_entry(sources.front().amount - MONEY_SUPPLY - MONEY_SUPPLY + 1 - TESTS_DEFAULT_FEE, bob_addr)); destinations.push_back(tx_destination_entry(sources.front().amount - MONEY_SUPPLY - MONEY_SUPPLY + 1 - TESTS_DEFAULT_FEE, bob_addr));
cryptonote::transaction tx_1; cryptonote::transaction tx_1;
if (!construct_tx(miner_account.get_keys(), sources, destinations, tx_1, 0)) if (!construct_tx(miner_account.get_keys(), sources, destinations, std::vector<uint8_t>(), tx_1, 0))
return false; return false;
events.push_back(tx_1); events.push_back(tx_1);
@ -174,7 +174,7 @@ bool gen_uint_overflow_2::generate(std::vector<test_event_entry>& events) const
destinations.push_back(de); destinations.push_back(de);
cryptonote::transaction tx_2; cryptonote::transaction tx_2;
if (!construct_tx(bob_account.get_keys(), sources, destinations, tx_2, 0)) if (!construct_tx(bob_account.get_keys(), sources, destinations, std::vector<uint8_t>(), tx_2, 0))
return false; return false;
events.push_back(tx_2); events.push_back(tx_2);

View file

@ -81,9 +81,7 @@ bool test_transaction_generation_and_ring_signature()
oe.second = boost::get<txout_to_key>(tx_mine_6.vout[0].target).key; oe.second = boost::get<txout_to_key>(tx_mine_6.vout[0].target).key;
src.outputs.push_back(oe); src.outputs.push_back(oe);
crypto::public_key tx_pub_key = null_pkey; src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(tx_mine_2);
cryptonote::parse_and_validate_tx_extra(tx_mine_2, tx_pub_key);
src.real_out_tx_key = tx_pub_key;
src.real_output = 1; src.real_output = 1;
src.real_output_in_tx_index = 0; src.real_output_in_tx_index = 0;
} }
@ -95,7 +93,7 @@ bool test_transaction_generation_and_ring_signature()
destinations.push_back(td); destinations.push_back(td);
transaction tx_rc1; transaction tx_rc1;
bool r = construct_tx(miner_acc2.get_keys(), sources, destinations, tx_rc1, 0); bool r = construct_tx(miner_acc2.get_keys(), sources, destinations, std::vector<uint8_t>(), tx_rc1, 0);
CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
crypto::hash pref_hash = get_transaction_prefix_hash(tx_rc1); crypto::hash pref_hash = get_transaction_prefix_hash(tx_rc1);

View file

@ -52,7 +52,7 @@ bool do_send_money(tools::wallet2& w1, tools::wallet2& w2, size_t mix_in_factor,
try try
{ {
w1.transfer(dsts, mix_in_factor, 0, DEFAULT_FEE, tools::detail::null_split_strategy, tools::tx_dust_policy(DEFAULT_FEE), tx); w1.transfer(dsts, mix_in_factor, 0, DEFAULT_FEE, std::vector<uint8_t>(), tools::detail::null_split_strategy, tools::tx_dust_policy(DEFAULT_FEE), tx);
return true; return true;
} }
catch (const std::exception&) catch (const std::exception&)
@ -144,7 +144,7 @@ bool transactions_flow_test(std::string& working_folder,
} }
//lets make a lot of small outs to ourselves //lets make a lot of small outs to ourselves
//since it is not possible to start from transaction that bigger than 20Kb, we gonna make transactions //since it is not possible to start from transaction that bigger than 20Kb, we gonna make transactions
//with 500 outs (about 18kb), and we have to wait appropriate count blocks, mined for test wallet //with 500 outs (about 18kb), and we have to wait appropriate count blocks, mined for test wallet
while(true) while(true)
{ {

View file

@ -204,8 +204,6 @@
#define GTEST_NAME_ "Google Test" #define GTEST_NAME_ "Google Test"
#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" #define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/"
#define GTEST_HAS_TR1_TUPLE 0
// Determines the version of gcc that is used to compile this. // Determines the version of gcc that is used to compile this.
#ifdef __GNUC__ #ifdef __GNUC__
// 40302 means version 4.3.2. // 40302 means version 4.3.2.

View file

@ -36,7 +36,7 @@ public:
std::vector<tx_destination_entry> destinations; std::vector<tx_destination_entry> destinations;
destinations.push_back(tx_destination_entry(this->m_source_amount, m_alice.get_keys().m_account_address)); destinations.push_back(tx_destination_entry(this->m_source_amount, m_alice.get_keys().m_account_address));
if (!construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, destinations, m_tx, 0)) if (!construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, destinations, std::vector<uint8_t>(), m_tx, 0))
return false; return false;
get_transaction_prefix_hash(m_tx, m_tx_prefix_hash); get_transaction_prefix_hash(m_tx, m_tx_prefix_hash);

View file

@ -42,7 +42,7 @@ public:
bool test() bool test()
{ {
return cryptonote::construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, m_destinations, m_tx, 0); return cryptonote::construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, m_destinations, std::vector<uint8_t>(), m_tx, 0);
} }
private: private:

View file

@ -14,7 +14,7 @@
void set_process_affinity(int core) void set_process_affinity(int core)
{ {
#if defined(__APPLE__) #if defined (__APPLE__)
return; return;
#elif defined(BOOST_WINDOWS) #elif defined(BOOST_WINDOWS)
DWORD_PTR mask = 1; DWORD_PTR mask = 1;

View file

@ -4,52 +4,132 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include <vector>
#include "common/util.h" #include "common/util.h"
#include "cryptonote_core/cryptonote_format_utils.h" #include "cryptonote_core/cryptonote_format_utils.h"
TEST(parse_and_validate_tx_extra, is_correct_parse_and_validate_tx_extra)
TEST(parse_tx_extra, handles_empty_extra)
{
std::vector<uint8_t> extra;;
std::vector<cryptonote::tx_extra_field> tx_extra_fields;
ASSERT_TRUE(cryptonote::parse_tx_extra(extra, tx_extra_fields));
ASSERT_TRUE(tx_extra_fields.empty());
}
TEST(parse_tx_extra, handles_padding_only_size_1)
{
const uint8_t extra_arr[] = {0};
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
std::vector<cryptonote::tx_extra_field> tx_extra_fields;
ASSERT_TRUE(cryptonote::parse_tx_extra(extra, tx_extra_fields));
ASSERT_EQ(1, tx_extra_fields.size());
ASSERT_EQ(typeid(cryptonote::tx_extra_padding), tx_extra_fields[0].type());
ASSERT_EQ(1, boost::get<cryptonote::tx_extra_padding>(tx_extra_fields[0]).size);
}
TEST(parse_tx_extra, handles_padding_only_size_2)
{
const uint8_t extra_arr[] = {0, 0};
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
std::vector<cryptonote::tx_extra_field> tx_extra_fields;
ASSERT_TRUE(cryptonote::parse_tx_extra(extra, tx_extra_fields));
ASSERT_EQ(1, tx_extra_fields.size());
ASSERT_EQ(typeid(cryptonote::tx_extra_padding), tx_extra_fields[0].type());
ASSERT_EQ(2, boost::get<cryptonote::tx_extra_padding>(tx_extra_fields[0]).size);
}
TEST(parse_tx_extra, handles_padding_only_max_size)
{
std::vector<uint8_t> extra(TX_EXTRA_NONCE_MAX_COUNT, 0);
std::vector<cryptonote::tx_extra_field> tx_extra_fields;
ASSERT_TRUE(cryptonote::parse_tx_extra(extra, tx_extra_fields));
ASSERT_EQ(1, tx_extra_fields.size());
ASSERT_EQ(typeid(cryptonote::tx_extra_padding), tx_extra_fields[0].type());
ASSERT_EQ(TX_EXTRA_NONCE_MAX_COUNT, boost::get<cryptonote::tx_extra_padding>(tx_extra_fields[0]).size);
}
TEST(parse_tx_extra, handles_padding_only_exceed_max_size)
{
std::vector<uint8_t> extra(TX_EXTRA_NONCE_MAX_COUNT + 1, 0);
std::vector<cryptonote::tx_extra_field> tx_extra_fields;
ASSERT_FALSE(cryptonote::parse_tx_extra(extra, tx_extra_fields));
}
TEST(parse_tx_extra, handles_invalid_padding_only)
{
std::vector<uint8_t> extra(2, 0);
extra[1] = 42;
std::vector<cryptonote::tx_extra_field> tx_extra_fields;
ASSERT_FALSE(cryptonote::parse_tx_extra(extra, tx_extra_fields));
}
TEST(parse_tx_extra, handles_pub_key_only)
{
const uint8_t extra_arr[] = {1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230};
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
std::vector<cryptonote::tx_extra_field> tx_extra_fields;
ASSERT_TRUE(cryptonote::parse_tx_extra(extra, tx_extra_fields));
ASSERT_EQ(1, tx_extra_fields.size());
ASSERT_EQ(typeid(cryptonote::tx_extra_pub_key), tx_extra_fields[0].type());
}
TEST(parse_tx_extra, handles_extra_nonce_only)
{
const uint8_t extra_arr[] = {2, 1, 42};
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
std::vector<cryptonote::tx_extra_field> tx_extra_fields;
ASSERT_TRUE(cryptonote::parse_tx_extra(extra, tx_extra_fields));
ASSERT_EQ(1, tx_extra_fields.size());
ASSERT_EQ(typeid(cryptonote::tx_extra_nonce), tx_extra_fields[0].type());
cryptonote::tx_extra_nonce extra_nonce = boost::get<cryptonote::tx_extra_nonce>(tx_extra_fields[0]);
ASSERT_EQ(1, extra_nonce.nonce.size());
ASSERT_EQ(42, extra_nonce.nonce[0]);
}
TEST(parse_tx_extra, handles_pub_key_and_padding)
{
const uint8_t extra_arr[] = {1, 30, 208, 98, 162, 133, 64, 85, 83, 112, 91, 188, 89, 211, 24, 131, 39, 154, 22, 228,
80, 63, 198, 141, 173, 111, 244, 183, 4, 149, 186, 140, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
std::vector<cryptonote::tx_extra_field> tx_extra_fields;
ASSERT_TRUE(cryptonote::parse_tx_extra(extra, tx_extra_fields));
ASSERT_EQ(2, tx_extra_fields.size());
ASSERT_EQ(typeid(cryptonote::tx_extra_pub_key), tx_extra_fields[0].type());
ASSERT_EQ(typeid(cryptonote::tx_extra_padding), tx_extra_fields[1].type());
}
TEST(parse_and_validate_tx_extra, is_valid_tx_extra_parsed)
{ {
cryptonote::transaction tx = AUTO_VAL_INIT(tx); cryptonote::transaction tx = AUTO_VAL_INIT(tx);
cryptonote::account_base acc; cryptonote::account_base acc;
acc.generate(); acc.generate();
cryptonote::blobdata b = "dsdsdfsdfsf"; cryptonote::blobdata b = "dsdsdfsdfsf";
bool r = cryptonote::construct_miner_tx(0, 0, 10000000000000, 1000, DEFAULT_FEE, acc.get_keys().m_account_address, tx, b, 1); ASSERT_TRUE(cryptonote::construct_miner_tx(0, 0, 10000000000000, 1000, DEFAULT_FEE, acc.get_keys().m_account_address, tx, b, 1));
ASSERT_TRUE(r); crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(tx);
crypto::public_key tx_pub_key; ASSERT_NE(tx_pub_key, cryptonote::null_pkey);
r = cryptonote::parse_and_validate_tx_extra(tx, tx_pub_key);
ASSERT_TRUE(r);
} }
TEST(parse_and_validate_tx_extra, is_correct_extranonce_too_big) TEST(parse_and_validate_tx_extra, fails_on_big_extra_nonce)
{ {
cryptonote::transaction tx = AUTO_VAL_INIT(tx); cryptonote::transaction tx = AUTO_VAL_INIT(tx);
cryptonote::account_base acc; cryptonote::account_base acc;
acc.generate(); acc.generate();
cryptonote::blobdata b(260, 0); cryptonote::blobdata b(TX_EXTRA_NONCE_MAX_COUNT + 1, 0);
bool r = cryptonote::construct_miner_tx(0, 0, 10000000000000, 1000, DEFAULT_FEE, acc.get_keys().m_account_address, tx, b, 1); ASSERT_FALSE(cryptonote::construct_miner_tx(0, 0, 10000000000000, 1000, DEFAULT_FEE, acc.get_keys().m_account_address, tx, b, 1));
ASSERT_FALSE(r);
} }
TEST(parse_and_validate_tx_extra, is_correct_wrong_extra_couner_too_big) TEST(parse_and_validate_tx_extra, fails_on_wrong_size_in_extra_nonce)
{ {
cryptonote::transaction tx = AUTO_VAL_INIT(tx); cryptonote::transaction tx = AUTO_VAL_INIT(tx);
tx.extra.resize(20, 0); tx.extra.resize(20, 0);
tx.extra[0] = TX_EXTRA_NONCE; tx.extra[0] = TX_EXTRA_NONCE;
tx.extra[1] = 255; tx.extra[1] = 255;
crypto::public_key tx_pub_key; std::vector<cryptonote::tx_extra_field> tx_extra_fields;
bool r = parse_and_validate_tx_extra(tx, tx_pub_key); ASSERT_FALSE(cryptonote::parse_tx_extra(tx.extra, tx_extra_fields));
ASSERT_FALSE(r);
} }
TEST(parse_and_validate_tx_extra, is_correct_wrong_extra_nonce_double_entry)
{
cryptonote::transaction tx = AUTO_VAL_INIT(tx);
tx.extra.resize(20, 0);
cryptonote::blobdata v = "asasdasd";
cryptonote::add_tx_extra_nonce(tx, v);
cryptonote::add_tx_extra_nonce(tx, v);
crypto::public_key tx_pub_key;
bool r = parse_and_validate_tx_extra(tx, tx_pub_key);
ASSERT_FALSE(r);
}
TEST(validate_parse_amount_case, validate_parse_amount) TEST(validate_parse_amount_case, validate_parse_amount)
{ {
uint64_t res = 0; uint64_t res = 0;