forked from lthn/blockchain
Merge branch 'develop' into release
This commit is contained in:
commit
5982abd525
69 changed files with 1874 additions and 656 deletions
|
|
@ -187,6 +187,7 @@ else()
|
|||
set(LLVM_USE_LINKER "gold")
|
||||
else()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
|
||||
link_libraries("$<$<AND:$<CXX_COMPILER_ID:GNU>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,9.0>>:-lstdc++fs>") # GCC < 9 requires additional linking for std::filesystem. Remove after stop supporting GCC 8.x -- sowle
|
||||
endif()
|
||||
endif()
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8))
|
||||
|
|
@ -248,7 +249,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
|||
#set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "${__iphonesimulator_archs}")
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
if(CAKEWALLET)
|
||||
find_package(Boost ${ZANO_BOOST_MIN_VER} REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale)
|
||||
find_package(Boost ${ZANO_BOOST_MIN_VER} REQUIRED COMPONENTS system filesystem locale thread timer date_time chrono regex serialization atomic program_options)
|
||||
else()
|
||||
set(Boost_LIBRARY_DIRS "${Boost_LIBRARY_DIRS}/${CMAKE_ANDROID_ARCH_ABI}/")
|
||||
set(Boost_LIBRARIES "${Boost_LIBRARY_DIRS}libboost_system.a;${Boost_LIBRARY_DIRS}libboost_filesystem.a;${Boost_LIBRARY_DIRS}libboost_thread.a;${Boost_LIBRARY_DIRS}libboost_timer.a;${Boost_LIBRARY_DIRS}libboost_date_time.a;${Boost_LIBRARY_DIRS}libboost_chrono.a;${Boost_LIBRARY_DIRS}libboost_regex.a;${Boost_LIBRARY_DIRS}libboost_serialization.a;${Boost_LIBRARY_DIRS}libboost_atomic.a;${Boost_LIBRARY_DIRS}libboost_program_options.a")
|
||||
|
|
@ -256,9 +257,9 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
|
|||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fPIC")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fPIC")
|
||||
elseif(APPLE)
|
||||
find_package(Boost ${ZANO_BOOST_MIN_VER} REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale)
|
||||
find_package(Boost ${ZANO_BOOST_MIN_VER} REQUIRED COMPONENTS system filesystem locale thread timer date_time chrono regex serialization atomic program_options)
|
||||
else()
|
||||
find_package(Boost ${ZANO_BOOST_MIN_VER} REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale log)
|
||||
find_package(Boost ${ZANO_BOOST_MIN_VER} REQUIRED COMPONENTS system filesystem locale thread timer date_time chrono regex serialization atomic program_options log)
|
||||
endif()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -115,13 +115,17 @@ else()
|
|||
set_source_files_properties("crypto/chacha8_stream.c" PROPERTIES COMPILE_FLAGS "-Wno-sign-compare -Wno-strict-prototypes")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(BCRYPT_LIB bcrypt)
|
||||
endif()
|
||||
|
||||
add_library(crypto ${CRYPTO})
|
||||
if(USE_BITCOIN_SECP256K1_FOR_ECDSA)
|
||||
add_dependencies(crypto secp256k1)
|
||||
target_link_libraries(crypto secp256k1)
|
||||
target_link_libraries(crypto secp256k1 ${BCRYPT_LIB})
|
||||
else()
|
||||
add_dependencies(crypto OpenSSL::Crypto)
|
||||
target_link_libraries(crypto OpenSSL::Crypto)
|
||||
target_link_libraries(crypto OpenSSL::Crypto ${BCRYPT_LIB})
|
||||
endif()
|
||||
|
||||
add_library(currency_core ${CURRENCY_CORE})
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ namespace tools
|
|||
*p_reason = std::string("file was corrupted, truncated: ") + epee::string_tools::num_to_string_fast(file_size) + " -> " + epee::string_tools::num_to_string_fast(corrected_size);
|
||||
}
|
||||
|
||||
m_filename = filename;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +78,7 @@ namespace tools
|
|||
|
||||
bool push_back(const pod_t& item)
|
||||
{
|
||||
if (!m_stream.is_open() || (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit))
|
||||
if (!is_opened_and_in_good_state())
|
||||
return false;
|
||||
|
||||
m_stream.seekp(0, std::ios_base::end);
|
||||
|
|
@ -93,7 +94,7 @@ namespace tools
|
|||
|
||||
bool get_item(size_t index, pod_t& result) const
|
||||
{
|
||||
if (!m_stream.is_open() || (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit))
|
||||
if (!is_opened_and_in_good_state())
|
||||
return false;
|
||||
|
||||
size_t offset = index * sizeof result;
|
||||
|
|
@ -108,20 +109,42 @@ namespace tools
|
|||
|
||||
size_t size_bytes() const
|
||||
{
|
||||
if (!m_stream.is_open() || (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit))
|
||||
if (!is_opened_and_in_good_state())
|
||||
return 0;
|
||||
|
||||
m_stream.seekg(0, std::ios_base::end);
|
||||
return m_stream.tellg();
|
||||
}
|
||||
|
||||
bool is_opened_and_in_good_state() const
|
||||
{
|
||||
if (!m_stream.is_open())
|
||||
return false;
|
||||
if (m_stream.rdstate() != std::ios::goodbit && m_stream.rdstate() != std::ios::eofbit)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return size_bytes() / sizeof(pod_t);
|
||||
}
|
||||
|
||||
bool clear()
|
||||
{
|
||||
if (!is_opened_and_in_good_state())
|
||||
return false;
|
||||
|
||||
// close and re-open stream with trunc bit
|
||||
m_stream.close();
|
||||
m_stream.open(m_filename, std::ios::binary | std::ios::trunc | std::ios::in | std::ios::out);
|
||||
|
||||
return is_opened_and_in_good_state();
|
||||
}
|
||||
|
||||
private:
|
||||
mutable boost::filesystem::fstream m_stream;
|
||||
std::wstring m_filename;
|
||||
};
|
||||
|
||||
} // namespace tools
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2024 Zano Project
|
||||
// Copyright (c) 2014-2025 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -57,8 +57,7 @@ namespace
|
|||
const command_line::arg_descriptor<std::string> arg_generate_genesis ("generate-genesis", "Generate genesis coinbase based on config file");
|
||||
const command_line::arg_descriptor<uint64_t> arg_genesis_split_amount ( "genesis-split-amount", "Set split amount for generating genesis block");
|
||||
const command_line::arg_descriptor<std::string> arg_get_info_flags ( "getinfo-flags-hex", "Set of bits for rpc-get-daemon-info", "");
|
||||
const command_line::arg_descriptor<int64_t> arg_set_peer_log_level ( "set-peer-log-level", "Set log level for remote peer");
|
||||
const command_line::arg_descriptor<std::string> arg_download_peer_log ( "download-peer-log", "Download log from remote peer <starting_offset>[,<count>]");
|
||||
const command_line::arg_descriptor<bool> arg_get_anonymized_peers( "get-anonymized-peers", "Retrieves anonymized peers connected to the specified peer.");
|
||||
const command_line::arg_descriptor<bool> arg_do_consloe_log ( "do-console-log", "Tool generates debug console output(debug purposes)");
|
||||
const command_line::arg_descriptor<std::string> arg_generate_integrated_address ( "generate-integrated-address", "Tool create integrated address from simple address and payment_id");
|
||||
const command_line::arg_descriptor<std::string> arg_pack_file ("pack-file", "perform gzip-packing and calculate hash for a given file");
|
||||
|
|
@ -746,23 +745,23 @@ bool get_private_key(crypto::secret_key& pk, po::variables_map& vm)
|
|||
}
|
||||
else
|
||||
{
|
||||
key_str = get_password("Enter maintain private key:");
|
||||
key_str = get_password("Enter maintenance private key:");
|
||||
}
|
||||
|
||||
if(!string_tools::hex_to_pod(key_str, pk))
|
||||
{
|
||||
std::cout << "ERROR: wrong secret key set" << ENDL;
|
||||
std::cout << "ERROR: incorrect private key entered" << ENDL;
|
||||
return false;
|
||||
}
|
||||
crypto::public_key pubkey = AUTO_VAL_INIT(pubkey);
|
||||
if(!crypto::secret_key_to_public_key(pk, pubkey))
|
||||
{
|
||||
std::cout << "ERROR: wrong secret key set(secret_key_to_public_key failed)" << ENDL;
|
||||
std::cout << "ERROR: wrong private key (secret_key_to_public_key failed)" << ENDL;
|
||||
return false;
|
||||
}
|
||||
if( pubkey != tools::get_public_key_from_string(P2P_MAINTAINERS_PUB_KEY))
|
||||
{
|
||||
std::cout << "ERROR: wrong secret key set(public keys not match)" << ENDL;
|
||||
std::cout << "ERROR: wrong pritvate key (public key missmatch)" << ENDL;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -827,7 +826,7 @@ bool handle_increment_build_no(po::variables_map& vm)
|
|||
bool handle_update_maintainers_info(po::variables_map& vm)
|
||||
{
|
||||
log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
|
||||
size_t rpc_port = RPC_DEFAULT_PORT;
|
||||
[[maybe_unused]] size_t rpc_port = RPC_DEFAULT_PORT;
|
||||
if(!command_line::has_arg(vm, arg_rpc_port))
|
||||
{
|
||||
std::cout << "ERROR: rpc port not set" << ENDL;
|
||||
|
|
@ -923,154 +922,34 @@ bool invoke_debug_command(po::variables_map& vm, const crypto::secret_key& sk, n
|
|||
return net_utils::invoke_remote_command2(command_t::ID, req, rsp, transport);
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
bool handle_set_peer_log_level(po::variables_map& vm)
|
||||
bool handle_get_anonymized_peers(po::variables_map& vm)
|
||||
{
|
||||
crypto::secret_key sk = AUTO_VAL_INIT(sk);
|
||||
crypto::secret_key sk{};
|
||||
if (!get_private_key(sk, vm))
|
||||
{
|
||||
std::cout << "ERROR: secret key error" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t log_level = command_line::get_arg(vm, arg_set_peer_log_level);
|
||||
if (log_level < LOG_LEVEL_0 || log_level > LOG_LEVEL_MAX)
|
||||
{
|
||||
std::cout << "Error: invalid log level value: " << log_level << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
net_utils::levin_client2 transport;
|
||||
peerid_type peer_id = 0;
|
||||
|
||||
COMMAND_SET_LOG_LEVEL::request req = AUTO_VAL_INIT(req);
|
||||
req.new_log_level = log_level;
|
||||
COMMAND_REQUEST_ANONYMIZED_PEERS::request req{};
|
||||
|
||||
COMMAND_SET_LOG_LEVEL::response rsp = AUTO_VAL_INIT(rsp);
|
||||
if (!invoke_debug_command<COMMAND_SET_LOG_LEVEL>(vm, sk, transport, peer_id, req, rsp))
|
||||
COMMAND_REQUEST_ANONYMIZED_PEERS::response rsp{};
|
||||
if (!invoke_debug_command<COMMAND_REQUEST_ANONYMIZED_PEERS>(vm, sk, transport, peer_id, req, rsp))
|
||||
{
|
||||
std::cout << "ERROR: invoking COMMAND_SET_LOG_LEVEL failed" << ENDL;
|
||||
std::cout << "ERROR: invoking COMMAND_REQUEST_ANONYMIZED_PEERS failed" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "OK! Log level changed: " << rsp.old_log_level << " -> " << rsp.current_log_level << ENDL;
|
||||
std::cout << "Success." << ENDL << ENDL;
|
||||
|
||||
std::cout << epee::serialization::store_t_to_json(rsp);
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
bool handle_download_peer_log(po::variables_map& vm)
|
||||
{
|
||||
crypto::secret_key sk = AUTO_VAL_INIT(sk);
|
||||
if (!get_private_key(sk, vm))
|
||||
{
|
||||
std::cout << "ERROR: secret key error" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t start_offset_signed = 0;
|
||||
int64_t count = -1;
|
||||
|
||||
std::string arg_str = command_line::get_arg(vm, arg_download_peer_log);
|
||||
size_t comma_pos = arg_str.find(',');
|
||||
if (comma_pos != std::string::npos)
|
||||
{
|
||||
// count is specified
|
||||
if (!epee::string_tools::string_to_num_fast(arg_str.substr(comma_pos + 1), count) || count < 0)
|
||||
{
|
||||
std::cout << "ERROR: invalid argument: " << arg_str << ENDL;
|
||||
return false;
|
||||
}
|
||||
arg_str.erase(comma_pos);
|
||||
}
|
||||
if (!epee::string_tools::string_to_num_fast(arg_str, start_offset_signed) || start_offset_signed < 0)
|
||||
{
|
||||
std::cout << "ERROR: couldn't parse start_offset: " << arg_str << ENDL;
|
||||
return false;
|
||||
}
|
||||
uint64_t start_offset = static_cast<uint64_t>(start_offset_signed);
|
||||
|
||||
net_utils::levin_client2 transport;
|
||||
peerid_type peer_id = 0;
|
||||
|
||||
COMMAND_REQUEST_LOG::request req = AUTO_VAL_INIT(req);
|
||||
COMMAND_REQUEST_LOG::response rsp = AUTO_VAL_INIT(rsp);
|
||||
if (!invoke_debug_command<COMMAND_REQUEST_LOG>(vm, sk, transport, peer_id, req, rsp) || !rsp.error.empty())
|
||||
{
|
||||
std::cout << "ERROR: invoking COMMAND_REQUEST_LOG failed: " << rsp.error << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "Current log level: " << rsp.current_log_level << ENDL;
|
||||
std::cout << "Current log size: " << rsp.current_log_size << ENDL;
|
||||
|
||||
if (start_offset == 0 && count == 0)
|
||||
return true; // a caller wanted to just get the info, end of story
|
||||
|
||||
if (start_offset >= rsp.current_log_size)
|
||||
{
|
||||
std::cout << "ERROR: invalid start offset: " << start_offset << ", log size: " << rsp.current_log_size << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "Downloading..." << ENDL;
|
||||
|
||||
std::string local_filename = tools::get_default_data_dir() + "/log_" + epee::string_tools::num_to_string_fast(peer_id) + ".log";
|
||||
std::ofstream log{ local_filename, std::ifstream::binary };
|
||||
if (!log)
|
||||
{
|
||||
std::cout << "Couldn't open " << local_filename << " for writing." << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint64_t chunk_size = 1024 * 1024 * 5;
|
||||
uint64_t end_offset = start_offset;
|
||||
while (true)
|
||||
{
|
||||
req.log_chunk_offset = end_offset;
|
||||
req.log_chunk_size = std::min(chunk_size, rsp.current_log_size - req.log_chunk_offset);
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
uint64_t bytes_left = count + start_offset - end_offset;
|
||||
req.log_chunk_size = std::min(req.log_chunk_size, bytes_left);
|
||||
}
|
||||
|
||||
if (req.log_chunk_size == 0)
|
||||
break;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
if (!invoke_debug_command<COMMAND_REQUEST_LOG>(vm, sk, transport, peer_id, req, rsp) || !rsp.error.empty())
|
||||
{
|
||||
std::cout << "ERROR: invoking COMMAND_REQUEST_LOG failed: " << rsp.error << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!epee::zlib_helper::unpack(rsp.log_chunk))
|
||||
{
|
||||
std::cout << "ERROR: zip unpack failed" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rsp.log_chunk.size() != req.log_chunk_size)
|
||||
{
|
||||
std::cout << "ERROR: unpacked size: " << rsp.log_chunk.size() << ", requested: " << req.log_chunk_size << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
log.write(rsp.log_chunk.c_str(), rsp.log_chunk.size());
|
||||
|
||||
end_offset += req.log_chunk_size;
|
||||
|
||||
std::cout << end_offset - start_offset << " bytes downloaded" << ENDL;
|
||||
}
|
||||
|
||||
std::cout << "Remote log from offset " << start_offset << " to offset " << end_offset << " (" << end_offset - start_offset << " bytes) " <<
|
||||
"was successfully downloaded to " << local_filename << ENDL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool handle_generate_integrated_address(po::variables_map& vm)
|
||||
{
|
||||
std::string add_and_payment_id = command_line::get_arg(vm, arg_generate_integrated_address);
|
||||
|
|
@ -1326,8 +1205,7 @@ int main(int argc, char* argv[])
|
|||
command_line::add_arg(desc_params, arg_genesis_split_amount);
|
||||
command_line::add_arg(desc_params, arg_get_info_flags);
|
||||
command_line::add_arg(desc_params, arg_log_journal_len);
|
||||
command_line::add_arg(desc_params, arg_set_peer_log_level);
|
||||
command_line::add_arg(desc_params, arg_download_peer_log);
|
||||
command_line::add_arg(desc_params, arg_get_anonymized_peers);
|
||||
command_line::add_arg(desc_params, arg_do_consloe_log);
|
||||
command_line::add_arg(desc_params, arg_generate_integrated_address);
|
||||
command_line::add_arg(desc_params, arg_pack_file);
|
||||
|
|
@ -1395,13 +1273,9 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
return generate_genesis(command_line::get_arg(vm, arg_generate_genesis), 10000000000000000) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
else if (command_line::has_arg(vm, arg_set_peer_log_level))
|
||||
else if (command_line::has_arg(vm, arg_get_anonymized_peers) && command_line::get_arg(vm, arg_get_anonymized_peers))
|
||||
{
|
||||
return handle_set_peer_log_level(vm) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
else if (command_line::has_arg(vm, arg_download_peer_log))
|
||||
{
|
||||
return handle_download_peer_log(vm) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
return handle_get_anonymized_peers(vm) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
else if (command_line::has_arg(vm, arg_generate_integrated_address))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2022 Zano Project
|
||||
// Copyright (c) 2014-2025 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -35,32 +35,20 @@ namespace crypto {
|
|||
const key_image I = *reinterpret_cast<const key_image*>(&I_);
|
||||
const key_image L = *reinterpret_cast<const key_image*>(&L_);
|
||||
|
||||
struct random_init_singleton
|
||||
{
|
||||
random_init_singleton()
|
||||
{
|
||||
grant_random_initialize();
|
||||
}
|
||||
};
|
||||
|
||||
random_init_singleton init_rand; //place initializer here to avoid grant_random_initialize first call after threads will be possible(local static variables init is not thread-safe)
|
||||
|
||||
using std::abort;
|
||||
using std::int32_t;
|
||||
using std::int64_t;
|
||||
using std::lock_guard;
|
||||
using std::mutex;
|
||||
using std::size_t;
|
||||
using std::uint32_t;
|
||||
using std::uint64_t;
|
||||
|
||||
extern "C" {
|
||||
#include "crypto-ops.h"
|
||||
#include "random.h"
|
||||
}
|
||||
|
||||
|
||||
mutex random_lock;
|
||||
std::mutex& random_lock_accessor() noexcept
|
||||
{
|
||||
// this is a thread-safe approach
|
||||
// note section 6.7: "If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization."
|
||||
static std::mutex random_lock;
|
||||
return random_lock;
|
||||
}
|
||||
|
||||
|
||||
static inline unsigned char *operator &(ec_point &point) {
|
||||
return &reinterpret_cast<unsigned char &>(point);
|
||||
|
|
@ -78,9 +66,10 @@ namespace crypto {
|
|||
return &reinterpret_cast<const unsigned char &>(scalar);
|
||||
}
|
||||
|
||||
static inline void random_scalar(ec_scalar &res) {
|
||||
static inline void random_scalar_no_lock(ec_scalar &res)
|
||||
{
|
||||
unsigned char tmp[64];
|
||||
generate_random_bytes(64, tmp);
|
||||
generate_random_bytes_no_lock(64, tmp);
|
||||
sc_reduce(tmp);
|
||||
memcpy(&res, tmp, 32);
|
||||
}
|
||||
|
|
@ -118,10 +107,11 @@ namespace crypto {
|
|||
sc_reduce32(&res);
|
||||
}
|
||||
|
||||
void crypto_ops::generate_keys(public_key &pub, secret_key &sec) {
|
||||
lock_guard<mutex> lock(random_lock);
|
||||
void crypto_ops::generate_keys(public_key &pub, secret_key &sec)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(random_lock_accessor());
|
||||
ge_p3 point;
|
||||
random_scalar(sec);
|
||||
random_scalar_no_lock(sec);
|
||||
ge_scalarmult_base(&point, &sec);
|
||||
ge_p3_tobytes(&pub, &point);
|
||||
}
|
||||
|
|
@ -239,7 +229,7 @@ namespace crypto {
|
|||
};
|
||||
|
||||
void crypto_ops::generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) {
|
||||
lock_guard<mutex> lock(random_lock);
|
||||
std::lock_guard<std::mutex> lock(random_lock_accessor());
|
||||
ge_p3 tmp3;
|
||||
ec_scalar k;
|
||||
s_comm buf;
|
||||
|
|
@ -255,7 +245,7 @@ namespace crypto {
|
|||
#endif
|
||||
buf.h = prefix_hash;
|
||||
buf.key = pub;
|
||||
random_scalar(k);
|
||||
random_scalar_no_lock(k);
|
||||
ge_scalarmult_base(&tmp3, &k);
|
||||
ge_p3_tobytes(&buf.comm, &tmp3);
|
||||
hash_to_scalar(&buf, sizeof(s_comm), sig.c);
|
||||
|
|
@ -294,6 +284,7 @@ namespace crypto {
|
|||
}
|
||||
|
||||
void crypto_ops::generate_key_image(const public_key &pub, const secret_key &sec, key_image &image) {
|
||||
// image = sec * 8 * ge_fromfe_frombytes_vartime(cn_fast_hash(pub)) = sec * Hp( pub )
|
||||
ge_p3 point;
|
||||
ge_p2 point2;
|
||||
crypto_assert(sc_check(&sec) == 0);
|
||||
|
|
@ -324,7 +315,7 @@ POP_VS_WARNINGS
|
|||
const public_key *const *pubs, size_t pubs_count,
|
||||
const secret_key &sec, size_t sec_index,
|
||||
signature *sig) {
|
||||
lock_guard<mutex> lock(random_lock);
|
||||
std::lock_guard<std::mutex> lock(random_lock_accessor());
|
||||
size_t i;
|
||||
ge_p3 image_unp;
|
||||
ge_dsmp image_pre;
|
||||
|
|
@ -361,15 +352,15 @@ POP_VS_WARNINGS
|
|||
ge_p2 tmp2;
|
||||
ge_p3 tmp3;
|
||||
if (i == sec_index) {
|
||||
random_scalar(k);
|
||||
random_scalar_no_lock(k);
|
||||
ge_scalarmult_base(&tmp3, &k);
|
||||
ge_p3_tobytes(&buf->ab[i].a, &tmp3);
|
||||
hash_to_ec(*pubs[i], tmp3);
|
||||
ge_scalarmult(&tmp2, &k, &tmp3);
|
||||
ge_tobytes(&buf->ab[i].b, &tmp2);
|
||||
} else {
|
||||
random_scalar(sig[i].c);
|
||||
random_scalar(sig[i].r);
|
||||
random_scalar_no_lock(sig[i].c);
|
||||
random_scalar_no_lock(sig[i].r);
|
||||
if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) {
|
||||
abort();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2025 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -31,7 +31,7 @@ namespace crypto {
|
|||
#include "random.h"
|
||||
}
|
||||
|
||||
extern std::mutex random_lock;
|
||||
std::mutex& random_lock_accessor() noexcept;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
POD_CLASS ec_point {
|
||||
|
|
@ -114,17 +114,27 @@ namespace crypto {
|
|||
|
||||
};
|
||||
|
||||
// thread-safe version
|
||||
inline void generate_random_bytes(size_t size, void* p_data)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(random_lock_accessor());
|
||||
generate_random_bytes_no_lock(size, p_data);
|
||||
}
|
||||
|
||||
|
||||
/* Generate a value filled with random bytes.
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_pod<T>::value, T>::type rand() {
|
||||
typename std::enable_if<std::is_pod<T>::value, T>::type rand()
|
||||
{
|
||||
typename std::remove_cv<T>::type res;
|
||||
std::lock_guard<std::mutex> lock(random_lock);
|
||||
generate_random_bytes(sizeof(T), &res);
|
||||
std::lock_guard<std::mutex> lock(random_lock_accessor());
|
||||
generate_random_bytes_no_lock(sizeof(T), &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* An adapter, to be used with std::shuffle, etc.
|
||||
* Uses thread-safe crypto::rand<>().
|
||||
*/
|
||||
struct uniform_random_bit_generator
|
||||
{
|
||||
|
|
@ -302,10 +312,11 @@ namespace crypto {
|
|||
} // namespace crypto
|
||||
|
||||
POD_MAKE_HASHABLE(crypto, public_key)
|
||||
POD_MAKE_LESS_OPERATOR(crypto, public_key)
|
||||
POD_MAKE_COMPARABLE(crypto, secret_key)
|
||||
POD_MAKE_HASHABLE(crypto, key_image)
|
||||
POD_MAKE_COMPARABLE(crypto, signature)
|
||||
POD_MAKE_COMPARABLE(crypto, key_derivation)
|
||||
POD_MAKE_LESS_OPERATOR(crypto, hash)
|
||||
POD_MAKE_LESS_OPERATOR(crypto, key_image)
|
||||
POP_GCC_WARNINGS
|
||||
POP_GCC_WARNINGS
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// Copyright (c) 2018-2025 Zano Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
|
@ -5,9 +6,10 @@
|
|||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hash-ops.h"
|
||||
//#include "initializer.h"
|
||||
#include "random.h"
|
||||
|
||||
static_assert(RANDOM_STATE_SIZE >= HASH_DATA_AREA, "Invalid RANDOM_STATE_SIZE");
|
||||
|
|
@ -15,19 +17,29 @@ static_assert(RANDOM_STATE_SIZE >= HASH_DATA_AREA, "Invalid RANDOM_STATE_SIZE");
|
|||
#if defined(_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#include <bcrypt.h>
|
||||
|
||||
void generate_system_random_bytes(size_t n, void *result) {
|
||||
HCRYPTPROV prov;
|
||||
#define must_succeed(x) do if (!(x)) assert(0); while (0)
|
||||
if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
|
||||
// thread-safe version
|
||||
bool generate_system_random_bytes(size_t n, void *result)
|
||||
{
|
||||
if (n == 0)
|
||||
return true;
|
||||
|
||||
if (result == NULL)
|
||||
return false;
|
||||
|
||||
NTSTATUS status = BCryptGenRandom(NULL, (PUCHAR)result, (ULONG)n, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||
return BCRYPT_SUCCESS(status);
|
||||
}
|
||||
|
||||
void generate_system_random_bytes_or_die(size_t n, void *result)
|
||||
{
|
||||
if (!generate_system_random_bytes(n, result))
|
||||
{
|
||||
int err = GetLastError();
|
||||
assert(0);
|
||||
fprintf(stderr, "Error: generate_system_random_bytes failed and this is fatal\n\n");
|
||||
fflush(stderr);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
must_succeed(CryptGenRandom(prov, (DWORD)n, result));
|
||||
must_succeed(CryptReleaseContext(prov, 0));
|
||||
#undef must_succeed
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
@ -40,28 +52,49 @@ void generate_system_random_bytes(size_t n, void *result) {
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void generate_system_random_bytes(size_t n, void *result) {
|
||||
bool generate_system_random_bytes(size_t n, void *result)
|
||||
{
|
||||
int fd;
|
||||
if ((fd = open("/dev/urandom", O_RDONLY | O_NOCTTY | O_CLOEXEC)) < 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
for (;;) {
|
||||
ssize_t res = read(fd, result, n);
|
||||
if ((size_t) res == n) {
|
||||
break;
|
||||
}
|
||||
if (res < 0) {
|
||||
if (errno != EINTR) {
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
size_t bytes_read = 0;
|
||||
while (bytes_read < n)
|
||||
{
|
||||
ssize_t res = read(fd, (char*)result + bytes_read, n - bytes_read);
|
||||
if (res < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
{
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
} else if (res == 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
result = padd(result, (size_t) res);
|
||||
n -= (size_t) res;
|
||||
// EINTR - interrupted by signal, continue reading
|
||||
}
|
||||
else if (res == 0)
|
||||
{
|
||||
// EOF - should not happen with /dev/urandom
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes_read += res;
|
||||
}
|
||||
}
|
||||
if (close(fd) < 0) {
|
||||
|
||||
close(fd); // don't check, 'cuz failing to close /dev/urandom is not truly fatal, the OS will clean up
|
||||
return true;
|
||||
}
|
||||
|
||||
void generate_system_random_bytes_or_die(size_t n, void *result)
|
||||
{
|
||||
if (!generate_system_random_bytes(n, result))
|
||||
{
|
||||
fprintf(stderr, "FATAL: Failed to generate %zu random bytes: %s\n\n", n, strerror(errno));
|
||||
fflush(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
|
@ -70,6 +103,8 @@ void generate_system_random_bytes(size_t n, void *result) {
|
|||
|
||||
static union hash_state state;
|
||||
|
||||
static_assert(sizeof(union hash_state) == RANDOM_STATE_SIZE, "RANDOM_STATE_SIZE and hash_state size missmatch");
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
static volatile int curstate; /* To catch thread safety problems. */
|
||||
#endif
|
||||
|
|
@ -83,11 +118,10 @@ FINALIZER(deinit_random) {
|
|||
}
|
||||
*/
|
||||
|
||||
//INITIALIZER(init_random) {
|
||||
void init_random(void)
|
||||
{
|
||||
generate_system_random_bytes(32, &state);
|
||||
//REGISTER_FINA\LIZER(deinit_random);
|
||||
generate_system_random_bytes_or_die(HASH_DATA_AREA, &state);
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
assert(curstate == 0);
|
||||
curstate = 1;
|
||||
|
|
@ -95,7 +129,7 @@ void init_random(void)
|
|||
}
|
||||
|
||||
|
||||
void grant_random_initialize(void)
|
||||
void grant_random_initialize_no_lock(void)
|
||||
{
|
||||
static bool initalized = false;
|
||||
if(!initalized)
|
||||
|
|
@ -105,9 +139,9 @@ void grant_random_initialize(void)
|
|||
}
|
||||
}
|
||||
|
||||
void random_prng_initialize_with_seed(uint64_t seed)
|
||||
void random_prng_initialize_with_seed_no_lock(uint64_t seed)
|
||||
{
|
||||
grant_random_initialize();
|
||||
grant_random_initialize_no_lock();
|
||||
#if !defined(NDEBUG)
|
||||
assert(curstate == 1);
|
||||
curstate = 3;
|
||||
|
|
@ -122,9 +156,9 @@ void random_prng_initialize_with_seed(uint64_t seed)
|
|||
#endif
|
||||
}
|
||||
|
||||
void random_prng_get_state(void *state_buffer, const size_t buffer_size)
|
||||
void random_prng_get_state_no_lock(void *state_buffer, const size_t buffer_size)
|
||||
{
|
||||
grant_random_initialize();
|
||||
grant_random_initialize_no_lock();
|
||||
#if !defined(NDEBUG)
|
||||
assert(curstate == 1);
|
||||
curstate = 4;
|
||||
|
|
@ -139,9 +173,9 @@ void random_prng_get_state(void *state_buffer, const size_t buffer_size)
|
|||
#endif
|
||||
}
|
||||
|
||||
void random_prng_set_state(const void *state_buffer, const size_t buffer_size)
|
||||
void random_prng_set_state_no_lock(const void *state_buffer, const size_t buffer_size)
|
||||
{
|
||||
grant_random_initialize();
|
||||
grant_random_initialize_no_lock();
|
||||
#if !defined(NDEBUG)
|
||||
assert(curstate == 1);
|
||||
curstate = 5;
|
||||
|
|
@ -156,8 +190,9 @@ void random_prng_set_state(const void *state_buffer, const size_t buffer_size)
|
|||
#endif
|
||||
}
|
||||
|
||||
void generate_random_bytes(size_t n, void *result) {
|
||||
grant_random_initialize();
|
||||
void generate_random_bytes_no_lock(size_t n, void *result)
|
||||
{
|
||||
grant_random_initialize_no_lock();
|
||||
#if !defined(NDEBUG)
|
||||
assert(curstate == 1);
|
||||
curstate = 2;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2018-2019 Zano Project
|
||||
// Copyright (c) 2018-2025 Zano Project
|
||||
// Copyright (c) 2014-2018 The Boolberry developers
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -9,13 +9,8 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// use the cryptographically secure Pseudo-Random Number Generator provided by the operating system
|
||||
void generate_system_random_bytes(size_t n, void *result);
|
||||
|
||||
void generate_random_bytes(size_t n, void *result);
|
||||
|
||||
// checks if PRNG is initialized and initializes it if necessary
|
||||
void grant_random_initialize(void);
|
||||
// NOT thread-safe, use with caution
|
||||
void generate_random_bytes_no_lock(size_t n, void *result);
|
||||
|
||||
#define RANDOM_STATE_SIZE 200
|
||||
|
||||
|
|
@ -24,14 +19,14 @@ void grant_random_initialize(void);
|
|||
// reinitializes PRNG with the given seed
|
||||
// !!!ATTENTION!!!! Improper use of this routine may lead to SECURITY BREACH!
|
||||
// Use with care and ONLY for tests or debug purposes!
|
||||
void random_prng_initialize_with_seed(uint64_t seed);
|
||||
void random_prng_initialize_with_seed_no_lock(uint64_t seed);
|
||||
|
||||
// gets internal RPNG state (state_buffer should be 200 bytes long)
|
||||
void random_prng_get_state(void *state_buffer, const size_t buffer_size);
|
||||
void random_prng_get_state_no_lock(void *state_buffer, const size_t buffer_size);
|
||||
|
||||
// sets internal RPNG state (state_buffer should be 200 bytes long)
|
||||
// !!!ATTENTION!!!! Improper use of this routine may lead to SECURITY BREACH!
|
||||
// Use with care and ONLY for tests or debug purposes!
|
||||
void random_prng_set_state(const void *state_buffer, const size_t buffer_size);
|
||||
void random_prng_set_state_no_lock(const void *state_buffer, const size_t buffer_size);
|
||||
|
||||
#endif // #ifdef USE_INSECURE_RANDOM_RPNG_ROUTINES
|
||||
|
|
|
|||
|
|
@ -74,8 +74,8 @@ using namespace currency;
|
|||
|
||||
DISABLE_VS_WARNINGS(4267)
|
||||
|
||||
const command_line::arg_descriptor<uint32_t> arg_db_cache_l1 ( "db-cache-l1", "Specify size of memory mapped db cache file");
|
||||
const command_line::arg_descriptor<uint32_t> arg_db_cache_l2 ( "db-cache-l2", "Specify cached elements in db helpers");
|
||||
const command_line::arg_descriptor<uint64_t> arg_db_cache_l1 ( "db-cache-l1", "Specify size of memory mapped db cache file");
|
||||
const command_line::arg_descriptor<uint64_t> arg_db_cache_l2 ( "db-cache-l2", "Specify cached elements in db helpers");
|
||||
|
||||
//------------------------------------------------------------------
|
||||
blockchain_storage::blockchain_storage(tx_memory_pool& tx_pool) :m_db(nullptr, m_rw_lock),
|
||||
|
|
@ -7101,7 +7101,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
if (!m_is_in_checkpoint_zone)
|
||||
{
|
||||
auto cleanup = [&](){
|
||||
bool add_res = m_tx_pool.add_tx(tx, tvc, true, true);
|
||||
m_tx_pool.add_tx(tx, tvc, true, true);
|
||||
m_tx_pool.add_transaction_to_black_list(tx);
|
||||
purge_block_data_from_blockchain(bl, tx_processed_count);
|
||||
bvc.m_verification_failed = true;
|
||||
|
|
@ -8102,7 +8102,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
|
|||
|
||||
for (size_t pk_n = 0; pk_n < pub_keys.size(); ++pk_n)
|
||||
{
|
||||
crypto::public_key& pk = pub_keys[pk_n];
|
||||
[[maybe_unused]] crypto::public_key& pk = pub_keys[pk_n];
|
||||
crypto::hash tx_id = null_hash;
|
||||
uint64_t out_n = UINT64_MAX;
|
||||
auto &off = abs_key_offsets[pk_n];
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ MARK_AS_POD_C11(macro_alias_1);
|
|||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL "core"
|
||||
|
||||
extern const command_line::arg_descriptor<uint32_t> arg_db_cache_l2;
|
||||
extern const command_line::arg_descriptor<uint64_t> arg_db_cache_l2;
|
||||
|
||||
namespace currency
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1091,7 +1091,7 @@ namespace currency
|
|||
BOOST_SERIALIZE(attachment)
|
||||
BOOST_END_VERSION_UNDER(1)
|
||||
BOOST_SERIALIZE(proofs)
|
||||
END_BOOST_SERIALIZATION()
|
||||
END_BOOST_SERIALIZATION()
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -736,14 +736,15 @@ namespace currency
|
|||
//------------------------------------------------------------------
|
||||
bool derive_ephemeral_key_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral)
|
||||
{
|
||||
// TODO: re-implement this to avoid double Hs calculation -- sowle
|
||||
crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation);
|
||||
bool r = crypto::generate_key_derivation(tx_public_key, ack.view_secret_key, recv_derivation);
|
||||
bool r = crypto::generate_key_derivation(tx_public_key, ack.view_secret_key, recv_derivation); // recv_derivation = 8 * ack.view_secret_key * tx_public_key
|
||||
CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.view_secret_key << ")");
|
||||
|
||||
r = crypto::derive_public_key(recv_derivation, real_output_index, ack.account_address.spend_public_key, in_ephemeral.pub);
|
||||
r = crypto::derive_public_key(recv_derivation, real_output_index, ack.account_address.spend_public_key, in_ephemeral.pub); // = Hs(recv_derivation, real_output_index) * G + spend_public_key
|
||||
CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to derive_public_key(" << recv_derivation << ", " << real_output_index << ", " << ack.account_address.spend_public_key << ")");
|
||||
|
||||
crypto::derive_secret_key(recv_derivation, real_output_index, ack.spend_secret_key, in_ephemeral.sec);
|
||||
crypto::derive_secret_key(recv_derivation, real_output_index, ack.spend_secret_key, in_ephemeral.sec); // = Hs(recv_derivation, real_output_index) + spend_secret_key
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
|
@ -764,6 +765,8 @@ namespace currency
|
|||
//---------------------------------------------------------------
|
||||
bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki)
|
||||
{
|
||||
// h = Hs(8 * ack.view_secret_key * tx_public_key, real_output_index)
|
||||
// ki = sec * Hp( pub ) = (h + spend_secret_key) * Hp( h * G + spend_public_key )
|
||||
bool r = derive_ephemeral_key_helper(ack, tx_public_key, real_output_index, in_ephemeral);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to call derive_ephemeral_key_helper(...)");
|
||||
|
||||
|
|
@ -1784,7 +1787,7 @@ namespace currency
|
|||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key, crypto::key_derivation& derivation)
|
||||
void encrypt_payload_items(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key, crypto::key_derivation& derivation)
|
||||
{
|
||||
bool r = crypto::generate_key_derivation(destination_addr.view_public_key, tx_random_key.sec, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, void(), "failed to generate_key_derivation");
|
||||
|
|
@ -1816,10 +1819,10 @@ namespace currency
|
|||
}
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key)
|
||||
void encrypt_payload_items(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key)
|
||||
{
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
|
||||
return encrypt_attachments(tx, sender_keys, destination_addr, tx_random_key, derivation);
|
||||
return encrypt_payload_items(tx, sender_keys, destination_addr, tx_random_key, derivation);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
void load_wallet_transfer_info_flags(tools::wallet_public::wallet_transfer_info& x)
|
||||
|
|
@ -2582,7 +2585,7 @@ namespace currency
|
|||
|
||||
//include offers if need
|
||||
tx.attachment = attachments;
|
||||
encrypt_attachments(tx, sender_account_keys, crypt_destination_addr, gen_context.tx_key, result.derivation);
|
||||
encrypt_payload_items(tx, sender_account_keys, crypt_destination_addr, gen_context.tx_key, result.derivation);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -396,8 +396,8 @@ namespace currency
|
|||
bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t current_blockchain_size, uint64_t current_time);
|
||||
crypto::key_derivation get_encryption_key_derivation(bool is_income, const transaction& tx, const account_keys& acc_keys);
|
||||
bool decrypt_payload_items(bool is_income, const transaction& tx, const account_keys& acc_keys, std::vector<payload_items_v>& decrypted_items);
|
||||
void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key, crypto::key_derivation& derivation);
|
||||
void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key);
|
||||
void encrypt_payload_items(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key, crypto::key_derivation& derivation);
|
||||
void encrypt_payload_items(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key);
|
||||
bool is_derivation_used_to_encrypt(const transaction& tx, const crypto::key_derivation& derivation);
|
||||
bool is_address_like_wrapped(const std::string& addr);
|
||||
void load_wallet_transfer_info_flags(tools::wallet_public::wallet_transfer_info& x);
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ namespace currency
|
|||
FIELD(ms_keys_count)
|
||||
FIELD(separately_signed_tx_complete)
|
||||
FIELD(htlc_origin)
|
||||
FIELD(asset_id)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 5bb46f99d5554d0c80752833a6bfd7ef4458174b
|
||||
Subproject commit bcd4021364bbcd29a4208225de33a359ee35a447
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Copyright (c) 2014-2025 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -144,8 +144,7 @@ namespace nodetool
|
|||
HANDLE_INVOKE_T2(COMMAND_REQUEST_STAT_INFO, &node_server::handle_get_stat_info)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_NETWORK_STATE, &node_server::handle_get_network_state)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_PEER_ID, &node_server::handle_get_peer_id)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_LOG, &node_server::handle_request_log)
|
||||
HANDLE_INVOKE_T2(COMMAND_SET_LOG_LEVEL, &node_server::handle_set_log_level)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_ANONYMIZED_PEERS, &node_server::handle_request_anonymized_peers)
|
||||
}
|
||||
#endif
|
||||
CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(m_payload_handler, typename t_payload_net_handler::connection_context&)
|
||||
|
|
@ -160,8 +159,7 @@ namespace nodetool
|
|||
int handle_get_stat_info(int command, typename COMMAND_REQUEST_STAT_INFO::request& arg, typename COMMAND_REQUEST_STAT_INFO::response& rsp, p2p_connection_context& context);
|
||||
int handle_get_network_state(int command, COMMAND_REQUEST_NETWORK_STATE::request& arg, COMMAND_REQUEST_NETWORK_STATE::response& rsp, p2p_connection_context& context);
|
||||
int handle_get_peer_id(int command, COMMAND_REQUEST_PEER_ID::request& arg, COMMAND_REQUEST_PEER_ID::response& rsp, p2p_connection_context& context);
|
||||
int handle_request_log(int command, COMMAND_REQUEST_LOG::request& arg, COMMAND_REQUEST_LOG::response& rsp, p2p_connection_context& context);
|
||||
int handle_set_log_level(int command, COMMAND_SET_LOG_LEVEL::request& arg, COMMAND_SET_LOG_LEVEL::response& rsp, p2p_connection_context& context);
|
||||
int handle_request_anonymized_peers(int command, COMMAND_REQUEST_ANONYMIZED_PEERS::request& req, COMMAND_REQUEST_ANONYMIZED_PEERS::response& rsp, p2p_connection_context& context);
|
||||
private:
|
||||
#endif
|
||||
bool init_config();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Copyright (c) 2014-2025 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -1321,7 +1321,7 @@ namespace nodetool
|
|||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
int node_server<t_payload_net_handler>::handle_request_log(int command, COMMAND_REQUEST_LOG::request& req, COMMAND_REQUEST_LOG::response& rsp, p2p_connection_context& context)
|
||||
int node_server<t_payload_net_handler>::handle_request_anonymized_peers(int command, COMMAND_REQUEST_ANONYMIZED_PEERS::request& req, COMMAND_REQUEST_ANONYMIZED_PEERS::response& rsp, p2p_connection_context& context)
|
||||
{
|
||||
if (!check_trust(req.tr))
|
||||
{
|
||||
|
|
@ -1329,30 +1329,15 @@ namespace nodetool
|
|||
return 1;
|
||||
}
|
||||
|
||||
rsp.current_log_level = static_cast<int64_t>(log_space::get_set_log_detalisation_level());
|
||||
tools::get_log_chunk_gzipped(req.log_chunk_offset, req.log_chunk_size, rsp.log_chunk, rsp.error);
|
||||
rsp.current_log_size = tools::get_log_file_size();
|
||||
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cn_context)
|
||||
{
|
||||
auto& el = rsp.peers.emplace_back();
|
||||
el.inbound = cn_context.m_is_income;
|
||||
el.time_started = cn_context.m_started;
|
||||
return true;
|
||||
});
|
||||
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
int node_server<t_payload_net_handler>::handle_set_log_level(int command, COMMAND_SET_LOG_LEVEL::request& req, COMMAND_SET_LOG_LEVEL::response& rsp, p2p_connection_context& context)
|
||||
{
|
||||
if (!check_trust(req.tr))
|
||||
{
|
||||
drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rsp.old_log_level = static_cast<int64_t>(log_space::get_set_log_detalisation_level());
|
||||
log_space::get_set_log_detalisation_level(true, static_cast<int>(req.new_log_level));
|
||||
rsp.current_log_level = static_cast<int64_t>(log_space::get_set_log_detalisation_level());
|
||||
|
||||
if (rsp.old_log_level != rsp.current_log_level)
|
||||
{
|
||||
LOG_PRINT_CC(context, "log level changed by debug command: " << rsp.old_log_level << " -> " << rsp.current_log_level, LOG_LEVEL_0);
|
||||
}
|
||||
std::shuffle(rsp.peers.begin(), rsp.peers.end(), crypto::uniform_random_bit_generator());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2025 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -425,65 +425,36 @@ namespace nodetool
|
|||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct COMMAND_REQUEST_LOG
|
||||
struct COMMAND_REQUEST_ANONYMIZED_PEERS
|
||||
{
|
||||
const static int ID = P2P_COMMANDS_POOL_BASE + 7;
|
||||
const static int ID = P2P_COMMANDS_POOL_BASE + 100;
|
||||
|
||||
struct request
|
||||
{
|
||||
proof_of_trust tr;
|
||||
uint64_t log_chunk_offset;
|
||||
uint64_t log_chunk_size;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tr)
|
||||
KV_SERIALIZE(log_chunk_offset)
|
||||
KV_SERIALIZE(log_chunk_size)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct anonymized_peer_info
|
||||
{
|
||||
uint64_t time_started;
|
||||
bool inbound;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(time_started)
|
||||
KV_SERIALIZE(inbound)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
int64_t current_log_level;
|
||||
uint64_t current_log_size;
|
||||
std::string error;
|
||||
std::string log_chunk;
|
||||
std::vector<anonymized_peer_info> peers;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(current_log_level)
|
||||
KV_SERIALIZE(current_log_size)
|
||||
KV_SERIALIZE(error)
|
||||
KV_SERIALIZE(log_chunk)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct COMMAND_SET_LOG_LEVEL
|
||||
{
|
||||
const static int ID = P2P_COMMANDS_POOL_BASE + 8;
|
||||
|
||||
struct request
|
||||
{
|
||||
proof_of_trust tr;
|
||||
int64_t new_log_level;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tr)
|
||||
KV_SERIALIZE(new_log_level)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
int64_t old_log_level;
|
||||
int64_t current_log_level;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(old_log_level)
|
||||
KV_SERIALIZE(current_log_level)
|
||||
KV_SERIALIZE(peers)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -983,7 +983,7 @@ namespace currency
|
|||
|
||||
if(!tvc.m_should_be_relayed)
|
||||
{
|
||||
LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed");
|
||||
LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed, tx blob: " << req.tx_as_hex);
|
||||
res.status = "Not relayed";
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -232,7 +232,10 @@ namespace tools
|
|||
else
|
||||
{
|
||||
m_password.push_back(ch);
|
||||
std::cout << (char_to_replace_user_input != '\0' ? char_to_replace_user_input : ch);
|
||||
std::cout.put((
|
||||
char_to_replace_user_input != '\0' ?
|
||||
char_to_replace_user_input : static_cast<char>(ch))
|
||||
).flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2024 Zano Project
|
||||
// Copyright (c) 2014-2025 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -96,22 +96,18 @@ namespace ph = boost::placeholders;
|
|||
} \
|
||||
catch (const tools::error::transfer_error& e) \
|
||||
{ \
|
||||
LOG_ERROR("unknown transfer error: " << e.to_string()); \
|
||||
fail_msg_writer() << "unknown transfer error: " << e.what(); \
|
||||
fail_msg_writer() << "(transfer) " << e.what(); \
|
||||
} \
|
||||
catch (const tools::error::wallet_internal_error& e) \
|
||||
{ \
|
||||
LOG_ERROR("internal error: " << e.to_string()); \
|
||||
fail_msg_writer() << "internal error: " << e.what(); \
|
||||
fail_msg_writer() << "(internal) " << e.what(); \
|
||||
} \
|
||||
catch (const std::exception& e) \
|
||||
{ \
|
||||
LOG_ERROR("unexpected error: " << e.what()); \
|
||||
fail_msg_writer() << "unexpected error: " << e.what(); \
|
||||
fail_msg_writer() << "(unexpected) " << e.what(); \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
LOG_ERROR("Unknown error"); \
|
||||
fail_msg_writer() << "unknown error"; \
|
||||
} \
|
||||
|
||||
|
|
@ -145,6 +141,8 @@ namespace
|
|||
const command_line::arg_descriptor<std::string> arg_voting_config_file("voting-config-file", "Set voting config instead of getting if from daemon", "");
|
||||
const command_line::arg_descriptor<bool> arg_no_password_confirmations("no-password-confirmation", "Enable/Disable password confirmation for transactions", false);
|
||||
const command_line::arg_descriptor<bool> arg_seed_doctor("seed-doctor", "Experimental: if your seed is not working for recovery this is likely because you've made a mistake whene you were doing back up(typo, wrong words order, missing word). This experimental code will attempt to recover seed phrase from with few approaches.");
|
||||
const command_line::arg_descriptor<bool> arg_no_whitelist("no-white-list", "Do not load white list from interned.");
|
||||
const command_line::arg_descriptor<std::string> arg_restore_ki_in_wo_wallet("restore-ki-in-wo-wallet", "Watch-only missing key images restoration. Please, DON'T use it unless you 100% sure of what are you doing.", "");
|
||||
|
||||
const command_line::arg_descriptor< std::vector<std::string> > arg_command ("command", "");
|
||||
|
||||
|
|
@ -301,7 +299,7 @@ simple_wallet::simple_wallet()
|
|||
m_cmd_binder.set_handler("export_recent_transfers", boost::bind(&simple_wallet::export_recent_transfers, this, ph::_1), "list_recent_transfers_tx - Write recent transfer in json to wallet_recent_transfers.txt");
|
||||
m_cmd_binder.set_handler("list_outputs", boost::bind(&simple_wallet::list_outputs, this, ph::_1), "list_outputs [spent|unspent] [ticker=ZANO] [unknown] - Lists all the outputs. The result may be filtered by spent status, asset ticker or unknown asset ids.");
|
||||
m_cmd_binder.set_handler("lo", boost::bind(&simple_wallet::list_outputs, this, ph::_1), "alias for list_outputs");
|
||||
m_cmd_binder.set_handler("dump_transfers", boost::bind(&simple_wallet::dump_trunsfers, this, ph::_1), "dump_transfers - Write transfers in json to dump_transfers.txt");
|
||||
m_cmd_binder.set_handler("dump_transfers", boost::bind(&simple_wallet::dump_transfers, this, ph::_1), "dump_transfers - Write transfers in json to dump_transfers.txt");
|
||||
m_cmd_binder.set_handler("dump_keyimages", boost::bind(&simple_wallet::dump_key_images, this, ph::_1), "dump_keyimages - Write key_images in json to dump_key_images.txt");
|
||||
m_cmd_binder.set_handler("payments", boost::bind(&simple_wallet::show_payments, this, ph::_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,ph::_1), "Show blockchain height");
|
||||
|
|
@ -408,6 +406,16 @@ void process_wallet_command_line_params(const po::variables_map& vm, tools::wall
|
|||
wal.set_disable_tor_relay(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (command_line::has_arg(vm, arg_no_whitelist))
|
||||
{
|
||||
wal.set_use_assets_whitelisting(!command_line::get_arg(vm, arg_no_whitelist));
|
||||
}
|
||||
else
|
||||
{
|
||||
wal.set_use_assets_whitelisting(true);
|
||||
}
|
||||
|
||||
|
||||
if (command_line::has_arg(vm, arg_set_timeout))
|
||||
{
|
||||
|
|
@ -513,8 +521,10 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
|
|||
else
|
||||
{
|
||||
bool r = open_wallet(m_wallet_file, pwd_container.password());
|
||||
CHECK_AND_ASSERT_MES(r, false, "could not open account");
|
||||
CHECK_AND_ASSERT_MES(r, false, "wallet could not be opened");
|
||||
was_open = true;
|
||||
if (!process_ki_restoration())
|
||||
return false;
|
||||
}
|
||||
process_wallet_command_line_params(vm, *m_wallet, false);
|
||||
|
||||
|
|
@ -554,6 +564,8 @@ void simple_wallet::handle_command_line(const boost::program_options::variables_
|
|||
m_disable_tor = command_line::get_arg(vm, arg_disable_tor_relay);
|
||||
m_voting_config_file = command_line::get_arg(vm, arg_voting_config_file);
|
||||
m_no_password_confirmations = command_line::get_arg(vm, arg_no_password_confirmations);
|
||||
m_no_whitelist = command_line::get_arg(vm, arg_no_whitelist);
|
||||
m_restore_ki_in_wo_wallet = command_line::get_arg(vm, arg_restore_ki_in_wo_wallet);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -615,6 +627,7 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas
|
|||
m_wallet->generate(epee::string_encoding::utf8_to_wstring(m_wallet_file), password, create_auditable_wallet);
|
||||
message_writer(epee::log_space::console_color_white, true) << "Generated new " << (create_auditable_wallet ? "AUDITABLE" : "") << " wallet: " << m_wallet->get_account().get_public_address_str();
|
||||
display_vote_info(*m_wallet);
|
||||
preconfig_wallet_obj();
|
||||
std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush;
|
||||
if (m_wallet->is_auditable())
|
||||
std::cout << "tracking seed: " << std::endl << m_wallet->get_account().get_tracking_seed() << std::endl << std::flush;
|
||||
|
|
@ -663,6 +676,7 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st
|
|||
std::cout << "tracking seed: " << std::endl << m_wallet->get_account().get_tracking_seed() << std::endl << std::flush;
|
||||
}
|
||||
display_vote_info(*m_wallet);
|
||||
preconfig_wallet_obj();
|
||||
if (m_do_not_set_date)
|
||||
m_wallet->reset_creation_time(0);
|
||||
}
|
||||
|
|
@ -689,7 +703,12 @@ bool simple_wallet::restore_wallet(const std::string& wallet_file, const std::st
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
||||
void simple_wallet::preconfig_wallet_obj()
|
||||
{
|
||||
if (m_no_whitelist)
|
||||
m_wallet->set_use_assets_whitelisting(false);
|
||||
}
|
||||
//
|
||||
bool simple_wallet::open_wallet(const string &wallet_file, const std::string& password)
|
||||
{
|
||||
m_wallet_file = wallet_file;
|
||||
|
|
@ -698,20 +717,25 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa
|
|||
if (!m_voting_config_file.empty())
|
||||
m_wallet->set_votes_config_path(m_voting_config_file);
|
||||
|
||||
auto print_wallet_opened_msg = [&](){
|
||||
message_writer(epee::log_space::console_color_white, true) << "Opened" << (m_wallet->is_auditable() ? " auditable" : "") << (m_wallet->is_watch_only() ? " watch-only" : "") << " wallet: " << m_wallet->get_account().get_public_address_str();
|
||||
};
|
||||
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_wallet->load(epee::string_encoding::utf8_to_wstring(m_wallet_file), password);
|
||||
message_writer(epee::log_space::console_color_white, true) << "Opened" << (m_wallet->is_auditable() ? " auditable" : "") << (m_wallet->is_watch_only() ? " watch-only" : "") << " wallet: " << m_wallet->get_account().get_public_address_str();
|
||||
print_wallet_opened_msg();
|
||||
preconfig_wallet_obj();
|
||||
display_vote_info(*m_wallet);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
catch (const tools::error::wallet_load_notice_wallet_restored& /*e*/)
|
||||
{
|
||||
message_writer(epee::log_space::console_color_white, true) << "Opened wallet: " << m_wallet->get_account().get_public_address_str();
|
||||
print_wallet_opened_msg();
|
||||
message_writer(epee::log_space::console_color_red, true) << "NOTICE: Wallet file was damaged and restored.";
|
||||
break;
|
||||
}
|
||||
|
|
@ -766,6 +790,27 @@ bool simple_wallet::save(const std::vector<std::string> &args)
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::process_ki_restoration()
|
||||
{
|
||||
if (!m_restore_ki_in_wo_wallet.empty())
|
||||
{
|
||||
std::wstring wo_filename = epee::string_encoding::utf8_to_wstring(m_restore_ki_in_wo_wallet);
|
||||
CHECK_AND_ASSERT_THROW_MES(std::filesystem::exists(wo_filename), "cannot open " << m_restore_ki_in_wo_wallet);
|
||||
|
||||
tools::password_container wo_password;
|
||||
if (!wo_password.read_password("Enter password for wallet " + m_restore_ki_in_wo_wallet + " :"))
|
||||
return false;
|
||||
|
||||
m_wallet->restore_key_images_in_wo_wallet(wo_filename, wo_password.password());
|
||||
|
||||
success_msg_writer() << "Missing key images have been successfully repared in " << m_restore_ki_in_wo_wallet << ENDL;
|
||||
|
||||
return false; // means the wallet processing should stop now
|
||||
}
|
||||
|
||||
return true; // means the wallet can load and work further normally
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
#ifdef CPU_MINING_ENABLED
|
||||
bool simple_wallet::start_mining(const std::vector<std::string>& args)
|
||||
{
|
||||
|
|
@ -898,7 +943,7 @@ void simple_wallet::on_transfer2(const tools::wallet_public::wallet_transfer_inf
|
|||
", tx " << wti.tx_hash;
|
||||
for (const auto& st : wti.subtransfers)
|
||||
{
|
||||
epee::log_space::console_colors color = st.is_income ? epee::log_space::console_color_green : epee::log_space::console_color_magenta;
|
||||
[[maybe_unused]] epee::log_space::console_colors color = st.is_income ? epee::log_space::console_color_green : epee::log_space::console_color_magenta;
|
||||
uint64_t decimal_points = CURRENCY_DISPLAY_DECIMAL_POINT;
|
||||
std::string token_info = get_token_info_string(st.asset_id, decimal_points);
|
||||
|
||||
|
|
@ -1131,7 +1176,7 @@ std::string wti_to_text_line(const tools::wallet_public::wallet_transfer_info& w
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::export_recent_transfers(const std::vector<std::string>& args)
|
||||
{
|
||||
bool export_to_json = true;
|
||||
[[maybe_unused]] bool export_to_json = true;
|
||||
bool ignore_pos = false;
|
||||
if (args.size() > 1)
|
||||
{
|
||||
|
|
@ -1167,12 +1212,12 @@ bool simple_wallet::export_recent_transfers(const std::vector<std::string>& args
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::dump_trunsfers(const std::vector<std::string>& args)
|
||||
bool simple_wallet::dump_transfers(const std::vector<std::string>& args)
|
||||
{
|
||||
|
||||
stringstream ss;
|
||||
success_msg_writer() << "Generating text....";
|
||||
m_wallet->dump_trunsfers(ss);
|
||||
m_wallet->dump_transfers(ss);
|
||||
success_msg_writer() << "Storing text to dump_transfers.txt....";
|
||||
file_io_utils::save_string_to_file(log_space::log_singletone::get_default_log_folder() + "/dump_transfers.txt", ss.str());
|
||||
success_msg_writer() << "Done....";
|
||||
|
|
@ -1850,6 +1895,12 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::show_seed(const std::vector<std::string> &args)
|
||||
{
|
||||
if (m_wallet->is_watch_only())
|
||||
{
|
||||
fail_msg_writer() << "watch-only wallet doesn't have the full set of keys, hence no seed phrase can be generated";
|
||||
return false;
|
||||
}
|
||||
|
||||
CONFIRM_WITH_PASSWORD();
|
||||
success_msg_writer() << "Please enter a password to secure this seed. Securing your seed is HIGHLY recommended. Leave password blank to stay unsecured.";
|
||||
success_msg_writer(true) << "Remember, restoring a wallet from Secured Seed can only be done if you know its password.";
|
||||
|
|
@ -2037,12 +2088,10 @@ bool simple_wallet::save_watch_only(const std::vector<std::string> &args)
|
|||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_ERROR("unexpected error: " << e.what());
|
||||
fail_msg_writer() << "unexpected error: " << e.what();
|
||||
fail_msg_writer() << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_ERROR("Unknown error");
|
||||
fail_msg_writer() << "unknown error";
|
||||
}
|
||||
return true;
|
||||
|
|
@ -2106,12 +2155,10 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args)
|
|||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_ERROR("unexpected error: " << e.what());
|
||||
fail_msg_writer() << "unexpected error: " << e.what();
|
||||
fail_msg_writer() << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_ERROR("Unknown error");
|
||||
fail_msg_writer() << "unknown error";
|
||||
}
|
||||
return true;
|
||||
|
|
@ -2132,12 +2179,10 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args)
|
|||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_ERROR("unexpected error: " << e.what());
|
||||
fail_msg_writer() << "unexpected error: " << e.what();
|
||||
fail_msg_writer() << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_ERROR("Unknown error");
|
||||
fail_msg_writer() << "unknown error";
|
||||
}
|
||||
return true;
|
||||
|
|
@ -2745,7 +2790,6 @@ bool simple_wallet::sweep_bare_outs(const std::vector<std::string> &args)
|
|||
{
|
||||
CONFIRM_WITH_PASSWORD();
|
||||
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
|
||||
bool r = false;
|
||||
|
||||
if (args.size() > 1)
|
||||
{
|
||||
|
|
@ -3097,7 +3141,7 @@ int seed_doctor()
|
|||
}
|
||||
|
||||
bool pass_protected = false;
|
||||
bool success = account_base::is_seed_password_protected(seed, pass_protected);
|
||||
account_base::is_seed_password_protected(seed, pass_protected);
|
||||
success_msg_writer() << "SECURED_SEED: " << (pass_protected ? "true" : "false");
|
||||
|
||||
if (pass_protected)
|
||||
|
|
@ -3203,7 +3247,7 @@ int seed_doctor()
|
|||
success_msg_writer() << "No address and no checksum, recovery is limited only to date reset";
|
||||
std::string result = boost::algorithm::join(words, " ");
|
||||
account_base acc;
|
||||
bool r = acc.restore_from_seed_phrase(result, passphrase);
|
||||
acc.restore_from_seed_phrase(result, passphrase);
|
||||
success_msg_writer() << "Potential seed candidate:\n" << result << "\nAddress: " << acc.get_public_address_str();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
@ -3297,6 +3341,8 @@ int main(int argc, char* argv[])
|
|||
command_line::add_arg(desc_params, command_line::arg_generate_rpc_autodoc);
|
||||
command_line::add_arg(desc_params, arg_seed_doctor);
|
||||
command_line::add_arg(desc_params, arg_derive_custom_seed);
|
||||
command_line::add_arg(desc_params, arg_no_whitelist);
|
||||
command_line::add_arg(desc_params, arg_restore_ki_in_wo_wallet);
|
||||
|
||||
|
||||
tools::wallet_rpc_server::init_options(desc_params);
|
||||
|
|
@ -3323,7 +3369,7 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
else if (command_line::get_arg(vm, command_line::arg_version))
|
||||
{
|
||||
success_msg_writer() << CURRENCY_NAME << " wallet v" << PROJECT_VERSION_LONG;
|
||||
success_msg_writer() << CURRENCY_NAME << " simplewallet v" << PROJECT_VERSION_LONG;
|
||||
exit_requested = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3349,6 +3395,7 @@ int main(int argc, char* argv[])
|
|||
std::string log_dir;
|
||||
log_dir = log_file_path.has_parent_path() ? log_file_path.parent_path().string() : log_space::log_singletone::get_default_log_folder();
|
||||
log_space::log_singletone::add_logger(LOGGER_FILE, log_file_path.filename().string().c_str(), log_dir.c_str(), LOG_LEVEL_4);
|
||||
LOG_PRINT_L0(ENDL << ENDL);
|
||||
message_writer(epee::log_space::console_color_white, true, std::string(), LOG_LEVEL_0) << CURRENCY_NAME << " simplewallet v" << PROJECT_VERSION_LONG;
|
||||
|
||||
if (command_line::has_arg(vm, command_line::arg_log_level))
|
||||
|
|
@ -3488,7 +3535,7 @@ int main(int argc, char* argv[])
|
|||
if (command_line::get_arg(vm, arg_generate_new_wallet).size() || command_line::get_arg(vm, arg_generate_new_auditable_wallet).size())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
wal.set_use_assets_whitelisting(true);
|
||||
|
||||
wal.callback(callback);
|
||||
|
||||
if (!offline_mode)
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ namespace currency
|
|||
bool show_balance(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool list_recent_transfers(const std::vector<std::string>& args);
|
||||
bool export_recent_transfers(const std::vector<std::string>& args);
|
||||
bool dump_trunsfers(const std::vector<std::string>& args);
|
||||
bool dump_transfers(const std::vector<std::string>& args);
|
||||
bool dump_key_images(const std::vector<std::string>& args);
|
||||
bool show_incoming_transfers(const std::vector<std::string> &args);
|
||||
bool show_staking_history(const std::vector<std::string>& args);
|
||||
|
|
@ -182,6 +182,9 @@ namespace currency
|
|||
};
|
||||
|
||||
private:
|
||||
void preconfig_wallet_obj();
|
||||
bool process_ki_restoration();
|
||||
|
||||
std::string m_wallet_file;
|
||||
std::string m_generate_new;
|
||||
std::string m_generate_new_aw;
|
||||
|
|
@ -198,6 +201,8 @@ namespace currency
|
|||
std::string m_restore_wallet;
|
||||
std::string m_voting_config_file;
|
||||
bool m_no_password_confirmations = false;
|
||||
bool m_no_whitelist = false;
|
||||
std::string m_restore_ki_in_wo_wallet;
|
||||
|
||||
crypto::hash m_password_hash;
|
||||
uint64_t m_password_salt;
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
#define PROJECT_MAJOR_VERSION "2"
|
||||
#define PROJECT_MINOR_VERSION "1"
|
||||
#define PROJECT_REVISION "7"
|
||||
#define PROJECT_REVISION "8"
|
||||
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
|
||||
|
||||
#define PROJECT_VERSION_BUILD_NO 424
|
||||
#define PROJECT_VERSION_BUILD_NO 427
|
||||
#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 "]"
|
||||
|
|
|
|||
|
|
@ -604,7 +604,9 @@ namespace plain_wallet
|
|||
{
|
||||
PLAIN_WALLET_BEGIN_TRY_ENTRY();
|
||||
GET_INSTANCE_PTR(inst_ptr);
|
||||
return inst_ptr->gwm.invoke(h, params);
|
||||
std::string res = inst_ptr->gwm.invoke(h, params);
|
||||
tools::sanitize_utf8(res);
|
||||
return res;
|
||||
PLAIN_WALLET_CATCH();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,11 @@ namespace tools
|
|||
m_core_runtime_config = currency::get_default_core_runtime_config();
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
wallet2::~wallet2()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t wallet2::get_max_unlock_time_from_receive_indices(const currency::transaction& tx, const wallet_public::employed_tx_entries& td)
|
||||
{
|
||||
uint64_t max_unlock_time = 0;
|
||||
|
|
@ -717,7 +722,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
{
|
||||
// normal wallet, calculate and store key images for own outs
|
||||
currency::keypair in_ephemeral = AUTO_VAL_INIT(in_ephemeral);
|
||||
currency::generate_key_image_helper(m_account.get_keys(), ptc.tx_pub_key, o, in_ephemeral, ki);
|
||||
currency::generate_key_image_helper(m_account.get_keys(), ptc.tx_pub_key, /* output index */ o, in_ephemeral, ki);
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(in_ephemeral.pub == out_key, "key_image generated ephemeral public key that does not match with output_key");
|
||||
}
|
||||
|
||||
|
|
@ -4218,29 +4223,25 @@ void wallet2::sign_transfer(const std::string& tx_sources_blob, std::string& sig
|
|||
// assumed to be called from normal, non-watch-only wallet
|
||||
THROW_IF_FALSE_WALLET_EX(!m_watch_only, error::wallet_common_error, "watch-only wallet is unable to sign transfers, you need to use normal wallet for that");
|
||||
|
||||
// decrypt the blob
|
||||
std::string decrypted_src_blob = crypto::chacha_crypt(tx_sources_blob, m_account.get_keys().view_secret_key);
|
||||
// decrypt the blob
|
||||
std::string decrypted_src_blob = crypto::chacha_crypt(tx_sources_blob, m_account.get_keys().view_secret_key);
|
||||
|
||||
// deserialize args
|
||||
currency::finalized_tx ft = AUTO_VAL_INIT(ft);
|
||||
currency::finalized_tx ft{};
|
||||
bool r = t_unserializable_object_from_blob(ft.ftp, decrypted_src_blob);
|
||||
THROW_IF_FALSE_WALLET_EX(r, error::wallet_common_error, "Failed to decrypt tx sources blob");
|
||||
|
||||
// make sure unsigned tx was created with the same keys
|
||||
THROW_IF_FALSE_WALLET_EX(ft.ftp.spend_pub_key == m_account.get_keys().account_address.spend_public_key, error::wallet_common_error, "The was created in a different wallet, keys missmatch");
|
||||
|
||||
finalize_transaction(ft.ftp, ft.tx, ft.one_time_key, false);
|
||||
finalize_transaction(ft.ftp, ft, false, true);
|
||||
|
||||
WLT_LOG_L0("sign_transfer: tx " << ft.tx_id << " has been successfully signed");
|
||||
|
||||
// calculate key images for each change output
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(
|
||||
crypto::generate_key_derivation(
|
||||
m_account.get_keys().account_address.view_public_key,
|
||||
ft.one_time_key,
|
||||
derivation),
|
||||
"internal error: sign_transfer: failed to generate key derivation("
|
||||
<< m_account.get_keys().account_address.view_public_key
|
||||
<< ", view secret key: " << ft.one_time_key << ")");
|
||||
crypto::key_derivation derivation{};
|
||||
r = crypto::generate_key_derivation(m_account.get_keys().account_address.view_public_key, ft.one_time_key, derivation);
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "sign_transfer: generate_key_derivation failed, tx: " << ft.tx_id);
|
||||
|
||||
for (size_t i = 0; i < ft.tx.vout.size(); ++i)
|
||||
{
|
||||
|
|
@ -4250,7 +4251,7 @@ void wallet2::sign_transfer(const std::string& tx_sources_blob, std::string& sig
|
|||
crypto::public_key ephemeral_pub{};
|
||||
if (!crypto::derive_public_key(derivation, i, m_account.get_keys().account_address.spend_public_key, ephemeral_pub))
|
||||
{
|
||||
WLT_LOG_ERROR("derive_public_key failed for tx " << get_transaction_hash(ft.tx) << ", out # " << i);
|
||||
WLT_LOG_ERROR("derive_public_key failed for tx " << ft.tx_id << ", out # " << i);
|
||||
}
|
||||
|
||||
if (out_pk == ephemeral_pub)
|
||||
|
|
@ -4263,6 +4264,7 @@ void wallet2::sign_transfer(const std::string& tx_sources_blob, std::string& sig
|
|||
crypto::generate_key_image(ephemeral_pub, ephemeral_sec, ki);
|
||||
|
||||
ft.outs_key_images.push_back(make_serializable_pair(static_cast<uint64_t>(i), ki));
|
||||
WLT_LOG_L1("sign_transfer: tx " << ft.tx_id << ", out index: " << i << ", ki: " << ki);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4391,6 +4393,9 @@ bool wallet2::attach_asset_descriptor(const wallet_public::COMMAND_ATTACH_ASSET_
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::transaction& tx)
|
||||
{
|
||||
// assumed to be called from watch-only wallet
|
||||
THROW_IF_FALSE_WALLET_EX(m_watch_only, error::wallet_common_error, "submit_transfer should be called in watch-only wallet only");
|
||||
|
||||
// decrypt sources
|
||||
std::string decrypted_src_blob = crypto::chacha_crypt(signed_tx_blob, m_account.get_keys().view_secret_key);
|
||||
|
||||
|
|
@ -4401,9 +4406,36 @@ void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::trans
|
|||
tx = ft.tx;
|
||||
crypto::hash tx_hash = get_transaction_hash(tx);
|
||||
|
||||
// foolproof
|
||||
// foolproof check
|
||||
THROW_IF_FALSE_WALLET_CMN_ERR_EX(ft.ftp.spend_pub_key == m_account.get_keys().account_address.spend_public_key, "The given tx was created in a different wallet, keys missmatch, tx hash: " << tx_hash);
|
||||
|
||||
// prepare and check data for watch-only outkey2ki before sending the tx
|
||||
std::vector<std::pair<crypto::public_key, crypto::key_image>> pk_ki_to_be_added;
|
||||
std::vector<std::pair<uint64_t, crypto::key_image>> tri_ki_to_be_added;
|
||||
if (m_watch_only)
|
||||
{
|
||||
for (auto& p : ft.outs_key_images)
|
||||
{
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(p.first < tx.vout.size(), "outs_key_images has invalid out index: " << p.first << ", tx.vout.size() = " << tx.vout.size());
|
||||
std::list<htlc_info> stub{};
|
||||
const crypto::public_key& pk = out_get_pub_key(tx.vout[p.first], stub);
|
||||
pk_ki_to_be_added.push_back(std::make_pair(pk, p.second));
|
||||
}
|
||||
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(tx.vin.size() == ft.ftp.sources.size(), "tx.vin and ft.ftp.sources sizes missmatch");
|
||||
for (size_t i = 0; i < tx.vin.size(); ++i)
|
||||
{
|
||||
const crypto::key_image& ki = get_key_image_from_txin_v(tx.vin[i]);
|
||||
const auto& src = ft.ftp.sources[i];
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(src.real_output < src.outputs.size(), "src.real_output is out of bounds: " << src.real_output);
|
||||
const crypto::public_key& out_key = src.outputs[src.real_output].stealth_address;
|
||||
tri_ki_to_be_added.push_back(std::make_pair(src.transfer_index, ki));
|
||||
pk_ki_to_be_added.push_back(std::make_pair(out_key, ki));
|
||||
}
|
||||
}
|
||||
|
||||
// SEND the transaction
|
||||
|
||||
try
|
||||
{
|
||||
send_transaction_to_network(tx);
|
||||
|
|
@ -4419,38 +4451,16 @@ void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::trans
|
|||
add_sent_tx_detailed_info(tx, ft.ftp.attachments, ft.ftp.prepared_destinations, ft.ftp.selected_transfers);
|
||||
m_tx_keys.insert(std::make_pair(tx_hash, ft.one_time_key));
|
||||
|
||||
// populate and store key images from own outputs, because otherwise a watch-only wallet cannot calculate it
|
||||
if (m_watch_only)
|
||||
{
|
||||
std::vector<std::pair<crypto::public_key, crypto::key_image>> pk_ki_to_be_added;
|
||||
std::vector<std::pair<uint64_t, crypto::key_image>> tri_ki_to_be_added;
|
||||
|
||||
for (auto& p : ft.outs_key_images)
|
||||
{
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(p.first < tx.vout.size(), "outs_key_images has invalid out index: " << p.first << ", tx.vout.size() = " << tx.vout.size());
|
||||
std::list<htlc_info> stub{};
|
||||
const crypto::public_key& pk = out_get_pub_key(tx.vout[p.first], stub);
|
||||
pk_ki_to_be_added.push_back(std::make_pair(pk, p.second));
|
||||
}
|
||||
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(tx.vin.size() == ft.ftp.sources.size(), "tx.vin and ft.ftp.sources sizes missmatch");
|
||||
for (size_t i = 0; i < tx.vin.size(); ++i)
|
||||
{
|
||||
const crypto::key_image& ki = get_key_image_from_txin_v(tx.vin[i]);
|
||||
|
||||
const auto& src = ft.ftp.sources[i];
|
||||
THROW_IF_FALSE_WALLET_INT_ERR_EX(src.real_output < src.outputs.size(), "src.real_output is out of bounds: " << src.real_output);
|
||||
const crypto::public_key& out_key = src.outputs[src.real_output].stealth_address;
|
||||
|
||||
tri_ki_to_be_added.push_back(std::make_pair(src.transfer_index, ki));
|
||||
pk_ki_to_be_added.push_back(std::make_pair(out_key, ki));
|
||||
}
|
||||
|
||||
for (auto& p : pk_ki_to_be_added)
|
||||
{
|
||||
auto it = m_pending_key_images.find(p.first);
|
||||
if (it != m_pending_key_images.end())
|
||||
{
|
||||
LOG_PRINT_YELLOW("warning: for tx " << tx_hash << " out pub key " << p.first << " already exist in m_pending_key_images, ki: " << it->second << ", proposed new ki: " << p.second, LOG_LEVEL_0);
|
||||
if (it->second != p.second)
|
||||
LOG_PRINT_YELLOW("warning: for tx " << tx_hash << " out pub key " << p.first << " already exist in m_pending_key_images, ki: " << it->second << ", proposed new ki: " << p.second, LOG_LEVEL_0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -5122,7 +5132,11 @@ bool wallet2::reset_history()
|
|||
std::wstring file_path = m_wallet_file;
|
||||
account_base acc_tmp = m_account;
|
||||
auto tx_keys = m_tx_keys;
|
||||
auto pending_key_images = m_pending_key_images;
|
||||
crypto::hash genesis_id = m_chain.get_genesis();
|
||||
clear();
|
||||
m_chain.set_genesis(genesis_id);
|
||||
m_pending_key_images = pending_key_images;
|
||||
m_tx_keys = tx_keys;
|
||||
m_account = acc_tmp;
|
||||
m_password = pass;
|
||||
|
|
@ -5812,9 +5826,9 @@ struct local_transfers_struct
|
|||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
void wallet2::dump_trunsfers(std::stringstream& ss, bool verbose, const crypto::public_key& asset_id) const
|
||||
void wallet2::dump_transfers(std::stringstream& ss, bool verbose, const crypto::public_key& asset_id_to_filter) const
|
||||
{
|
||||
bool filter_by_asset_id = asset_id != currency::null_pkey;
|
||||
bool filter_by_asset_id = asset_id_to_filter != currency::null_pkey;
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
|
|
@ -5824,7 +5838,7 @@ void wallet2::dump_trunsfers(std::stringstream& ss, bool verbose, const crypto::
|
|||
{
|
||||
uint64_t i = tr.first;
|
||||
const transfer_details& td = tr.second;
|
||||
if (filter_by_asset_id && td.get_asset_id() != asset_id)
|
||||
if (filter_by_asset_id && td.get_asset_id() != asset_id_to_filter)
|
||||
continue;
|
||||
ss << "{ \"i\": " << i << "," << ENDL;
|
||||
ss << "\"entry\": " << epee::serialization::store_t_to_json(td) << "}," << ENDL;
|
||||
|
|
@ -5833,16 +5847,22 @@ void wallet2::dump_trunsfers(std::stringstream& ss, bool verbose, const crypto::
|
|||
else
|
||||
{
|
||||
boost::io::ios_flags_saver ifs(ss);
|
||||
ss << "index amount spent_h g_index block block_ts flg tx out# key image" << ENDL;
|
||||
ss << "index amount spent_h g_index block block_ts flg tx out# asset id" << ENDL;
|
||||
for (const auto& tr : m_transfers)
|
||||
{
|
||||
uint64_t i = tr.first;
|
||||
const transfer_details& td = tr.second;
|
||||
if (filter_by_asset_id && td.get_asset_id() != asset_id)
|
||||
const crypto::public_key asset_id = td.get_asset_id();
|
||||
if (filter_by_asset_id && asset_id != asset_id_to_filter)
|
||||
continue;
|
||||
|
||||
uint32_t asset_flags = 0;
|
||||
currency::asset_descriptor_base asset_info{};
|
||||
get_asset_info(asset_id, asset_info, asset_flags);
|
||||
|
||||
ss << std::right <<
|
||||
std::setw(5) << i << " " <<
|
||||
std::setw(21) << print_money(td.amount()) << " " <<
|
||||
std::setw(21) << print_money(td.amount(), asset_info.decimal_point) << " " <<
|
||||
std::setw(7) << td.m_spent_height << " " <<
|
||||
std::setw(7) << td.m_global_output_index << " " <<
|
||||
std::setw(6) << td.m_ptx_wallet_info->m_block_height << " " <<
|
||||
|
|
@ -5850,15 +5870,15 @@ void wallet2::dump_trunsfers(std::stringstream& ss, bool verbose, const crypto::
|
|||
std::setw(4) << td.m_flags << " " <<
|
||||
get_transaction_hash(td.m_ptx_wallet_info->m_tx) << " " <<
|
||||
std::setw(4) << td.m_internal_output_index << " " <<
|
||||
td.m_key_image << ENDL;
|
||||
(asset_id == native_coin_asset_id ? std::string() : crypto::pod_to_hex(asset_id)) << ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string wallet2::dump_trunsfers(bool verbose, const crypto::public_key& asset_id) const
|
||||
std::string wallet2::dump_transfers(bool verbose, const crypto::public_key& asset_id) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
dump_trunsfers(ss, verbose, asset_id);
|
||||
dump_transfers(ss, verbose, asset_id);
|
||||
return ss.str();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -6617,8 +6637,8 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, bool use_all_decoys
|
|||
if (true)
|
||||
{
|
||||
size_t fake_outputs_count = fake_outputs_count_;
|
||||
uint64_t zarcanum_start_from = m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM];
|
||||
uint64_t current_size = m_chain.get_blockchain_current_size();
|
||||
[[maybe_unused]] uint64_t zarcanum_start_from = m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM];
|
||||
[[maybe_unused]] uint64_t current_size = m_chain.get_blockchain_current_size();
|
||||
|
||||
bool need_to_request = fake_outputs_count != 0;
|
||||
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request req = AUTO_VAL_INIT(req);
|
||||
|
|
@ -7630,6 +7650,122 @@ bool wallet2::is_need_to_split_outputs()
|
|||
return !is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::restore_key_images_in_wo_wallet(const std::wstring& filename, const std::string& password) const
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!m_watch_only, "restore_key_images_in_wo_wallet can only be used in non watch-only wallet");
|
||||
bool r = false;
|
||||
|
||||
// load the given watch-only wallet
|
||||
wallet2 wo;
|
||||
wo.load(filename, password);
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(wo.is_watch_only(), epee::string_encoding::wstring_to_utf8(filename) << " is not a watch-only wallet");
|
||||
if (m_account.get_keys().view_secret_key != wo.get_account().get_keys().view_secret_key ||
|
||||
m_account.get_public_address() != wo.get_account().get_public_address())
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(false, epee::string_encoding::wstring_to_utf8(filename) << " has keys that differ from this wallet's keys; wrong wallet?");
|
||||
}
|
||||
|
||||
//
|
||||
// 1. Find missing key images and calculate them using secret spend key. Populate missing_ki_items container.
|
||||
//
|
||||
struct missing_ki_item
|
||||
{
|
||||
crypto::public_key tx_pub_key;
|
||||
crypto::public_key out_pub_key;
|
||||
uint64_t output_index;
|
||||
uint64_t transfer_index;
|
||||
crypto::key_image ki;
|
||||
};
|
||||
|
||||
std::set<size_t> transfer_indices_to_include;
|
||||
for(auto el : wo.m_pending_key_images)
|
||||
{
|
||||
const crypto::key_image& ki = el.second;
|
||||
auto it = wo.m_key_images.find(ki);
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it != wo.m_key_images.end(), "restore_key_images_in_wo_wallet: m_key_images inconsistency, ki: " << ki);
|
||||
size_t transfer_index = it->second;
|
||||
transfer_indices_to_include.insert(transfer_index);
|
||||
WLT_LOG_L1("restore_key_images_in_wo_wallet: transfer " << transfer_index << " is in m_pending_key_images, included");
|
||||
}
|
||||
|
||||
for(auto el : wo.m_transfers)
|
||||
{
|
||||
size_t transfer_index = el.first;
|
||||
if (el.second.m_key_image == null_ki)
|
||||
{
|
||||
transfer_indices_to_include.insert(transfer_index);
|
||||
WLT_LOG_L1("restore_key_images_in_wo_wallet: ki is null for ti " << transfer_index << ", included");
|
||||
}
|
||||
}
|
||||
|
||||
// now in transfer_indices_to_include we have ordered and unique list of transfer indices
|
||||
std::vector<missing_ki_item> missing_ki_items;
|
||||
std::set<crypto::public_key> pk_uniqueness_set;
|
||||
for(size_t transfer_index : transfer_indices_to_include)
|
||||
{
|
||||
const auto& td = wo.m_transfers.at(transfer_index);
|
||||
auto& item = missing_ki_items.emplace_back();
|
||||
item.output_index = td.m_internal_output_index;
|
||||
crypto::public_key out_pub_key{};
|
||||
r = get_out_pub_key_from_tx_out_v(td.output(), out_pub_key);
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "restore_key_images_in_wo_wallet failed for ti: " << transfer_index);
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(pk_uniqueness_set.insert(out_pub_key).second, "restore_key_images_in_wo_wallet: out pub key in not unique: " << out_pub_key << ", ti: " << transfer_index);
|
||||
item.out_pub_key = out_pub_key;
|
||||
item.transfer_index = transfer_index;
|
||||
item.tx_pub_key = get_tx_pub_key_from_extra(td.m_ptx_wallet_info->m_tx);
|
||||
WLT_LOG_L0("restore_key_images_in_wo_wallet: including: " << item.out_pub_key << ", " << transfer_index);
|
||||
|
||||
// calculate key image
|
||||
keypair ephemeral{};
|
||||
generate_key_image_helper(m_account.get_keys(), item.tx_pub_key, item.output_index, ephemeral, item.ki);
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(ephemeral.pub == item.out_pub_key, "restore_key_images_in_wo_wallet: out pub key missmatch, ti: " << transfer_index);
|
||||
};
|
||||
|
||||
//
|
||||
// 2. Actually restore key images in the 'wo' object.
|
||||
//
|
||||
r = wo.m_pending_key_images_file_container.clear();
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "restore_key_images_in_wo_wallet: pending ki container clearing failed");
|
||||
wo.m_pending_key_images.clear();
|
||||
|
||||
for(size_t i = 0; i < missing_ki_items.size(); ++i)
|
||||
{
|
||||
const auto& item = missing_ki_items[i];
|
||||
auto& td = wo.m_transfers[item.transfer_index]; // item.transfer_index validity was checked above
|
||||
|
||||
td.m_key_image = item.ki; // TODO: it's unclear whether we need to update m_transfers[].m_key_image since later I decided to clear history to trigger resync later. Probably, no. -- sowle
|
||||
r = wo.m_pending_key_images.insert(std::make_pair(item.out_pub_key, item.ki)).second;
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "restore_key_images_in_wo_wallet: insert failed, out_pub_key: " << item.out_pub_key << ", i: " << i);
|
||||
wo.m_pending_key_images_file_container.push_back(out_key_to_ki{item.out_pub_key, item.ki});
|
||||
LOG_PRINT_L0("restore_key_images_in_wo_wallet: added #" << i << " ti: " << item.transfer_index << ", pk: " << item.out_pub_key << ", ki: " << item.ki);
|
||||
}
|
||||
|
||||
wo.reset_history();
|
||||
wo.store();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::clear_utxo_cold_sig_reservation(std::vector<uint64_t>& affected_transfer_ids)
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(m_watch_only, "clear_utxo_cold_sig_reservation can only be used in watch-only wallet");
|
||||
affected_transfer_ids.clear();
|
||||
|
||||
for(auto& [tid, td] : m_transfers)
|
||||
{
|
||||
if (!td.is_spent() && (td.m_flags & WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION) != 0)
|
||||
{
|
||||
affected_transfer_ids.push_back(tid);
|
||||
crypto::public_key pk{};
|
||||
get_out_pub_key_from_tx_out_v(td.output(), pk);
|
||||
WLT_LOG_L0("clear_utxo_cold_sig_reservation: tid: " << tid << ", pk: " << pk << ", amount: " << td.amount() <<
|
||||
(!td.is_native_coin() ? std::string(", aid: ") + crypto::pod_to_hex(td.get_asset_id()) : std::string()) <<
|
||||
(td.m_key_image != null_ki ? std::string(", ki: ") + crypto::pod_to_hex(td.m_key_image) : std::string()));
|
||||
}
|
||||
}
|
||||
|
||||
clear_transfers_from_flag(affected_transfer_ids, WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION, "clear_utxo_cold_sig_reservation");
|
||||
m_found_free_amounts.clear();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::prepare_tx_destinations(const assets_selection_context& needed_money_map,
|
||||
detail::split_strategy_id_t destination_split_strategy_id,
|
||||
const tx_dust_policy& dust_policy,
|
||||
|
|
@ -8002,6 +8138,20 @@ void wallet2::check_and_throw_if_self_directed_tx_with_payment_id_requested(cons
|
|||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!has_payment_id, "sending funds to yourself with payment id is not allowed");
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::check_and_throw_if_smth_not_good_with_comment_or_payment_id(const construct_tx_param& ctp)
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!have_type_in_variant_container<currency::tx_comment>(ctp.attachments), "tx_comment is not allowed to be in attachments");
|
||||
|
||||
if (ctp.dsts.size() > 1 && have_type_in_variant_container<currency::tx_comment>(ctp.extra))
|
||||
{
|
||||
const auto& first_destination = ctp.dsts.front();
|
||||
for(size_t i = 1; i < ctp.dsts.size(); ++i)
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(ctp.dsts[i].addr == first_destination.addr, "currently tx_comment cannot be used with multi-destination transfer");
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::transfer(construct_tx_param& ctp,
|
||||
currency::transaction& tx,
|
||||
bool send_to_network,
|
||||
|
|
@ -8020,6 +8170,7 @@ void wallet2::transfer(construct_tx_param& ctp,
|
|||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!is_auditable() || !is_watch_only(), "You can't initiate coins transfer using an auditable watch-only wallet."); // btw, watch-only wallets can call transfer() within cold-signing process
|
||||
|
||||
check_and_throw_if_self_directed_tx_with_payment_id_requested(ctp);
|
||||
check_and_throw_if_smth_not_good_with_comment_or_payment_id(ctp);
|
||||
|
||||
bool asset_operation_requested = count_type_in_variant_container<asset_descriptor_operation>(ctp.extra) != 0;
|
||||
bool dont_have_zero_asset_ids_in_destinations = std::count_if(ctp.dsts.begin(), ctp.dsts.end(), [](const tx_destination_entry& de) { return de.asset_id == null_pkey; }) == 0;
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ namespace tools
|
|||
wallet2(const wallet2&) = delete;
|
||||
public:
|
||||
wallet2();
|
||||
virtual ~wallet2() {}
|
||||
virtual ~wallet2();
|
||||
|
||||
static std::string transfer_flags_to_str(uint32_t flags);
|
||||
|
||||
|
|
@ -624,6 +624,9 @@ namespace tools
|
|||
void submit_transfer_files(const std::string& signed_tx_file, currency::transaction& tx);
|
||||
void submit_externally_signed_asset_tx(const currency::finalized_tx& ft, const crypto::generic_schnorr_sig_s& gss_sig, bool unlock_transfers_on_fail, currency::transaction& result_tx, bool& transfers_unlocked);
|
||||
void submit_externally_signed_asset_tx(const currency::finalized_tx& ft, const crypto::eth_signature& eth_sig, bool unlock_transfers_on_fail, currency::transaction& result_tx, bool& transfers_unlocked);
|
||||
|
||||
void restore_key_images_in_wo_wallet(const std::wstring& filename, const std::string& password) const;
|
||||
void clear_utxo_cold_sig_reservation(std::vector<uint64_t>& affected_transfer_ids);
|
||||
|
||||
void sweep_below(size_t fake_outs_count, const currency::account_public_address& destination_addr, uint64_t threshold_amount, const currency::payment_id_t& payment_id,
|
||||
uint64_t fee, size_t& outs_total, uint64_t& amount_total, size_t& outs_swept, uint64_t& amount_swept, currency::transaction* p_result_tx = nullptr, std::string* p_filename_or_unsigned_tx_blob_str = nullptr);
|
||||
|
|
@ -690,8 +693,8 @@ namespace tools
|
|||
|
||||
void scan_tx_to_key_inputs(std::vector<uint64_t>& found_transfers, const currency::transaction& tx);
|
||||
// asset_id = null_pkey means no filtering by asset id
|
||||
void dump_trunsfers(std::stringstream& ss, bool verbose = true, const crypto::public_key& asset_id = currency::null_pkey) const;
|
||||
std::string dump_trunsfers(bool verbose = false, const crypto::public_key& asset_id = currency::null_pkey) const;
|
||||
void dump_transfers(std::stringstream& ss, bool verbose = true, const crypto::public_key& asset_id = currency::null_pkey) const;
|
||||
std::string dump_transfers(bool verbose = false, const crypto::public_key& asset_id = currency::null_pkey) const;
|
||||
void dump_key_images(std::stringstream& ss);
|
||||
void get_multisig_transfers(multisig_transfer_container& ms_transfers);
|
||||
const multisig_transfer_container& get_multisig_transfers() const { return m_multisig_transfers; }
|
||||
|
|
@ -909,6 +912,7 @@ private:
|
|||
bool generate_utxo_defragmentation_transaction_if_needed(currency::transaction& tx);
|
||||
bool store_unsigned_tx_to_file_and_reserve_transfers(const currency::finalize_tx_param& ftp, const std::string& filename, std::string* p_unsigned_tx_blob_str = nullptr);
|
||||
void check_and_throw_if_self_directed_tx_with_payment_id_requested(const construct_tx_param& ctp);
|
||||
void check_and_throw_if_smth_not_good_with_comment_or_payment_id(const construct_tx_param& ctp);
|
||||
void push_new_block_id(const crypto::hash& id, uint64_t height);
|
||||
bool lookup_item_around(uint64_t i, std::pair<uint64_t, crypto::hash>& result);
|
||||
//void get_short_chain_history(std::list<crypto::hash>& ids);
|
||||
|
|
|
|||
|
|
@ -71,10 +71,10 @@ namespace tools
|
|||
std::string to_string() const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << m_loc << '[' << boost::replace_all_copy(std::string(typeid(*this).name()), "struct ", "");
|
||||
ss << '[' << boost::replace_all_copy(std::string(typeid(*this).name()), "struct ", "");
|
||||
if (!m_error_code.empty())
|
||||
ss << "[" << m_error_code << "]";
|
||||
ss << "] " << Base::what();
|
||||
ss << "] " << m_loc << ENDL << " " << Base::what();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2159,5 +2159,35 @@ namespace wallet_public
|
|||
};
|
||||
};
|
||||
|
||||
struct COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION
|
||||
{
|
||||
DOC_COMMAND("Clears cold sig reservation flag for all unspent transaction outputs, that have one. Please, use with CAUTION!");
|
||||
|
||||
struct request
|
||||
{
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response_item
|
||||
{
|
||||
crypto::public_key pk;
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(pk) DOC_DSCR("Output's one-time public key") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
std::vector<response_item> affected_outputs;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(status) DOC_DSCR("Status of the call") DOC_EXMP("OK") DOC_END
|
||||
KV_SERIALIZE(affected_outputs) DOC_DSCR("List of affected outputs (for reference).") DOC_EXMP_AUTO(1) DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace wallet_rpc
|
||||
} // namespace tools
|
||||
|
|
|
|||
|
|
@ -38,25 +38,25 @@ POP_VS_WARNINGS
|
|||
catch (const tools::error::daemon_busy& e) \
|
||||
{ \
|
||||
er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY; \
|
||||
er.message = std::string("WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY") + e.what(); \
|
||||
er.message = std::string("WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY: ") + e.what(); \
|
||||
return false; \
|
||||
} \
|
||||
catch (const tools::error::not_enough_money& e) \
|
||||
{ \
|
||||
er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY; \
|
||||
er.message = std::string("WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY") + e.error_code(); \
|
||||
er.message = std::string("WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY: ") + e.what(); \
|
||||
return false; \
|
||||
} \
|
||||
catch (const tools::error::wallet_error& e) \
|
||||
{ \
|
||||
er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; \
|
||||
er.message = e.error_code(); \
|
||||
er.message = std::string("WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR: ") + e.what(); \
|
||||
return false; \
|
||||
} \
|
||||
catch (const std::exception& e) \
|
||||
{ \
|
||||
er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; \
|
||||
er.message = std::string("WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR: ") + e.what(); \
|
||||
er.code = WALLET_RPC_ERROR_CODE_GENERIC_ERROR; \
|
||||
er.message = std::string("WALLET_RPC_ERROR_CODE_GENERIC_ERROR: ") + e.what(); \
|
||||
return false; \
|
||||
} \
|
||||
catch (...) \
|
||||
|
|
@ -73,11 +73,11 @@ void exception_handler()
|
|||
namespace tools
|
||||
{
|
||||
//-----------------------------------------------------------------------------------
|
||||
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_bind_port ("rpc-bind-port", "Starts wallet as rpc server for wallet operations, sets bind port for server");
|
||||
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_bind_ip ("rpc-bind-ip", "Specify ip to bind rpc server", "127.0.0.1");
|
||||
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_miner_text_info ( "miner-text-info", "Wallet password");
|
||||
const command_line::arg_descriptor<bool> wallet_rpc_server::arg_deaf_mode ( "deaf", "Put wallet into 'deaf' mode make it ignore any rpc commands(usable for safe PoS mining)");
|
||||
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_jwt_secret("jwt-secret", "Enables JWT auth over secret string provided");
|
||||
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_bind_port ("rpc-bind-port", "Starts wallet as rpc server for wallet operations, sets bind port for server");
|
||||
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_bind_ip ("rpc-bind-ip", "Specify ip to bind rpc server", "127.0.0.1");
|
||||
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_miner_text_info ("miner-text-info", "Wallet password");
|
||||
const command_line::arg_descriptor<bool> wallet_rpc_server::arg_deaf_mode ("deaf", "Put wallet into 'deaf' mode make it ignore any rpc commands(usable for safe PoS mining)");
|
||||
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_jwt_secret ("jwt-secret", "Enables JWT auth over secret string provided");
|
||||
|
||||
void wallet_rpc_server::init_options(boost::program_options::options_description& desc)
|
||||
{
|
||||
|
|
@ -428,7 +428,7 @@ namespace tools
|
|||
return true;
|
||||
WALLET_RPC_CATCH_TRY_ENTRY();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::on_transfer(const wallet_public::COMMAND_RPC_TRANSFER::request& req, wallet_public::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
WALLET_RPC_BEGIN_TRY_ENTRY();
|
||||
|
|
@ -505,6 +505,12 @@ namespace tools
|
|||
er.message = std::string("embedded payment id: ") + embedded_payment_id + " conflicts with previously set payment id: " + payment_id;
|
||||
return false;
|
||||
}
|
||||
if (it != req.destinations.begin())
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
|
||||
er.message = std::string("payment id: ") + embedded_payment_id + " currently can only be set for the first destination (an so you can use integrated address only for the fist destination)";
|
||||
return false;
|
||||
}
|
||||
payment_id = embedded_payment_id;
|
||||
}
|
||||
de.amount = it->amount;
|
||||
|
|
@ -523,9 +529,10 @@ namespace tools
|
|||
|
||||
if (!req.comment.empty() && payment_id.empty())
|
||||
{
|
||||
currency::tx_comment comment = AUTO_VAL_INIT(comment);
|
||||
comment.comment = req.comment;
|
||||
extra.push_back(comment);
|
||||
// tx_comment is temporary disabled -- sowle
|
||||
//currency::tx_comment comment = AUTO_VAL_INIT(comment);
|
||||
//comment.comment = req.comment;
|
||||
//extra.push_back(comment);
|
||||
}
|
||||
|
||||
if (req.push_payer && !wrap)
|
||||
|
|
@ -1576,6 +1583,31 @@ namespace tools
|
|||
WALLET_RPC_CATCH_TRY_ENTRY();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::on_clear_utxo_cold_sig_reservation(const wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::request& req, wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
WALLET_RPC_BEGIN_TRY_ENTRY();
|
||||
|
||||
std::vector<uint64_t> affected_transfer_ids;
|
||||
w.get_wallet()->clear_utxo_cold_sig_reservation(affected_transfer_ids);
|
||||
|
||||
for (auto tid : affected_transfer_ids)
|
||||
{
|
||||
transfer_details td{};
|
||||
if (!w.get_wallet()->get_transfer_info_by_index(tid, td))
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||
er.message = "internal error: get_transfer_info_by_index failed for tid " + epee::string_tools::num_to_string_fast(tid);
|
||||
return false;
|
||||
}
|
||||
|
||||
res.affected_outputs.emplace_back();
|
||||
currency::get_out_pub_key_from_tx_out_v(td.output(), res.affected_outputs.back().pk);
|
||||
}
|
||||
|
||||
return true;
|
||||
WALLET_RPC_CATCH_TRY_ENTRY();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::on_decrypt_data(const wallet_public::COMMAND_DECRYPT_DATA::request& req, wallet_public::COMMAND_DECRYPT_DATA::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
WALLET_RPC_BEGIN_TRY_ENTRY();
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ namespace tools
|
|||
|
||||
//utility call
|
||||
MAP_JON_RPC_WE("proxy_to_daemon", on_proxy_to_daemon, wallet_public::COMMAND_PROXY_TO_DAEMON)
|
||||
MAP_JON_RPC_WE("clear_utxo_cold_sig_reservation", on_clear_utxo_cold_sig_reservation, wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION)
|
||||
END_JSON_RPC_MAP()
|
||||
END_URI_MAP2()
|
||||
|
||||
|
|
@ -242,6 +243,7 @@ namespace tools
|
|||
bool on_decrypt_data(const wallet_public::COMMAND_DECRYPT_DATA::request& req, wallet_public::COMMAND_DECRYPT_DATA::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
|
||||
bool on_proxy_to_daemon(const wallet_public::COMMAND_PROXY_TO_DAEMON::request& req, wallet_public::COMMAND_PROXY_TO_DAEMON::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_clear_utxo_cold_sig_reservation(const wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::request& req, wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
|
||||
|
||||
//std::shared_ptr<wallet2> get_wallet();
|
||||
|
|
|
|||
|
|
@ -15,3 +15,4 @@
|
|||
#define WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT -6
|
||||
#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY -7
|
||||
#define WALLET_RPC_ERROR_CODE_WRONG_MIXINS_FOR_AUDITABLE_WALLET -8
|
||||
#define WALLET_RPC_ERROR_CODE_GENERIC_ERROR -9
|
||||
|
|
|
|||
|
|
@ -1922,10 +1922,11 @@ std::string wallets_manager::get_wallet_restore_info(uint64_t wallet_id, std::st
|
|||
{
|
||||
GET_WALLET_OPT_BY_ID(wallet_id, wo);
|
||||
|
||||
if (wo.wallet_state != view::wallet_status_info::wallet_state_ready || wo.long_refresh_in_progress)
|
||||
return API_RETURN_CODE_CORE_BUSY;
|
||||
seed_phrase = wo.w.unlocked_get()->get_account().get_seed_phrase(seed_password);
|
||||
|
||||
seed_phrase = wo.w->get()->get_account().get_seed_phrase(seed_password);
|
||||
//if (wo.wallet_state != view::wallet_status_info::wallet_state_ready || wo.long_refresh_in_progress)
|
||||
// return API_RETURN_CODE_CORE_BUSY;
|
||||
//seed_phrase = wo.w->get()->get_account().get_seed_phrase(seed_password);
|
||||
|
||||
return API_RETURN_CODE_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ target_link_libraries(coretests rpc wallet currency_core common crypto zlibstati
|
|||
target_link_libraries(functional_tests rpc wallet currency_core crypto common zlibstatic ethash libminiupnpc-static ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
|
||||
target_link_libraries(hash-tests crypto ethash)
|
||||
target_link_libraries(hash-target-tests crypto currency_core ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
|
||||
target_link_libraries(performance_tests rpc wallet currency_core common crypto zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
|
||||
target_link_libraries(performance_tests wallet rpc currency_core common crypto zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
|
||||
target_link_libraries(unit_tests wallet currency_core common crypto gtest_main zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
|
||||
target_link_libraries(net_load_tests_clt currency_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
|
||||
target_link_libraries(net_load_tests_srv currency_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
|
||||
|
|
|
|||
|
|
@ -1202,3 +1202,151 @@ bool block_reward_in_alt_chain_basic::assert_reward(currency::core& core, size_t
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
block_choice_rule_bigger_fee::block_choice_rule_bigger_fee()
|
||||
{
|
||||
REGISTER_CALLBACK("c1", block_choice_rule_bigger_fee::c1);
|
||||
}
|
||||
|
||||
struct block_choice_rule_bigger_fee::argument_assert
|
||||
{
|
||||
std::list<crypto::hash> transactions{};
|
||||
|
||||
argument_assert() = default;
|
||||
|
||||
argument_assert(const std::list<crypto::hash>& txs)
|
||||
: transactions(txs)
|
||||
{}
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(transactions)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
// Test idea: fork-choice rule based on transactions’ median fees
|
||||
/* Sets up three competing chains:
|
||||
* - Main(blk_1a): 4 transactions with fee 6 (fees = [6, 6, 6, 6], median = (6 + 6) / 2 = 6, score = 6 * 4 = 24)
|
||||
* - Alt1(blk_1b): 2 transactions with fee 11 (fees = [11, 11], median = (11 + 11) / 2 = 11, score = 11 * 2 = 22)
|
||||
* - Alt2(blk_1): 2 transactions with fee 10 (fees = [10, 10], median = (10 + 10) / 2 = 10, score = 10 * 2 = 20)
|
||||
*
|
||||
* Fork-choice rule:
|
||||
* - Even count: median = average of the two middle fees, then multiply by the number of transactions.
|
||||
* - Odd count: median = fee of the central transaction, then multiply by the number of transactions.
|
||||
*
|
||||
* The chain with the highest resulting value wins. In this test, Main(blk_1a) wins (24 > 22 and 24 > 20)
|
||||
* and remains the preferred chain even after Alt2Alt2(blk_1) appears.
|
||||
*/
|
||||
bool block_choice_rule_bigger_fee::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
GENERATE_ACCOUNT(miner);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time());
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
|
||||
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
// Main chain
|
||||
MAKE_TX_FEE(events, tx_1, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE * 10, blk_0r);
|
||||
MAKE_TX_FEE(events, tx_2, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE * 10, blk_0r);
|
||||
|
||||
std::list<transaction> txs_1{tx_1, tx_2};
|
||||
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner, txs_1);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(blk_1));
|
||||
DO_CALLBACK(events, "check_tx_pool_empty");
|
||||
|
||||
/* 0 10 11
|
||||
(blk_0) - ... - (blk_0r) - (blk_1)
|
||||
{tx0} {tx1, tx2}
|
||||
*/
|
||||
|
||||
// Alt chain
|
||||
MAKE_TX_FEE(events, tx_3, miner, miner, MK_TEST_COINS(8), TESTS_DEFAULT_FEE * 6, blk_0r);
|
||||
MAKE_TX_FEE(events, tx_4, miner, miner, MK_TEST_COINS(8), TESTS_DEFAULT_FEE * 6, blk_0r);
|
||||
MAKE_TX_FEE(events, tx_5, miner, miner, MK_TEST_COINS(8), TESTS_DEFAULT_FEE * 6, blk_0r);
|
||||
MAKE_TX_FEE(events, tx_6, miner, miner, MK_TEST_COINS(8), TESTS_DEFAULT_FEE * 6, blk_0r);
|
||||
|
||||
std::list<transaction> txs_1a{tx_3, tx_4, tx_5, tx_6};
|
||||
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1a, blk_0r, miner, txs_1a);
|
||||
|
||||
// tx_1,tx_2 should be in pool
|
||||
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(blk_1a));
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
|
||||
|
||||
// Fees are pre-sorted:
|
||||
// - If count is even: sum the two middle fees -> e.g., 6 + 6 / 2 * 4 = 24 (blk_1a)
|
||||
// - If the number is odd: take the central transaction, for example tx1 tx2 tx3 - the fee of tx2 will be median
|
||||
/* 0 10 11
|
||||
(blk_0) - ... - (blk_0r) - (blk_1a) - win because 1
|
||||
{tx0} {tx_3, tx_4, tx_5, tx_6}
|
||||
|
|
||||
| 11
|
||||
\ - (blk_1)
|
||||
*/
|
||||
|
||||
std::list<crypto::hash> transactions;
|
||||
for (const auto& tx : txs_1)
|
||||
{
|
||||
transactions.push_back(get_transaction_hash(tx));
|
||||
}
|
||||
argument_assert argument_1a{transactions};
|
||||
|
||||
DO_CALLBACK_PARAMS_STR(events, "c1", t_serializable_object_to_blob(argument_1a));
|
||||
|
||||
MAKE_TX_FEE(events, tx_7, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE * 11, blk_0r);
|
||||
MAKE_TX_FEE(events, tx_8, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE * 11, blk_0r);
|
||||
|
||||
std::list<transaction> txs_1b{tx_7, tx_8};
|
||||
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1b, blk_0r, miner, txs_1b);
|
||||
|
||||
/* 0 10 11
|
||||
(blk_0) - ... - (blk_0r) - (blk_1a) - won because (6 + 6) / 2 * 4 = 24 > 22(blk_1b)
|
||||
{tx0} {tx_3, tx_4, tx_5, tx_6}
|
||||
|
|
||||
| 11
|
||||
\ - (blk_1b) - lost because after sorting the central element has the value (11 + 11) / 2 * 2 = 22 < 24
|
||||
|
|
||||
| 11
|
||||
\ - (blk_1) - lost (10 + 10) / 2 * 2 = 20 < 24
|
||||
*/
|
||||
|
||||
// tx_1, tx_2, tx_7, tx_8 should be in pool
|
||||
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(blk_1a));
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(4));
|
||||
|
||||
for (const auto& tx : txs_1b)
|
||||
{
|
||||
transactions.push_back(get_transaction_hash(tx));
|
||||
}
|
||||
argument_assert argument_1b{transactions};
|
||||
DO_CALLBACK_PARAMS_STR(events, "c1", t_serializable_object_to_blob(argument_1b));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool block_choice_rule_bigger_fee::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
argument_assert argument{};
|
||||
{
|
||||
const auto serialized_argument{boost::get<callback_entry>(events.at(ev_index)).callback_params};
|
||||
|
||||
CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(argument, serialized_argument), true);
|
||||
}
|
||||
|
||||
std::list<currency::transaction> txs;
|
||||
c.get_pool_transactions(txs);
|
||||
|
||||
CHECK_AND_ASSERT_MES(txs.size() == argument.transactions.size(), false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
std::list<crypto::hash> hash_txs;
|
||||
for (const auto& tx : txs)
|
||||
{
|
||||
hash_txs.push_back(get_transaction_hash(tx));
|
||||
}
|
||||
|
||||
hash_txs.sort();
|
||||
argument.transactions.sort();
|
||||
CHECK_AND_ASSERT_MES(hash_txs == argument.transactions, false, "Unexpected transactions in the mempool");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,3 +217,13 @@ private:
|
|||
bool assert_reward(currency::core& core, size_t event_index, const std::vector<test_event_entry>& events) const;
|
||||
struct argument_assert;
|
||||
};
|
||||
|
||||
struct block_choice_rule_bigger_fee : public wallet_test
|
||||
{
|
||||
block_choice_rule_bigger_fee();
|
||||
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);
|
||||
|
||||
private:
|
||||
struct argument_assert;
|
||||
};
|
||||
|
|
@ -684,7 +684,7 @@ bool test_generator::find_kernel(const std::list<currency::account_base>& accs,
|
|||
for (size_t wallet_index = 0, size = wallets.size(); wallet_index < size; ++wallet_index)
|
||||
{
|
||||
std::shared_ptr<tools::wallet2> w = wallets[wallet_index].wallet;
|
||||
LOG_PRINT_L0("wallet #" << wallet_index << " @ block " << w->get_top_block_height() << ENDL << wallets[wallet_index].wallet->dump_trunsfers());
|
||||
LOG_PRINT_L0("wallet #" << wallet_index << " @ block " << w->get_top_block_height() << ENDL << wallets[wallet_index].wallet->dump_transfers());
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -940,7 +940,7 @@ bool test_generator::construct_block(int64_t manual_timestamp_adjustment,
|
|||
const crypto::hash& prev_id/* = crypto::hash()*/, const wide_difficulty_type& diffic/* = 1*/,
|
||||
const transaction& miner_tx/* = transaction()*/,
|
||||
const std::vector<crypto::hash>& tx_hashes/* = std::vector<crypto::hash>()*/,
|
||||
size_t txs_sizes/* = 0*/)
|
||||
size_t txs_sizes/* = 0*/, currency::blobdata extra_nonce/* = blobdata()*/)
|
||||
{
|
||||
size_t height = get_block_height(prev_block) + 1;
|
||||
blk.major_version = actual_params & bf_major_ver ? major_ver : m_hardforks.get_block_major_version_by_height(height);
|
||||
|
|
@ -966,7 +966,7 @@ bool test_generator::construct_block(int64_t manual_timestamp_adjustment,
|
|||
size_t current_block_size = txs_sizes + get_object_blobsize(blk.miner_tx);
|
||||
// TODO: This will work, until size of constructed block is less then CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE
|
||||
if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, current_block_size, 0,
|
||||
miner_acc.get_public_address(), miner_acc.get_public_address(), blk.miner_tx, base_block_reward, block_reward, tx_version, tx_hardfork_id, blobdata(), 1))
|
||||
miner_acc.get_public_address(), miner_acc.get_public_address(), blk.miner_tx, base_block_reward, block_reward, tx_version, tx_hardfork_id, extra_nonce, 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1421,7 +1421,7 @@ bool fill_tx_sources(std::vector<tx_source_entry>& sources, const std::vector<te
|
|||
|
||||
bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std::vector<test_event_entry>& events,
|
||||
const currency::block& blk_head, const currency::account_keys& from, uint64_t amount, size_t nmix, const std::vector<currency::tx_source_entry>& sources_to_avoid,
|
||||
bool check_for_spends, bool check_for_unlocktime, bool use_ref_by_id, uint64_t* p_sources_amount_found /* = nullptr */)
|
||||
bool check_for_spends, bool check_for_unlocktime, bool use_ref_by_id, uint64_t* p_sources_amount_found /* = nullptr */, const mixins_per_input* nmix_map /* = nullptr */)
|
||||
{
|
||||
uint64_t fts_flags =
|
||||
(check_for_spends ? fts_check_for_spends : fts_none) |
|
||||
|
|
@ -1429,17 +1429,18 @@ bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std:
|
|||
(use_ref_by_id ? fts_use_ref_by_id : fts_none) |
|
||||
fts_check_for_hf4_min_coinage;
|
||||
|
||||
return fill_tx_sources(sources, events, blk_head, from, amount, nmix, sources_to_avoid, fts_flags, p_sources_amount_found);
|
||||
return fill_tx_sources(sources, events, blk_head, from, amount, nmix, sources_to_avoid, fts_flags, p_sources_amount_found, nmix_map);
|
||||
}
|
||||
|
||||
bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std::vector<test_event_entry>& events,
|
||||
const currency::block& blk_head, const currency::account_keys& from, uint64_t amount, size_t nmix,
|
||||
const std::vector<currency::tx_source_entry>& sources_to_avoid, uint64_t fts_flags, uint64_t* p_sources_amount_found /* = nullptr */)
|
||||
const std::vector<currency::tx_source_entry>& sources_to_avoid, uint64_t fts_flags, uint64_t* p_sources_amount_found /* = nullptr */,
|
||||
const mixins_per_input* nmix_map /* = nullptr */)
|
||||
{
|
||||
std::unordered_map<crypto::public_key, uint64_t> amounts;
|
||||
amounts[native_coin_asset_id] = amount;
|
||||
std::unordered_map<crypto::public_key, uint64_t> sources_amounts;
|
||||
if (!fill_tx_sources(sources, events, blk_head, from, amounts, nmix, sources_to_avoid, fts_flags, &sources_amounts))
|
||||
if (!fill_tx_sources(sources, events, blk_head, from, amounts, nmix, sources_to_avoid, fts_flags, &sources_amounts, nmix_map))
|
||||
return false;
|
||||
if (p_sources_amount_found)
|
||||
*p_sources_amount_found = sources_amounts[native_coin_asset_id];
|
||||
|
|
@ -1448,7 +1449,8 @@ bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std:
|
|||
|
||||
bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std::vector<test_event_entry>& events,
|
||||
const currency::block& blk_head, const currency::account_keys& from, const std::unordered_map<crypto::public_key, uint64_t>& amounts, size_t nmix,
|
||||
const std::vector<currency::tx_source_entry>& sources_to_avoid, uint64_t fts_flags, std::unordered_map<crypto::public_key, uint64_t>* p_sources_amounts /* = nullptr */)
|
||||
const std::vector<currency::tx_source_entry>& sources_to_avoid, uint64_t fts_flags, std::unordered_map<crypto::public_key, uint64_t>* p_sources_amounts /* = nullptr */,
|
||||
const mixins_per_input* nmix_map /* = nullptr */)
|
||||
{
|
||||
map_output_idx_t outs;
|
||||
map_output_t outs_mine;
|
||||
|
|
@ -1558,7 +1560,23 @@ bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std:
|
|||
ts.real_out_amount_blinding_mask = oi.amount_blinding_mask;
|
||||
ts.real_output_in_tx_index = oi.out_no;
|
||||
ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // source tx public key
|
||||
if (!fill_output_entries(outs[o.first], sender_out, nmix, fts_flags & fts_check_for_unlocktime, fts_flags & fts_use_ref_by_id,
|
||||
|
||||
// If we use nmix_map, we should use local_nmix instead of nmix
|
||||
// to allow different nmix for different inputs in the same transaction.
|
||||
// If nmix_map is not provided, we use nmix as local_nmix.
|
||||
size_t local_nmix = nmix;
|
||||
if (nmix_map)
|
||||
{
|
||||
// Try to find an override for this input index 'i'
|
||||
auto it = nmix_map->find(i);
|
||||
if (it != nmix_map->end())
|
||||
{
|
||||
local_nmix = it->second;
|
||||
}
|
||||
// leave local_nmix at its default
|
||||
}
|
||||
|
||||
if (!fill_output_entries(outs[o.first], sender_out, local_nmix, fts_flags & fts_check_for_unlocktime, fts_flags & fts_use_ref_by_id,
|
||||
next_block_height, head_block_ts, ts.real_output, ts.outputs))
|
||||
{
|
||||
continue;
|
||||
|
|
@ -1592,7 +1610,9 @@ bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
|
|||
bool check_for_spends,
|
||||
bool check_for_unlocktime,
|
||||
size_t minimum_sigs,
|
||||
bool use_ref_by_id)
|
||||
bool use_ref_by_id,
|
||||
const mixins_per_input* nmix_map
|
||||
)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!to.empty(), false, "destination addresses vector is empty");
|
||||
CHECK_AND_ASSERT_MES(amount + fee > amount, false, "amount + fee overflow!");
|
||||
|
|
@ -1601,7 +1621,7 @@ bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
|
|||
bool b_multisig = to.size() > 1;
|
||||
|
||||
uint64_t source_amount_found = 0;
|
||||
bool r = fill_tx_sources(sources, events, blk_head, from, amount + fee, nmix, std::vector<currency::tx_source_entry>(), check_for_spends, check_for_unlocktime, use_ref_by_id, &source_amount_found);
|
||||
bool r = fill_tx_sources(sources, events, blk_head, from, amount + fee, nmix, std::vector<currency::tx_source_entry>(), check_for_spends, check_for_unlocktime, use_ref_by_id, &source_amount_found, nmix_map);
|
||||
CHECK_AND_ASSERT_MES(r, false, "couldn't fill transaction sources (nmix = " << nmix << "): " << ENDL <<
|
||||
" required: " << print_money(amount + fee) << " = " << std::fixed << std::setprecision(1) << ceil(1.0 * (amount + fee) / TESTS_DEFAULT_FEE) << " x TESTS_DEFAULT_FEE" << ENDL <<
|
||||
" found coins: " << print_money(source_amount_found) << " = " << std::fixed << std::setprecision(1) << ceil(1.0 * source_amount_found / TESTS_DEFAULT_FEE) << " x TESTS_DEFAULT_FEE" << ENDL <<
|
||||
|
|
@ -1673,9 +1693,10 @@ bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
|
|||
std::vector<tx_destination_entry>& destinations,
|
||||
bool check_for_spends,
|
||||
bool check_for_unlocktime,
|
||||
bool use_ref_by_id)
|
||||
bool use_ref_by_id,
|
||||
const mixins_per_input* nmix_map)
|
||||
{
|
||||
return fill_tx_sources_and_destinations(events, blk_head, from, std::list<account_public_address>({ to }), amount, fee, nmix, sources, destinations, check_for_spends, check_for_unlocktime, 0, use_ref_by_id);
|
||||
return fill_tx_sources_and_destinations(events, blk_head, from, std::list<account_public_address>({ to }), amount, fee, nmix, sources, destinations, check_for_spends, check_for_unlocktime, 0, use_ref_by_id, nmix_map);
|
||||
}
|
||||
|
||||
bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& events, const currency::block& blk_head,
|
||||
|
|
@ -1685,9 +1706,10 @@ bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
|
|||
std::vector<currency::tx_destination_entry>& destinations,
|
||||
bool check_for_spends,
|
||||
bool check_for_unlocktime,
|
||||
bool use_ref_by_id)
|
||||
bool use_ref_by_id,
|
||||
const mixins_per_input* nmix_map)
|
||||
{
|
||||
return fill_tx_sources_and_destinations(events, blk_head, from.get_keys(), to.get_public_address(), amount, fee, nmix, sources, destinations, check_for_spends, check_for_unlocktime, use_ref_by_id);
|
||||
return fill_tx_sources_and_destinations(events, blk_head, from.get_keys(), to.get_public_address(), amount, fee, nmix, sources, destinations, check_for_spends, check_for_unlocktime, use_ref_by_id, nmix_map);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2190,7 +2212,7 @@ bool check_balance_via_wallet(const tools::wallet2& w, const char* account_name,
|
|||
|
||||
if (!r)
|
||||
{
|
||||
LOG_PRINT(account_name << "'s transfers for asset_id " << asset_id << ": " << ENDL << w.dump_trunsfers(false, asset_id), LOG_LEVEL_0);
|
||||
LOG_PRINT(account_name << "'s transfers for asset_id " << asset_id << ": " << ENDL << w.dump_transfers(false, asset_id), LOG_LEVEL_0);
|
||||
}
|
||||
|
||||
return r;
|
||||
|
|
@ -2451,7 +2473,7 @@ bool refresh_wallet_and_check_balance(const char* intro_log_message, const char*
|
|||
|
||||
if (print_transfers)
|
||||
{
|
||||
LOG_PRINT_CYAN(wallet_name << "'s transfers: " << ENDL << wallet->dump_trunsfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN(wallet_name << "'s transfers: " << ENDL << wallet->dump_transfers(), LOG_LEVEL_0);
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*wallet.get(), wallet_name, expected_total, expected_mined, expected_unlocked, expected_awaiting_in, expected_awaiting_out), false, "");
|
||||
|
|
@ -2498,6 +2520,102 @@ uint64_t decode_native_output_amount_or_throw(const account_base& acc, const tra
|
|||
return amount;
|
||||
}
|
||||
|
||||
bool generate_pos_block_with_extra_nonce(test_generator& generator, const std::vector<test_event_entry>& events, const currency::account_base& miner, const currency::account_base& recipient, const currency::block& prev_block, const currency::transaction& stake_tx, const currency::blobdata& pos_nonce, currency::block& result)
|
||||
{
|
||||
// get params for PoS
|
||||
crypto::hash prev_id = get_block_hash(prev_block);
|
||||
wide_difficulty_type pos_diff{};
|
||||
crypto::hash last_pow_block_hash{}, last_pos_block_kernel_hash{};
|
||||
bool r = generator.get_params_for_next_pos_block(
|
||||
prev_id, pos_diff, last_pow_block_hash, last_pos_block_kernel_hash
|
||||
);
|
||||
CHECK_AND_ASSERT_MES(r, false, "get_params_for_next_pos_block failed");
|
||||
|
||||
// tx key and key image for stake out
|
||||
crypto::public_key stake_pk = get_tx_pub_key_from_extra(stake_tx);
|
||||
keypair kp;
|
||||
crypto::key_image ki;
|
||||
size_t stake_output_idx = 0;
|
||||
generate_key_image_helper(miner.get_keys(), stake_pk, stake_output_idx, kp, ki);
|
||||
|
||||
// glob index for stake out
|
||||
uint64_t stake_output_gidx = UINT64_MAX;
|
||||
r = find_global_index_for_output(events, prev_id, stake_tx, stake_output_idx, stake_output_gidx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "find_global_index_for_output failed");
|
||||
|
||||
pos_block_builder pb;
|
||||
uint64_t height = get_block_height(prev_block) + 1;
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs({});
|
||||
|
||||
if (generator.get_hardforks().is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, height))
|
||||
{
|
||||
std::vector<tx_source_entry> sources;
|
||||
fill_tx_sources(
|
||||
sources, events, prev_block, miner.get_keys(),
|
||||
UINT64_MAX, 0, false, false, true
|
||||
);
|
||||
|
||||
auto it = std::find_if(sources.begin(), sources.end(),
|
||||
[&](const tx_source_entry &e){
|
||||
return e.real_out_tx_key == stake_pk
|
||||
&& e.real_output_in_tx_index == stake_output_idx;
|
||||
});
|
||||
CHECK_AND_ASSERT_MES(it != sources.end(), false, "source entry not found");
|
||||
const tx_source_entry& se = *it;
|
||||
|
||||
pb.step3a(pos_diff, last_pow_block_hash, last_pos_block_kernel_hash);
|
||||
pb.step3b(
|
||||
se.amount, ki,
|
||||
se.real_out_tx_key, se.real_output_in_tx_index,
|
||||
se.real_out_amount_blinding_mask,
|
||||
miner.get_keys().view_secret_key,
|
||||
stake_output_gidx,
|
||||
prev_block.timestamp,
|
||||
POS_SCAN_WINDOW, POS_SCAN_STEP
|
||||
);
|
||||
|
||||
// insert extra_nonce
|
||||
pb.step4_generate_coinbase_tx(
|
||||
generator.get_timestamps_median(prev_id),
|
||||
generator.get_already_generated_coins(prev_block),
|
||||
recipient.get_public_address(),
|
||||
pos_nonce,
|
||||
CURRENCY_MINER_TX_MAX_OUTS
|
||||
);
|
||||
|
||||
pb.step5_sign(se, miner.get_keys());
|
||||
}
|
||||
else // HF3: SLSAG
|
||||
{
|
||||
uint64_t amount = boost::get<tx_out_bare>(stake_tx.vout[stake_output_idx]).amount;
|
||||
pb.step3_build_stake_kernel(
|
||||
amount,
|
||||
stake_output_gidx,
|
||||
ki,
|
||||
pos_diff,
|
||||
last_pow_block_hash,
|
||||
last_pos_block_kernel_hash,
|
||||
prev_block.timestamp
|
||||
);
|
||||
|
||||
// insert extra_nonce
|
||||
pb.step4_generate_coinbase_tx(
|
||||
generator.get_timestamps_median(prev_id),
|
||||
generator.get_already_generated_coins(prev_block),
|
||||
recipient.get_public_address(),
|
||||
pos_nonce,
|
||||
CURRENCY_MINER_TX_MAX_OUTS
|
||||
);
|
||||
|
||||
crypto::public_key out_pk = boost::get<txout_to_key>(boost::get<tx_out_bare>(stake_tx.vout[stake_output_idx]).target).key;
|
||||
pb.step5_sign(stake_pk, stake_output_idx, out_pk, miner);
|
||||
}
|
||||
|
||||
result = pb.m_block;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool generate_pos_block_with_given_coinstake(test_generator& generator, const std::vector<test_event_entry> &events, const currency::account_base& miner, const currency::block& prev_block,
|
||||
const currency::transaction& stake_tx, size_t stake_output_idx, currency::block& result, uint64_t stake_output_gidx /* = UINT64_MAX */)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ VARIANT_TAG(binary_archive, core_hardforks_config, 0xd2);
|
|||
|
||||
typedef boost::variant<currency::block, currency::transaction, currency::account_base, callback_entry, serialized_block, serialized_transaction, event_visitor_settings, event_special_block, event_core_time, core_hardforks_config> test_event_entry;
|
||||
typedef std::unordered_map<crypto::hash, const currency::transaction*> map_hash2tx_t;
|
||||
typedef std::unordered_map<std::size_t, std::size_t> mixins_per_input;
|
||||
|
||||
enum test_tx_split_strategy { tests_default_split_strategy /*height-based, TODO*/, tests_void_split_strategy, tests_null_split_strategy, tests_digits_split_strategy, tests_random_split_strategy };
|
||||
struct test_gentime_settings
|
||||
|
|
@ -570,7 +571,8 @@ public:
|
|||
const currency::account_base& miner_acc, int actual_params = bf_none, uint8_t major_ver = 0,
|
||||
uint8_t minor_ver = 0, uint64_t timestamp = 0, const crypto::hash& prev_id = crypto::hash(),
|
||||
const currency::wide_difficulty_type& diffic = 1, const currency::transaction& miner_tx = currency::transaction(),
|
||||
const std::vector<crypto::hash>& tx_hashes = std::vector<crypto::hash>(), size_t txs_sizes = 0);
|
||||
const std::vector<crypto::hash>& tx_hashes = std::vector<crypto::hash>(), size_t txs_sizes = 0,
|
||||
currency::blobdata extra_nonce = currency::blobdata());
|
||||
bool construct_block_manually_tx(currency::block& blk, const currency::block& prev_block,
|
||||
const currency::account_base& miner_acc, const std::vector<crypto::hash>& tx_hashes, size_t txs_size);
|
||||
bool find_nounce(currency::block& blk, std::vector<const block_info*>& blocks, currency::wide_difficulty_type dif, uint64_t height) const;
|
||||
|
|
@ -754,13 +756,16 @@ bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std:
|
|||
bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std::vector<test_event_entry>& events,
|
||||
const currency::block& blk_head, const currency::account_keys& from, uint64_t amount, size_t nmix,
|
||||
const std::vector<currency::tx_source_entry>& sources_to_avoid, bool check_for_spends = true, bool check_for_unlocktime = true,
|
||||
bool use_ref_by_id = false, uint64_t* p_sources_amount_found = nullptr);
|
||||
bool use_ref_by_id = false, uint64_t* p_sources_amount_found = nullptr,
|
||||
const mixins_per_input* nmix_map = nullptr);
|
||||
bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std::vector<test_event_entry>& events,
|
||||
const currency::block& blk_head, const currency::account_keys& from, uint64_t amount, size_t nmix,
|
||||
const std::vector<currency::tx_source_entry>& sources_to_avoid, uint64_t fts_flags, uint64_t* p_sources_amount_found = nullptr);
|
||||
const std::vector<currency::tx_source_entry>& sources_to_avoid, uint64_t fts_flags, uint64_t* p_sources_amount_found = nullptr,
|
||||
const mixins_per_input* nmix_map = nullptr);
|
||||
bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std::vector<test_event_entry>& events,
|
||||
const currency::block& blk_head, const currency::account_keys& from, const std::unordered_map<crypto::public_key, uint64_t>& amounts, size_t nmix,
|
||||
const std::vector<currency::tx_source_entry>& sources_to_avoid, uint64_t fts_flags, std::unordered_map<crypto::public_key, uint64_t>* p_sources_amounts = nullptr);
|
||||
const std::vector<currency::tx_source_entry>& sources_to_avoid, uint64_t fts_flags, std::unordered_map<crypto::public_key, uint64_t>* p_sources_amounts = nullptr,
|
||||
const mixins_per_input* nmix_map = nullptr);
|
||||
|
||||
bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& events, const currency::block& blk_head,
|
||||
const currency::account_keys& from, const std::list<currency::account_public_address>& to,
|
||||
|
|
@ -769,7 +774,8 @@ bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
|
|||
bool check_for_spends = true,
|
||||
bool check_for_unlocktime = true,
|
||||
size_t minimum_sigs = SIZE_MAX,
|
||||
bool use_ref_by_id = false);
|
||||
bool use_ref_by_id = false,
|
||||
const mixins_per_input* nmix_map = nullptr);
|
||||
bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& events, const currency::block& blk_head,
|
||||
const currency::account_keys& from, const currency::account_public_address& to,
|
||||
uint64_t amount, uint64_t fee, size_t nmix,
|
||||
|
|
@ -777,7 +783,8 @@ bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
|
|||
std::vector<currency::tx_destination_entry>& destinations,
|
||||
bool check_for_spends = true,
|
||||
bool check_for_unlocktime = true,
|
||||
bool use_ref_by_id = false);
|
||||
bool use_ref_by_id = false,
|
||||
const mixins_per_input* nmix_map = nullptr);
|
||||
bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& events, const currency::block& blk_head,
|
||||
const currency::account_base& from, const currency::account_base& to,
|
||||
uint64_t amount, uint64_t fee, size_t nmix,
|
||||
|
|
@ -785,7 +792,8 @@ bool fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
|
|||
std::vector<currency::tx_destination_entry>& destinations,
|
||||
bool check_for_spends = true,
|
||||
bool check_for_unlocktime = true,
|
||||
bool use_ref_by_id = false);
|
||||
bool use_ref_by_id = false,
|
||||
const mixins_per_input* nmix_map = nullptr);
|
||||
uint64_t get_balance(const currency::account_keys& addr, const std::vector<currency::block>& blockchain, const map_hash2tx_t& mtx, bool dbg_log = false);
|
||||
uint64_t get_balance(const currency::account_base& addr, const std::vector<currency::block>& blockchain, const map_hash2tx_t& mtx, bool dbg_log = false);
|
||||
void balance_via_wallet(const tools::wallet2& w, const crypto::public_key& asset_id, uint64_t* p_total, uint64_t* p_unlocked = 0, uint64_t* p_awaiting_in = 0, uint64_t* p_awaiting_out = 0, uint64_t* p_mined = 0);
|
||||
|
|
@ -828,6 +836,7 @@ uint64_t get_last_block_of_type(bool looking_for_pos, const test_generator::bloc
|
|||
bool decode_output_amount_and_asset_id(const currency::account_base& acc, const currency::transaction& tx, size_t output_index, uint64_t &amount, crypto::public_key* p_asset_id = nullptr);
|
||||
uint64_t decode_native_output_amount_or_throw(const currency::account_base& acc, const currency::transaction& tx, size_t output_index);
|
||||
|
||||
bool generate_pos_block_with_extra_nonce(test_generator& generator, const std::vector<test_event_entry>& events, const currency::account_base& miner, const currency::account_base& recipient, const currency::block& prev_block, const currency::transaction& stake_tx, const currency::blobdata& pos_nonce, currency::block& result);
|
||||
bool generate_pos_block_with_given_coinstake(test_generator& generator, const std::vector<test_event_entry> &events, const currency::account_base& miner, const currency::block& prev_block, const currency::transaction& stake_tx, size_t stake_output_idx, currency::block& result, uint64_t stake_output_gidx = UINT64_MAX);
|
||||
bool check_ring_signature_at_gen_time(const std::vector<test_event_entry>& events, const crypto::hash& last_block_id, const currency::txin_to_key& in_t_k,
|
||||
const crypto::hash& hash_for_sig, const std::vector<crypto::signature> &sig);
|
||||
|
|
@ -1356,12 +1365,14 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
|
||||
#define MAKE_TX_LIST_START_WITH_ATTACHS(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD, ATTACHS) MAKE_TX_LIST_START_MIX_ATTR(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD, CURRENCY_TO_KEY_OUT_RELAXED, ATTACHS)
|
||||
|
||||
#define MAKE_TX_ATTACH_FEE(EVENTS, TX_VAR, FROM, TO, AMOUNT, FEE, HEAD, ATTACH) \
|
||||
PRINT_EVENT_N(EVENTS); \
|
||||
currency::transaction TX_VAR = AUTO_VAL_INIT(TX_VAR); \
|
||||
CHECK_AND_ASSERT_MES(construct_tx_to_key(generator.get_hardforks(), EVENTS, TX_VAR, HEAD, FROM, TO, AMOUNT, FEE, 0, generator.last_tx_generated_secret_key, CURRENCY_TO_KEY_OUT_RELAXED, empty_extra, ATTACH), false, "construct_tx_to_key failed"); \
|
||||
#define MAKE_TX_EXTRA_ATTACH_FEE(EVENTS, TX_VAR, FROM, TO, AMOUNT, FEE, HEAD, EXTRA, ATTACH) \
|
||||
PRINT_EVENT_N(EVENTS); \
|
||||
currency::transaction TX_VAR{}; \
|
||||
CHECK_AND_ASSERT_MES(construct_tx_to_key(generator.get_hardforks(), EVENTS, TX_VAR, HEAD, FROM, TO, AMOUNT, FEE, 0, generator.last_tx_generated_secret_key, CURRENCY_TO_KEY_OUT_RELAXED, EXTRA, ATTACH), false, "construct_tx_to_key failed"); \
|
||||
EVENTS.push_back(TX_VAR)
|
||||
|
||||
#define MAKE_TX_ATTACH_FEE(EVENTS, TX_VAR, FROM, TO, AMOUNT, FEE, HEAD, ATTACH) MAKE_TX_EXTRA_ATTACH_FEE(EVENTS, TX_VAR, FROM, TO, AMOUNT, FEE, HEAD, empty_extra, ATTACH)
|
||||
|
||||
#define MAKE_TX_ATTACH(EVENTS, TX_VAR, FROM, TO, AMOUNT, HEAD, ATTACH) MAKE_TX_ATTACH_FEE(EVENTS, TX_VAR, FROM, TO, AMOUNT, TESTS_DEFAULT_FEE, HEAD, ATTACH)
|
||||
|
||||
#define MAKE_MINER_TX_AND_KEY_MANUALLY(TX, PREV_BLOCK, P_KEYPAIR) \
|
||||
|
|
@ -1417,30 +1428,25 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
|
||||
#define MAKE_TEST_WALLET_TX(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC) \
|
||||
PRINT_EVENT_N(EVENTS_VEC); \
|
||||
transaction TX_VAR = AUTO_VAL_INIT(TX_VAR); \
|
||||
transaction TX_VAR{}; \
|
||||
{ \
|
||||
std::vector<tx_destination_entry> destinations(1, tx_destination_entry(MONEY, DEST_ACC.get_public_address())); \
|
||||
WLT_WAR->transfer(destinations, 0, 0, TESTS_DEFAULT_FEE, std::vector<extra_v>(), std::vector<attachment_v>(), TX_VAR); \
|
||||
} \
|
||||
EVENTS_VEC.push_back(TX_VAR)
|
||||
|
||||
#define MAKE_TEST_WALLET_TX_ATTACH(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, ATTACH) \
|
||||
#define MAKE_TEST_WALLET_TX_EXTRA_ATTACH(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, EXTRA, ATTACH) \
|
||||
PRINT_EVENT_N(EVENTS_VEC); \
|
||||
transaction TX_VAR = AUTO_VAL_INIT(TX_VAR); \
|
||||
transaction TX_VAR{}; \
|
||||
{ \
|
||||
std::vector<tx_destination_entry> destinations(1, tx_destination_entry(MONEY, DEST_ACC.get_public_address())); \
|
||||
WLT_WAR->transfer(destinations, 0, 0, TESTS_DEFAULT_FEE, std::vector<extra_v>(), ATTACH, TX_VAR); \
|
||||
WLT_WAR->transfer(destinations, 0, 0, TESTS_DEFAULT_FEE, EXTRA, ATTACH, TX_VAR); \
|
||||
} \
|
||||
EVENTS_VEC.push_back(TX_VAR)
|
||||
|
||||
#define MAKE_TEST_WALLET_TX_EXTRA(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, EXTRA) \
|
||||
PRINT_EVENT_N(EVENTS_VEC); \
|
||||
transaction TX_VAR = AUTO_VAL_INIT(TX_VAR); \
|
||||
{ \
|
||||
std::vector<tx_destination_entry> destinations(1, tx_destination_entry(MONEY, DEST_ACC.get_public_address())); \
|
||||
WLT_WAR->transfer(destinations, 0, 0, TESTS_DEFAULT_FEE, EXTRA, std::vector<attachment_v>(), TX_VAR); \
|
||||
} \
|
||||
EVENTS_VEC.push_back(TX_VAR)
|
||||
#define MAKE_TEST_WALLET_TX_ATTACH(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, ATTACH) MAKE_TEST_WALLET_TX_EXTRA_ATTACH(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, empty_extra, ATTACH)
|
||||
|
||||
#define MAKE_TEST_WALLET_TX_EXTRA(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, EXTRA) MAKE_TEST_WALLET_TX_EXTRA_ATTACH(EVENTS_VEC, TX_VAR, WLT_WAR, MONEY, DEST_ACC, EXTRA, empty_attachment)
|
||||
|
||||
#define CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(WLT_WAR, TOTAL_BALANCE) \
|
||||
if (!check_balance_via_wallet(*WLT_WAR.get(), #WLT_WAR, TOTAL_BALANCE)) \
|
||||
|
|
|
|||
|
|
@ -1077,7 +1077,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(gen_wallet_oversized_payment_id);
|
||||
GENERATE_AND_PLAY(gen_wallet_transfers_and_outdated_unconfirmed_txs);
|
||||
GENERATE_AND_PLAY(gen_wallet_transfers_and_chain_switch);
|
||||
GENERATE_AND_PLAY(gen_wallet_decrypted_attachments);
|
||||
GENERATE_AND_PLAY(gen_wallet_decrypted_payload_items);
|
||||
GENERATE_AND_PLAY_HF(gen_wallet_alias_and_unconfirmed_txs, "3-*");
|
||||
GENERATE_AND_PLAY_HF(gen_wallet_alias_via_special_wallet_funcs, "3-*");
|
||||
GENERATE_AND_PLAY(gen_wallet_fake_outputs_randomness);
|
||||
|
|
@ -1104,6 +1104,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY_HF(wallet_rpc_exchange_suite, "3,4");
|
||||
GENERATE_AND_PLAY_HF(wallet_true_rpc_pos_mining, "4-*");
|
||||
GENERATE_AND_PLAY_HF(wallet_rpc_cold_signing, "3,5-*");
|
||||
// GENERATE_AND_PLAY_HF(wallet_rpc_multiple_receivers, "5-*"); work in progress -- sowle
|
||||
GENERATE_AND_PLAY(wallet_chain_switch_with_spending_the_same_ki);
|
||||
GENERATE_AND_PLAY(wallet_sending_to_integrated_address);
|
||||
GENERATE_AND_PLAY_HF(block_template_blacklist_test, "4-*");
|
||||
|
|
@ -1118,7 +1119,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(gen_pos_coinstake_already_spent);
|
||||
GENERATE_AND_PLAY(gen_pos_incorrect_timestamp);
|
||||
GENERATE_AND_PLAY(gen_pos_too_early_pos_block);
|
||||
GENERATE_AND_PLAY(gen_pos_extra_nonce);
|
||||
GENERATE_AND_PLAY_HF(gen_pos_extra_nonce, "3-*");
|
||||
GENERATE_AND_PLAY(gen_pos_min_allowed_height);
|
||||
GENERATE_AND_PLAY(gen_pos_invalid_coinbase);
|
||||
// GENERATE_AND_PLAY(pos_wallet_minting_same_amount_diff_outs); // Long test! Takes ~10 hours to simulate 6000 blocks on 2015 middle-end computer
|
||||
|
|
@ -1191,7 +1192,8 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY_HF(gen_block_miner_tx_has_out_to_initiator, "0,3");
|
||||
GENERATE_AND_PLAY_HF(gen_block_has_invalid_tx, "0,3");
|
||||
GENERATE_AND_PLAY_HF(gen_block_is_too_big, "0,3");
|
||||
GENERATE_AND_PLAY_HF(gen_block_wrong_version_agains_hardfork, "0,3");
|
||||
GENERATE_AND_PLAY_HF(gen_block_wrong_version_agains_hardfork, "0,3");
|
||||
GENERATE_AND_PLAY_HF(block_choice_rule_bigger_fee, "4-*");
|
||||
//GENERATE_AND_PLAY(gen_block_invalid_binary_format); // Takes up to 3 hours, if CURRENCY_MINED_MONEY_UNLOCK_WINDOW == 500, up to 30 minutes, if CURRENCY_MINED_MONEY_UNLOCK_WINDOW == 10
|
||||
|
||||
|
||||
|
|
@ -1228,6 +1230,8 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY_HF(tx_pool_semantic_validation, "3");
|
||||
GENERATE_AND_PLAY(input_refers_to_incompatible_by_type_output);
|
||||
GENERATE_AND_PLAY_HF(tx_pool_validation_and_chain_switch, "4-*");
|
||||
GENERATE_AND_PLAY_HF(tx_coinbase_separate_sig_flag, "4-*");
|
||||
GENERATE_AND_PLAY(tx_input_mixins);
|
||||
|
||||
// Double spend
|
||||
GENERATE_AND_PLAY(gen_double_spend_in_tx<false>);
|
||||
|
|
|
|||
|
|
@ -319,7 +319,7 @@ bool escrow_altchain_meta_impl::c1(currency::core& c, size_t ev_index, const std
|
|||
alice_wlt->refresh(blocks_fetched);
|
||||
//fetched blocks disabled since resync might happened on different situation and number of blocks_fetched might be unexpected
|
||||
//CHECK_AND_ASSERT_MES(blocks_fetched == se.expected_blocks, false, "Alice got " << blocks_fetched << " after refresh, but " << se.expected_blocks << " is expected");
|
||||
LOG_PRINT_GREEN("Alice's transfers:" << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_1);
|
||||
LOG_PRINT_GREEN("Alice's transfers:" << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_1);
|
||||
if (se.a_balance != UINT64_MAX)
|
||||
{
|
||||
uint64_t alice_balance = alice_wlt->balance();
|
||||
|
|
@ -338,7 +338,7 @@ bool escrow_altchain_meta_impl::c1(currency::core& c, size_t ev_index, const std
|
|||
bob_wlt->refresh(blocks_fetched);
|
||||
//fetched blocks disabled since resync might happened on different situation and number of blocks_fetched might be unexpected
|
||||
//CHECK_AND_ASSERT_MES(blocks_fetched == se.expected_blocks, false, "Bob got " << blocks_fetched << " after refresh, but " << se.expected_blocks << " is expected");
|
||||
LOG_PRINT_GREEN("Bob's transfers:" << ENDL << bob_wlt->dump_trunsfers(), LOG_LEVEL_1);
|
||||
LOG_PRINT_GREEN("Bob's transfers:" << ENDL << bob_wlt->dump_transfers(), LOG_LEVEL_1);
|
||||
if (se.b_balance != UINT64_MAX)
|
||||
{
|
||||
uint64_t bob_balance = bob_wlt->balance();
|
||||
|
|
|
|||
|
|
@ -759,7 +759,7 @@ bool escrow_proposal_expiration::c1(currency::core& c, size_t ev_index, const st
|
|||
bob_wlt->refresh();
|
||||
|
||||
uint64_t alice_start_balance = alice_wlt->balance();
|
||||
LOG_PRINT_CYAN("Alice's wallet transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("Alice's wallet transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0);
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool");
|
||||
|
||||
|
|
@ -777,7 +777,7 @@ bool escrow_proposal_expiration::c1(currency::core& c, size_t ev_index, const st
|
|||
transaction proposal_tx = AUTO_VAL_INIT(proposal_tx);
|
||||
transaction escrow_template_tx = AUTO_VAL_INIT(escrow_template_tx);
|
||||
alice_wlt->send_escrow_proposal(cpd, 0, 0, expiration_period, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, "", proposal_tx, escrow_template_tx);
|
||||
LOG_PRINT_CYAN("alice transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("alice transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0);
|
||||
uint64_t alice_post_proposal_balance = alice_wlt->balance();
|
||||
uint64_t alice_post_proposal_balance_expected = alice_start_balance - TESTS_DEFAULT_FEE;
|
||||
CHECK_AND_ASSERT_MES(alice_post_proposal_balance == alice_post_proposal_balance_expected, false, "Incorrect alice_post_proposal_balance: " << print_money(alice_post_proposal_balance) << ", expected: " << print_money(alice_post_proposal_balance_expected));
|
||||
|
|
@ -840,9 +840,9 @@ bool escrow_proposal_expiration::c2(currency::core& c, size_t ev_index, const st
|
|||
bob_wlt->refresh();
|
||||
|
||||
uint64_t alice_start_balance = alice_wlt->balance();
|
||||
LOG_PRINT_CYAN("Alice's wallet transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("Alice's wallet transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0);
|
||||
uint64_t bob_start_balance = bob_wlt->balance();
|
||||
LOG_PRINT_CYAN("Bob's wallet transfers: " << ENDL << bob_wlt->dump_trunsfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("Bob's wallet transfers: " << ENDL << bob_wlt->dump_transfers(), LOG_LEVEL_0);
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
|
|
@ -860,7 +860,7 @@ bool escrow_proposal_expiration::c2(currency::core& c, size_t ev_index, const st
|
|||
transaction proposal_tx = AUTO_VAL_INIT(proposal_tx);
|
||||
transaction escrow_template_tx = AUTO_VAL_INIT(escrow_template_tx);
|
||||
alice_wlt->send_escrow_proposal(cpd, 0, 0, expiration_period, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, "", proposal_tx, escrow_template_tx);
|
||||
LOG_PRINT_CYAN("%%%%% Escrow proposal sent, Alice's transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("%%%%% Escrow proposal sent, Alice's transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0);
|
||||
CHECK_AND_ASSERT_MES(check_wallet_balance_blocked_for_escrow(*alice_wlt.get(), "Alice", cpd.amount_a_pledge + cpd.amount_to_pay), false, "");
|
||||
crypto::hash ms_id = get_multisig_out_id(escrow_template_tx, get_multisig_out_index(escrow_template_tx.vout));
|
||||
CHECK_AND_ASSERT_MES(ms_id != null_hash, false, "Can't obtain multisig id from escrow template tx");
|
||||
|
|
@ -996,7 +996,7 @@ bool escrow_proposal_and_accept_expiration::c1(currency::core& c, size_t ev_inde
|
|||
transaction proposal_tx = AUTO_VAL_INIT(proposal_tx);
|
||||
transaction escrow_template_tx = AUTO_VAL_INIT(escrow_template_tx);
|
||||
alice_wlt->send_escrow_proposal(cpd, 0, 0, expiration_period, TESTS_DEFAULT_FEE, b_release_fee, "", proposal_tx, escrow_template_tx);
|
||||
LOG_PRINT_CYAN("%%%%% Escrow proposal sent, Alice's transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("%%%%% Escrow proposal sent, Alice's transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0);
|
||||
CHECK_AND_ASSERT_MES(check_wallet_balance_blocked_for_escrow(*alice_wlt.get(), "Alice", cpd.amount_a_pledge + cpd.amount_to_pay), false, "");
|
||||
|
||||
crypto::hash ms_id = get_multisig_out_id(escrow_template_tx, get_multisig_out_index(escrow_template_tx.vout));
|
||||
|
|
@ -1021,8 +1021,8 @@ bool escrow_proposal_and_accept_expiration::c1(currency::core& c, size_t ev_inde
|
|||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_contract_state("Alice", alice_wlt, tools::wallet_public::escrow_contract_details::contract_accepted, ms_id, 0), false, "");
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_contract_state("Bob", bob_wlt, tools::wallet_public::escrow_contract_details::contract_accepted, ms_id, 0), false, "");
|
||||
|
||||
LOG_PRINT_CYAN("%%%%% Escrow proposal accepted (unconfirmed), Alice's transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("%%%%% Escrow proposal accepted (unconfirmed), Bob's transfers: " << ENDL << bob_wlt->dump_trunsfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("%%%%% Escrow proposal accepted (unconfirmed), Alice's transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("%%%%% Escrow proposal accepted (unconfirmed), Bob's transfers: " << ENDL << bob_wlt->dump_transfers(), LOG_LEVEL_0);
|
||||
|
||||
|
||||
// mine a few blocks with no txs
|
||||
|
|
@ -1047,8 +1047,8 @@ bool escrow_proposal_and_accept_expiration::c1(currency::core& c, size_t ev_inde
|
|||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_contract_state("Alice", alice_wlt, tools::wallet_public::escrow_contract_details::contract_accepted, ms_id, TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW + 1), false, "");
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_contract_state("Bob", bob_wlt, tools::wallet_public::escrow_contract_details::contract_accepted, ms_id, TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW + 1), false, "");
|
||||
|
||||
LOG_PRINT_CYAN("%%%%% Escrow acceptance tx expired and removed from tx pool, Alice's transfers: " << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("%%%%% Escrow acceptance tx expired and removed from tx pool, Bob's transfers: " << ENDL << bob_wlt->dump_trunsfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("%%%%% Escrow acceptance tx expired and removed from tx pool, Alice's transfers: " << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("%%%%% Escrow acceptance tx expired and removed from tx pool, Bob's transfers: " << ENDL << bob_wlt->dump_transfers(), LOG_LEVEL_0);
|
||||
|
||||
// try to accept expired proposal once again -- an exception should be thrown
|
||||
r = false;
|
||||
|
|
@ -1318,7 +1318,7 @@ bool escrow_incorrect_proposal_acceptance::check_normal_acceptance(currency::cor
|
|||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
|
||||
alice_wlt->refresh();
|
||||
std::stringstream ss;
|
||||
alice_wlt->dump_trunsfers(ss, false);
|
||||
alice_wlt->dump_transfers(ss, false);
|
||||
LOG_PRINT_L0("check_normal_acceptance(" << release_instruction << "):" << ENDL << "Alice transfers: " << ENDL << ss.str());
|
||||
uint64_t alice_balance = alice_wlt->balance();
|
||||
uint64_t alice_balance_expected = m_alice_bob_start_amount - m_cpd.amount_a_pledge - m_cpd.amount_to_pay - TESTS_DEFAULT_FEE;
|
||||
|
|
@ -1392,7 +1392,7 @@ bool escrow_incorrect_proposal_acceptance::check_incorrect_acceptance(currency::
|
|||
alice_wlt->refresh();
|
||||
uint64_t alice_balance = alice_wlt->balance();
|
||||
std::stringstream ss;
|
||||
alice_wlt->dump_trunsfers(ss, false);
|
||||
alice_wlt->dump_transfers(ss, false);
|
||||
LOG_PRINT_L0("check_incorrect_acceptance(" << param << "):" << ENDL << "Alice balance: " << print_money(alice_balance) << ", transfers: " << ENDL << ss.str());
|
||||
|
||||
tools::escrow_contracts_container contracts;
|
||||
|
|
@ -2110,7 +2110,7 @@ bool escrow_incorrect_cancel_proposal::check_normal_cancel_proposal(currency::co
|
|||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
|
||||
alice_wlt->refresh();
|
||||
std::stringstream ss;
|
||||
alice_wlt->dump_trunsfers(ss, false);
|
||||
alice_wlt->dump_transfers(ss, false);
|
||||
LOG_PRINT_L0("check_normal_cancel_proposal:" << ENDL << "Alice transfers: " << ENDL << ss.str());
|
||||
uint64_t alice_balance = alice_wlt->balance();
|
||||
uint64_t alice_balance_expected = m_alice_bob_start_amount - m_cpd.amount_a_pledge - m_cpd.amount_to_pay - TESTS_DEFAULT_FEE - TESTS_DEFAULT_FEE; // one fee for escrow request, second - for cancel request
|
||||
|
|
@ -2198,7 +2198,7 @@ bool escrow_incorrect_cancel_proposal::check_incorrect_cancel_proposal_internal(
|
|||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
|
||||
alice_wlt->refresh();
|
||||
std::stringstream ss;
|
||||
alice_wlt->dump_trunsfers(ss, false);
|
||||
alice_wlt->dump_transfers(ss, false);
|
||||
LOG_PRINT_L0("Alice transfers: " << ENDL << ss.str());
|
||||
uint64_t alice_balance = alice_wlt->balance();
|
||||
uint64_t alice_balance_expected = m_alice_bob_start_amount - m_cpd.amount_a_pledge - m_cpd.amount_to_pay - TESTS_DEFAULT_FEE - TESTS_DEFAULT_FEE; // one fee for escrow request, second - for cancel request
|
||||
|
|
|
|||
|
|
@ -227,8 +227,6 @@ bool hardfork_4_wallet_transfer_with_mandatory_mixins::generate(std::vector<test
|
|||
* (It should also work prior to HF4.)
|
||||
*/
|
||||
|
||||
bool r = false;
|
||||
|
||||
uint64_t ts = test_core_time::get_time();
|
||||
m_accounts.resize(TOTAL_ACCS_COUNT);
|
||||
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
|
||||
|
|
@ -441,7 +439,6 @@ bool hardfork_4_pop_tx_from_global_index::generate(std::vector<test_event_entry>
|
|||
bool hardfork_4_pop_tx_from_global_index::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
auto& bcs = c.get_blockchain_storage();
|
||||
bool r = false;
|
||||
|
||||
//currency::outs_index_stat outs_stat{};
|
||||
//bcs.get_outs_index_stat(outs_stat); // 24 - bad, 22 - good
|
||||
|
|
|
|||
|
|
@ -1469,8 +1469,6 @@ bool eth_signed_asset_basics::c1(currency::core& c, size_t ev_index, const std::
|
|||
crypto::public_key asset_id = currency::null_pkey;
|
||||
miner_wlt->deploy_new_asset(adb, destinations, ft, asset_id);
|
||||
|
||||
const transaction& tx = ft.tx;
|
||||
|
||||
LOG_PRINT_L0("Deployed new asset: " << asset_id << ", tx_id: " << ft.tx_id);
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
|
||||
|
|
@ -2122,7 +2120,7 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec
|
|||
std::vector<tx_destination_entry> destinations{};
|
||||
const auto& ado{m_ados_register.at(asset_position::gamma)};
|
||||
crypto::secret_key one_time{};
|
||||
size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_1r));
|
||||
//size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_1r));
|
||||
//fill_ado_version_based_onhardfork(ado, hf_n);
|
||||
//fill_adb_version_based_onhardfork(*ado.opt_descriptor, hf_n);
|
||||
|
||||
|
|
@ -2148,7 +2146,7 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec
|
|||
std::vector<tx_destination_entry> destinations{};
|
||||
crypto::secret_key one_time{};
|
||||
const auto& ado{m_ados_register.at(asset_position::alpha)};
|
||||
size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r));
|
||||
//size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r));
|
||||
//fill_ado_version_based_onhardfork(ado, hf_n);
|
||||
//fill_adb_version_based_onhardfork(*ado.opt_descriptor, hf_n);
|
||||
|
||||
|
|
@ -2173,7 +2171,7 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec
|
|||
std::vector<tx_destination_entry> destinations{};
|
||||
crypto::secret_key one_time{};
|
||||
const auto& ado{m_ados_register.at(asset_position::beta)};
|
||||
size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r));
|
||||
//size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r));
|
||||
//fill_ado_version_based_onhardfork(ado, hf_n);
|
||||
//fill_adb_version_based_onhardfork(*ado.opt_descriptor, hf_n);
|
||||
|
||||
|
|
@ -2210,7 +2208,6 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec
|
|||
const auto& ado_register{m_ados_register.at(asset_position::beta)};
|
||||
std::vector<tx_source_entry> sources{};
|
||||
std::vector<tx_destination_entry> destinations{};
|
||||
crypto::secret_key one_time{};
|
||||
tx_source_entry source{};
|
||||
finalize_tx_param ftp{};
|
||||
finalized_tx ftx{};
|
||||
|
|
@ -2452,8 +2449,6 @@ bool several_asset_emit_burn_txs_in_pool::generate(std::vector<test_event_entry>
|
|||
|
||||
bool several_asset_emit_burn_txs_in_pool::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
|
||||
miner_wlt->refresh();
|
||||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
|
||||
|
|
@ -2614,7 +2609,6 @@ bool assets_transfer_with_smallest_amount::generate(std::vector<test_event_entry
|
|||
// Only for HF >= 4
|
||||
//
|
||||
|
||||
bool r = false;
|
||||
uint64_t ts = test_core_time::get_time();
|
||||
m_accounts.resize(TOTAL_ACCS_COUNT);
|
||||
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
|
||||
|
|
@ -2947,7 +2941,6 @@ bool asset_operations_and_chain_switching::generate(std::vector<test_event_entry
|
|||
|
||||
bool asset_operations_and_chain_switching::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
bool r = false, stub = false;;
|
||||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]);
|
||||
alice_wlt->refresh();
|
||||
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]);
|
||||
|
|
@ -2962,7 +2955,7 @@ bool asset_operations_and_chain_switching::c1(currency::core& c, size_t ev_index
|
|||
|
||||
bool asset_operations_and_chain_switching::c2(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
bool r = false, stub = false;;
|
||||
bool r = false;
|
||||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]);
|
||||
alice_wlt->refresh();
|
||||
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]);
|
||||
|
|
@ -2984,7 +2977,7 @@ bool asset_operations_and_chain_switching::c2(currency::core& c, size_t ev_index
|
|||
|
||||
bool asset_operations_and_chain_switching::c3(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
bool r = false, stub = false;;
|
||||
bool r = false;
|
||||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]);
|
||||
alice_wlt->refresh();
|
||||
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]);
|
||||
|
|
|
|||
|
|
@ -2576,7 +2576,7 @@ bool multisig_unconfirmed_transfer_and_multiple_scan_pool_calls::c1(currency::co
|
|||
|
||||
alice_wlt->scan_tx_pool(stub);
|
||||
alice_wlt->get_transfers(transfers);
|
||||
CHECK_AND_ASSERT_MES(transfers.size() == 0, false, "incorrect transfers size for Alice: " << transfers.size() << "\n" << alice_wlt->dump_trunsfers());
|
||||
CHECK_AND_ASSERT_MES(transfers.size() == 0, false, "incorrect transfers size for Alice: " << transfers.size() << "\n" << alice_wlt->dump_transfers());
|
||||
alice_wlt->get_unconfirmed_transfers(unconfirmed_transfers);
|
||||
CHECK_AND_ASSERT_MES(unconfirmed_transfers.size() == 1, false, "incorrect unconfirmed transfers size for Alice: " << unconfirmed_transfers.size());
|
||||
CHECK_AND_ASSERT_MES(alice_wlt->get_multisig_transfers().size() == 1, false, "incorrect multisig transfers size for Alice: " << alice_wlt->get_multisig_transfers().size());
|
||||
|
|
@ -2590,7 +2590,7 @@ bool multisig_unconfirmed_transfer_and_multiple_scan_pool_calls::c1(currency::co
|
|||
transfers.clear();
|
||||
unconfirmed_transfers.clear();
|
||||
alice_wlt->get_transfers(transfers);
|
||||
CHECK_AND_ASSERT_MES(transfers.size() == 0, false, "incorrect transfers size for Alice: " << transfers.size() << "\n" << alice_wlt->dump_trunsfers());
|
||||
CHECK_AND_ASSERT_MES(transfers.size() == 0, false, "incorrect transfers size for Alice: " << transfers.size() << "\n" << alice_wlt->dump_transfers());
|
||||
alice_wlt->get_unconfirmed_transfers(unconfirmed_transfers);
|
||||
CHECK_AND_ASSERT_MES(unconfirmed_transfers.size() == 1, false, "incorrect unconfirmed transfers size for Alice: " << unconfirmed_transfers.size());
|
||||
CHECK_AND_ASSERT_MES(alice_wlt->get_multisig_transfers().size() == 1, false, "incorrect multisig transfers size for Alice: " << alice_wlt->get_multisig_transfers().size());
|
||||
|
|
|
|||
|
|
@ -658,7 +658,7 @@ bool offer_removing_and_selected_output::check_offers(currency::core& c, size_t
|
|||
|
||||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]);
|
||||
alice_wlt->refresh();
|
||||
LOG_PRINT_CYAN("Alice's transfers:" << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("Alice's transfers:" << ENDL << alice_wlt->dump_transfers(), LOG_LEVEL_0);
|
||||
uint64_t alice_start_balance = alice_wlt->balance();
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
|
@ -1354,7 +1354,7 @@ bool offer_cancellation_with_zero_fee::c1(currency::core& c, size_t ev_index, co
|
|||
bool r = false;
|
||||
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, m_accounts[MINER_ACC_IDX]);
|
||||
miner_wlt->refresh();
|
||||
LOG_PRINT_CYAN("Miners's transfers:" << ENDL << miner_wlt->dump_trunsfers(), LOG_LEVEL_0);
|
||||
LOG_PRINT_CYAN("Miners's transfers:" << ENDL << miner_wlt->dump_transfers(), LOG_LEVEL_0);
|
||||
uint64_t miner_start_balance = miner_wlt->balance();
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ bool gen_pos_coinstake_already_spent::generate(std::vector<test_event_entry>& ev
|
|||
|
||||
CREATE_TEST_WALLET(miner_wlt, miner, blk_0);
|
||||
REFRESH_TEST_WALLET_AT_GEN_TIME(events, miner_wlt, blk_2, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
|
||||
LOG_PRINT_L0("miner's transfers:" << ENDL << miner_wlt->dump_trunsfers(false));
|
||||
LOG_PRINT_L0("miner's transfers:" << ENDL << miner_wlt->dump_transfers(false));
|
||||
|
||||
// Legend: (n) - PoW block, [m] - PoS block
|
||||
// 0 1 11 12 13 <-- blockchain height (assuming CURRENCY_MINED_MONEY_UNLOCK_WINDOW == 10)
|
||||
|
|
@ -217,56 +217,110 @@ bool gen_pos_too_early_pos_block::configure_core(currency::core& c, size_t ev_in
|
|||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
bool gen_pos_extra_nonce::generate(std::vector<test_event_entry>& events) const
|
||||
bool gen_pos_extra_nonce::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>&)
|
||||
{
|
||||
uint64_t ts = time(NULL);
|
||||
|
||||
GENERATE_ACCOUNT(miner);
|
||||
GENERATE_ACCOUNT(alice);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner, ts);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS(events, blk_0r, blk_0, miner);
|
||||
|
||||
// Legend: (n) - PoW block, [m] - PoS block
|
||||
// 0 10 11 <-- blockchain height (assuming CURRENCY_MINED_MONEY_UNLOCK_WINDOW == 10)
|
||||
// (0 )--(0r)--[1 ] main chain
|
||||
|
||||
// make a PoS block manually with incorrect timestamp
|
||||
crypto::hash prev_id = get_block_hash(blk_0r);
|
||||
size_t height = CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1;
|
||||
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
|
||||
|
||||
const transaction& stake = blk_0.miner_tx;
|
||||
crypto::public_key stake_tx_pub_key = get_tx_pub_key_from_extra(stake);
|
||||
size_t stake_output_idx = 0;
|
||||
size_t stake_output_gidx = 0;
|
||||
uint64_t stake_output_amount =boost::get<currency::tx_out_bare>( stake.vout[stake_output_idx]).amount;
|
||||
crypto::key_image stake_output_key_image;
|
||||
keypair kp;
|
||||
generate_key_image_helper(miner.get_keys(), stake_tx_pub_key, stake_output_idx, kp, stake_output_key_image);
|
||||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(boost::get<currency::tx_out_bare>(stake.vout[stake_output_idx]).target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(generator.get_hardforks(), height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, blk_0r.timestamp);
|
||||
|
||||
// use biggest possible extra nonce (255 bytes) + largest alias
|
||||
currency::blobdata extra_nonce(255, 'x');
|
||||
//currency::extra_alias_entry alias = AUTO_VAL_INIT(alias); // TODO: this alias entry was ignored for a long time, now I commented it out, make sure it's okay -- sowle
|
||||
//alias.m_alias = std::string(255, 'a');
|
||||
//alias.m_address = miner.get_keys().account_address;
|
||||
//alias.m_text_comment = std::string(255, 'y');
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(blk_0r), alice.get_public_address(), extra_nonce, CURRENCY_MINER_TX_MAX_OUTS);
|
||||
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, miner);
|
||||
block blk_1 = pb.m_block;
|
||||
|
||||
// EXPECTED: blk_1 is accepted
|
||||
events.push_back(blk_1);
|
||||
|
||||
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
|
||||
pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE;
|
||||
pc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH;
|
||||
pc.hf4_minimum_mixins = 0;
|
||||
pc.hard_forks = m_hardforks;
|
||||
c.get_blockchain_storage().set_core_runtime_config(pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
gen_pos_extra_nonce::gen_pos_extra_nonce()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(gen_pos_extra_nonce, configure_core);
|
||||
REGISTER_CALLBACK_METHOD(gen_pos_extra_nonce, request_pow_template_with_nonce);
|
||||
REGISTER_CALLBACK_METHOD(gen_pos_extra_nonce, check_pow_nonce);
|
||||
REGISTER_CALLBACK_METHOD(gen_pos_extra_nonce, check_pos_nonce);
|
||||
}
|
||||
|
||||
// Test: verify custom extra_nonce in blocks and templates
|
||||
/*
|
||||
* Scenarios:
|
||||
* 1. PoW block contains m_pow_nonce
|
||||
* 2. PoS block contains m_pos_nonce
|
||||
* 3. PoW mining template contains m_pow_template_nonce
|
||||
*/
|
||||
bool gen_pos_extra_nonce::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
GENERATE_ACCOUNT(miner);
|
||||
GENERATE_ACCOUNT(alice);
|
||||
m_accounts.push_back(miner);
|
||||
m_accounts.push_back(alice);
|
||||
m_pow_nonce = currency::blobdata(254, 'w');
|
||||
m_pos_nonce = currency::blobdata(255, 's');
|
||||
m_pow_template_nonce = "POW_TEMPLATE123";
|
||||
|
||||
uint64_t ts = test_core_time::get_time();
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner, ts);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner);
|
||||
|
||||
block blk_2 = AUTO_VAL_INIT(blk_2);
|
||||
ts = blk_2.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN / 2; // to increase main chain difficulty
|
||||
bool r = generator.construct_block_manually(blk_2, blk_1, miner, test_generator::bf_timestamp, 0, 0,
|
||||
ts, crypto::hash(), 1, transaction(), std::vector<crypto::hash>(), 0, m_pow_nonce);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_block_manually failed");
|
||||
events.push_back(blk_2);
|
||||
|
||||
DO_CALLBACK(events, "check_pow_nonce");
|
||||
REWIND_BLOCKS(events, blk_0r, blk_2, miner);
|
||||
|
||||
// setup params for PoS
|
||||
const currency::transaction& stake = blk_2.miner_tx;
|
||||
|
||||
currency::block new_pos_block;
|
||||
bool ok = generate_pos_block_with_extra_nonce(generator, events, miner, alice, blk_0r, stake, m_pos_nonce, new_pos_block);
|
||||
CHECK_AND_ASSERT_MES(ok, false, "generate_pos_block_with_extra_nonce failed");
|
||||
|
||||
events.push_back(new_pos_block);
|
||||
DO_CALLBACK(events, "check_pos_nonce");
|
||||
DO_CALLBACK(events, "request_pow_template_with_nonce");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gen_pos_extra_nonce::request_pow_template_with_nonce(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
block bl;
|
||||
wide_difficulty_type diff;
|
||||
uint64_t height;
|
||||
bool ok = c.get_block_template(bl, m_accounts[0].get_public_address(), m_accounts[0].get_public_address(), diff, height, m_pow_template_nonce);
|
||||
CHECK_AND_ASSERT_MES(ok, false, "get_block_template failed");
|
||||
CHECK_AND_ASSERT_MES(has_extra_nonce(bl, m_pow_template_nonce), false, "PoW extra_nonce not found");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gen_pos_extra_nonce::check_pow_nonce(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
block top;
|
||||
bool ok = c.get_blockchain_storage().get_top_block(top);
|
||||
CHECK_AND_ASSERT_MES(ok, false, "get_top_block failed");
|
||||
CHECK_AND_ASSERT_MES(has_extra_nonce(top, m_pow_nonce), false, "PoW extra_nonce not found");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gen_pos_extra_nonce::check_pos_nonce(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
block top;
|
||||
bool ok = c.get_blockchain_storage().get_top_block(top);
|
||||
CHECK_AND_ASSERT_MES(ok, false, "get_top_block failed");
|
||||
CHECK_AND_ASSERT_MES(has_extra_nonce(top, m_pos_nonce), false, "PoS extra_nonce not found");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gen_pos_extra_nonce::has_extra_nonce(currency::block& blk, const std::string& expected_nonce)
|
||||
{
|
||||
if (auto const* ud = get_type_in_variant_container<extra_user_data>(blk.miner_tx.extra)) {
|
||||
LOG_PRINT_L0("Found extra nonce: '" << ud->buff << "' expected: '" << expected_nonce << "'");
|
||||
return ud->buff == expected_nonce;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
gen_pos_min_allowed_height::gen_pos_min_allowed_height()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(gen_pos_min_allowed_height, configure_core);
|
||||
|
|
@ -728,7 +782,7 @@ void pos_wallet_minting_same_amount_diff_outs::dump_wallets_entries(const std::v
|
|||
LOG_PRINT2(LOG2_FILENAME, ENDL << ENDL << ENDL << ENDL << ENDL << ENDL, LOG_LEVEL_0);
|
||||
for (size_t i = 0; i < minting_wallets.size(); ++i)
|
||||
{
|
||||
LOG_PRINT2(LOG2_FILENAME, "wallet #" << i << ":" << ENDL << minting_wallets[i].w->dump_trunsfers() << ENDL, LOG_LEVEL_0);
|
||||
LOG_PRINT2(LOG2_FILENAME, "wallet #" << i << ":" << ENDL << minting_wallets[i].w->dump_transfers() << ENDL, LOG_LEVEL_0);
|
||||
}
|
||||
#undef LOG2_FILENAME
|
||||
}
|
||||
|
|
@ -806,7 +860,7 @@ bool pos_wallet_big_block_test::c1(currency::core& c, size_t ev_index, const std
|
|||
miner_wlt->refresh();
|
||||
miner_wlt->scan_tx_pool(stub_bool);
|
||||
|
||||
LOG_PRINT_L0("miner transfers:" << ENDL << miner_wlt->dump_trunsfers(false));
|
||||
LOG_PRINT_L0("miner transfers:" << ENDL << miner_wlt->dump_transfers(false));
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Incorrect number of txs in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,21 @@ struct gen_pos_too_early_pos_block : public pos_validation
|
|||
|
||||
struct gen_pos_extra_nonce : public pos_validation
|
||||
{
|
||||
gen_pos_extra_nonce();
|
||||
bool configure_core(currency::core& c, size_t, const std::vector<test_event_entry>& events);
|
||||
bool request_pow_template_with_nonce(currency::core& c, size_t, const std::vector<test_event_entry>& events);
|
||||
bool check_pos_nonce(currency::core& c, size_t, const std::vector<test_event_entry>& events);
|
||||
bool check_pow_nonce(currency::core& c, size_t, const std::vector<test_event_entry>& events);
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
|
||||
private:
|
||||
bool has_extra_nonce(currency::block& blk, const std::string& expected_nonce);
|
||||
|
||||
private:
|
||||
mutable currency::blobdata m_pow_nonce;
|
||||
mutable currency::blobdata m_pos_nonce;
|
||||
mutable currency::blobdata m_pow_template_nonce;
|
||||
mutable std::vector<currency::account_base> m_accounts;
|
||||
};
|
||||
|
||||
struct gen_pos_min_allowed_height : public pos_validation
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Copyright (c) 2014-2025 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
|
@ -16,15 +16,15 @@ struct random_state_test_restorer
|
|||
{
|
||||
random_state_test_restorer()
|
||||
{
|
||||
crypto::random_prng_get_state(&m_state, sizeof m_state);
|
||||
crypto::random_prng_get_state_no_lock(&m_state, sizeof m_state);
|
||||
}
|
||||
~random_state_test_restorer()
|
||||
{
|
||||
crypto::random_prng_set_state(&m_state, sizeof m_state);
|
||||
crypto::random_prng_set_state_no_lock(&m_state, sizeof m_state);
|
||||
}
|
||||
static void reset_random(uint64_t seed = 0)
|
||||
{
|
||||
crypto::random_prng_initialize_with_seed(seed);
|
||||
crypto::random_prng_initialize_with_seed_no_lock(seed);
|
||||
}
|
||||
private:
|
||||
uint8_t m_state[RANDOM_STATE_SIZE];
|
||||
|
|
|
|||
|
|
@ -1651,6 +1651,7 @@ bool tx_version_against_hardfork::generate(std::vector<test_event_entry>& events
|
|||
{
|
||||
case ZANO_HARDFORK_04_ZARCANUM:
|
||||
tx_hardfork_id = 0;
|
||||
[[fallthrough]];
|
||||
case ZANO_HARDFORK_05:
|
||||
tx_version_good = TRANSACTION_VERSION_POST_HF4;
|
||||
tx_version_bad = TRANSACTION_VERSION_PRE_HF4;
|
||||
|
|
@ -1836,6 +1837,7 @@ bool tx_pool_semantic_validation::generate(std::vector<test_event_entry>& events
|
|||
}
|
||||
|
||||
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true);
|
||||
|
||||
}
|
||||
|
||||
// Two entries of the same type in extra.
|
||||
|
|
@ -2567,7 +2569,6 @@ bool input_refers_to_incompatible_by_type_output::assert_zc_input_refers_bare_ou
|
|||
}
|
||||
|
||||
{
|
||||
bool all_inputs_have_explicit_native_asset_id{};
|
||||
blockchain_storage::check_tx_inputs_context ctic{};
|
||||
|
||||
CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get<const txin_zc_input>(tx.vin.front()), get_transaction_hash(tx), ctic), false);
|
||||
|
|
@ -2728,3 +2729,137 @@ bool tx_pool_validation_and_chain_switch::c1(currency::core& c, size_t ev_index,
|
|||
return true;
|
||||
}
|
||||
|
||||
// Сoinbase transactions must NOT allow the TX_FLAG_SIGNATURE_MODE_SEPARATE flag.
|
||||
// Сhecks that setting this flag for coinbase fails, while a default coinbase (without the flag) succeeds.
|
||||
bool tx_coinbase_separate_sig_flag::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
GENERATE_ACCOUNT(miner);
|
||||
|
||||
uint64_t ts = test_core_time::get_time();
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner, ts);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner);
|
||||
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
|
||||
|
||||
block blk_2;
|
||||
auto coinbase_default_cb = [](transaction& miner_tx, const keypair&) -> bool { return true; };
|
||||
auto coinbase_separate_cb = [](transaction& miner_tx, const keypair&) -> bool
|
||||
{
|
||||
set_tx_flags(miner_tx, get_tx_flags(miner_tx) | TX_FLAG_SIGNATURE_MODE_SEPARATE);
|
||||
return true;
|
||||
};
|
||||
|
||||
// сonstruct a block with the forbidden flag, should fail after hf4
|
||||
bool with_separate_flag = generator.construct_block_gentime_with_coinbase_cb(blk_1r, miner, coinbase_separate_cb, blk_2);
|
||||
CHECK_AND_ASSERT_MES(with_separate_flag, false, "expected failure because TX_FLAG_SIGNATURE_MODE_SEPARATE is forbidden for coinbase after HF4");
|
||||
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
events.push_back(blk_2);
|
||||
|
||||
// construct a default coinbase block, should succeed
|
||||
bool default_tx = generator.construct_block_gentime_with_coinbase_cb(blk_1r, miner, coinbase_default_cb, blk_2);
|
||||
CHECK_AND_ASSERT_MES(default_tx, true, "default coinbase must succeed");
|
||||
|
||||
events.push_back(blk_2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
tx_input_mixins::tx_input_mixins()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(tx_input_mixins, configure_core);
|
||||
}
|
||||
|
||||
bool tx_input_mixins::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
|
||||
pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE;
|
||||
pc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH;
|
||||
pc.hf4_minimum_mixins = 5;
|
||||
pc.hard_forks.set_hardfork_height(1, 0);
|
||||
pc.hard_forks.set_hardfork_height(2, 1);
|
||||
pc.hard_forks.set_hardfork_height(3, 1);
|
||||
pc.hard_forks.set_hardfork_height(4, 31);
|
||||
c.get_blockchain_storage().set_core_runtime_config(pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Tests that post-HF4, legacy txin_to_key inputs accept any mixin count, while new txin_zc inputs enforce a >= 15 mixin minimum
|
||||
// are in the same vin and work together
|
||||
bool tx_input_mixins::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
uint64_t ts = test_core_time::get_time();
|
||||
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
GENERATE_ACCOUNT(alice_acc);
|
||||
GENERATE_ACCOUNT(bob_acc);
|
||||
|
||||
m_hardforks.set_hardfork_height(1, 0);
|
||||
m_hardforks.set_hardfork_height(2, 1);
|
||||
m_hardforks.set_hardfork_height(3, 1);
|
||||
m_hardforks.set_hardfork_height(4, 31);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
|
||||
// mine one block, then rewind enough to unlock initial coinbase funds
|
||||
MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner_acc);
|
||||
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW*2);
|
||||
|
||||
// build tx_a_1: single txin_to_key output of 15 coins to Alice
|
||||
transaction tx_a_1;
|
||||
bool r = construct_tx_with_many_outputs(m_hardforks, events, blk_1r, miner_acc.get_keys(),
|
||||
alice_acc.get_public_address(), MK_TEST_COINS(15), 1, TESTS_DEFAULT_FEE, tx_a_1);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs 1 failed");
|
||||
events.push_back(tx_a_1);
|
||||
|
||||
// build tx_a_2: 16 outputs of 15 coins each to Bob for mixins
|
||||
transaction tx_a_2;
|
||||
r = construct_tx_with_many_outputs(m_hardforks, events, blk_1r, miner_acc.get_keys(),
|
||||
bob_acc.get_public_address(), MK_TEST_COINS(15*16), 16, TESTS_DEFAULT_FEE, tx_a_2);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs 2 failed");
|
||||
events.push_back(tx_a_2);
|
||||
|
||||
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1r_1, blk_1r, miner_acc, std::list<transaction>({ tx_a_1, tx_a_2 }));
|
||||
|
||||
// mine a couple more blocks and rewind to generate new spendable outputs
|
||||
MAKE_NEXT_BLOCK(events, blk_2, blk_1r_1, miner_acc);
|
||||
REWIND_BLOCKS_N(events, blk_2r, blk_2, miner_acc, 4);
|
||||
MAKE_NEXT_BLOCK(events, blk_3, blk_2r, miner_acc);
|
||||
REWIND_BLOCKS_N(events, blk_4r, blk_3, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
// make sure HF4 is active at 31 height
|
||||
DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM});
|
||||
|
||||
// build tx_b with zc hf4 input, send 15 coins from miner -> Alice
|
||||
std::vector<currency::tx_source_entry> sources_b;
|
||||
std::vector<currency::tx_destination_entry> destinations_b;
|
||||
CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations(
|
||||
events, blk_4r, miner_acc, alice_acc, MK_TEST_COINS(15), TESTS_DEFAULT_FEE, 2, sources_b, destinations_b),
|
||||
false, "fill_tx_sources_and_destinations failed");
|
||||
currency::transaction tx_b{};
|
||||
r = construct_tx(miner_acc.get_keys(), sources_b, destinations_b, events, this, tx_b);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
events.push_back(tx_b);
|
||||
|
||||
// mine tx_b and rewind to unlock its outputs
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_5, blk_4r, miner_acc, tx_b);
|
||||
REWIND_BLOCKS_N(events, blk_5r, blk_5, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
std::vector<currency::tx_source_entry> sources_c;
|
||||
std::vector<currency::tx_destination_entry> destinations_c;
|
||||
// For input #0 use 5 mixins (old-style ring-CT allows any mixins)
|
||||
// For input #1 use 16 mixins (new-style txin_zc enforces >=15 once HF4 is live)
|
||||
mixins_per_input nmix_map = { {0, 5}, {1, 16} };
|
||||
CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations(
|
||||
events, blk_5r, alice_acc, bob_acc, MK_TEST_COINS(29), TESTS_DEFAULT_FEE, 5, sources_c, destinations_c,
|
||||
true, true, false, &nmix_map), false, "fill_tx_sources_and_destinations failed");
|
||||
currency::transaction tx_c{};
|
||||
r = construct_tx(alice_acc.get_keys(), sources_c, destinations_c, events, this, tx_c);
|
||||
LOG_PRINT_GREEN("tx_c alice -> bob \n" << obj_to_json_str(tx_c), LOG_LEVEL_0);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
events.push_back(tx_c);
|
||||
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_6, blk_5r, miner_acc, tx_c);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,3 +183,16 @@ struct tx_pool_validation_and_chain_switch : 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 tx_coinbase_separate_sig_flag : public test_chain_unit_enchanced
|
||||
{
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct tx_input_mixins: public test_chain_unit_enchanced
|
||||
{
|
||||
tx_input_mixins();
|
||||
|
||||
bool configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -830,7 +830,6 @@ bool wallet_true_rpc_pos_mining::generate(std::vector<test_event_entry>& events)
|
|||
|
||||
bool wallet_true_rpc_pos_mining::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
bool r = false;
|
||||
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet_with_true_http_rpc(events, c, MINER_ACC_IDX);
|
||||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet_with_true_http_rpc(events, c, ALICE_ACC_IDX);
|
||||
|
||||
|
|
@ -1284,12 +1283,7 @@ bool wallet_rpc_cold_signing::generate(std::vector<test_event_entry>& events) co
|
|||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
|
||||
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
MAKE_TX(events, tx_0, miner_acc, alice_acc, MK_TEST_COINS(100), blk_0r);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0);
|
||||
|
||||
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
|
||||
|
||||
DO_CALLBACK(events, "c1");
|
||||
|
||||
|
|
@ -1306,6 +1300,14 @@ bool make_cold_signing_transaction(tools::wallet_rpc_server& rpc_wo, tools::wall
|
|||
r = invoke_text_json_for_rpc(rpc_wo, "transfer", req_transfer, res_transfer);
|
||||
CHECK_AND_ASSERT_MES(r, false, "RPC 'transfer' failed");
|
||||
|
||||
// (optional step) skip this reservation just for fun and then create a transaction once again
|
||||
tools::wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::request req_clear_csr{};
|
||||
tools::wallet_public::COMMAND_CLEAR_UTXO_COLD_SIG_RESERVATION::response res_clear_csr{};
|
||||
invoke_text_json_for_rpc(rpc_wo, "clear_utxo_cold_sig_reservation", req_clear_csr, res_clear_csr);
|
||||
CHECK_AND_ASSERT_MES(res_clear_csr.affected_outputs.size() > 0, false, "no outputs were affected after clear_utxo_cold_sig_reservation");
|
||||
res_transfer = tools::wallet_public::COMMAND_RPC_TRANSFER::response{};
|
||||
r = invoke_text_json_for_rpc(rpc_wo, "transfer", req_transfer, res_transfer);
|
||||
CHECK_AND_ASSERT_MES(r, false, "RPC 'transfer' failed");
|
||||
|
||||
// secure wallet with full keys set signs the transaction
|
||||
tools::wallet_public::COMMAND_SIGN_TRANSFER::request req_sign{};
|
||||
|
|
@ -1314,8 +1316,11 @@ bool make_cold_signing_transaction(tools::wallet_rpc_server& rpc_wo, tools::wall
|
|||
r = invoke_text_json_for_rpc(rpc, "sign_transfer", req_sign, res_sign);
|
||||
CHECK_AND_ASSERT_MES(r, false, "RPC 'sign_transfer' failed");
|
||||
|
||||
// (optional step) make sure clear_utxo_cold_sig_reservation cannot be called in a full keys wallet
|
||||
r = !invoke_text_json_for_rpc(rpc, "clear_utxo_cold_sig_reservation", req_clear_csr, res_clear_csr);
|
||||
CHECK_AND_ASSERT_MES(r, false, "clear_utxo_cold_sig_reservation called in full key wallet");
|
||||
|
||||
// watch only wallet submits it
|
||||
// watch only wallet submits signed transaction
|
||||
tools::wallet_public::COMMAND_SUBMIT_TRANSFER::request req_submit{};
|
||||
req_submit.tx_signed_hex = res_sign.tx_signed_hex;
|
||||
tools::wallet_public::COMMAND_SUBMIT_TRANSFER::response res_submit{};
|
||||
|
|
@ -1342,14 +1347,46 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std::
|
|||
|
||||
miner_wlt->refresh();
|
||||
bob_wlt->refresh();
|
||||
check_balance_via_wallet(*bob_wlt, "Bob", 0, 0, 0, 0, 0);
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt, "Bob", 0, 0, 0, 0, 0), false, "");
|
||||
|
||||
// for post HF4 cases transfer some assets along with native coins
|
||||
crypto::public_key deployed_asset_id{};
|
||||
size_t deployed_asset_decimal_point = 0;
|
||||
const bool use_assets = c.get_blockchain_storage().is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM);
|
||||
if (use_assets)
|
||||
{
|
||||
// miner deploys new asset and sends 50 coins of it to Alice
|
||||
tools::wallet_rpc_server miner_rpc(miner_wlt);
|
||||
tools::wallet_public::COMMAND_ASSETS_DEPLOY::request req_deploy{};
|
||||
req_deploy.asset_descriptor.current_supply = 50;
|
||||
req_deploy.asset_descriptor.decimal_point = deployed_asset_decimal_point;
|
||||
req_deploy.asset_descriptor.full_name = "50 pounds per person";
|
||||
req_deploy.asset_descriptor.ticker = "50PPP";
|
||||
req_deploy.asset_descriptor.total_max_supply = 200; // for a family of four
|
||||
req_deploy.destinations.emplace_back(tools::wallet_public::transfer_destination{50, m_accounts[ALICE_ACC_IDX].get_public_address_str(), null_pkey});
|
||||
req_deploy.do_not_split_destinations = true;
|
||||
tools::wallet_public::COMMAND_ASSETS_DEPLOY::response res_deploy{};
|
||||
r = invoke_text_json_for_rpc(miner_rpc, "deploy_asset", req_deploy, res_deploy);
|
||||
CHECK_AND_ASSERT_MES(r, false, "RPC 'deploy_asset' failed");
|
||||
deployed_asset_id = res_deploy.new_asset_id;
|
||||
}
|
||||
|
||||
// also, send some native coins
|
||||
miner_wlt->transfer(MK_TEST_COINS(100), m_accounts[ALICE_ACC_IDX].get_public_address(), native_coin_asset_id);
|
||||
|
||||
// confirm this tx and mine 10 block to unlock the coins
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == (use_assets ? 2 : 1), false, "enexpected pool txs count: " << c.get_pool_transactions_count());
|
||||
r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed");
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Tx pool is not empty: " << c.get_pool_transactions_count());
|
||||
|
||||
// Alice: prepare watch-only wallet
|
||||
account_base alice_acc_wo = m_accounts[ALICE_ACC_IDX];
|
||||
alice_acc_wo.make_account_watch_only();
|
||||
std::shared_ptr<tools::wallet2> alice_wlt_wo = init_playtime_test_wallet(events, c, alice_acc_wo);
|
||||
|
||||
alice_wlt_wo->refresh();
|
||||
check_balance_via_wallet(*alice_wlt_wo, "Alice (WO)", MK_TEST_COINS(100), 0, MK_TEST_COINS(100), 0, 0);
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt_wo, "Alice (WO)", MK_TEST_COINS(100), 0, MK_TEST_COINS(100), 0, 0), false, "");
|
||||
|
||||
// Alice: perform initial save-load to properly initialize internal wallet2 structures
|
||||
boost::filesystem::remove(epee::string_tools::cut_off_extension(m_wallet_filename) + L".outkey2ki");
|
||||
|
|
@ -1364,17 +1401,17 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std::
|
|||
tools::wallet_rpc_server alice_rpc(alice_wlt);
|
||||
std::shared_ptr<tools::wallet_rpc_server> alice_rpc_wo_ptr{ new tools::wallet_rpc_server(alice_wlt_wo) };
|
||||
|
||||
// send a cold-signed transaction
|
||||
// send a cold-signed transaction: Alice -> Bob; 50 test coins + 50 of the asset
|
||||
tools::wallet_public::COMMAND_RPC_TRANSFER::request req{};
|
||||
req.destinations.emplace_back();
|
||||
req.destinations.back().amount = MK_TEST_COINS(50);
|
||||
req.destinations.back().address = m_accounts[BOB_ACC_IDX].get_public_address_str();
|
||||
req.destinations.emplace_back(tools::wallet_public::transfer_destination{MK_TEST_COINS(50), m_accounts[BOB_ACC_IDX].get_public_address_str(), native_coin_asset_id});
|
||||
if (use_assets)
|
||||
req.destinations.emplace_back(tools::wallet_public::transfer_destination{50, m_accounts[BOB_ACC_IDX].get_public_address_str(), deployed_asset_id});
|
||||
req.fee = TESTS_DEFAULT_FEE;
|
||||
req.mixin = 10;
|
||||
r = make_cold_signing_transaction(*alice_rpc_wo_ptr, alice_rpc, req);
|
||||
CHECK_AND_ASSERT_MES(r, false, "make_cold_signing_transaction failed");
|
||||
|
||||
uint64_t bob_expected_balance = req.destinations.back().amount;
|
||||
uint64_t bob_expected_balance = req.destinations.front().amount;
|
||||
|
||||
// mine few blocks to unlock Alice's coins
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "unexpected pool txs count: " << c.get_pool_transactions_count());
|
||||
|
|
@ -1407,7 +1444,7 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std::
|
|||
CHECK_AND_ASSERT_EQ(blocks_fetched, 0);
|
||||
|
||||
|
||||
// send a cold-signed transaction
|
||||
// send a cold-signed transaction: Alice -> Bob; all rest test coins (should be 50 - 1 = 49)
|
||||
req = tools::wallet_public::COMMAND_RPC_TRANSFER::request{};
|
||||
req.destinations.emplace_back();
|
||||
req.destinations.back().amount = alice_expected_balance - TESTS_DEFAULT_FEE;
|
||||
|
|
@ -1437,7 +1474,7 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std::
|
|||
CURRENCY_MINED_MONEY_UNLOCK_WINDOW, alice_expected_balance, 0, 0, 0), false, "");
|
||||
|
||||
|
||||
// send a cold-signed transaction
|
||||
// send a cold-signed transaction: Alice -> Bob; all rest test coins (should be 7 - 1 = 6)
|
||||
req = tools::wallet_public::COMMAND_RPC_TRANSFER::request{};
|
||||
req.destinations.emplace_back();
|
||||
req.destinations.back().amount = alice_expected_balance - TESTS_DEFAULT_FEE;
|
||||
|
|
@ -1461,11 +1498,167 @@ bool wallet_rpc_cold_signing::c1(currency::core& c, size_t ev_index, const std::
|
|||
// check Alice's balance
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("after sending the second cold-signed tx:", "Alice", alice_wlt_wo, alice_expected_balance, true,
|
||||
CURRENCY_MINED_MONEY_UNLOCK_WINDOW, alice_expected_balance, 0, 0, 0), false, "");
|
||||
if (use_assets)
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt_wo.get(), "Alice", 0, 0, 0, 0, 0, deployed_asset_id, deployed_asset_decimal_point), false, "");
|
||||
|
||||
|
||||
|
||||
// finally, check Bob's balance
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, bob_expected_balance, true, 3 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW, bob_expected_balance, 0, 0, 0), false, "");
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, bob_expected_balance, true, 4 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW, bob_expected_balance, 0, 0, 0), false, "");
|
||||
if (use_assets)
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", 50, 0, 50, 0, 0, deployed_asset_id, deployed_asset_decimal_point), false, "");
|
||||
|
||||
|
||||
// Alice watch-only: reload the wallet, make sure the balance is still okay (zero)
|
||||
alice_rpc_wo_ptr.reset();
|
||||
alice_wlt_wo->reset_password(m_wallet_password);
|
||||
alice_wlt_wo->store(m_wallet_filename);
|
||||
CHECK_AND_ASSERT_EQ(alice_wlt_wo.unique(), true);
|
||||
alice_wlt_wo.reset(new tools::wallet2);
|
||||
alice_wlt_wo->load(m_wallet_filename, m_wallet_password);
|
||||
alice_wlt_wo->set_core_proxy(m_core_proxy);
|
||||
alice_wlt_wo->set_core_runtime_config(c.get_blockchain_storage().get_core_runtime_config());
|
||||
set_wallet_options(alice_wlt_wo);
|
||||
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("after re-loading with zero balance:", "Alice", alice_wlt_wo, 0, true, 0, 0, 0, 0, 0), false, "");
|
||||
if (use_assets)
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt_wo.get(), "Alice", 0, 0, 0, 0, 0, deployed_asset_id, deployed_asset_decimal_point), false, "");
|
||||
|
||||
|
||||
// Alice: remove outkey2ki file with key images copies and restore the wallet from watch-only account
|
||||
std::string alice_seed_phrase = m_accounts[ALICE_ACC_IDX].get_seed_phrase("");
|
||||
CHECK_AND_ASSERT_EQ(alice_wlt_wo.unique(), true);
|
||||
alice_wlt_wo.reset();
|
||||
CHECK_AND_ASSERT_MES(boost::filesystem::remove(epee::string_tools::cut_off_extension(m_wallet_filename) + L".outkey2ki"), false, "boost::filesystem::remove failed");
|
||||
CHECK_AND_ASSERT_MES(boost::filesystem::remove(m_wallet_filename), false, "boost::filesystem::remove failed");
|
||||
|
||||
alice_wlt_wo = init_playtime_test_wallet(events, c, alice_acc_wo);
|
||||
alice_wlt_wo->set_core_proxy(m_core_proxy);
|
||||
alice_wlt_wo->set_core_runtime_config(c.get_blockchain_storage().get_core_runtime_config());
|
||||
set_wallet_options(alice_wlt_wo);
|
||||
|
||||
// without key images Alice watch-only wallet is only able to detect incoming transfers and thus calculate incorrect balance
|
||||
alice_expected_balance = MK_TEST_COINS(100 + 49 + 7);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("after sending the second cold-signed tx:", "Alice", alice_wlt_wo, alice_expected_balance, true,
|
||||
5 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1, alice_expected_balance, 0, 0, 0), false, "");
|
||||
if (use_assets)
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt_wo.get(), "Alice", 50, 0, 50, 0, 0, deployed_asset_id, deployed_asset_decimal_point), false, "");
|
||||
|
||||
// store this broken watch-only wallet into a file ...
|
||||
alice_wlt_wo->reset_password(m_wallet_password);
|
||||
alice_wlt_wo->store(m_wallet_filename);
|
||||
CHECK_AND_ASSERT_EQ(alice_wlt_wo.unique(), true);
|
||||
alice_wlt_wo.reset();
|
||||
|
||||
// ... and repair it using full key wallet
|
||||
alice_wlt->restore_key_images_in_wo_wallet(m_wallet_filename, m_wallet_password);
|
||||
|
||||
alice_wlt_wo.reset(new tools::wallet2);
|
||||
alice_wlt_wo->load(m_wallet_filename, m_wallet_password);
|
||||
alice_wlt_wo->set_core_proxy(m_core_proxy);
|
||||
alice_wlt_wo->set_core_runtime_config(c.get_blockchain_storage().get_core_runtime_config());
|
||||
set_wallet_options(alice_wlt_wo);
|
||||
|
||||
// re-check the balance, it should be zero now
|
||||
alice_expected_balance = 0;
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("after sending the second cold-signed tx:", "Alice", alice_wlt_wo, alice_expected_balance, true,
|
||||
5 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1, alice_expected_balance, 0, 0, 0), false, "");
|
||||
if (use_assets)
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt_wo.get(), "Alice", 0, 0, 0, 0, 0, deployed_asset_id, deployed_asset_decimal_point), false, "");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// TODO: work in progress -- sowle
|
||||
wallet_rpc_multiple_receivers::wallet_rpc_multiple_receivers()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(wallet_rpc_multiple_receivers, c1);
|
||||
}
|
||||
|
||||
void wallet_rpc_multiple_receivers::set_wallet_options(std::shared_ptr<tools::wallet2> w)
|
||||
{
|
||||
set_playtime_test_wallet_options(w);
|
||||
w->set_concise_mode(false);
|
||||
}
|
||||
|
||||
bool wallet_rpc_multiple_receivers::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());
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
|
||||
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
|
||||
|
||||
DO_CALLBACK(events, "c1");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wallet_rpc_multiple_receivers::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
bool r = false;
|
||||
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
|
||||
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);
|
||||
|
||||
tools::wallet_rpc_server miner_rpc(miner_wlt);
|
||||
tools::wallet_rpc_server alice_rpc(alice_wlt);
|
||||
|
||||
miner_wlt->refresh();
|
||||
//bob_wlt->refresh();
|
||||
//check_balance_via_wallet(*bob_wlt, "Bob", 0, 0, 0, 0, 0);
|
||||
|
||||
// for post HF4 cases transfer some assets along with native coins
|
||||
crypto::public_key deployed_asset_id{};
|
||||
size_t deployed_asset_decimal_point = 0;
|
||||
|
||||
// miner deploys new asset and sends 50 coins of it to Alice
|
||||
tools::wallet_public::COMMAND_ASSETS_DEPLOY::request req_deploy{};
|
||||
req_deploy.asset_descriptor.current_supply = 50;
|
||||
req_deploy.asset_descriptor.decimal_point = deployed_asset_decimal_point;
|
||||
req_deploy.asset_descriptor.full_name = "50 pounds per person";
|
||||
req_deploy.asset_descriptor.ticker = "50PPP";
|
||||
req_deploy.asset_descriptor.total_max_supply = 200; // for a family of four
|
||||
req_deploy.destinations.emplace_back(tools::wallet_public::transfer_destination{50, m_accounts[ALICE_ACC_IDX].get_public_address_str(), null_pkey});
|
||||
req_deploy.do_not_split_destinations = true;
|
||||
tools::wallet_public::COMMAND_ASSETS_DEPLOY::response res_deploy{};
|
||||
r = invoke_text_json_for_rpc(miner_rpc, "deploy_asset", req_deploy, res_deploy);
|
||||
CHECK_AND_ASSERT_MES(r, false, "RPC 'deploy_asset' failed");
|
||||
deployed_asset_id = res_deploy.new_asset_id;
|
||||
|
||||
|
||||
//
|
||||
tools::wallet_public::COMMAND_RPC_TRANSFER::request tr_req{};
|
||||
tools::wallet_public::COMMAND_RPC_TRANSFER::response tr_res{};
|
||||
tr_req.destinations.emplace_back(tools::wallet_public::transfer_destination{MK_TEST_COINS(80), m_accounts[ALICE_ACC_IDX].get_public_address_str()});
|
||||
tr_req.destinations.emplace_back(tools::wallet_public::transfer_destination{MK_TEST_COINS(90), m_accounts[BOB_ACC_IDX].get_public_address_str()});
|
||||
tr_req.fee = TESTS_DEFAULT_FEE;
|
||||
tr_req.mixin = 0;
|
||||
tr_req.hide_receiver = false;
|
||||
tr_req.push_payer = true;
|
||||
r = invoke_text_json_for_rpc(miner_rpc, "transfer", tr_req, tr_res);
|
||||
CHECK_AND_ASSERT_MES(r, false, "RPC failed");
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "enexpected pool txs count: " << c.get_pool_transactions_count());
|
||||
r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed");
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Tx pool is not empty: " << c.get_pool_transactions_count());
|
||||
|
||||
|
||||
// Alice: prepare watch-only wallet
|
||||
alice_wlt->refresh();
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", MK_TEST_COINS(80), 0, MK_TEST_COINS(80), 0, 0), false, "");
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", req_deploy.asset_descriptor.current_supply, 0, req_deploy.asset_descriptor.current_supply, 0, 0, deployed_asset_id, deployed_asset_decimal_point), false, "");
|
||||
|
||||
bob_wlt->refresh();
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt, "Bob", MK_TEST_COINS(90), 0, MK_TEST_COINS(90), 0, 0), false, "");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,3 +74,11 @@ struct wallet_rpc_cold_signing : public wallet_test
|
|||
mutable std::wstring m_wallet_filename = L"~coretests.wallet_rpc_cold_signing.file.tmp";
|
||||
mutable std::string m_wallet_password = "ballerinacappuccina";
|
||||
};
|
||||
|
||||
struct wallet_rpc_multiple_receivers : public wallet_test
|
||||
{
|
||||
wallet_rpc_multiple_receivers();
|
||||
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);
|
||||
void set_wallet_options(std::shared_ptr<tools::wallet2> w);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1443,14 +1443,14 @@ bool gen_wallet_transfers_and_chain_switch::generate(std::vector<test_event_entr
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
gen_wallet_decrypted_attachments::gen_wallet_decrypted_attachments()
|
||||
gen_wallet_decrypted_payload_items::gen_wallet_decrypted_payload_items()
|
||||
: m_on_transfer2_called(false)
|
||||
{
|
||||
m_hardforks.set_hardfork_height(1, 0);
|
||||
m_hardforks.set_hardfork_height(2, 0); // tx_payer requires HF2
|
||||
}
|
||||
|
||||
bool gen_wallet_decrypted_attachments::generate(std::vector<test_event_entry>& events) const
|
||||
bool gen_wallet_decrypted_payload_items::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
// Test outline
|
||||
// NOTE: All transactions are sending with same attachments: tx_payer, tx_comment and tx_message
|
||||
|
|
@ -1508,16 +1508,18 @@ bool gen_wallet_decrypted_attachments::generate(std::vector<test_event_entry>& e
|
|||
// that feeling when you are a bit paranoid
|
||||
std::vector<currency::payload_items_v> decrypted_attachments;
|
||||
currency::keypair k = currency::keypair::generate();
|
||||
transaction t = AUTO_VAL_INIT(t);
|
||||
t.attachment = std::vector<currency::attachment_v>({ a_tx_payer, a_tx_comment, a_tx_message });
|
||||
transaction t{};
|
||||
t.attachment.push_back(a_tx_payer);
|
||||
t.attachment.push_back(a_tx_message);
|
||||
t.extra.push_back(a_tx_comment);
|
||||
add_tx_pub_key_to_extra(t, k.pub);
|
||||
add_attachments_info_to_extra(t.extra, t.attachment);
|
||||
currency::encrypt_attachments(t, miner_acc.get_keys(), alice_acc.get_public_address(), k);
|
||||
currency::encrypt_payload_items(t, miner_acc.get_keys(), alice_acc.get_public_address(), k);
|
||||
bool r = currency::decrypt_payload_items(true, t, alice_acc.get_keys(), decrypted_attachments);
|
||||
CHECK_AND_ASSERT_MES(r, false, "encrypt_attachments + decrypt_attachments failed to work together");
|
||||
CHECK_AND_ASSERT_MES(r, false, "encrypt_payload_items + decrypt_attachments failed to work together");
|
||||
}
|
||||
|
||||
MAKE_TX_ATTACH(events, tx_0, miner_acc, alice_acc, MK_TEST_COINS(10000), blk_0r, std::vector<currency::attachment_v>({ a_tx_payer, a_tx_comment, a_tx_message }));
|
||||
MAKE_TX_EXTRA_ATTACH_FEE(events, tx_0, miner_acc, alice_acc, MK_TEST_COINS(10000), TESTS_DEFAULT_FEE, blk_0r, std::vector<currency::payload_items_v>({ a_tx_comment }), std::vector<currency::payload_items_v>({ a_tx_payer, a_tx_message }));
|
||||
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc); // don't put tx_0 into this block, the block is only necessary to trigger tx_pool scan on in wallet2::refresh()
|
||||
|
||||
// wallet callback must be passed as shared_ptr, so to avoid deleting "this" construct shared_ptr with custom null-deleter
|
||||
|
|
@ -1540,7 +1542,7 @@ bool gen_wallet_decrypted_attachments::generate(std::vector<test_event_entry>& e
|
|||
// Do the same in opposite direction: alice -> miner. Unlock money, received by Alice first.
|
||||
REWIND_BLOCKS_N(events, blk_2r, blk_2, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE);
|
||||
|
||||
MAKE_TX_ATTACH(events, tx_1, alice_acc, miner_acc, MK_TEST_COINS(100), blk_2r, std::vector<currency::attachment_v>({ a_tx_payer, a_tx_comment, a_tx_message }));
|
||||
MAKE_TX_EXTRA_ATTACH_FEE(events, tx_1, alice_acc, miner_acc, MK_TEST_COINS(100), TESTS_DEFAULT_FEE, blk_2r, std::vector<currency::payload_items_v>({ a_tx_comment }), std::vector<currency::payload_items_v>({ a_tx_payer, a_tx_message }));
|
||||
MAKE_NEXT_BLOCK(events, blk_3, blk_2r, miner_acc); // don't put tx_1 into this block, the block is only necessary to trigger tx_pool scan on in wallet2::refresh()
|
||||
|
||||
// Spend tx was not sent via Alice wallet instance, so wallet can't obtain destination address and pass it to callback (although, it decrypts attachments & extra)
|
||||
|
|
@ -1573,7 +1575,7 @@ bool gen_wallet_decrypted_attachments::generate(std::vector<test_event_entry>& e
|
|||
m_comment_to_be_checked = a_tx_comment.comment;
|
||||
m_address_to_be_checked = get_account_address_as_str(bob_acc.get_public_address()); // note, that a_tx_payer is NOT refering to Bob's account, but in the callback we should get correct sender addr
|
||||
m_on_transfer2_called = false;
|
||||
MAKE_TEST_WALLET_TX_ATTACH(events, tx_2, alice_wlt, MK_TEST_COINS(2000), bob_acc, std::vector<currency::attachment_v>({ a_tx_payer, a_tx_comment, a_tx_message }));
|
||||
MAKE_TEST_WALLET_TX_EXTRA_ATTACH(events, tx_2, alice_wlt, MK_TEST_COINS(2000), bob_acc, std::vector<currency::extra_v>({ a_tx_comment }), std::vector<currency::attachment_v>({ a_tx_payer, a_tx_message }));
|
||||
CHECK_AND_ASSERT_MES(m_on_transfer2_called, false, "on_transfer2() was not called (5)");
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_5, blk_4r, miner_acc); // don't put tx_2 into this block, the block is only necessary to trigger tx_pool scan on in wallet2::refresh()
|
||||
|
|
@ -1595,7 +1597,7 @@ bool gen_wallet_decrypted_attachments::generate(std::vector<test_event_entry>& e
|
|||
REFRESH_TEST_WALLET_AT_GEN_TIME(events, bob_wlt, blk_6r, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2 + WALLET_DEFAULT_TX_SPENDABLE_AGE + 2 + WALLET_DEFAULT_TX_SPENDABLE_AGE + 2 + WALLET_DEFAULT_TX_SPENDABLE_AGE);
|
||||
|
||||
a_tx_payer.acc_addr = bob_acc.get_public_address(); // here we specify correct payer address, as it will not be masked by wallet
|
||||
MAKE_TEST_WALLET_TX_ATTACH(events, tx_3, bob_wlt, MK_TEST_COINS(200), alice_acc, std::vector<currency::attachment_v>({ a_tx_payer, a_tx_comment, a_tx_message }));
|
||||
MAKE_TEST_WALLET_TX_EXTRA_ATTACH(events, tx_3, bob_wlt, MK_TEST_COINS(200), alice_acc, std::vector<currency::extra_v>({ a_tx_comment }), std::vector<currency::attachment_v>({ a_tx_payer, a_tx_message }));
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_7, blk_6r, miner_acc); // don't put tx_3 into this block, the block is only necessary to trigger tx_pool scan on in wallet2::refresh()
|
||||
|
||||
|
|
@ -1612,7 +1614,7 @@ bool gen_wallet_decrypted_attachments::generate(std::vector<test_event_entry>& e
|
|||
return true;
|
||||
}
|
||||
|
||||
void gen_wallet_decrypted_attachments::on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list<tools::wallet_public::asset_balance_entry>& balances, uint64_t total_mined)
|
||||
void gen_wallet_decrypted_payload_items::on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list<tools::wallet_public::asset_balance_entry>& balances, uint64_t total_mined)
|
||||
{
|
||||
m_on_transfer2_called = true;
|
||||
//try {
|
||||
|
|
@ -2986,7 +2988,7 @@ bool mined_balance_wallet_test::c1(currency::core& c, size_t ev_index, const std
|
|||
miner_wlt->refresh();
|
||||
|
||||
std::stringstream ss;
|
||||
miner_wlt->dump_trunsfers(ss, false);
|
||||
miner_wlt->dump_transfers(ss, false);
|
||||
LOG_PRINT_CYAN("miner transfers: " << ENDL << ss.str(), LOG_LEVEL_0);
|
||||
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*miner_wlt.get(), "miner", miner_mined_money, miner_mined_money), false, "wrong balance");
|
||||
|
|
@ -3798,7 +3800,6 @@ bool wallet_and_sweep_below::generate(std::vector<test_event_entry>& events) con
|
|||
|
||||
bool wallet_and_sweep_below::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
bool r = false;
|
||||
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
|
||||
|
||||
uint64_t miner_balance = (3 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW - 1) * COIN;
|
||||
|
|
@ -3959,14 +3960,12 @@ bool wallet_reorganize_and_trim_test::c1(currency::core& c, size_t ev_index, con
|
|||
mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 2);
|
||||
|
||||
mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, WALLET_REORGANIZE_AND_TRIM_TEST_REORG_SIZE);
|
||||
uint64_t h1 = c.get_blockchain_storage().get_top_block_height();
|
||||
miner_wlt->refresh();
|
||||
uint64_t unlocked = 0;
|
||||
uint64_t total = miner_wlt->balance(unlocked);
|
||||
|
||||
c.get_blockchain_storage().truncate_blockchain(c.get_blockchain_storage().get_top_block_height() - (WALLET_REORGANIZE_AND_TRIM_TEST_REORG_SIZE-1));
|
||||
mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 10);
|
||||
uint64_t h2 = c.get_blockchain_storage().get_top_block_height();
|
||||
miner_wlt->refresh();
|
||||
uint64_t unlocked2 = 0;
|
||||
uint64_t total2 = miner_wlt->balance(unlocked2);
|
||||
|
|
|
|||
|
|
@ -104,9 +104,9 @@ struct gen_wallet_transfers_and_chain_switch : public wallet_test
|
|||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct gen_wallet_decrypted_attachments : public wallet_test, virtual public tools::i_wallet2_callback
|
||||
struct gen_wallet_decrypted_payload_items : public wallet_test, virtual public tools::i_wallet2_callback
|
||||
{
|
||||
gen_wallet_decrypted_attachments();
|
||||
gen_wallet_decrypted_payload_items();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
|
||||
// intrface tools::i_wallet2_callback
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ bool check_scalar(const crypto::ec_scalar &scalar) {
|
|||
}
|
||||
|
||||
void random_scalar(crypto::ec_scalar &res) {
|
||||
crypto::random_scalar(res);
|
||||
crypto::random_scalar_no_lock(res);
|
||||
}
|
||||
|
||||
void hash_to_scalar(const void *data, std::size_t length, crypto::ec_scalar &res) {
|
||||
|
|
|
|||
|
|
@ -690,12 +690,12 @@ size_t find_pos_hash(const boost::multiprecision::uint256_t& L_div_D, const curr
|
|||
TEST(crypto, pos)
|
||||
{
|
||||
//scalar_t D = 10000000000000001u;
|
||||
scalar_t D = 13042196742415129u; // prime number
|
||||
currency::wide_difficulty_type D_w = D.as_boost_mp_type<boost::multiprecision::uint256_t>().convert_to<currency::wide_difficulty_type>();
|
||||
uint64_t amount = 1000000000000;
|
||||
size_t count_old = 0;
|
||||
size_t count_new = 0;
|
||||
size_t count_3 = 0;
|
||||
[[maybe_unused]] scalar_t D = 13042196742415129u; // prime number
|
||||
[[maybe_unused]] currency::wide_difficulty_type D_w = D.as_boost_mp_type<boost::multiprecision::uint256_t>().convert_to<currency::wide_difficulty_type>();
|
||||
[[maybe_unused]] uint64_t amount = 1000000000000;
|
||||
[[maybe_unused]] size_t count_old = 0;
|
||||
[[maybe_unused]] size_t count_new = 0;
|
||||
[[maybe_unused]] size_t count_3 = 0;
|
||||
scalar_t x;
|
||||
x.make_random();
|
||||
|
||||
|
|
@ -704,14 +704,14 @@ TEST(crypto, pos)
|
|||
|
||||
const boost::multiprecision::uint256_t c_L_w = c_scalar_L.as_boost_mp_type<boost::multiprecision::uint256_t>();
|
||||
const boost::multiprecision::uint256_t c_L_div_D_w = c_L_w / D_w;
|
||||
boost::multiprecision::uint512_t h_tres = c_L_div_D_w * amount;
|
||||
[[maybe_unused]] boost::multiprecision::uint512_t h_tres = c_L_div_D_w * amount;
|
||||
|
||||
currency::wide_difficulty_type final_diff = D_w / amount;
|
||||
[[maybe_unused]] currency::wide_difficulty_type final_diff = D_w / amount;
|
||||
|
||||
boost::multiprecision::uint512_t Lv = boost::multiprecision::uint512_t(c_L_w) * amount;
|
||||
[[maybe_unused]] boost::multiprecision::uint512_t Lv = boost::multiprecision::uint512_t(c_L_w) * amount;
|
||||
|
||||
constexpr uint64_t c_coin = 1000000000000;
|
||||
const uint64_t amounts[] = {
|
||||
[[maybe_unused]] const uint64_t amounts[] = {
|
||||
c_coin / 100,
|
||||
c_coin / 50,
|
||||
c_coin / 20,
|
||||
|
|
@ -738,9 +738,9 @@ TEST(crypto, pos)
|
|||
c_coin * 500000
|
||||
};
|
||||
|
||||
uint64_t kernel = 0;
|
||||
scalar_t d0 = 0;
|
||||
uint64_t d1 = 0;
|
||||
[[maybe_unused]] uint64_t kernel = 0;
|
||||
[[maybe_unused]] scalar_t d0 = 0;
|
||||
[[maybe_unused]] uint64_t d1 = 0;
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -1064,7 +1064,8 @@ TEST(crypto, hp)
|
|||
TEST(perf, cn_fast_hash)
|
||||
{
|
||||
//return true;
|
||||
const crypto::hash h_initial = *(crypto::hash*)(&scalar_t::random());
|
||||
scalar_t s_rnd = scalar_t::random();
|
||||
const crypto::hash h_initial = *(crypto::hash*)(&s_rnd);
|
||||
|
||||
std::vector<std::vector<uint8_t>> test_data;
|
||||
test_data.push_back(std::vector<uint8_t>(32, 0));
|
||||
|
|
@ -1631,8 +1632,8 @@ TEST(crypto, schnorr_sig)
|
|||
{
|
||||
public_key invalid_pk = parse_tpod_from_hex_string<public_key>("0000000000000000000000000000000000000000000000000000000000000001");
|
||||
ASSERT_FALSE(check_key(invalid_pk));
|
||||
|
||||
hash m = *(crypto::hash*)(&scalar_t::random());
|
||||
scalar_t s_rnd = scalar_t::random();
|
||||
hash m = *(crypto::hash*)(&s_rnd);
|
||||
for(size_t i = 0; i < 100; ++i)
|
||||
{
|
||||
generic_schnorr_sig_s ss{};
|
||||
|
|
|
|||
|
|
@ -219,8 +219,6 @@ TEST(clsag, bad_sig)
|
|||
|
||||
TEST(clsag, sig_difference)
|
||||
{
|
||||
int cmp_res = 0;
|
||||
|
||||
clsag_gg_sig_check_t cc0, cc1;
|
||||
cc0.prepare_random_data(8);
|
||||
cc1 = cc0; // get the same input data
|
||||
|
|
|
|||
|
|
@ -344,7 +344,8 @@ TEST(perf, primitives)
|
|||
p = p + p;
|
||||
}
|
||||
ge_p3 Q;
|
||||
ge_scalarmult_base(&Q, &scalar_t::random().m_s[0]);
|
||||
scalar_t s_rnd = scalar_t::random();
|
||||
ge_scalarmult_base(&Q, &s_rnd.m_s[0]);
|
||||
std::vector<ge_p1p1> results(rnd_indecies.size());
|
||||
|
||||
t.start();
|
||||
|
|
@ -1109,8 +1110,6 @@ struct pme_runner_t : public pme_runner_i
|
|||
|
||||
TEST(perf, msm)
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
std::deque<std::unique_ptr<pme_runner_i>> runners;
|
||||
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 1));
|
||||
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 2));
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ TEST(bppe, power_128)
|
|||
std::vector<point_t>& commitments = commitments_vector.back();
|
||||
|
||||
scalar_vec_t masks, masks2;
|
||||
for(auto& el: values)
|
||||
for (size_t i = 0; i < values.size(); ++i)
|
||||
{
|
||||
masks.emplace_back(scalar_t::random());
|
||||
masks2.emplace_back(scalar_t::random());
|
||||
|
|
|
|||
|
|
@ -236,7 +236,6 @@ void perform_simulation_for_function(const std::map<uint64_t, uint64_t>& timesta
|
|||
std::vector<currency::wide_difficulty_type> backward_cumul_difficulties;
|
||||
backward_cumul_difficulties.reserve(BBR_DIFFICULTY_WINDOW);
|
||||
std::copy(cumul_difficulties.rbegin(), cumul_difficulties.rbegin() + BBR_DIFFICULTY_WINDOW - 1, std::back_inserter(backward_cumul_difficulties));
|
||||
uint64_t ts = timestamps.back();
|
||||
curren_difficulty = cb(backward_timestamps, backward_cumul_difficulties, BBR_DIFFICULTY_TARGET);
|
||||
}
|
||||
cumul_difficulties.push_back(cumul_difficulties.back() + curren_difficulty);
|
||||
|
|
@ -357,7 +356,7 @@ void hash_rate_analysis(const std::string& path)
|
|||
uint64_t curren_hashrate = 0;
|
||||
uint64_t step = 10;
|
||||
uint64_t hash_rate_range = 10;
|
||||
uint64_t second_windowf_or_hashrate = 20*60;
|
||||
// uint64_t second_windowf_or_hashrate = 20*60;
|
||||
|
||||
for (size_t i = hash_rate_range; i != blocks.size(); i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ int test_get_rand_outs()
|
|||
m_core_proxy->set_connection_addr("127.0.0.1:11211");
|
||||
m_core_proxy->check_connection();
|
||||
|
||||
bool r = m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(req, rsp);
|
||||
m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(req, rsp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,9 +41,8 @@ bool perform_crypt_stream_iteration(const std::list<currency::block_extended_inf
|
|||
in.push(data_file);
|
||||
try {
|
||||
|
||||
bool res2 = tools::portable_unserialize_obj_from_stream(verification_list, in);
|
||||
tools::portable_unserialize_obj_from_stream(verification_list, in);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Failed to unserialize wallet");
|
||||
size_t i = 0;
|
||||
CHECK_AND_ASSERT_MES(test_list.size() == verification_list.size(), false, "restored list is wrong size");
|
||||
return true;
|
||||
}
|
||||
|
|
@ -81,9 +80,8 @@ bool perform_just_substream_stream_iteration(const std::list<currency::block_ext
|
|||
in.push(data_file);
|
||||
try {
|
||||
|
||||
bool res2 = tools::portable_unserialize_obj_from_stream(verification_list, in);
|
||||
tools::portable_unserialize_obj_from_stream(verification_list, in);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Failed to unserialize wallet");
|
||||
size_t i = 0;
|
||||
CHECK_AND_ASSERT_MES(test_list.size() == verification_list.size(), false, "restored list is wrong size");
|
||||
return true;
|
||||
}
|
||||
|
|
@ -122,9 +120,8 @@ bool perform_no_crypt_stream_iteration(const std::list<currency::block_extended_
|
|||
// in.push(data_file);
|
||||
try {
|
||||
|
||||
bool res2 = tools::portable_unserialize_obj_from_stream(verification_list, data_file);
|
||||
tools::portable_unserialize_obj_from_stream(verification_list, data_file);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Failed to unserialize wallet");
|
||||
size_t i = 0;
|
||||
CHECK_AND_ASSERT_MES(test_list.size() == verification_list.size(), false, "restored list is wrong size");
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ void parse_weird_tx()
|
|||
std::string tx_blob;
|
||||
epee::string_tools::parse_hexstr_to_binbuff(tx_hex_buff, tx_blob);
|
||||
currency::transaction tx;
|
||||
bool r = currency::parse_and_validate_tx_from_blob(tx_blob, tx);
|
||||
currency::parse_and_validate_tx_from_blob(tx_blob, tx);
|
||||
std::string res_hash = epee::string_tools::pod_to_hex(currency::get_transaction_hash(tx));
|
||||
if (res_hash != expected_hash)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ void test_base64_serialization()
|
|||
epee::serialization::store_t_to_json(rsp, str_json);
|
||||
|
||||
currency::COMMAND_RPC_GET_POOL_TXS_DETAILS::response rsp2;
|
||||
bool res = epee::serialization::load_t_from_json(rsp2, str_json);
|
||||
epee::serialization::load_t_from_json(rsp2, str_json);
|
||||
if (rsp.txs.back().blob != rsp2.txs.back().blob)
|
||||
{
|
||||
LOG_PRINT_L0("Troubles");
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ TEST(chacha_stream_test, basic_test_with_serialization_on_top)
|
|||
|
||||
|
||||
//out << buff;
|
||||
bool res = tools::portble_serialize_obj_to_stream(test_list, out);
|
||||
tools::portble_serialize_obj_to_stream(test_list, out);
|
||||
|
||||
out.flush();
|
||||
store_data_file.close();
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ struct bcs_stub_t
|
|||
|
||||
TEST(db_accessor_tests, median_db_cache_test)
|
||||
{
|
||||
crypto::random_prng_initialize_with_seed(0); // make this test deterministic (the same crypto::rand() sequence)
|
||||
crypto::random_prng_initialize_with_seed_no_lock(0); // make this test deterministic (the same crypto::rand() sequence)
|
||||
|
||||
epee::shared_recursive_mutex m_rw_lock;
|
||||
tools::db::basic_db_accessor m_db(std::shared_ptr<tools::db::i_db_backend>(new tools::db::lmdb_db_backend), m_rw_lock);
|
||||
|
|
|
|||
|
|
@ -362,8 +362,8 @@ namespace db_test
|
|||
void multithread_test_1()
|
||||
{
|
||||
char prng_state[200] = {};
|
||||
crypto::random_prng_get_state(prng_state, sizeof prng_state); // store current RPNG state
|
||||
crypto::random_prng_initialize_with_seed(0); // this mades this test deterministic
|
||||
crypto::random_prng_get_state_no_lock(prng_state, sizeof prng_state); // store current RPNG state
|
||||
crypto::random_prng_initialize_with_seed_no_lock(0); // this mades this test deterministic
|
||||
|
||||
bool result = false;
|
||||
try
|
||||
|
|
@ -377,7 +377,7 @@ namespace db_test
|
|||
}
|
||||
|
||||
// restore PRNG state to keep other tests unaffected
|
||||
crypto::random_prng_set_state(prng_state, sizeof prng_state);
|
||||
crypto::random_prng_set_state_no_lock(prng_state, sizeof prng_state);
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
TEST(decoy_selection_test, decoy_selection_test)
|
||||
{
|
||||
const uint64_t test_scale_size = 20000;
|
||||
// const uint64_t test_scale_size = 20000;
|
||||
decoy_selection_generator dsg;
|
||||
dsg.init(100);
|
||||
std::map<uint64_t, uint64_t> hits;
|
||||
|
|
|
|||
|
|
@ -443,8 +443,6 @@ TEST(multiassets, native_serialization_get_or_calculate_asset_id_undefined)
|
|||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x97', '\x9e', '\xb7', '\x06', '\xac', '\xe2', '\xeb', '\x83', '\xf9', '\x12', 'V', 'X', '\xb2', '?', '\xb3', 'R', ' ',
|
||||
'\x84', '\x80', '\xcb', ';', '\x90', '\xc4', '>', '-', '\xf0', '\xd2', '\x98', '\xf9', 'u', 'N', '\xbc'};
|
||||
|
||||
crypto::point_t expected_point_asset_id{};
|
||||
crypto::public_key expected_asset_id{};
|
||||
crypto::point_t calculated_point_asset_id{};
|
||||
crypto::public_key calculated_asset_id{};
|
||||
const std::optional ado{deserialize<currency::asset_descriptor_operation>(serialization_method::native, serialized_ado)};
|
||||
|
|
|
|||
364
tests/unit_tests/pod_array_file_container.cpp
Normal file
364
tests/unit_tests/pod_array_file_container.cpp
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
// Copyright (c) 2025 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "epee/include/include_base_utils.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/crypto-sugar.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "common/pod_array_file_container.h"
|
||||
|
||||
// helper: returns a unique temp file path
|
||||
static boost::filesystem::path make_temp_file()
|
||||
{
|
||||
return boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("pod_test_%%%%-%%%%.bin");
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// typed test fixture for pod_array_file_container<T>
|
||||
// container = alias for pod_array_file_container<T>
|
||||
// tmp_path = temp file for test
|
||||
// SetUp() = generate temp path (SetUp from ::testing::Test)
|
||||
// TearDown() = remove temp file (TearDown from ::testing::Test)
|
||||
//======================================================================
|
||||
|
||||
template <typename T>
|
||||
class pod_array_file_typed_test : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
using container = tools::pod_array_file_container<T>;
|
||||
boost::filesystem::path tmp_path;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
tmp_path = make_temp_file();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
if (boost::filesystem::exists(tmp_path))
|
||||
boost::filesystem::remove(tmp_path);
|
||||
}
|
||||
};
|
||||
|
||||
// list of integral types to test
|
||||
using integral_types = ::testing::Types<
|
||||
int8_t, uint8_t,
|
||||
int16_t, uint16_t,
|
||||
int32_t, uint32_t,
|
||||
int64_t, uint64_t
|
||||
>;
|
||||
// register typed tests
|
||||
TYPED_TEST_CASE(pod_array_file_typed_test, integral_types);
|
||||
|
||||
// push back and get items:
|
||||
// write values [-1,0,1] and verify they are read back correctly
|
||||
TYPED_TEST(pod_array_file_typed_test, push_back_and_get_items)
|
||||
{
|
||||
typename TestFixture::container c;
|
||||
ASSERT_TRUE(c.open(this->tmp_path.wstring(), true));
|
||||
|
||||
std::vector<TypeParam> values =
|
||||
{
|
||||
static_cast<TypeParam>(-1),
|
||||
0,
|
||||
static_cast<TypeParam>(1)
|
||||
};
|
||||
|
||||
for (auto v : values)
|
||||
ASSERT_TRUE(c.push_back(v));
|
||||
|
||||
EXPECT_EQ(c.size(), values.size());
|
||||
|
||||
TypeParam read_value;
|
||||
for (size_t i = 0; i < values.size(); ++i)
|
||||
{
|
||||
ASSERT_TRUE(c.get_item(i, read_value));
|
||||
EXPECT_EQ(read_value, values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// ensure get_item returns false for index >= size
|
||||
TYPED_TEST(pod_array_file_typed_test, get_item_out_of_range)
|
||||
{
|
||||
typename TestFixture::container c;
|
||||
ASSERT_TRUE(c.open(this->tmp_path.wstring(), true));
|
||||
|
||||
TypeParam dummy;
|
||||
EXPECT_FALSE(c.get_item(0, dummy));
|
||||
EXPECT_FALSE(c.get_item(100, dummy));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
typedef uint32_t pod_t;
|
||||
typedef tools::pod_array_file_container<pod_t> pod_container;
|
||||
|
||||
// open fails if not exist without create:
|
||||
// open() false when file missing and create_if_not_exist=false
|
||||
TEST(pod_array_file_container, open_fails_if_not_exist_without_create)
|
||||
{
|
||||
auto path = make_temp_file();
|
||||
pod_container c;
|
||||
std::string reason;
|
||||
bool opened = c.open(path.wstring(), false, nullptr, &reason);
|
||||
EXPECT_FALSE(opened);
|
||||
EXPECT_TRUE(reason.find("not exist") != std::string::npos);
|
||||
}
|
||||
|
||||
// open creates file when not exist:
|
||||
// open() with create flag creates empty file and size=0
|
||||
TEST(pod_array_file_container, open_creates_file_when_not_exist)
|
||||
{
|
||||
auto path = make_temp_file();
|
||||
pod_container c;
|
||||
bool corrupted = true;
|
||||
ASSERT_TRUE(c.open(path.wstring(), true, &corrupted, nullptr));
|
||||
EXPECT_FALSE(corrupted);
|
||||
EXPECT_EQ(c.size(), 0u);
|
||||
c.close();
|
||||
EXPECT_TRUE(boost::filesystem::exists(path));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// POD struct with fixed-size fields
|
||||
struct test_struct
|
||||
{
|
||||
crypto::public_key pubkey;
|
||||
crypto::key_image key;
|
||||
};
|
||||
|
||||
typedef tools::pod_array_file_container<test_struct> struct_container;
|
||||
|
||||
// push back and get items struct:
|
||||
// write two test_struct and verify memory equality
|
||||
TEST(pod_array_file_container_struct, push_back_and_get_items_struct)
|
||||
{
|
||||
auto path = make_temp_file();
|
||||
struct_container c;
|
||||
ASSERT_TRUE(c.open(path.wstring(), true));
|
||||
|
||||
test_struct a1{}, a2{};
|
||||
|
||||
// use random values for pubkey and key
|
||||
a1.pubkey = (crypto::scalar_t::random() * crypto::c_point_G).to_public_key();
|
||||
a1.key = (crypto::scalar_t::random() * crypto::c_point_G).to_key_image();
|
||||
a2.pubkey = (crypto::scalar_t::random() * crypto::c_point_G).to_public_key();
|
||||
a2.key = (crypto::scalar_t::random() * crypto::c_point_G).to_key_image();
|
||||
|
||||
ASSERT_TRUE(c.push_back(a1));
|
||||
ASSERT_TRUE(c.push_back(a2));
|
||||
EXPECT_EQ(c.size(), 2u);
|
||||
|
||||
test_struct got;
|
||||
ASSERT_TRUE(c.get_item(0, got));
|
||||
EXPECT_EQ(got.pubkey, a1.pubkey);
|
||||
EXPECT_EQ(got.key, a1.key);
|
||||
ASSERT_TRUE(c.get_item(1, got));
|
||||
EXPECT_EQ(got.pubkey, a2.pubkey);
|
||||
EXPECT_EQ(got.key, a2.key);
|
||||
}
|
||||
|
||||
// get item out of range struct:
|
||||
// get_item false when no items written
|
||||
TEST(pod_array_file_container_struct, get_item_out_of_range_struct)
|
||||
{
|
||||
auto path = make_temp_file();
|
||||
struct_container c;
|
||||
ASSERT_TRUE(c.open(path.wstring(), true));
|
||||
test_struct dummy;
|
||||
EXPECT_FALSE(c.get_item(0, dummy));
|
||||
}
|
||||
|
||||
// corrupted file truncation struct:
|
||||
// simulate corrupted file tail and check truncation flag and size
|
||||
TEST(pod_array_file_container_struct, corrupted_file_truncation_struct)
|
||||
{
|
||||
auto path = make_temp_file();
|
||||
{
|
||||
// write a valid test_struct followed by garbage data
|
||||
boost::filesystem::ofstream out(path, std::ios::binary | std::ios::out);
|
||||
test_struct tmp{};
|
||||
std::fill(std::begin(tmp.pubkey.data), std::end(tmp.pubkey.data), 'X');
|
||||
std::fill(std::begin(tmp.key.data), std::end(tmp.key.data), 'Y');
|
||||
out.write(reinterpret_cast<char*>(&tmp), sizeof(tmp));
|
||||
const char garbage[5] = {1,2,3,4,5};
|
||||
out.write(garbage, sizeof(garbage));
|
||||
}
|
||||
|
||||
struct_container c;
|
||||
bool corrupted = false;
|
||||
std::string reason;
|
||||
ASSERT_TRUE(c.open(path.wstring(), false, &corrupted, &reason));
|
||||
EXPECT_TRUE(corrupted);
|
||||
EXPECT_EQ(c.size(), 1u);
|
||||
|
||||
test_struct got;
|
||||
ASSERT_TRUE(c.get_item(0, got));
|
||||
|
||||
for (size_t i = 0; i < sizeof(got.pubkey.data); ++i)
|
||||
EXPECT_EQ(got.pubkey.data[i], 'X');
|
||||
for (size_t i = 0; i < sizeof(got.key.data); ++i)
|
||||
EXPECT_EQ(got.key.data[i], 'Y');
|
||||
|
||||
EXPECT_TRUE(reason.find("truncated") != std::string::npos);
|
||||
}
|
||||
|
||||
// persistence between opens struct:
|
||||
// write multiple structs, reopen file, verify data persists
|
||||
TEST(pod_array_file_container_struct, persistence_between_opens_struct)
|
||||
{
|
||||
auto path = make_temp_file();
|
||||
{
|
||||
// write 3 test_struct with different pubkey and key values
|
||||
struct_container c;
|
||||
ASSERT_TRUE(c.open(path.wstring(), true));
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
test_struct tmp{};
|
||||
tmp.pubkey.data[0] = '0' + i;
|
||||
tmp.key.data[0] = 'A' + i;
|
||||
ASSERT_TRUE(c.push_back(tmp));
|
||||
}
|
||||
EXPECT_EQ(c.size(), 3u);
|
||||
}
|
||||
|
||||
// reopen and verify data
|
||||
struct_container c2;
|
||||
ASSERT_TRUE(c2.open(path.wstring(), false));
|
||||
EXPECT_EQ(c2.size(), 3u);
|
||||
test_struct got;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
ASSERT_TRUE(c2.get_item(i, got));
|
||||
EXPECT_EQ(got.pubkey.data[0], '0' + i);
|
||||
EXPECT_EQ(got.key.data[0], 'A' + i);
|
||||
}
|
||||
}
|
||||
|
||||
// size bytes and size:
|
||||
// check size_bytes() matches raw byte count and size() element count
|
||||
TEST(pod_array_file_container, size_bytes_and_size)
|
||||
{
|
||||
auto path = make_temp_file();
|
||||
pod_container c;
|
||||
ASSERT_TRUE(c.open(path.wstring(), true));
|
||||
EXPECT_EQ(c.size_bytes(), 0u);
|
||||
EXPECT_EQ(c.size(), 0u);
|
||||
// push one element
|
||||
pod_t value = 42;
|
||||
ASSERT_TRUE(c.push_back(value));
|
||||
EXPECT_EQ(c.size_bytes(), sizeof(pod_t));
|
||||
EXPECT_EQ(c.size(), 1u);
|
||||
}
|
||||
|
||||
// operations after close:
|
||||
// ensure push_back and get_item fail after close()
|
||||
TEST(pod_array_file_container, operations_after_close)
|
||||
{
|
||||
auto path = make_temp_file();
|
||||
pod_container c;
|
||||
ASSERT_TRUE(c.open(path.wstring(), true));
|
||||
ASSERT_TRUE(c.push_back(123u));
|
||||
c.close();
|
||||
// after close, operations should return false
|
||||
EXPECT_FALSE(c.push_back(456u));
|
||||
pod_t dummy = 0;
|
||||
EXPECT_FALSE(c.get_item(0, dummy));
|
||||
}
|
||||
|
||||
// open fails if cannot open (directory):
|
||||
// attempt to open a directory path should fail with "file could not be opened"
|
||||
TEST(pod_array_file_container, open_fails_if_cannot_open)
|
||||
{
|
||||
// create a directory instead of a file
|
||||
auto dir_path = make_temp_file();
|
||||
boost::filesystem::create_directory(dir_path);
|
||||
pod_container c;
|
||||
std::string reason;
|
||||
bool opened = c.open(dir_path.wstring(), true, nullptr, &reason);
|
||||
EXPECT_FALSE(opened);
|
||||
EXPECT_TRUE(reason.find("could not be opened") != std::string::npos);
|
||||
boost::filesystem::remove(dir_path);
|
||||
}
|
||||
|
||||
// corrupted file truncation uint32:
|
||||
// simulate corrupted file tail on uint32_t and check truncation
|
||||
TEST(pod_array_file_container, corrupted_file_truncation_uint32)
|
||||
{
|
||||
auto path = make_temp_file();
|
||||
{
|
||||
boost::filesystem::ofstream out(path, std::ios::binary | std::ios::out);
|
||||
pod_t v = 0x12345678u;
|
||||
out.write(reinterpret_cast<char*>(&v), sizeof(v));
|
||||
const char junk[3] = {9,8,7};
|
||||
out.write(junk, sizeof(junk));
|
||||
}
|
||||
pod_container c;
|
||||
bool corrupted = false;
|
||||
std::string reason;
|
||||
ASSERT_TRUE(c.open(path.wstring(), false, &corrupted, &reason));
|
||||
EXPECT_TRUE(corrupted);
|
||||
EXPECT_EQ(c.size(), 1u);
|
||||
pod_t read_v;
|
||||
ASSERT_TRUE(c.get_item(0, read_v));
|
||||
EXPECT_EQ(read_v, 0x12345678u);
|
||||
EXPECT_TRUE(reason.find("truncated") != std::string::npos);
|
||||
}
|
||||
|
||||
// operations without open:
|
||||
// ensure push_back/get_item/size_bytes/size behave when container never opened
|
||||
TEST(pod_array_file_container, operations_without_open)
|
||||
{
|
||||
pod_container c;
|
||||
EXPECT_FALSE(c.push_back(1u));
|
||||
pod_t dummy;
|
||||
EXPECT_FALSE(c.get_item(0, dummy));
|
||||
EXPECT_EQ(c.size_bytes(), 0u);
|
||||
EXPECT_EQ(c.size(), 0u);
|
||||
}
|
||||
|
||||
// checks stream state transitions
|
||||
TEST(pod_array_file_container, is_opened_and_in_good_state)
|
||||
{
|
||||
auto path = make_temp_file();
|
||||
pod_container c;
|
||||
|
||||
// not opened yet
|
||||
EXPECT_FALSE(c.is_opened_and_in_good_state());
|
||||
|
||||
// open for create
|
||||
ASSERT_TRUE(c.open(path.wstring(), true));
|
||||
EXPECT_TRUE(c.is_opened_and_in_good_state());
|
||||
|
||||
// after close
|
||||
c.close();
|
||||
EXPECT_FALSE(c.is_opened_and_in_good_state());
|
||||
}
|
||||
|
||||
// wipes file contents and resets size
|
||||
TEST(pod_array_file_container, clear_resets_file)
|
||||
{
|
||||
auto path = make_temp_file();
|
||||
pod_container c;
|
||||
ASSERT_TRUE(c.open(path.wstring(), true));
|
||||
|
||||
// add some elements
|
||||
ASSERT_TRUE(c.push_back(123u));
|
||||
ASSERT_TRUE(c.push_back(456u));
|
||||
EXPECT_EQ(c.size(), 2u);
|
||||
|
||||
// clear the container
|
||||
ASSERT_TRUE(c.clear());
|
||||
EXPECT_EQ(c.size(), 0u);
|
||||
|
||||
// file should still be usable
|
||||
ASSERT_TRUE(c.push_back(789u));
|
||||
EXPECT_EQ(c.size(), 1u);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue