1
0
Fork 0
forked from lthn/blockchain

merged from develop

This commit is contained in:
cryptozoidberg 2019-10-28 19:52:15 +01:00
commit 19d3ba7fb2
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
14 changed files with 458 additions and 94 deletions

View file

@ -117,34 +117,34 @@ namespace net_utils
//some helpers
inline
std::string print_connection_context(const connection_context_base& ctx)
inline std::string print_connection_context(const connection_context_base& ctx)
{
std::stringstream ss;
ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
return ss.str();
}
inline
void print_connection_context_short(const connection_context_base& ctx, std::stringstream& ss)
inline std::ostream &operator <<(std::ostream &o, const connection_context_base& ctx)
{
ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << (ctx.m_is_income ? " INC" : " OUT");
}
o << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << (ctx.m_is_income ? " INC" : " OUT");
return o;
}
inline
std::string print_connection_context_short(const connection_context_base& ctx)
inline std::string print_connection_context_short(const connection_context_base& ctx)
{
std::stringstream ss;
print_connection_context_short(ctx, ss);
ss << ctx;
return ss.str();
}
inline std::string print_connection_context_list(const std::list<connection_context_base>& contexts)
inline std::string print_connection_context_list(const std::list<connection_context_base>& contexts, const std::string& delim = std::string("\n"))
{
std::stringstream ss;
for (auto& c : contexts)
{
ss << epee::string_tools::get_ip_string_from_int32(c.m_remote_ip) << ":" << c.m_remote_port << (c.m_is_income ? " INC" : " OUT") << ENDL;
if (ss.tellp())
ss << delim;
ss << c;
}
return ss.str();
}
@ -179,7 +179,7 @@ namespace net_utils
#define CHECK_AND_ASSERT_MES_CC(condition, return_val, err_message) CHECK_AND_ASSERT_MES(condition, return_val, "[" << epee::net_utils::print_connection_context_short(context) << "]" << err_message)
}
}
} // namespace net_utils
} // namespace epee
#endif //_NET_UTILS_BASE_H_

View file

@ -34,6 +34,8 @@ DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated
#define CURRENCY_POOLDATA_FOLDERNAME_SUFFIX "_v1"
#define CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL 50 // if there's a conflict in key images between tx in the pool and in the blockchain this much depth in required to remove correspongin tx from pool
#undef LOG_DEFAULT_CHANNEL
#define LOG_DEFAULT_CHANNEL "tx_pool"
ENABLE_CHANNEL_BY_DEFAULT("tx_pool");
@ -429,18 +431,41 @@ namespace currency
int64_t tx_age = get_core_time() - tx_entry.receive_time;
if ((tx_age > CURRENCY_MEMPOOL_TX_LIVETIME ))
{
LOG_PRINT_L0("Tx " << h << " removed from tx pool, reason: outdated, age: " << tx_age);
LOG_PRINT_L0("tx " << h << " is about to be removed from tx pool, reason: outdated, age: " << tx_age << " = " << misc_utils::get_time_interval_string(tx_age));
to_delete.push_back(tx_to_delete_entry(h, tx_entry.tx, tx_entry.kept_by_block));
}
// expiration time check - remove expired
if (is_tx_expired(tx_entry.tx, tx_expiration_ts_median) )
{
LOG_PRINT_L0("Tx " << h << " removed from tx pool, reason: expired, expiration time: " << get_tx_expiration_time(tx_entry.tx) << ", blockchain median: " << tx_expiration_ts_median);
LOG_PRINT_L0("tx " << h << " is about to be removed from tx pool, reason: expired, expiration time: " << get_tx_expiration_time(tx_entry.tx) << ", blockchain median: " << tx_expiration_ts_median);
to_delete.push_back(tx_to_delete_entry(h, tx_entry.tx, tx_entry.kept_by_block));
}
// if a tx has at least one key image already used in blockchain (deep enough) -- remove such tx, as it cannot be added to any block
// although it will be removed by the age check above, we consider desireable
// to remove it from the pool faster in order to unblock related key images used in the same tx
uint64_t should_be_spent_before_height = m_blockchain.get_current_blockchain_size() - 1;
if (should_be_spent_before_height > CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL)
{
should_be_spent_before_height -= CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL;
for (auto& in : tx_entry.tx.vin)
{
if (in.type() == typeid(txin_to_key))
{
// if at least one key image is spent deep enought -- remove such tx
const crypto::key_image& ki = boost::get<txin_to_key>(in).k_image;
if (m_blockchain.have_tx_keyimg_as_spent(ki, should_be_spent_before_height))
{
LOG_PRINT_L0("tx " << h << " is about to be removed from tx pool, reason: ki was spent in the blockchain before height " << should_be_spent_before_height << ", tx age: " << misc_utils::get_time_interval_string(tx_age));
to_delete.push_back(tx_to_delete_entry(h, tx_entry.tx, tx_entry.kept_by_block));
return true;
}
}
}
}
return true;
});

View file

@ -22,7 +22,7 @@
PUSH_VS_WARNINGS
DISABLE_VS_WARNINGS(4355)
#define ASYNC_RELAY_MODE
#define ASYNC_RELAY_MODE // relay transactions asyncronously via m_relay_que
namespace currency
{
@ -117,25 +117,25 @@ namespace currency
int64_t m_last_ntp2local_time_difference;
template<class t_parametr>
bool post_notify(typename t_parametr::request& arg, currency_connection_context& context)
{
LOG_PRINT_L2("[POST]" << typeid(t_parametr).name());
std::string blob;
epee::serialization::store_t_to_binary(arg, blob);
return m_p2p->invoke_notify_to_peer(t_parametr::ID, blob, context);
}
bool post_notify(typename t_parametr::request& arg, currency_connection_context& context)
{
LOG_PRINT_L3("[POST]" << typeid(t_parametr).name() << " to " << context);
std::string blob;
epee::serialization::store_t_to_binary(arg, blob);
return m_p2p->invoke_notify_to_peer(t_parametr::ID, blob, context);
}
template<class t_parametr>
bool relay_post_notify(typename t_parametr::request& arg, currency_connection_context& exlude_context)
{
std::string arg_buff;
epee::serialization::store_t_to_binary(arg, arg_buff);
std::list<epee::net_utils::connection_context_base> relayed_peers;
bool r = m_p2p->relay_notify_to_all(t_parametr::ID, arg_buff, exlude_context, relayed_peers);
template<class t_parametr>
bool relay_post_notify(typename t_parametr::request& arg, currency_connection_context& exlude_context)
{
std::string arg_buff;
epee::serialization::store_t_to_binary(arg, arg_buff);
std::list<epee::net_utils::connection_context_base> relayed_peers;
bool r = m_p2p->relay_notify_to_all(t_parametr::ID, arg_buff, exlude_context, relayed_peers);
LOG_PRINT_GREEN("[POST RELAY] " << typeid(t_parametr).name() << " relayed contexts list: " << ENDL << print_connection_context_list(relayed_peers), LOG_LEVEL_2);
return r;
}
LOG_PRINT_GREEN("[POST RELAY] " << typeid(t_parametr).name() << " to (" << relayed_peers.size() << "): " << print_connection_context_list(relayed_peers, ", "), LOG_LEVEL_2);
return r;
}
};
}

View file

@ -94,22 +94,32 @@ namespace currency
<< std::setw(20) << "Peer id"
<< std::setw(25) << "Recv/Sent (idle,sec)"
<< std::setw(25) << "State"
<< std::setw(20) << "Livetime(seconds)"
<< std::setw(20) << "Livetime"
<< std::setw(20) << "Client version" << ENDL;
size_t incoming_count = 0, outgoing_count = 0;
std::multimap<time_t, std::string> conn_map;
m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id)
{
ss << std::setw(29) << std::left << std::string(cntxt.m_is_income ? "[INC]":"[OUT]") +
std::stringstream conn_ss;
time_t livetime = time(NULL) - cntxt.m_started;
conn_ss << std::setw(29) << std::left << std::string(cntxt.m_is_income ? "[INC]":"[OUT]") +
string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port)
<< std::setw(20) << std::hex << peer_id
<< std::setw(25) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")"
<< std::setw(25) << get_protocol_state_string(cntxt.m_state)
<< std::setw(20) << std::to_string(time(NULL) - cntxt.m_started)
<< std::setw(20) << epee::misc_utils::get_time_interval_string(livetime)
<< std::setw(20) << cntxt.m_remote_version
<< ENDL;
conn_map.insert(std::make_pair(livetime, conn_ss.str()));
(cntxt.m_is_income ? incoming_count : outgoing_count) += 1;
return true;
});
LOG_PRINT_L0("Connections: " << ENDL << ss.str());
for(auto it = conn_map.rbegin(); it != conn_map.rend(); ++it)
ss << it->second;
LOG_PRINT_L0("Connections (" << incoming_count << " in, " << outgoing_count << " out, " << incoming_count + outgoing_count << " total):" << ENDL << ss.str());
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
@ -235,7 +245,6 @@ namespace currency
if(context.m_state != currency_connection_context::state_normal)
return 1;
//check if block already exists
block b = AUTO_VAL_INIT(b);
block_verification_context bvc = AUTO_VAL_INIT(bvc);
@ -245,6 +254,7 @@ namespace currency
m_p2p->drop_connection(context);
return 1;
}
crypto::hash block_id = get_block_hash(b);
LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK " << block_id << " HEIGHT " << get_block_height(b) << " (hop " << arg.hop << ")", LOG_LEVEL_2);
@ -314,11 +324,11 @@ namespace currency
m_p2p->drop_connection(context);
return 1;
}
LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK EXTRA: id: " << block_id
<< ",bvc.m_added_to_main_chain " << bvc.m_added_to_main_chain
//<< ",prevalidate_result " << prevalidate_relayed
<< ",bvc.added_to_altchain " << bvc.added_to_altchain
<< ",bvc.m_marked_as_orphaned " << bvc.m_marked_as_orphaned, LOG_LEVEL_2);
LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK EXTRA " << block_id
<< " bvc.m_added_to_main_chain=" << bvc.m_added_to_main_chain
//<< ", prevalidate_result=" << prevalidate_relayed
<< ", bvc.added_to_altchain=" << bvc.added_to_altchain
<< ", bvc.m_marked_as_orphaned=" << bvc.m_marked_as_orphaned, LOG_LEVEL_2);
if (bvc.m_added_to_main_chain || (bvc.added_to_altchain && bvc.height_difference < 2))
{
@ -723,13 +733,14 @@ namespace currency
if (req.txs.size())
{
post_notify<NOTIFY_NEW_TRANSACTIONS>(req, cc);
print_connection_context_short(cc, debug_ss);
debug_ss << ": " << req.txs.size() << ENDL;
if (debug_ss.tellp())
debug_ss << ", ";
debug_ss << cc << ": " << req.txs.size();
}
}
TIME_MEASURE_FINISH_MS(ms);
LOG_PRINT_GREEN("[POST RELAY] NOTIFY_NEW_TRANSACTIONS relayed (" << ms << "ms)contexts list: " << debug_ss.str(), LOG_LEVEL_2);
LOG_PRINT_GREEN("[POST RELAY] NOTIFY_NEW_TRANSACTIONS relayed (" << ms << "ms) to: " << debug_ss.str(), LOG_LEVEL_2);
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>

View file

@ -32,6 +32,7 @@ using namespace epee;
#undef LOG_DEFAULT_CHANNEL
#define LOG_DEFAULT_CHANNEL "p2p"
ENABLE_CHANNEL_BY_DEFAULT(LOG_DEFAULT_CHANNEL);
#define CURRENT_P2P_STORAGE_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+13)
@ -198,6 +199,7 @@ namespace nodetool
bool make_new_connection_from_peerlist(bool use_white_list);
bool try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist = false, uint64_t last_seen_stamp = 0, bool white = true);
size_t get_random_index_with_fixed_probability(size_t max_index);
bool is_peer_id_used(const peerid_type id);
bool is_peer_used(const peerlist_entry& peer);
bool is_addr_connected(const net_address& peer);
template<class t_callback>

View file

@ -511,6 +511,13 @@ namespace nodetool
return;
}
if (is_peer_id_used(rsp.node_data.peer_id))
{
LOG_PRINT_L0("It seems that peer " << std::hex << rsp.node_data.peer_id << " has already been connected, dropping connection");
hsh_result = false;
return;
}
pi = context.peer_id = rsp.node_data.peer_id;
m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_ip, context.m_remote_port);
@ -535,7 +542,7 @@ namespace nodetool
if(!hsh_result)
{
LOG_PRINT_CC_L0(context_, "COMMAND_HANDSHAKE Failed");
LOG_PRINT_CC_L0(context_, "COMMAND_HANDSHAKE Failed, closing connection");
m_net_server.get_config_object().close(context_.m_connection_id);
}
@ -597,6 +604,26 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::is_peer_id_used(const peerid_type id)
{
if (id == m_config.m_peer_id)
return true; // ourself
bool used = false;
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
{
if (id == cntxt.peer_id)
{
used = true;
return false; // stop enumerating
}
return true;
});
return used;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::is_peer_used(const peerlist_entry& peer)
{
@ -638,7 +665,7 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, bool white)
{
LOG_PRINT_L0("Connecting to " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) << "(white=" << white << ", last_seen: " << (last_seen_stamp?misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never" ) << ")...");
LOG_PRINT_L1("Connecting to " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) << "(white=" << white << ", last_seen: " << (last_seen_stamp?misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never" ) << ")...");
typename net_server::t_connection_context con = AUTO_VAL_INIT(con);
bool res = m_net_server.connect(string_tools::get_ip_string_from_int32(na.ip),
@ -647,7 +674,7 @@ namespace nodetool
con);
if(!res)
{
LOG_PRINT_L0("Connect failed to "
LOG_PRINT_L1("Connect failed to "
<< string_tools::get_ip_string_from_int32(na.ip)
<< ":" << string_tools::num_to_string_fast(na.port)
/*<< ", try " << try_count*/);
@ -661,9 +688,11 @@ namespace nodetool
LOG_PRINT_CC_L0(con, "Failed to HANDSHAKE with peer "
<< string_tools::get_ip_string_from_int32(na.ip)
<< ":" << string_tools::num_to_string_fast(na.port)
/*<< ", try " << try_count*/);
<< ", closing connection");
m_net_server.get_config_object().close(con.m_connection_id);
return false;
}
if(just_take_peerlist)
{
m_net_server.get_config_object().close(con.m_connection_id);
@ -807,7 +836,10 @@ namespace nodetool
if(is_addr_connected(na))
continue;
try_to_connect_and_handshake_with_new_peer(na);
if (!try_to_connect_and_handshake_with_new_peer(na))
{
LOG_PRINT_L0("connection to priority node " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) << " failed");
}
}
if(m_use_only_priority_peers)
return true;
@ -1310,6 +1342,13 @@ namespace nodetool
return 1;
}
if (is_peer_id_used(arg.node_data.peer_id))
{
LOG_PRINT_CCONTEXT_L1("COMMAND_HANDSHAKE came, but seems that peer " << std::hex << arg.node_data.peer_id << " has already been connected to this node, dropping connection");
drop_connection(context);
return 1;
}
if (!tools::check_remote_client_version(arg.payload_data.client_version))
{
LOG_PRINT_CCONTEXT_L2("COMMAND_HANDSHAKE: wrong client version: " << arg.payload_data.client_version << ", closing connection.");

View file

@ -8,6 +8,6 @@
#define PROJECT_REVISION "2"
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
#define PROJECT_VERSION_BUILD_NO 67
#define PROJECT_VERSION_BUILD_NO 68
#define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO)
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"

View file

@ -2066,7 +2066,7 @@ void wallet2::store(const std::wstring& path_to_save, const std::string& passwor
{
LOG_PRINT_L0("(before storing: pending_key_images: " << m_pending_key_images.size() << ", pki file elements: " << m_pending_key_images_file_container.size() << ", tx_keys: " << m_tx_keys.size() << ")");
check_for_free_space_and_throw_if_it_lacks(path_to_save);
// check_for_free_space_and_throw_if_it_lacks(path_to_save); temporary disabled, wallet saving implemented in two-stage scheme to avoid data loss due to lack of space
std::string ascii_path_to_save = epee::string_encoding::convert_to_ansii(path_to_save);
@ -2099,8 +2099,9 @@ void wallet2::store(const std::wstring& path_to_save, const std::string& passwor
r = tools::portble_serialize_obj_to_stream(*this, data_file);
if (!r)
{
data_file.close();
boost::filesystem::remove(tmp_file_path); // remove tmp file if smth went wrong
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(false, "portble_serialize_obj_to_stream failed for wallet " << tmp_file_path.string());
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(false, "IO error while storing wallet to " << tmp_file_path.string() << " (portble_serialize_obj_to_stream failed)");
}
data_file.flush();
@ -2229,7 +2230,7 @@ uint64_t wallet2::balance(uint64_t& unlocked, uint64_t& awaiting_in, uint64_t& a
for(auto& td : m_transfers)
{
if (td.is_spendable() || td.is_reserved_for_escrow())
if (td.is_spendable() || (td.is_reserved_for_escrow() && !td.is_spent()))
{
balance_total += td.amount();
if (is_transfer_unlocked(td))

View file

@ -731,6 +731,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(escrow_cancellation_acceptance_expiration);
// GENERATE_AND_PLAY(escrow_proposal_acceptance_in_alt_chain); -- work in progress
GENERATE_AND_PLAY(escrow_zero_amounts);
GENERATE_AND_PLAY(escrow_acceptance_and_balance);
GENERATE_AND_PLAY(escrow_altchain_meta_test<0>);
GENERATE_AND_PLAY(escrow_altchain_meta_test<1>);

View file

@ -3095,3 +3095,200 @@ bool escrow_zero_amounts::c1(currency::core& c, size_t ev_index, const std::vect
return true;
}
//------------------------------------------------------------------------------
escrow_acceptance_and_balance::escrow_acceptance_and_balance()
: m_alice_bob_start_amount(0)
, m_alice_bob_start_chunk_amount(0)
, m_alice_fee_proposal(0)
, m_bob_fee_accept(0)
, m_bob_fee_release(0)
{
REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_proposal_not_confirmed);
REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_proposal_confirmed);
REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_acceptance_not_confirmed);
REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_acceptance_confirmed);
}
bool escrow_acceptance_and_balance::generate(std::vector<test_event_entry>& events) const
{
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate();
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate();
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
m_alice_bob_start_amount = MK_TEST_COINS(200);
uint64_t amount_chunks = 10;
m_alice_bob_start_chunk_amount = m_alice_bob_start_amount / 10;
transaction tx_0 = AUTO_VAL_INIT(tx_0);
bool r = construct_tx_with_many_outputs(events, blk_0r, miner_acc.get_keys(), alice_acc.get_public_address(), m_alice_bob_start_amount, 10, TESTS_DEFAULT_FEE, tx_0);
CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs failed");
events.push_back(tx_0);
transaction tx_1 = AUTO_VAL_INIT(tx_1);
r = construct_tx_with_many_outputs(events, blk_0r, miner_acc.get_keys(), bob_acc.get_public_address(), m_alice_bob_start_amount, 10, TESTS_DEFAULT_FEE, tx_1);
CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs failed");
events.push_back(tx_1);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, std::list<transaction>({tx_0, tx_1}));
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE);
// prepare contract details
m_cpd = AUTO_VAL_INIT(m_cpd);
m_cpd.amount_a_pledge = MK_TEST_COINS(7);
m_cpd.amount_b_pledge = MK_TEST_COINS(5);
m_cpd.amount_to_pay = MK_TEST_COINS(3);
m_cpd.a_addr = alice_acc.get_public_address();
m_cpd.b_addr = bob_acc.get_public_address();
m_alice_fee_proposal = MK_TEST_COINS(4);
m_bob_fee_accept = MK_TEST_COINS(2);
m_bob_fee_release = MK_TEST_COINS(9); // Alice states that Bob should pay this much money for upcoming contract release (which will be sent by Alice)
std::vector<tx_source_entry> used_sources;
// escrow proposal
bc_services::proposal_body prop = AUTO_VAL_INIT(prop);
transaction escrow_proposal_tx = AUTO_VAL_INIT(escrow_proposal_tx);
r = build_custom_escrow_proposal(events, blk_1r, alice_acc.get_keys(), m_cpd, 0, 0, 0, blk_1r.timestamp + 36000, 0, m_alice_fee_proposal, m_bob_fee_release, eccf_normal, escrow_proposal_tx, used_sources, &prop);
CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_proposal failed");
events.push_back(escrow_proposal_tx);
DO_CALLBACK(events, "check_balance_after_proposal_not_confirmed");
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, escrow_proposal_tx);
DO_CALLBACK(events, "check_balance_after_proposal_confirmed");
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc);
DO_CALLBACK(events, "check_balance_after_proposal_confirmed");
// escrow proposal acceptance
transaction escrow_normal_acceptance_tx = prop.tx_template;
uint64_t normal_acceptance_mask = eccf_normal;
r = build_custom_escrow_accept_proposal(events, blk_2, 0, bob_acc.get_keys(), m_cpd, 0, 0, 0, 0, m_bob_fee_accept, m_bob_fee_release, normal_acceptance_mask, prop.tx_onetime_secret_key, escrow_normal_acceptance_tx, used_sources);
CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_accept_proposal failed");
events.push_back(escrow_normal_acceptance_tx);
DO_CALLBACK(events, "check_balance_after_acceptance_not_confirmed");
MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3, miner_acc, escrow_normal_acceptance_tx);
DO_CALLBACK(events, "check_balance_after_acceptance_confirmed");
MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_acc);
DO_CALLBACK(events, "check_balance_after_acceptance_confirmed");
return true;
}
bool escrow_acceptance_and_balance::check_balance_after_proposal_not_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
m_alice_bob_start_amount - m_alice_fee_proposal, // total
true, UINT64_MAX,
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
MK_TEST_COINS(0) // awainted out
), false, "");
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
m_alice_bob_start_amount, // total
true, UINT64_MAX,
m_alice_bob_start_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
MK_TEST_COINS(0) // awaited out
), false, "");
return true;
}
bool escrow_acceptance_and_balance::check_balance_after_proposal_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
m_alice_bob_start_amount - m_alice_fee_proposal, // total
true, UINT64_MAX,
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
MK_TEST_COINS(0) // awaited out
), false, "");
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
m_alice_bob_start_amount, // total
true, UINT64_MAX,
m_alice_bob_start_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
MK_TEST_COINS(0) // awaited out
), false, "");
return true;
}
bool escrow_acceptance_and_balance::check_balance_after_acceptance_not_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
m_alice_bob_start_amount - m_alice_fee_proposal - m_cpd.amount_a_pledge - m_cpd.amount_to_pay, // total
true, UINT64_MAX,
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
m_cpd.amount_a_pledge + m_cpd.amount_to_pay), // awaited out
false, "");
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
m_alice_bob_start_amount - m_cpd.amount_b_pledge - m_bob_fee_release - m_bob_fee_accept, // total
true, UINT64_MAX,
m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
m_cpd.amount_b_pledge + m_bob_fee_release), // awaited out
false, "");
return true;
}
bool escrow_acceptance_and_balance::check_balance_after_acceptance_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
m_alice_bob_start_amount - m_alice_fee_proposal - m_cpd.amount_a_pledge - m_cpd.amount_to_pay, // total
true, UINT64_MAX,
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
MK_TEST_COINS(0) // awaited out
), false, "");
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
m_alice_bob_start_amount - m_cpd.amount_b_pledge - m_bob_fee_release - m_bob_fee_accept, // total
true, UINT64_MAX,
m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
MK_TEST_COINS(0) // awaited out
), false, "");
return true;
}

View file

@ -141,3 +141,20 @@ struct escrow_zero_amounts : public wallet_test
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};
struct escrow_acceptance_and_balance : public wallet_test
{
escrow_acceptance_and_balance();
bool generate(std::vector<test_event_entry>& events) const;
bool check_balance_after_proposal_not_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
bool check_balance_after_proposal_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
bool check_balance_after_acceptance_not_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
bool check_balance_after_acceptance_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
mutable uint64_t m_alice_bob_start_amount;
mutable uint64_t m_alice_bob_start_chunk_amount;
mutable uint64_t m_alice_fee_proposal;
mutable uint64_t m_bob_fee_release;
mutable uint64_t m_bob_fee_accept;
mutable bc_services::contract_private_details m_cpd;
};

View file

@ -1453,14 +1453,13 @@ bool tx_expiration_time_and_chain_switching::generate(std::vector<test_event_ent
//------------------------------------------------------------------
tx_key_image_pool_conflict::tx_key_image_pool_conflict()
{
REGISTER_CALLBACK_METHOD(tx_key_image_pool_conflict, c1);
REGISTER_CALLBACK_METHOD(tx_key_image_pool_conflict, c2);
}
bool tx_key_image_pool_conflict::generate(std::vector<test_event_entry>& events) const
{
// Test idea: check tx that is stuck in tx pool because one on its key images is already spent in the blockchain
// 1) if it's linked to an alt block -- tx will not be removed as long as linked alt block exists (in order to be able to switch)
// 2) if it's not linked to an alt block -- it will be removed after CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL confirmations of conflicted tx
// or it will be removed once tx is old enough (CURRENCY_MEMPOOL_TX_LIVETIME)
bool r = false;
m_miner_acc.generate();
@ -1534,44 +1533,49 @@ bool tx_key_image_pool_conflict::generate(std::vector<test_event_entry>& events)
// however, it does not remove tx from the pool
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
//
// make sure stuck tx will be removed from the pool when it's too old
//
MAKE_NEXT_BLOCK(events, blk_2, blk_1, m_miner_acc);
DO_CALLBACK(events, "remove_stuck_txs");
// remove_stuck_txs should not remove anything, tx_1 and tx_2 should be in the pool
DO_CALLBACK(events, "remove_stuck_txs");
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
// shift time by CURRENCY_MEMPOOL_TX_LIVETIME
events.push_back(event_core_time(CURRENCY_MEMPOOL_TX_LIVETIME + 1, true));
// remove_stuck_txs should remove only tx_2 and left tx_1
// remove_stuck_txs should have removed tx_2 because it's too old
DO_CALLBACK(events, "remove_stuck_txs");
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
//
// make sure stuck tx will be removed from the pool as soon as one of its key images is spent deep enough in the blockchain
// (even if it's not too old to be removed by age)
//
MAKE_NEXT_BLOCK(events, blk_3, blk_2, m_miner_acc);
// re-add tx_2 with kept_by_block flag
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true));
events.push_back(tx_2);
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false));
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
// remove_stuck_txs should not remove anything, tx_1 and tx_2 should be in the pool
DO_CALLBACK(events, "remove_stuck_txs");
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
// rewind 50 blocks so tx_0 spending its key image will be deep enough
REWIND_BLOCKS_N_WITH_TIME(events, blk_3r, blk_3, m_miner_acc, 50);
// remove_stuck_txs should remove only tx_2 and left tx_1 (linked to alt block)
DO_CALLBACK(events, "remove_stuck_txs");
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
DO_CALLBACK(events, "print_tx_pool");
return true;
}
bool tx_key_image_pool_conflict::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "incorrect tx pool count = " << c.get_pool_transactions_count());
// try to mine a block and make sure tx_1 is still in the pool (was not added to the blocktemplate)
block b;
r = mine_next_pow_block_in_playtime(m_miner_acc.get_public_address(), c, &b);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed");
// make sure tx_1 is still here
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "incorrect tx pool count = " << c.get_pool_transactions_count());
return true;
}
bool tx_key_image_pool_conflict::c2(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
return true;
}

View file

@ -150,10 +150,6 @@ struct tx_expiration_time_and_chain_switching : public test_chain_unit_enchanced
struct tx_key_image_pool_conflict : public test_chain_unit_enchanced
{
tx_key_image_pool_conflict();
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
bool c2(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
mutable currency::account_base m_miner_acc;
};

View file

@ -11,6 +11,8 @@
#include "misc_log_ex.h"
namespace fs = boost::filesystem;
std::string exec(const char* cmd)
{
std::array<char, 1024> buffer;
@ -32,11 +34,59 @@ std::string exec(const char* cmd)
return result;
}
bool try_write_test_file(size_t size_bytes)
{
static const std::string filename = "test_out_file";
static const fs::path filename_p = filename;
try
{
fs::ofstream s;
s.open(filename, std::ios_base::binary | std::ios_base::out| std::ios::trunc);
if(s.fail())
return false;
uint8_t block[32 * 1024] = {};
crypto::generate_random_bytes(sizeof block, &block);
size_t size_total = 0;
for (size_t i = 0; i < size_bytes / (sizeof block); ++i)
{
s.write((const char*)&block, sizeof block);
size_total += sizeof block;
}
if (size_bytes > size_total)
s.write((const char*)&block, size_bytes - size_total);
s.close();
size_t size_actual = fs::file_size(filename_p);
CHECK_AND_ASSERT_MES(size_bytes == size_actual, false, "size_bytes = " << size_bytes << ", size_actual = " << size_actual);
CHECK_AND_ASSERT_MES(fs::remove(filename_p), false, "remove failed");
}
catch (std::exception& e)
{
LOG_PRINT_RED("caught: " << e.what(), LOG_LEVEL_0);
return false;
}
catch (...)
{
LOG_PRINT_RED("caught unknown exception", LOG_LEVEL_0);
return false;
}
return true;
}
void free_space_check()
{
static const size_t test_file_size = 1024 * 1024;
namespace fs = boost::filesystem;
std::string output;
bool r = false;
#ifdef WIN32
output = exec("dir");
@ -46,9 +96,13 @@ void free_space_check()
LOG_PRINT_L0("test command output:" << std::endl << output);
r = try_write_test_file(test_file_size);
LOG_PRINT_L0("test file write: " << (r ? "OK" : "fail"));
boost::filesystem::path current_path(".");
size_t counter = 0;
bool need_backspace = false;
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds( 900 ));
@ -59,26 +113,43 @@ void free_space_check()
{
// free space is ok
counter = (counter + 1) % 4;
std::cout << '\b';
if (need_backspace)
std::cout << '\b';
std::cout << ( counter == 0 ? '*' : counter == 1 ? '\\' : counter == 2 ? '|' : '/' );
std::cout << std::flush;
need_backspace = true;
continue;
}
// free space is not ok!
LOG_PRINT_YELLOW("free space available: " << si.available, LOG_LEVEL_0);
LOG_PRINT_YELLOW("1) fs::space() : available: " << si.available << ", free: " << si.free << ", capacity: " << si.capacity, LOG_LEVEL_0);
#ifdef WIN32
output = exec("dir");
#else
output = exec("df -h");
#endif
LOG_PRINT_YELLOW(output, LOG_LEVEL_0);
// try one again asap
si = fs::space(current_path);
LOG_PRINT_YELLOW("2) fs::space() : available: " << si.available << ", free: " << si.free << ", capacity: " << si.capacity, LOG_LEVEL_0);
if (!try_write_test_file(test_file_size))
{
LOG_PRINT_YELLOW("try_write_test_file(" << test_file_size << ") failed", LOG_LEVEL_0);
}
need_backspace = false;
}
catch (std::exception& e)
{
LOG_ERROR("failed to determine free space: " << e.what());
need_backspace = false;
}
catch (...)
{
LOG_ERROR("failed to determine free space: unknown exception");
need_backspace = false;
}
}