1
0
Fork 0
forked from lthn/blockchain

Merge branch 'develop' into release

This commit is contained in:
sowle 2025-08-13 17:02:57 +03:00
commit 5982abd525
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
69 changed files with 1874 additions and 656 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1091,7 +1091,7 @@ namespace currency
BOOST_SERIALIZE(attachment)
BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(proofs)
END_BOOST_SERIALIZATION()
END_BOOST_SERIALIZATION()
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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