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