Skip to content

Commit

Permalink
payment_id support, partially code taken from bytecoin
Browse files Browse the repository at this point in the history
  • Loading branch information
cryptozoidberg committed May 29, 2014
1 parent e2ccd42 commit feb5ca3
Show file tree
Hide file tree
Showing 14 changed files with 334 additions and 24 deletions.
37 changes: 36 additions & 1 deletion src/common/unordered_containers_boost_serialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down
18 changes: 16 additions & 2 deletions src/currency_core/currency_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,25 @@ namespace currency
//check if tx use different key images
if(!check_tx_inputs_keyimages_diff(tx))
{
LOG_PRINT_RED_L0("tx have to big size " << get_object_blobsize(tx) << ", expected not bigger than " << m_blockchain_storage.get_current_comulative_blocksize_limit() - CURRENCY_COINBASE_BLOB_RESERVED_SIZE);
LOG_PRINT_RED_L0("tx have the similar keyimages");
return false;
}

if(!check_tx_extra(tx))
{
LOG_PRINT_RED_L0("Tx have wrong extra, rejected");
return false;
}


return true;
}
//-----------------------------------------------------------------------------------------------
bool core::check_tx_extra(const transaction& tx)
{
tx_extra_info ei = AUTO_VAL_INIT(ei);
bool r = parse_and_validate_tx_extra(tx, ei);
if(!r)
return false;
return true;
}
//-----------------------------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions src/currency_core/currency_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ namespace currency
bool add_new_block(const block& b, block_verification_context& bvc);
bool load_state_data();
bool parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash, const blobdata& blob);
bool check_tx_extra(const transaction& tx);

bool check_tx_syntax(const transaction& tx);
//check correct values, amounts and all lightweight checks not related with database
Expand Down
69 changes: 68 additions & 1 deletion src/currency_core/currency_format_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,8 @@ namespace currency
++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_user_data_found = true;
if(tx.extra[i])
extra.m_user_data_blob.assign(reinterpret_cast<const char*>(&tx.extra[i+1]), static_cast<size_t>(tx.extra[i]));
i += tx.extra[i];//actually don't need to extract it now, just skip
}else if(tx.extra[i] == TX_EXTRA_TAG_ALIAS)
{
Expand All @@ -443,6 +445,19 @@ namespace currency
return true;
}
//---------------------------------------------------------------
bool parse_payment_id_from_hex_str(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;
}
//---------------------------------------------------------------
bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key)
{
tx.extra.resize(tx.extra.size() + 1 + sizeof(crypto::public_key));
Expand Down Expand Up @@ -490,13 +505,22 @@ namespace currency
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,
uint8_t tx_outs_attr)
{
return construct_tx(sender_account_keys, sources, destinations, std::vector<uint8_t>(), tx, unlock_time, tx_outs_attr);
}
bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources,
const std::vector<tx_destination_entry>& destinations,
const std::vector<uint8_t>& extra,
transaction& tx,
uint64_t unlock_time,
uint8_t tx_outs_attr)
{
tx.vin.clear();
tx.vout.clear();
tx.signatures.clear();
tx.extra.clear();
tx.extra = extra;

tx.version = CURRENT_TRANSACTION_VERSION;
tx.unlock_time = unlock_time;
Expand Down Expand Up @@ -730,6 +754,49 @@ namespace currency
return true;
}
//---------------------------------------------------------------
bool set_payment_id_to_tx_extra(std::vector<uint8_t>& extra, const std::string& payment_id)
{
if(!payment_id.size() || payment_id.size() >= TX_MAX_PAYMENT_ID_SIZE)
return false;

if(std::find(extra.begin(), extra.end(), TX_EXTRA_TAG_USER_DATA) != extra.end())
return false;

extra.push_back(TX_EXTRA_TAG_USER_DATA);
extra.push_back(static_cast<uint8_t>(payment_id.size()+2));
extra.push_back(TX_USER_DATA_TAG_PAYMENT_ID);
extra.push_back(static_cast<uint8_t>(payment_id.size()));

const uint8_t* payment_id_ptr = reinterpret_cast<const uint8_t*>(payment_id.data());
std::copy(payment_id_ptr, payment_id_ptr + payment_id.size(), std::back_inserter(extra));
return true;
}
//---------------------------------------------------------------
bool get_payment_id_from_user_data(const std::string& user_data, std::string& paymnet_id)
{
if(!user_data.size())
return false;
if(user_data[0] != TX_USER_DATA_TAG_PAYMENT_ID)
return false;
if(user_data.size() < 2)
return false;

paymnet_id = user_data.substr(2, static_cast<size_t>(user_data[1]));
return true;
}
//---------------------------------------------------------------
bool get_payment_id_from_tx_extra(const transaction& tx, std::string& payment_id)
{
tx_extra_info tei = AUTO_VAL_INIT(tei);
bool r = parse_and_validate_tx_extra(tx, tei);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse and validate extra");
if(!tei.m_user_data_blob.size())
return false;
if(!get_payment_id_from_user_data(tei.m_user_data_blob, payment_id))
return false;
return true;
}
//---------------------------------------------------------------
void get_blob_hash(const blobdata& blob, crypto::hash& res)
{
cn_fast_hash(blob.data(), blob.size(), res);
Expand Down
30 changes: 27 additions & 3 deletions src/currency_core/currency_format_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ namespace currency
{
crypto::public_key m_tx_pub_key;
alias_info m_alias;
std::string m_user_data_blob;
};

//---------------------------------------------------------------
Expand Down Expand Up @@ -88,6 +89,7 @@ namespace currency
bool construct_tx_out(const account_public_address& destination_addr, const crypto::secret_key& tx_sec_key, size_t output_index, uint64_t amount, transaction& tx, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
bool validate_alias_name(const std::string& al);
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, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const std::vector<uint8_t>& extra, transaction& tx, uint64_t unlock_time, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
bool sign_update_alias(alias_info& ai, const crypto::public_key& pkey, const crypto::secret_key& skey);
bool make_tx_extra_alias_entry(std::string& buff, const alias_info& alinfo, bool make_buff_to_sign = false);
bool add_tx_extra_alias(transaction& tx, const alias_info& alinfo);
Expand Down Expand Up @@ -127,6 +129,7 @@ namespace currency
bool check_outs_valid(const transaction& tx);
blobdata get_block_hashing_blob(const block& b);
bool parse_amount(uint64_t& amount, const std::string& str_amount);
bool parse_payment_id_from_hex_str(const std::string& payment_id_str, crypto::hash& payment_id);

bool check_money_overflow(const transaction& tx);
bool check_outs_overflow(const transaction& tx);
Expand All @@ -140,11 +143,32 @@ namespace currency

bool addendum_to_hexstr(const std::vector<crypto::hash>& add, std::string& hex_buff);
bool hexstr_to_addendum(const std::string& hex_buff, std::vector<crypto::hash>& add);

bool set_payment_id_to_tx_extra(std::vector<uint8_t>& extra, const std::string& payment_id);
bool get_payment_id_from_tx_extra(const transaction& tx, std::string& payment_id);

void print_currency_details();



//---------------------------------------------------------------
template<class payment_id_type>
bool set_payment_id_to_tx_extra(std::vector<uint8_t>& extra, const payment_id_type& payment_id)
{
std::string payment_id_blob;
epee::string_tools::apped_pod_to_strbuff(payment_id_blob, payment_id);
return set_payment_id_to_tx_extra(extra, payment_id_blob);
}
//---------------------------------------------------------------
template<class payment_id_type>
bool get_payment_id_from_tx_extra(const transaction& tx, payment_id_type& payment_id)
{
std::string payment_id_blob;
if(!get_payment_id_from_tx_extra(tx, payment_id_blob))
return false;

if(payment_id_blob.size() != sizeof(payment_id_type))
return false;
payment_id = *reinterpret_cast<const payment_id_type*>(payment_id_blob.data());
return true;
}
//---------------------------------------------------------------
bool get_block_scratchpad_data(const block& b, std::string& res, uint64_t selector);
struct get_scratchpad_param
Expand Down
4 changes: 4 additions & 0 deletions src/currency_core/tx_extra.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,9 @@
#define TX_EXTRA_TAG_ALIAS_FLAGS_OP_UPDATE 0x01
#define TX_EXTRA_TAG_ALIAS_FLAGS_ADDR_WITH_TRACK 0x02

//types predefined in TX_EXTRA_TAG_USER_DATA, rules are not strict, just a recommendation
#define TX_USER_DATA_TAG_PAYMENT_ID 0x00

#define TX_EXTRA_MAX_USER_DATA_SIZE 250
#define TX_MAX_PAYMENT_ID_SIZE TX_EXTRA_MAX_USER_DATA_SIZE

1 change: 0 additions & 1 deletion src/currency_core/tx_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ namespace currency
}
}


crypto::hash max_used_block_id = null_hash;
uint64_t max_used_block_height = 0;
bool ch_inp_res = m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id);
Expand Down
75 changes: 73 additions & 2 deletions src/simplewallet/simplewallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ namespace
}
}


std::string simple_wallet::get_commands_str()
{
std::stringstream ss;
Expand All @@ -171,6 +170,7 @@ 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("set_log", boost::bind(&simple_wallet::set_log, this, _1), "set_log <level> - Change current log detalization level, <level> is a number 0-4");
Expand Down Expand Up @@ -583,6 +583,56 @@ 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_from_hex_str(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;
Expand Down Expand Up @@ -689,6 +739,27 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
return true;
}

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_from_hex_str(payment_id_str, payment_id);
if(r)
{
std::string extra_nonce;
r = set_payment_id_to_tx_extra(extra, payment_id);
}

if(!r)
{
fail_msg_writer() << "payment id has invalid format: \"" << payment_id_str << "\", expected 64-character string";
return true;
}
}

vector<currency::tx_destination_entry> dsts;
for (size_t i = 1; i < local_args.size(); i += 2)
{
Expand Down Expand Up @@ -719,7 +790,7 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
try
{
currency::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) << ", " << get_object_blobsize(tx) << " bytes";
}
catch (const tools::error::daemon_busy&)
Expand Down
1 change: 1 addition & 0 deletions src/simplewallet/simplewallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ namespace currency
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>());
Expand Down
Loading

2 comments on commit feb5ca3

@pcdinh
Copy link
Contributor

@pcdinh pcdinh commented on feb5ca3 May 30, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it mean that BoolBerry is ready to list on an exchange? I understand that without payment_id support, exchanges can not implement features like withdraw or deposit. Is it correct?

@cryptozoidberg
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, correct. Sorry for late response.
You may know, we are already on exchanges.

Please sign in to comment.