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

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

View File

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

View File

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

View File

@ -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)
{

View File

@ -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)
{

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)) {
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");

View File

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

View File

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

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 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);

View File

@ -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

View File

@ -5,7 +5,90 @@
#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);

View File

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

View File

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

View File

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

View File

@ -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;

View File

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

View File

@ -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:
@ -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");
@ -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);
@ -217,7 +268,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if(!m_wallet_file.empty()) ++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;
}
@ -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;

View File

@ -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;

View File

@ -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 ")"

View File

@ -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);
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));
}
// We don't know how to handle this weird tx, so return
if (!r) return;
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;
}
r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, tx_money_got_in_outs);
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)
@ -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;
}
//----------------------------------------------------------------------------------------------------
@ -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);
}
//----------------------------------------------------------------------------------------------------
}

View File

@ -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,6 +68,14 @@ 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;
@ -75,6 +84,7 @@ namespace tools
};
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);
@ -156,6 +172,7 @@ namespace tools
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);
@ -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);

View File

@ -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)

View File

@ -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
@ -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;
}
@ -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;
}
//------------------------------------------------------------------------------------------------------------------------------
}

View File

@ -38,6 +38,7 @@ namespace tools
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);

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

@ -9,3 +9,4 @@
#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

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);
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);

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.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,

View File

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

View File

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

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;
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);

View File

@ -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&)

View File

@ -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.

View File

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

View File

@ -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:

View File

@ -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;

View File

@ -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;