forked from lthn/blockchain
Merge branch 'develop' into release
This commit is contained in:
commit
d71d82b690
87 changed files with 7331 additions and 725 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -12,3 +12,6 @@
|
|||
[submodule "contrib/jwt-cpp"]
|
||||
path = contrib/jwt-cpp
|
||||
url = https://github.com/Thalhammer/jwt-cpp.git
|
||||
[submodule "contrib/bitcoin-secp256k1"]
|
||||
path = contrib/bitcoin-secp256k1
|
||||
url = https://github.com/bitcoin-core/secp256k1.git
|
||||
|
|
|
|||
|
|
@ -226,7 +226,12 @@ endif()
|
|||
message("CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 12.00)
|
||||
set(Boost_LIBRARIES "libboost.a")
|
||||
if(NOT DEFINED SKIP_BOOST_FATLIB_LIB OR NOT SKIP_BOOST_FATLIB_LIB)
|
||||
message("Ios: libboost.a included as library")
|
||||
set(Boost_LIBRARIES "libboost.a")
|
||||
else()
|
||||
message("Ios: libboost.a not included as library")
|
||||
endif()
|
||||
#workaround for new XCode 12 policy for builds(now it includes a slice for the "arm64" when builds for simulator)
|
||||
set(__iphoneos_archs "arm64")
|
||||
#set(__iphonesimulator_archs "arm64,x86_64")
|
||||
|
|
|
|||
|
|
@ -5,6 +5,14 @@ add_subdirectory(zlib)
|
|||
add_subdirectory(db)
|
||||
add_subdirectory(ethereum)
|
||||
|
||||
option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." OFF)
|
||||
option(SECP256K1_BUILD_TESTS "Build tests." OFF)
|
||||
option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." OFF)
|
||||
option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." OFF)
|
||||
option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF)
|
||||
set_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED 1)
|
||||
add_subdirectory(bitcoin-secp256k1)
|
||||
|
||||
if( NOT DISABLE_TOR)
|
||||
add_subdirectory(tor-connect)
|
||||
endif()
|
||||
|
|
@ -23,6 +31,9 @@ set_property(TARGET libminiupnpc-static PROPERTY FOLDER "contrib")
|
|||
set_property(TARGET zlibstatic PROPERTY FOLDER "contrib")
|
||||
set_property(TARGET mdbx PROPERTY FOLDER "contrib")
|
||||
set_property(TARGET lmdb PROPERTY FOLDER "contrib")
|
||||
set_property(TARGET secp256k1 PROPERTY FOLDER "contrib")
|
||||
set_property(TARGET secp256k1_precomputed PROPERTY FOLDER "contrib")
|
||||
|
||||
if( NOT DISABLE_TOR)
|
||||
set_property(TARGET tor-connect PROPERTY FOLDER "contrib")
|
||||
endif()
|
||||
|
|
|
|||
1
contrib/bitcoin-secp256k1
Submodule
1
contrib/bitcoin-secp256k1
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit a5269373fa13ff845f654d81b90629dd78495641
|
||||
|
|
@ -35,7 +35,19 @@
|
|||
#include <iostream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <filesystem>
|
||||
|
||||
|
||||
#if __has_include(<filesystem>)
|
||||
#include <filesystem>
|
||||
namespace stdfs = std::filesystem;
|
||||
#else
|
||||
#if TARGET_OS_IOS
|
||||
#error "This should never happen on ios."
|
||||
#endif
|
||||
namespace stdfs = boost::filesystem;
|
||||
#endif
|
||||
|
||||
//#include <filesystem>
|
||||
|
||||
#ifndef MAKE64
|
||||
#define MAKE64(low,high) ((__int64)(((DWORD)(low)) | ((__int64)((DWORD)(high))) << 32))
|
||||
|
|
@ -562,10 +574,10 @@ namespace file_io_utils
|
|||
try
|
||||
{
|
||||
|
||||
std::filesystem::directory_iterator end_itr; // default construction yields past-the-end
|
||||
for ( std::filesystem::directory_iterator itr( epee::string_encoding::utf8_to_wstring(path) ); itr != end_itr; ++itr )
|
||||
stdfs::directory_iterator end_itr; // default construction yields past-the-end
|
||||
for (stdfs::directory_iterator itr( epee::string_encoding::utf8_to_wstring(path) ); itr != end_itr; ++itr )
|
||||
{
|
||||
if ( only_files && std::filesystem::is_directory(itr->status()) )
|
||||
if ( only_files && stdfs::is_directory(itr->status()) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,9 +84,9 @@ namespace misc_utils
|
|||
{
|
||||
|
||||
template<typename t_type_a, typename t_type_b>
|
||||
void cast_assign_a_to_b(t_type_a& a, const t_type_b& b)
|
||||
void cast_assign_a_to_b(const t_type_a& a, t_type_b& b)
|
||||
{
|
||||
*static_cast<t_type_b*>(&a) = b;
|
||||
*static_cast<t_type_a*>(&b) = a;
|
||||
}
|
||||
|
||||
template<class _Ty1,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// Copyright (c) 2024, Zano Project
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
|
|
@ -473,6 +474,29 @@ namespace epee
|
|||
return r;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//std::optional
|
||||
template<class t_type, class t_storage>
|
||||
bool kv_serialize(const std::optional<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
if(d.has_value())
|
||||
{
|
||||
return kv_serialize(*d, stg, hparent_section, pname);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
bool kv_unserialize(std::optional<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
d = t_type{};
|
||||
bool r = kv_unserialize(*d, stg, hparent_section, pname);
|
||||
if (!r)
|
||||
{
|
||||
d = std::nullopt;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//boost::shared_ptr
|
||||
template<class t_type, class t_storage>
|
||||
bool kv_serialize(const boost::shared_ptr<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
|
|
@ -496,6 +520,30 @@ namespace epee
|
|||
}
|
||||
return r;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//std::shared_ptr
|
||||
template<class t_type, class t_storage>
|
||||
bool kv_serialize(const std::shared_ptr<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
if (d.get())
|
||||
{
|
||||
return kv_serialize(*d, stg, hparent_section, pname);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_type, class t_storage>
|
||||
bool kv_unserialize(std::shared_ptr<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
d.reset();
|
||||
t_type* ptr = new t_type();
|
||||
bool r = kv_unserialize(*ptr, stg, hparent_section, pname);
|
||||
if (!r)
|
||||
{
|
||||
d.reset(ptr);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -444,7 +444,7 @@ POP_GCC_WARNINGS
|
|||
inline bool string_to_num_fast(const std::string& buff, int& val)
|
||||
{
|
||||
val = atoi(buff.c_str());
|
||||
if(buff != "0" && val == 0)
|
||||
if (val == 0 && buff.find_first_not_of('0') != std::string::npos)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -116,6 +116,8 @@ else()
|
|||
endif()
|
||||
|
||||
add_library(crypto ${CRYPTO})
|
||||
add_dependencies(crypto secp256k1)
|
||||
target_link_libraries(crypto secp256k1)
|
||||
|
||||
add_library(currency_core ${CURRENCY_CORE})
|
||||
add_dependencies(currency_core version ${PCH_LIB_NAME})
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define BEGIN_BOOST_SERIALIZATION() template <class t_archive> inline void serialize(t_archive &_arch, const unsigned int ver) {
|
||||
#define BEGIN_BOOST_SERIALIZATION() template <class t_archive> void serialize(t_archive &_arch, const unsigned int ver) {
|
||||
|
||||
template<size_t A, size_t B> struct TAssertEquality {
|
||||
static_assert(A == B, "Serialization map is not updated, sizeof() missmatch");
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "crypto/clsag.h"
|
||||
#include "crypto/zarcanum.h"
|
||||
#include "crypto/one_out_of_many_proofs.h"
|
||||
#include "crypto/eth_signature.h"
|
||||
#include "boost_serialization_maps.h"
|
||||
#include "serialization/keyvalue_enable_POD_serialize_as_string.h"
|
||||
//
|
||||
|
|
@ -230,6 +231,8 @@ BLOB_SERIALIZER(crypto::key_image);
|
|||
BLOB_SERIALIZER(crypto::signature);
|
||||
BLOB_SERIALIZER(crypto::scalar_t);
|
||||
BLOB_SERIALIZER(crypto::point_t);
|
||||
BLOB_SERIALIZER(crypto::eth_public_key);
|
||||
BLOB_SERIALIZER(crypto::eth_signature);
|
||||
|
||||
VARIANT_TAG(debug_archive, crypto::hash, "hash");
|
||||
VARIANT_TAG(debug_archive, crypto::public_key, "public_key");
|
||||
|
|
@ -237,6 +240,8 @@ VARIANT_TAG(debug_archive, crypto::secret_key, "secret_key");
|
|||
VARIANT_TAG(debug_archive, crypto::key_derivation, "key_derivation");
|
||||
VARIANT_TAG(debug_archive, crypto::key_image, "key_image");
|
||||
VARIANT_TAG(debug_archive, crypto::signature, "signature");
|
||||
VARIANT_TAG(debug_archive, crypto::eth_public_key, "eth_public_key");
|
||||
VARIANT_TAG(debug_archive, crypto::eth_signature, "eth_signature");
|
||||
|
||||
|
||||
//
|
||||
|
|
@ -245,6 +250,8 @@ VARIANT_TAG(debug_archive, crypto::signature, "signature");
|
|||
|
||||
KV_ENABLE_POD_SERIALIZATION_AS_HEX(crypto::scalar_t);
|
||||
KV_ENABLE_POD_SERIALIZATION_AS_HEX(crypto::hash);
|
||||
KV_ENABLE_POD_SERIALIZATION_AS_HEX(crypto::eth_public_key);
|
||||
KV_ENABLE_POD_SERIALIZATION_AS_HEX(crypto::eth_signature);
|
||||
|
||||
//
|
||||
// Boost serialization
|
||||
|
|
@ -296,5 +303,15 @@ namespace boost
|
|||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::point_t)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::eth_public_key &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::eth_public_key)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::eth_signature &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::eth_signature)]>(x);
|
||||
}
|
||||
} // namespace serialization
|
||||
} // namespace boost
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Copyright (c) 2014-2024 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.
|
||||
|
|
@ -394,10 +394,67 @@ namespace tools
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* lmdb_db_backend::name()
|
||||
{
|
||||
return "lmdb";
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::convert_db_4kb_page_to_16kb_page(const std::string& source_path, const std::string& destination_path)
|
||||
{
|
||||
#define MDB_CHECK(x, msg) {int rc = x; CHECK_AND_ASSERT_MES(rc == MDB_SUCCESS, false, "LMDB 4k->16k error: " << msg << ": " << mdb_strerror(rc));}
|
||||
|
||||
MDB_env *env_src = nullptr, *env_dst = nullptr;
|
||||
|
||||
// source
|
||||
MDB_CHECK(mdb_env_create(&env_src), "failed to create LMDB environment");
|
||||
MDB_CHECK(mdb_env_set_mapsize(env_src, 4 * 1024 * 1024), "failed to set mapsize"); // mapsize ?
|
||||
MDB_CHECK(mdb_env_open(env_src, source_path.c_str(), 0, 0664), "failed to open source LMDB");
|
||||
|
||||
// destination (16k page size)
|
||||
MDB_CHECK(mdb_env_create(&env_dst), "failed to create LMDB environment");
|
||||
MDB_CHECK(mdb_env_set_mapsize(env_dst, 16 * 1024 * 1024), "failed to set mapsize"); // mapsize ?
|
||||
|
||||
// TODO uncomment after mdb_env_set_pagesize is supported
|
||||
// MDB_CHECK(mdb_env_set_pagesize(env_dst, 16 * 1024), "failed to set page size to 16K");
|
||||
|
||||
MDB_CHECK(mdb_env_open(env_dst, destination_path.c_str(), 0, 0664), "failed to open destination LMDB");
|
||||
|
||||
// begin transactions
|
||||
MDB_txn *txn_src = nullptr, *txn_dst = nullptr;
|
||||
MDB_dbi dbi_src, dbi_dst;
|
||||
MDB_CHECK(mdb_txn_begin(env_src, nullptr, MDB_RDONLY, &txn_src), "failed to begin source transaction");
|
||||
MDB_CHECK(mdb_dbi_open(txn_src, nullptr, 0, &dbi_src), "failed to open source database");
|
||||
MDB_CHECK(mdb_txn_begin(env_dst, nullptr, 0, &txn_dst), "failed to begin destination transaction");
|
||||
MDB_CHECK(mdb_dbi_open(txn_dst, nullptr, MDB_CREATE, &dbi_dst), "failed to open destination database");
|
||||
|
||||
MDB_cursor *cursor;
|
||||
MDB_val key, data;
|
||||
|
||||
// Iterate over the source database and copy all key-value pairs to the destination database
|
||||
MDB_CHECK(mdb_cursor_open(txn_src, dbi_src, &cursor), "failed to open cursor");
|
||||
|
||||
while (mdb_cursor_get(cursor, &key, &data, MDB_NEXT) == MDB_SUCCESS)
|
||||
{
|
||||
MDB_CHECK(mdb_put(txn_dst, dbi_dst, &key, &data, 0), "failed to put data in destination database");
|
||||
}
|
||||
|
||||
mdb_cursor_close(cursor);
|
||||
|
||||
// commit transactions
|
||||
MDB_CHECK(mdb_txn_commit(txn_src), "failed to commit source transaction");
|
||||
MDB_CHECK(mdb_txn_commit(txn_dst), "failed to commit destination transaction");
|
||||
|
||||
mdb_dbi_close(env_src, dbi_src);
|
||||
mdb_dbi_close(env_dst, dbi_dst);
|
||||
mdb_env_close(env_src);
|
||||
mdb_env_close(env_dst);
|
||||
|
||||
return true;
|
||||
|
||||
#undef MDB_CHECK
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Copyright (c) 2014-2024 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.
|
||||
|
|
@ -36,6 +36,7 @@ namespace tools
|
|||
boost::recursive_mutex m_write_exclusive_lock;
|
||||
std::map<std::thread::id, transactions_list> m_txs; // size_t -> count of nested read_only transactions
|
||||
bool pop_tx_entry(tx_entry& txe);
|
||||
|
||||
public:
|
||||
lmdb_db_backend();
|
||||
~lmdb_db_backend();
|
||||
|
|
@ -60,6 +61,8 @@ namespace tools
|
|||
bool have_tx();
|
||||
MDB_txn* get_current_tx();
|
||||
|
||||
static bool convert_db_4kb_page_to_16kb_page(const std::string& source_path, const std::string& destination_path);
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3391,5 +3391,9 @@ namespace tools
|
|||
CHECK_AND_ASSERT_THROW_MES(it!= wordsMap.end(), "unable to find word \"" << w << "\" in mnemonic dictionary");
|
||||
return it->second;
|
||||
}
|
||||
const map<string, uint32_t>& get_words_map()
|
||||
{
|
||||
return wordsMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,5 +47,6 @@ namespace tools
|
|||
std::string word_by_num(uint32_t n);
|
||||
uint64_t num_by_word(const std::string& w);
|
||||
bool valid_word(const std::string& w);
|
||||
const std::map<std::string, uint32_t>& get_words_map();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -658,31 +658,68 @@ std::string get_nix_version_display_string()
|
|||
return static_cast<uint64_t>(in.tellg());
|
||||
}
|
||||
|
||||
bool check_remote_client_version(const std::string& client_ver)
|
||||
bool parse_client_version(const std::string& str, int& major, int& minor, int& revision, int& build_number, std::string& commit_id, bool& dirty)
|
||||
{
|
||||
std::string v = client_ver.substr(0, client_ver.find('[')); // remove commit id
|
||||
v = v.substr(0, v.rfind('.')); // remove build number
|
||||
// "10.101.999.28391"
|
||||
// "10.101.999.28391[deadbeef31337]"
|
||||
// "10.101.999.28391[deadbeef31337-dirty]"
|
||||
// 0123456789012345678901234567890123456
|
||||
|
||||
int v_major = 0, v_minor = 0, v_revision = 0;
|
||||
|
||||
size_t dot_pos = v.find('.');
|
||||
if (dot_pos == std::string::npos || !epee::string_tools::string_to_num_fast(v.substr(0, dot_pos), v_major))
|
||||
if (str.size() == 0)
|
||||
return false;
|
||||
|
||||
v = v.substr(dot_pos + 1);
|
||||
dot_pos = v.find('.');
|
||||
if (!epee::string_tools::string_to_num_fast(v.substr(0, dot_pos), v_minor))
|
||||
return false;
|
||||
|
||||
if (dot_pos != std::string::npos)
|
||||
auto bracket_pos = str.find('[');
|
||||
if (bracket_pos != std::string::npos)
|
||||
{
|
||||
// revision
|
||||
v = v.substr(dot_pos + 1);
|
||||
if (!epee::string_tools::string_to_num_fast(v, v_revision))
|
||||
if (str[str.size() - 1] != ']')
|
||||
return false;
|
||||
|
||||
commit_id = str.substr(bracket_pos + 1, str.size() - bracket_pos - 2);
|
||||
auto d_pos = commit_id.find("-dirty");
|
||||
if (d_pos != std::string::npos)
|
||||
{
|
||||
dirty = true;
|
||||
commit_id.erase(d_pos);
|
||||
}
|
||||
}
|
||||
|
||||
// got v_major, v_minor, v_revision
|
||||
std::string ver_str = str.substr(0, bracket_pos);
|
||||
std::vector<std::string> versions;
|
||||
boost::split(versions, ver_str, boost::is_any_of("."));
|
||||
if (versions.size() != 4)
|
||||
return false;
|
||||
|
||||
if (!epee::string_tools::string_to_num_fast(versions[0], major))
|
||||
return false;
|
||||
|
||||
if (!epee::string_tools::string_to_num_fast(versions[1], minor))
|
||||
return false;
|
||||
|
||||
if (!epee::string_tools::string_to_num_fast(versions[2], revision))
|
||||
return false;
|
||||
|
||||
if (!epee::string_tools::string_to_num_fast(versions[3], build_number))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_client_version_build_number(const std::string& str, int& build_number)
|
||||
{
|
||||
int major = -1, minor = -1, revision = -1;
|
||||
std::string commit_id;
|
||||
bool dirty = false;
|
||||
return tools::parse_client_version(str, major, minor, revision, build_number, commit_id, dirty);
|
||||
}
|
||||
|
||||
bool check_remote_client_version(const std::string& client_ver)
|
||||
{
|
||||
int v_major = 0, v_minor = 0, v_revision = 0, v_build_number = 0;
|
||||
std::string commit_id;
|
||||
bool dirty_flag = false;
|
||||
|
||||
if (!parse_client_version(client_ver, v_major, v_minor, v_revision, v_build_number, commit_id, dirty_flag))
|
||||
return false;
|
||||
|
||||
// allow 2.x and greater
|
||||
if (v_major < 2)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ namespace tools
|
|||
std::string get_current_username();
|
||||
std::string get_os_version_string();
|
||||
bool copy_dir(boost::filesystem::path const & source, boost::filesystem::path const & destination);
|
||||
|
||||
bool parse_client_version(const std::string& str, int& major, int& minor, int& revision, int& build_number, std::string& commit_id, bool& dirty);
|
||||
bool parse_client_version_build_number(const std::string& str, int& build_number);
|
||||
bool check_remote_client_version(const std::string& client_ver);
|
||||
|
||||
bool create_directories_if_necessary(const std::string& path);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2019 Zano Project
|
||||
// Copyright (c) 2014-2024 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
|
||||
|
|
@ -25,6 +25,7 @@ using namespace epee;
|
|||
#include "storages/http_abstract_invoke.h"
|
||||
#include "net/http_client.h"
|
||||
#include "currency_core/genesis_acc.h"
|
||||
#include "common/db_backend_lmdb.h"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
|
@ -63,6 +64,7 @@ namespace
|
|||
const command_line::arg_descriptor<std::string> arg_pack_file ("pack-file", "perform gzip-packing and calculate hash for a given file");
|
||||
const command_line::arg_descriptor<std::string> arg_unpack_file ("unpack-file", "Perform gzip-unpacking and calculate hash for a given file");
|
||||
const command_line::arg_descriptor<std::string> arg_target_file ("target-file", "Specify target file for pack-file and unpack-file commands");
|
||||
const command_line::arg_descriptor<std::string> arg_lmdb_page_4to16 ("convert-lmdb-4to16", "Perform LMDB conversion from 4k page size to 16k page size");
|
||||
//const command_line::arg_descriptor<std::string> arg_send_ipc ("send-ipc", "Send IPC request to UI");
|
||||
}
|
||||
|
||||
|
|
@ -1220,7 +1222,10 @@ bool handle_pack_file(po::variables_map& vm)
|
|||
}
|
||||
|
||||
if (!command_line::has_arg(vm, arg_target_file))
|
||||
{
|
||||
std::cout << "Error: Parameter target_file is not set." << ENDL;
|
||||
return false;
|
||||
}
|
||||
path_target = command_line::get_arg(vm, arg_target_file);
|
||||
|
||||
std::ifstream source;
|
||||
|
|
@ -1251,6 +1256,34 @@ bool handle_pack_file(po::variables_map& vm)
|
|||
}
|
||||
}
|
||||
|
||||
bool handle_lmdb_page_4to16(po::variables_map& vm)
|
||||
{
|
||||
std::string path_source;
|
||||
std::string path_target;
|
||||
|
||||
if (!command_line::has_arg(vm, arg_lmdb_page_4to16))
|
||||
return false;
|
||||
|
||||
path_source = command_line::get_arg(vm, arg_lmdb_page_4to16);
|
||||
|
||||
if (!command_line::has_arg(vm, arg_target_file))
|
||||
{
|
||||
std::cout << "Error: Parameter target_file is not set." << ENDL;
|
||||
return false;
|
||||
}
|
||||
path_target = command_line::get_arg(vm, arg_target_file);
|
||||
|
||||
if (tools::db::lmdb_db_backend::convert_db_4kb_page_to_16kb_page(path_source, path_target))
|
||||
{
|
||||
std::cout << "Conversion failed" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "Converted successfully" << ENDL;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
|
|
@ -1375,6 +1408,10 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
return handle_pack_file(vm) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
else if (command_line::has_arg(vm, arg_lmdb_page_4to16))
|
||||
{
|
||||
return handle_lmdb_page_4to16(vm) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
/*else if (command_line::has_arg(vm, arg_send_ipc))
|
||||
{
|
||||
handle_send_ipc(command_line::get_arg(vm, arg_send_ipc)) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <string>
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include "crypto.h"
|
||||
#include "eth_signature.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
|
|
@ -1209,6 +1210,16 @@ namespace crypto
|
|||
m_elements.emplace_back(pk);
|
||||
}
|
||||
|
||||
void add_eth_pub_key(const crypto::eth_public_key& epk)
|
||||
{
|
||||
static_assert(sizeof(item_t) == 32, "unexpected size of hs_t::item_t");
|
||||
static_assert(sizeof epk.data == 33, "unexpected size of eth_public_key");
|
||||
m_elements.emplace_back(c_scalar_0);
|
||||
m_elements.emplace_back(c_scalar_0);
|
||||
char* p = m_elements[m_elements.size() - 2].c; // pointer to the first of the two added items
|
||||
memcpy(p, &epk.data, sizeof epk.data);
|
||||
}
|
||||
|
||||
void add_key_image(const crypto::key_image& ki)
|
||||
{
|
||||
m_elements.emplace_back(ki);
|
||||
|
|
|
|||
162
src/crypto/eth_signature.cpp
Normal file
162
src/crypto/eth_signature.cpp
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
// Copyright (c) 2024 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#include "eth_signature.h"
|
||||
#include "crypto.h"
|
||||
#include "bitcoin-secp256k1/include/secp256k1.h"
|
||||
#include "random.h"
|
||||
#include "misc_language.h"
|
||||
#include <string_tools.h>
|
||||
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
bool generate_eth_key_pair(eth_secret_key& sec_key, eth_public_key& pub_key) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
auto slh = epee::misc_utils::create_scope_leave_handler([&ctx](){
|
||||
secp256k1_context_destroy(ctx);
|
||||
ctx = nullptr;
|
||||
});
|
||||
|
||||
uint8_t randomness[32];
|
||||
crypto::generate_random_bytes(sizeof randomness, randomness);
|
||||
if (!secp256k1_context_randomize(ctx, randomness))
|
||||
return false;
|
||||
|
||||
for(size_t i = 1024; i != 0; --i)
|
||||
{
|
||||
crypto::generate_random_bytes(sizeof sec_key, sec_key.data);
|
||||
if (secp256k1_ec_seckey_verify(ctx, sec_key.data))
|
||||
break;
|
||||
if (i == 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
secp256k1_pubkey uncompressed_pub_key{};
|
||||
if (!secp256k1_ec_pubkey_create(ctx, &uncompressed_pub_key, sec_key.data))
|
||||
return false;
|
||||
|
||||
size_t output_len = sizeof pub_key;
|
||||
if (!secp256k1_ec_pubkey_serialize(ctx, pub_key.data, &output_len, &uncompressed_pub_key, SECP256K1_EC_COMPRESSED))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool eth_secret_key_to_public_key(const eth_secret_key& sec_key, eth_public_key& pub_key) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: do we need this? consider using static context
|
||||
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
auto slh = epee::misc_utils::create_scope_leave_handler([&ctx](){
|
||||
secp256k1_context_destroy(ctx);
|
||||
ctx = nullptr;
|
||||
});
|
||||
|
||||
secp256k1_pubkey uncompressed_pub_key{};
|
||||
if (!secp256k1_ec_pubkey_create(ctx, &uncompressed_pub_key, sec_key.data))
|
||||
return false;
|
||||
|
||||
size_t output_len = sizeof pub_key;
|
||||
if (!secp256k1_ec_pubkey_serialize(ctx, pub_key.data, &output_len, &uncompressed_pub_key, SECP256K1_EC_COMPRESSED))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// generates secp256k1 ECDSA signature
|
||||
bool generate_eth_signature(const hash& m, const eth_secret_key& sec_key, eth_signature& sig) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
auto slh = epee::misc_utils::create_scope_leave_handler([&ctx](){
|
||||
secp256k1_context_destroy(ctx);
|
||||
ctx = nullptr;
|
||||
});
|
||||
|
||||
uint8_t randomness[32];
|
||||
crypto::generate_random_bytes(sizeof randomness, randomness);
|
||||
if (!secp256k1_context_randomize(ctx, randomness))
|
||||
return false;
|
||||
|
||||
secp256k1_ecdsa_signature secp256k1_ecdsa_sig{};
|
||||
if (!secp256k1_ecdsa_sign(ctx, &secp256k1_ecdsa_sig, (const unsigned char*)m.data, sec_key.data, NULL, NULL))
|
||||
return false;
|
||||
|
||||
if (!secp256k1_ecdsa_signature_serialize_compact(ctx, sig.data, &secp256k1_ecdsa_sig))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// verifies secp256k1 ECDSA signature
|
||||
bool verify_eth_signature(const hash& m, const eth_public_key& pub_key, const eth_signature& sig) noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO (performance) consider using secp256k1_context_static for verification -- sowle
|
||||
|
||||
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
auto slh = epee::misc_utils::create_scope_leave_handler([&ctx](){
|
||||
secp256k1_context_destroy(ctx);
|
||||
ctx = nullptr;
|
||||
});
|
||||
|
||||
uint8_t randomness[32];
|
||||
crypto::generate_random_bytes(sizeof randomness, randomness);
|
||||
if (!secp256k1_context_randomize(ctx, randomness))
|
||||
return false;
|
||||
|
||||
secp256k1_ecdsa_signature secp256k1_ecdsa_sig{};
|
||||
secp256k1_pubkey uncompressed_pub_key{};
|
||||
|
||||
if (!secp256k1_ecdsa_signature_parse_compact(ctx, &secp256k1_ecdsa_sig, sig.data))
|
||||
return false;
|
||||
|
||||
if (!secp256k1_ec_pubkey_parse(ctx, &uncompressed_pub_key, pub_key.data, sizeof pub_key))
|
||||
return false;
|
||||
|
||||
// verify a signature
|
||||
if (!secp256k1_ecdsa_verify(ctx, &secp256k1_ecdsa_sig, (const unsigned char*)m.data, &uncompressed_pub_key))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const eth_secret_key& v)
|
||||
{
|
||||
return o << epee::string_tools::pod_to_hex(v);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const eth_public_key& v)
|
||||
{
|
||||
return o << epee::string_tools::pod_to_hex(v);
|
||||
}
|
||||
|
||||
|
||||
} // namespace crypto
|
||||
66
src/crypto/eth_signature.h
Normal file
66
src/crypto/eth_signature.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) 2024 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <iosfwd>
|
||||
#include "hash.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
|
||||
// secp256k1 public key in serialized (compressed) form that is used in Etherium
|
||||
struct eth_public_key
|
||||
{
|
||||
uint8_t data[33];
|
||||
};
|
||||
|
||||
// secp256k1 secret key
|
||||
struct eth_secret_key
|
||||
{
|
||||
uint8_t data[32];
|
||||
};
|
||||
|
||||
// secp256k1 ECDSA signature is serialized (compressed) form that is used in Etherium
|
||||
struct eth_signature
|
||||
{
|
||||
uint8_t data[64];
|
||||
};
|
||||
|
||||
// generates secp256k1 keypair
|
||||
bool generate_eth_key_pair(eth_secret_key& sec_key, eth_public_key& pub_key) noexcept;
|
||||
|
||||
// converts eth_secret_key to eth_public_key
|
||||
bool eth_secret_key_to_public_key(const eth_secret_key& sec_key, eth_public_key& pub_key) noexcept;
|
||||
|
||||
// generates secp256k1 ECDSA signature
|
||||
bool generate_eth_signature(const hash& m, const eth_secret_key& sec_key, eth_signature& sig) noexcept;
|
||||
|
||||
// verifies secp256k1 ECDSA signature
|
||||
bool verify_eth_signature(const hash& m, const eth_public_key& pub_key, const eth_signature& sig) noexcept;
|
||||
|
||||
|
||||
inline bool operator==(const eth_public_key& lhs, const eth_public_key& rhs)
|
||||
{
|
||||
return memcmp(lhs.data, rhs.data, sizeof lhs.data) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(const eth_public_key& lhs, const eth_public_key& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
inline bool operator==(const eth_secret_key& lhs, const eth_secret_key& rhs)
|
||||
{
|
||||
return memcmp(lhs.data, rhs.data, sizeof lhs.data) == 0;
|
||||
}
|
||||
|
||||
inline bool operator!=(const eth_secret_key& lhs, const eth_secret_key& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const eth_secret_key& v);
|
||||
std::ostream& operator<<(std::ostream& o, const eth_public_key& v);
|
||||
|
||||
} // namespace crypto
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
// Copyright (c) 2023 Zano Project
|
||||
// Copyright (c) 2023 sowle (val@zano.org, crypto.sowle@gmail.com)
|
||||
// Copyright (c) 2023-2024 Zano Project
|
||||
// Copyright (c) 2023-2024 sowle (val@zano.org, crypto.sowle@gmail.com)
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
//
|
||||
#include "one_out_of_many_proofs.h"
|
||||
#include "../currency_core/crypto_config.h"
|
||||
#include "../currency_core/currency_config.h" // for static asset checks
|
||||
#include "epee/include/misc_log_ex.h"
|
||||
|
||||
//DISABLE_GCC_AND_CLANG_WARNING(unused-function)
|
||||
|
|
@ -22,6 +23,8 @@ namespace crypto
|
|||
static const size_t N_max = 256;
|
||||
static const size_t mn_max = 16;
|
||||
|
||||
static_assert(CURRENCY_TX_MAX_ALLOWED_INPUTS <= N_max, "CURRENCY_TX_MAX_ALLOWED_INPUTS is inconsistent with one-out-of-many proof limits"); // TODO: consider moving this check out -- sowle
|
||||
|
||||
const point_t& get_BGE_generator(size_t index, bool& ok)
|
||||
{
|
||||
static std::vector<point_t> precalculated_generators;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ void generate_system_random_bytes(size_t n, void *result) {
|
|||
void generate_system_random_bytes(size_t n, void *result) {
|
||||
int fd;
|
||||
if ((fd = open("/dev/urandom", O_RDONLY | O_NOCTTY | O_CLOEXEC)) < 0) {
|
||||
err(EXIT_FAILURE, "open /dev/urandom");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
for (;;) {
|
||||
ssize_t res = read(fd, result, n);
|
||||
|
|
@ -52,17 +52,17 @@ void generate_system_random_bytes(size_t n, void *result) {
|
|||
}
|
||||
if (res < 0) {
|
||||
if (errno != EINTR) {
|
||||
err(EXIT_FAILURE, "read /dev/urandom");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (res == 0) {
|
||||
errx(EXIT_FAILURE, "read /dev/urandom: end of file");
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
result = padd(result, (size_t) res);
|
||||
n -= (size_t) res;
|
||||
}
|
||||
}
|
||||
if (close(fd) < 0) {
|
||||
err(EXIT_FAILURE, "close /dev/urandom");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,6 +123,15 @@ namespace crypto
|
|||
return generate_schnorr_sig(m, point_t(A), scalar_t(secret_a), result);
|
||||
}
|
||||
|
||||
inline bool generate_schnorr_sig(const hash& m, const secret_key& secret_a, generic_schnorr_sig& result)
|
||||
{
|
||||
scalar_t secret_a_s(secret_a);
|
||||
if (!secret_a_s.is_reduced())
|
||||
return false;
|
||||
point_t A = secret_a_s * c_point_G;
|
||||
return generate_schnorr_sig_custom_generator(m, A, secret_a_s, result, c_point_G);
|
||||
}
|
||||
|
||||
|
||||
template<generator_tag gen = gt_G>
|
||||
inline bool verify_schnorr_sig(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ namespace currency
|
|||
return m_keys;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void crypt_with_pass(const void* scr_data, std::size_t src_length, void* dst_data, const std::string& password)
|
||||
void account_base::crypt_with_pass(const void* scr_data, std::size_t src_length, void* dst_data, const std::string& password)
|
||||
{
|
||||
crypto::chacha8_key key = AUTO_VAL_INIT(key);
|
||||
crypto::generate_chacha8_key(password, key);
|
||||
|
|
@ -71,28 +71,35 @@ namespace currency
|
|||
crypto::chacha8(scr_data, src_length, key, iv, (char*)dst_data);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
std::string account_base::get_seed_phrase(const std::string& password) const
|
||||
std::string account_base::get_seed_phrase(const std::string& password) const
|
||||
{
|
||||
if (m_keys_seed_binary.empty())
|
||||
return "";
|
||||
return get_seed_phrase(password, m_keys_seed_binary);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
std::string account_base::get_seed_phrase(const std::string& password, const std::vector<unsigned char>& keys_seed_binary) const
|
||||
{
|
||||
if (keys_seed_binary.empty())
|
||||
return "";
|
||||
|
||||
std::vector<unsigned char> processed_seed_binary = m_keys_seed_binary;
|
||||
std::vector<unsigned char> processed_seed_binary = keys_seed_binary;
|
||||
if (!password.empty())
|
||||
{
|
||||
//encrypt seed phrase binary data
|
||||
crypt_with_pass(&m_keys_seed_binary[0], m_keys_seed_binary.size(), &processed_seed_binary[0], password);
|
||||
crypt_with_pass(&keys_seed_binary[0], keys_seed_binary.size(), &processed_seed_binary[0], password);
|
||||
}
|
||||
|
||||
std::string keys_seed_text = tools::mnemonic_encoding::binary2text(processed_seed_binary);
|
||||
std::string timestamp_word = currency::get_word_from_timstamp(m_creation_timestamp, !password.empty());
|
||||
std::string timestamp_word = currency::get_word_from_timestamp(m_creation_timestamp, !password.empty());
|
||||
|
||||
// floor creation time to WALLET_BRAIN_DATE_QUANTUM to make checksum calculation stable
|
||||
bool self_check_is_password_used = false;
|
||||
uint64_t creation_timestamp_rounded = get_timstamp_from_word(timestamp_word, self_check_is_password_used);
|
||||
uint64_t creation_timestamp_rounded = get_timestamp_from_word(timestamp_word, self_check_is_password_used);
|
||||
CHECK_AND_ASSERT_THROW_MES(self_check_is_password_used == !password.empty(), "Account seed phrase internal error: password flag encoded wrong");
|
||||
|
||||
constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum
|
||||
std::string binary_for_check_sum((const char*)&m_keys_seed_binary[0], m_keys_seed_binary.size());
|
||||
std::string binary_for_check_sum((const char*)&keys_seed_binary[0], keys_seed_binary.size());
|
||||
binary_for_check_sum.append(password);
|
||||
crypto::hash h = crypto::cn_fast_hash(binary_for_check_sum.data(), binary_for_check_sum.size());
|
||||
*reinterpret_cast<uint64_t*>(&h) = creation_timestamp_rounded;
|
||||
|
|
@ -127,11 +134,12 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::restore_from_seed_phrase(const std::string& seed_phrase, const std::string& seed_password)
|
||||
bool account_base::restore_from_seed_phrase(const std::string& seed_phrase_, const std::string& seed_password)
|
||||
{
|
||||
//cut the last timestamp word from restore_dats
|
||||
std::list<std::string> words;
|
||||
boost::split(words, seed_phrase, boost::is_space());
|
||||
std::string seed_phrase = epee::string_tools::trim(seed_phrase_);
|
||||
boost::split(words, seed_phrase, boost::is_space(), boost::token_compress_on);
|
||||
|
||||
std::string keys_seed_text, timestamp_word, auditable_flag_and_checksum_word;
|
||||
if (words.size() == SEED_PHRASE_V1_WORDS_COUNT)
|
||||
|
|
@ -176,7 +184,7 @@ namespace currency
|
|||
|
||||
bool has_password = false;
|
||||
try {
|
||||
m_creation_timestamp = get_timstamp_from_word(timestamp_word, has_password);
|
||||
m_creation_timestamp = get_timestamp_from_word(timestamp_word, has_password);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
|
@ -230,11 +238,13 @@ namespace currency
|
|||
return seed_phrase.find(':') != std::string::npos;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::is_seed_password_protected(const std::string& seed_phrase, bool& is_password_protected)
|
||||
bool account_base::is_seed_password_protected(const std::string& seed_phrase_, bool& is_password_protected)
|
||||
{
|
||||
//cut the last timestamp word from restore_dats
|
||||
std::list<std::string> words;
|
||||
boost::split(words, seed_phrase, boost::is_space());
|
||||
|
||||
std::string seed_phrase = epee::string_tools::trim(seed_phrase_);
|
||||
boost::split(words, seed_phrase, boost::is_space(), boost::token_compress_on);
|
||||
|
||||
//let's validate each word
|
||||
for (const auto& w: words)
|
||||
|
|
@ -260,7 +270,7 @@ namespace currency
|
|||
return false;
|
||||
}
|
||||
|
||||
get_timstamp_from_word(timestamp_word, is_password_protected);
|
||||
get_timestamp_from_word(timestamp_word, is_password_protected);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ namespace currency
|
|||
std::string get_public_address_str() const;
|
||||
|
||||
std::string get_seed_phrase(const std::string& seed_password) const;
|
||||
std::string get_seed_phrase(const std::string& password, const std::vector<unsigned char>& keys_seed_binary) const;
|
||||
std::string get_tracking_seed() const;
|
||||
bool restore_from_seed_phrase(const std::string& seed_phrase, const std::string& seed_password);
|
||||
bool restore_from_tracking_seed(const std::string& tracking_seed);
|
||||
|
|
@ -82,6 +83,8 @@ namespace currency
|
|||
static std::vector<unsigned char> string_to_vector_of_chars(const std::string& v) { return std::vector<unsigned char>(v.begin(), v.end()); }
|
||||
static bool is_seed_password_protected(const std::string& seed_phrase, bool& is_password_protected);
|
||||
static bool is_seed_tracking(const std::string& seed_phrase);
|
||||
static void crypt_with_pass(const void* scr_data, std::size_t src_length, void* dst_data, const std::string& password);
|
||||
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_keys)
|
||||
|
|
|
|||
|
|
@ -3880,11 +3880,9 @@ uint64_t blockchain_storage::get_assets(uint64_t offset, uint64_t count, std::li
|
|||
m_db_assets.enumerate_items([&](uint64_t i, const crypto::public_key& asset_id, const std::list<asset_descriptor_operation>& asset_descriptor_history)
|
||||
{
|
||||
if (i < offset)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true; // continue
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(asset_descriptor_history.size(), "asset_descriptor_history unexpectedly have 0 size");
|
||||
CHECK_AND_ASSERT_THROW_MES(asset_descriptor_history.size(), "asset_descriptor_history unexpectedly have 0 size, asset_id: " << asset_id);
|
||||
assets.push_back(asset_descriptor_with_id());
|
||||
static_cast<asset_descriptor_base&>(assets.back()) = asset_descriptor_history.back().descriptor;
|
||||
assets.back().asset_id = asset_id;
|
||||
|
|
@ -4010,7 +4008,8 @@ bool blockchain_storage::put_alias_info(const transaction & tx, extra_alias_entr
|
|||
//@@ remove get_tx_fee_median();
|
||||
LOG_PRINT_MAGENTA("[ALIAS_REGISTERED]: " << ai.m_alias << ": " << get_account_address_as_str(ai.m_address) << ", fee median: " << get_tx_fee_median(), LOG_LEVEL_1);
|
||||
rise_core_event(CORE_EVENT_ADD_ALIAS, alias_info_to_rpc_alias_info(ai));
|
||||
}else
|
||||
}
|
||||
else
|
||||
{
|
||||
//update procedure
|
||||
CHECK_AND_ASSERT_MES(ai.m_sign.size() == 1, false, "alias " << ai.m_alias << " can't be update, wrong ai.m_sign.size() count: " << ai.m_sign.size());
|
||||
|
|
@ -4103,16 +4102,30 @@ bool blockchain_storage::pop_asset_info(const crypto::public_key& asset_id)
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool validate_ado_ownership(asset_op_verification_context& avc)
|
||||
bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& avc) const
|
||||
{
|
||||
asset_operation_ownership_proof aoop = AUTO_VAL_INIT(aoop);
|
||||
bool r = get_type_in_variant_container(avc.tx.proofs, aoop);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Ownership validation failed - missing signature (asset_operation_ownership_proof)");
|
||||
bool r = false;
|
||||
CHECK_AND_ASSERT_MES(avc.asset_op_history->size() != 0, false, "asset with id " << avc.asset_id << " has empty history record");
|
||||
const asset_descriptor_operation& last_ado = avc.asset_op_history->back();
|
||||
|
||||
CHECK_AND_ASSERT_MES(avc.asset_op_history->size() != 0, false, "asset with id " << avc.asset_id << " has invalid history size() == 0");
|
||||
if (is_hardfork_active(ZANO_HARDFORK_05)) // TODO: consider changing to height-specific check
|
||||
{
|
||||
if (last_ado.descriptor.owner_eth_pub_key.has_value())
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(last_ado.descriptor.owner == null_pkey, false, "owner_eth_pub_key is set but owner pubkey is nonzero");
|
||||
asset_operation_ownership_proof_eth aoop_eth{};
|
||||
r = get_type_in_variant_container(avc.tx.proofs, aoop_eth);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Ownership validation failed: asset_operation_ownership_proof_eth is missing");
|
||||
return crypto::verify_eth_signature(avc.tx_id, last_ado.descriptor.owner_eth_pub_key.value(), aoop_eth.eth_sig);
|
||||
}
|
||||
// owner_eth_pub_key has no value -- fallback to default
|
||||
}
|
||||
|
||||
crypto::public_key owner_key = avc.asset_op_history->back().descriptor.owner;
|
||||
return crypto::verify_schnorr_sig(avc.tx_id, owner_key, aoop.gss);
|
||||
asset_operation_ownership_proof aoop{};
|
||||
r = get_type_in_variant_container(avc.tx.proofs, aoop);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Ownership validation failed: asset_operation_ownership_proof is missing");
|
||||
|
||||
return crypto::verify_schnorr_sig(avc.tx_id, last_ado.descriptor.owner, aoop.gss);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::validate_asset_operation_against_current_blochain_state(asset_op_verification_context& avc) const
|
||||
|
|
@ -4124,11 +4137,12 @@ bool blockchain_storage::validate_asset_operation_against_current_blochain_state
|
|||
|
||||
const asset_descriptor_operation& ado = avc.ado;
|
||||
|
||||
bool need_to_validate_ao_amount_commitment = true;
|
||||
|
||||
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!avc.asset_op_history, false, "asset with id " << avc.asset_id << " has already been registered");
|
||||
avc.amount_to_validate = ado.descriptor.current_supply;
|
||||
CHECK_AND_ASSERT_MES(validate_asset_operation_amount_commitment(avc), false, "validate_asset_operation_amount_commitment failed!");
|
||||
if(this->is_hardfork_active(ZANO_HARDFORK_05))
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(validate_ado_initial(ado.descriptor), false, "validate_ado_initial failed!");
|
||||
|
|
@ -4136,48 +4150,48 @@ bool blockchain_storage::validate_asset_operation_against_current_blochain_state
|
|||
}
|
||||
else
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(avc.asset_op_history && avc.asset_op_history->size(), false, "asset with id " << avc.asset_id << " has not been registered");
|
||||
CHECK_AND_ASSERT_MES(avc.asset_op_history && avc.asset_op_history->size() > 0, false, "asset with id " << avc.asset_id << " has not been registered");
|
||||
const asset_descriptor_operation& last_ado = avc.asset_op_history->back();
|
||||
// check ownership permission
|
||||
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE /*|| ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN*/)
|
||||
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE)
|
||||
{
|
||||
bool r = validate_ado_ownership(avc);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Faild to validate ownership of asset_descriptor_operation, rejecting");
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to validate ownership of asset_descriptor_operation, rejecting");
|
||||
}
|
||||
|
||||
avc.amount_to_validate = 0;
|
||||
bool need_to_validate_balance_proof = true;
|
||||
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE)
|
||||
{
|
||||
//check that total current_supply haven't changed
|
||||
CHECK_AND_ASSERT_MES(ado.descriptor.current_supply == avc.asset_op_history->back().descriptor.current_supply, false, "update operation attempted to change emission, failed");
|
||||
CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, avc.asset_op_history->back().descriptor), false, "update operation attempted to change fileds that shouldn't be modified, failed");
|
||||
need_to_validate_balance_proof = false;
|
||||
CHECK_AND_ASSERT_MES(ado.descriptor.current_supply == last_ado.descriptor.current_supply, false, "update operation attempted to change emission, failed");
|
||||
CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, last_ado.descriptor), false, "update operation modifies asset descriptor in a prohibited manner");
|
||||
need_to_validate_ao_amount_commitment = false;
|
||||
}
|
||||
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(ado.descriptor.current_supply > avc.asset_op_history->back().descriptor.current_supply, false, "emit operation does not increase the current supply, failed");
|
||||
CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, avc.asset_op_history->back().descriptor), false, "emit operation is not allowed to update fields");
|
||||
CHECK_AND_ASSERT_MES(ado.descriptor.meta_info == avc.asset_op_history->back().descriptor.meta_info, false, "emit operation is not allowed to update meta info");
|
||||
avc.amount_to_validate = ado.descriptor.current_supply - avc.asset_op_history->back().descriptor.current_supply;
|
||||
CHECK_AND_ASSERT_MES(ado.descriptor.current_supply > last_ado.descriptor.current_supply, false, "emit operation does not increase the current supply, failed");
|
||||
CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, last_ado.descriptor), false, "emit operation modifies asset descriptor in a prohibited manner");
|
||||
CHECK_AND_ASSERT_MES(ado.descriptor.meta_info == last_ado.descriptor.meta_info, false, "emit operation is not allowed to update meta info");
|
||||
avc.amount_to_validate = ado.descriptor.current_supply - last_ado.descriptor.current_supply;
|
||||
}
|
||||
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(ado.descriptor.current_supply < avc.asset_op_history->back().descriptor.current_supply, false, "burn operation does not decrease the current supply, failed");
|
||||
CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, avc.asset_op_history->back().descriptor), false, "burn operation is not allowed to update fields");
|
||||
CHECK_AND_ASSERT_MES(ado.descriptor.meta_info == avc.asset_op_history->back().descriptor.meta_info, false, "burn operation is not allowed to update meta info");
|
||||
avc.amount_to_validate = avc.asset_op_history->back().descriptor.current_supply - ado.descriptor.current_supply;
|
||||
CHECK_AND_ASSERT_MES(ado.descriptor.current_supply < last_ado.descriptor.current_supply, false, "burn operation does not decrease the current supply, failed");
|
||||
CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, last_ado.descriptor), false, "burn operation modifies asset descriptor in a prohibited manner");
|
||||
CHECK_AND_ASSERT_MES(ado.descriptor.meta_info == last_ado.descriptor.meta_info, false, "burn operation is not allowed to update meta info");
|
||||
avc.amount_to_validate = last_ado.descriptor.current_supply - ado.descriptor.current_supply;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Unknown operation type: " << (int)ado.operation_type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_to_validate_balance_proof)
|
||||
{
|
||||
bool r = validate_asset_operation_amount_commitment(avc);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Balance proof validation failed for asset_descriptor_operation");
|
||||
}
|
||||
if (need_to_validate_ao_amount_commitment)
|
||||
{
|
||||
bool r = validate_asset_operation_amount_commitment(avc);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Balance proof validation failed for asset_descriptor_operation");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -5803,6 +5817,7 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
|
|||
bool var_is_after_hardfork_2_zone = m_core_runtime_config.is_hardfork_active_for_height(2, block_height);
|
||||
bool var_is_after_hardfork_3_zone = m_core_runtime_config.is_hardfork_active_for_height(3, block_height);
|
||||
bool var_is_after_hardfork_4_zone = m_core_runtime_config.is_hardfork_active_for_height(4, block_height);
|
||||
bool var_is_after_hardfork_5_zone = m_core_runtime_config.is_hardfork_active_for_height(5, block_height);
|
||||
|
||||
auto is_allowed_before_hardfork1 = [&](const auto& el) -> bool
|
||||
{
|
||||
|
|
@ -5932,8 +5947,22 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
|
|||
LOG_ERROR("asset_descriptor_operation not allowed in tx with TX_FLAG_SIGNATURE_MODE_SEPARATE");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (var_is_after_hardfork_5_zone)
|
||||
{
|
||||
// additional checks here
|
||||
}
|
||||
else
|
||||
{
|
||||
if (count_type_in_variant_container<asset_operation_ownership_proof_eth>(tx.proofs) != 0)
|
||||
{
|
||||
LOG_ERROR("asset_operation_ownership_proof_eth is not allowed prior to HF5");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -380,6 +380,7 @@ namespace currency
|
|||
bool for_altchain,
|
||||
const alt_chain_type& alt_chain = alt_chain_type(),
|
||||
uint64_t split_height = 0)const;
|
||||
bool validate_ado_ownership(asset_op_verification_context& avc) const;
|
||||
bool validate_asset_operation_against_current_blochain_state(asset_op_verification_context& avc) const;
|
||||
|
||||
void set_core_runtime_config(const core_runtime_config& pc) const;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ namespace currency
|
|||
uint64_t m_last_response_height;
|
||||
int64_t m_time_delta;
|
||||
std::string m_remote_version;
|
||||
int m_build_number = 0;
|
||||
|
||||
private:
|
||||
template<class t_core> friend class t_currency_protocol_handler;
|
||||
uncopybale_currency_context m_priv;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2020 Zano Project
|
||||
// Copyright (c) 2014-2024 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Boolberry developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -109,10 +109,16 @@ namespace currency
|
|||
wide_difficulty_type max_pos_difficulty;
|
||||
|
||||
hard_forks_descriptor hard_forks;
|
||||
std::array<int, ZANO_HARDFORKS_TOTAL> min_build_numbers_for_hard_forks;
|
||||
|
||||
bool is_hardfork_active_for_height(size_t hardfork_id, uint64_t height) const
|
||||
bool is_hardfork_active_for_height(size_t hardfork_id, uint64_t upcoming_block_height) const
|
||||
{
|
||||
return hard_forks.is_hardfork_active_for_height(hardfork_id, height);
|
||||
return hard_forks.is_hardfork_active_for_height(hardfork_id, upcoming_block_height);
|
||||
}
|
||||
|
||||
int get_min_allowed_build_version_for_height(uint64_t upcoming_block_height) const
|
||||
{
|
||||
return min_build_numbers_for_hard_forks[hard_forks.get_the_most_recent_hardfork_id_for_height(upcoming_block_height)];
|
||||
}
|
||||
|
||||
static uint64_t _default_core_time_function()
|
||||
|
|
@ -123,7 +129,7 @@ namespace currency
|
|||
|
||||
inline core_runtime_config get_default_core_runtime_config()
|
||||
{
|
||||
core_runtime_config pc = AUTO_VAL_INIT(pc);
|
||||
core_runtime_config pc{};
|
||||
pc.min_coinstake_age = POS_MINIMUM_COINSTAKE_AGE;
|
||||
pc.pos_minimum_heigh = POS_START_HEIGHT;
|
||||
pc.tx_pool_min_fee = TX_MINIMUM_FEE;
|
||||
|
|
@ -137,7 +143,9 @@ namespace currency
|
|||
pc.hard_forks.set_hardfork_height(2, ZANO_HARDFORK_02_AFTER_HEIGHT);
|
||||
pc.hard_forks.set_hardfork_height(3, ZANO_HARDFORK_03_AFTER_HEIGHT);
|
||||
pc.hard_forks.set_hardfork_height(4, ZANO_HARDFORK_04_AFTER_HEIGHT);
|
||||
|
||||
pc.hard_forks.set_hardfork_height(5, ZANO_HARDFORK_05_AFTER_HEIGHT); pc.min_build_numbers_for_hard_forks[5] = ZANO_HARDFORK_05_MIN_BUILD_VER;
|
||||
static_assert(5 + 1 == ZANO_HARDFORKS_TOTAL);
|
||||
|
||||
pc.get_core_time = &core_runtime_config::_default_core_time_function;
|
||||
bool r = epee::string_tools::hex_to_pod(ALIAS_SHORT_NAMES_VALIDATION_PUB_KEY, pc.alias_validation_pubkey);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "failed to parse alias_validation_pub_key");
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include "crypto/hash.h"
|
||||
#include "crypto/range_proofs.h"
|
||||
#include "crypto/zarcanum.h"
|
||||
#include "crypto/eth_signature.h"
|
||||
#include "misc_language.h"
|
||||
#include "block_flags.h"
|
||||
#include "etc_custom_serialization.h"
|
||||
|
|
@ -695,6 +696,9 @@ namespace currency
|
|||
}
|
||||
};
|
||||
|
||||
#define ASSET_DESCRIPTOR_BASE_STRUCTURE_VER 1
|
||||
|
||||
typedef boost::variant<crypto::public_key, crypto::eth_public_key> asset_owner_pub_key_v;
|
||||
|
||||
struct asset_descriptor_base
|
||||
{
|
||||
|
|
@ -706,9 +710,11 @@ namespace currency
|
|||
std::string meta_info;
|
||||
crypto::public_key owner = currency::null_pkey; // consider premultipling by 1/8
|
||||
bool hidden_supply = false;
|
||||
uint8_t version = 0;
|
||||
boost::optional<crypto::eth_public_key> owner_eth_pub_key; // note: the size is 33 bytes (if present) // NOTE: using boost::optional instead of std::optional because of the Boost compilation issue: https://github.com/boostorg/serialization/issues/319 -- sowle
|
||||
|
||||
BEGIN_VERSIONED_SERIALIZE(0, version)
|
||||
uint8_t version = ASSET_DESCRIPTOR_BASE_STRUCTURE_VER;
|
||||
|
||||
BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_BASE_STRUCTURE_VER, version)
|
||||
FIELD(total_max_supply)
|
||||
FIELD(current_supply)
|
||||
FIELD(decimal_point)
|
||||
|
|
@ -717,9 +723,10 @@ namespace currency
|
|||
FIELD(meta_info)
|
||||
FIELD(owner)
|
||||
FIELD(hidden_supply)
|
||||
END_VERSION_UNDER(1)
|
||||
FIELD(owner_eth_pub_key)
|
||||
END_SERIALIZE()
|
||||
|
||||
|
||||
BEGIN_BOOST_SERIALIZATION()
|
||||
BOOST_SERIALIZE(total_max_supply)
|
||||
BOOST_SERIALIZE(current_supply)
|
||||
|
|
@ -729,17 +736,20 @@ namespace currency
|
|||
BOOST_SERIALIZE(meta_info)
|
||||
BOOST_SERIALIZE(owner)
|
||||
BOOST_SERIALIZE(hidden_supply)
|
||||
BOOST_END_VERSION_UNDER(1)
|
||||
BOOST_SERIALIZE(owner_eth_pub_key)
|
||||
END_BOOST_SERIALIZATION()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(total_max_supply) DOC_DSCR("Maximum possible supply for given asset, can't be changed after deployment") DOC_EXMP(1000000000000000000) DOC_END
|
||||
KV_SERIALIZE(current_supply) DOC_DSCR("Currently emitted supply for given asset (ignored for REGISTER operation)") DOC_EXMP(500000000000000000) DOC_END
|
||||
KV_SERIALIZE(decimal_point) DOC_DSCR("Decimal point") DOC_EXMP(12) DOC_END
|
||||
KV_SERIALIZE(ticker) DOC_DSCR("Ticker associated with asset") DOC_EXMP("ZUSD") DOC_END
|
||||
KV_SERIALIZE(full_name) DOC_DSCR("Full name of the asset") DOC_EXMP("Zano wrapped USD") DOC_END
|
||||
KV_SERIALIZE(meta_info) DOC_DSCR("Any other information assetiaded with asset in a free form") DOC_EXMP("Stable and private") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(owner) DOC_DSCR("Owner's key, used only for EMIT and UPDATE validation, could be changed by transferring asset ownership") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
KV_SERIALIZE(hidden_supply) DOC_DSCR("This one reserved for future use, will be documented later") DOC_END
|
||||
KV_SERIALIZE(total_max_supply) DOC_DSCR("Maximum possible supply for a given asset, cannot be changed after deployment.") DOC_EXMP(1000000000000000000) DOC_END
|
||||
KV_SERIALIZE(current_supply) DOC_DSCR("Currently emitted supply for the given asset (ignored for REGISTER operation).") DOC_EXMP(500000000000000000) DOC_END
|
||||
KV_SERIALIZE(decimal_point) DOC_DSCR("Decimal point.") DOC_EXMP(12) DOC_END
|
||||
KV_SERIALIZE(ticker) DOC_DSCR("Ticker associated with the asset.") DOC_EXMP("ZABC") DOC_END
|
||||
KV_SERIALIZE(full_name) DOC_DSCR("Full name of the asset.") DOC_EXMP("Zano wrapped ABC") DOC_END
|
||||
KV_SERIALIZE(meta_info) DOC_DSCR("Any other information associated with the asset in free form.") DOC_EXMP("Stable and private") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(owner) DOC_DSCR("Owner's key, used only for EMIT and UPDATE validation, can be changed by transferring asset ownership.") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
KV_SERIALIZE(hidden_supply) DOC_DSCR("This field is reserved for future use and will be documented later.") DOC_END
|
||||
KV_SERIALIZE(owner_eth_pub_key) DOC_DSCR("[Optional] Owner's key in the case when ETH signature is used.") DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
@ -793,6 +803,13 @@ namespace currency
|
|||
BOOST_END_VERSION_UNDER(1)
|
||||
BOOST_SERIALIZE(opt_asset_id)
|
||||
END_BOOST_SERIALIZATION()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(operation_type) DOC_DSCR("Asset operation type identifier") DOC_EXMP(1) DOC_END
|
||||
KV_SERIALIZE(descriptor) DOC_DSCR("Asset descriptor") DOC_EXMP_AUTO() DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(amount_commitment) DOC_DSCR("Amount commitment") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(opt_asset_id) DOC_DSCR("ID of an asset.") DOC_EXMP("cc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6") DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct asset_operation_proof
|
||||
|
|
@ -833,6 +850,26 @@ namespace currency
|
|||
};
|
||||
|
||||
|
||||
struct asset_operation_ownership_proof_eth
|
||||
{
|
||||
crypto::eth_signature eth_sig; // 64 bytes
|
||||
uint8_t version = 0;
|
||||
|
||||
BEGIN_VERSIONED_SERIALIZE(0, version)
|
||||
FIELD(eth_sig)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_BOOST_SERIALIZATION()
|
||||
BOOST_SERIALIZE(eth_sig)
|
||||
BOOST_SERIALIZE(version)
|
||||
END_BOOST_SERIALIZATION()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(eth_sig) DOC_DSCR("HEX-encoded ETH signature (64 bytes)") DOC_EXMP("674bb56a5b4fa562e679ccacc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6add697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
KV_SERIALIZE(version) DOC_DSCR("Structure version") DOC_EXMP(0) DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct extra_padding
|
||||
{
|
||||
std::vector<uint8_t> buff; //stub
|
||||
|
|
@ -936,7 +973,7 @@ namespace currency
|
|||
|
||||
typedef boost::variant<NLSAG_sig, void_sig, ZC_sig, zarcanum_sig> signature_v;
|
||||
|
||||
typedef boost::variant<zc_asset_surjection_proof, zc_outs_range_proof, zc_balance_proof, asset_operation_proof, asset_operation_ownership_proof> proof_v;
|
||||
typedef boost::variant<zc_asset_surjection_proof, zc_outs_range_proof, zc_balance_proof, asset_operation_proof, asset_operation_ownership_proof, asset_operation_ownership_proof_eth> proof_v;
|
||||
|
||||
|
||||
//include backward compatibility defintions
|
||||
|
|
@ -1195,6 +1232,10 @@ SET_VARIANT_TAGS(currency::zc_balance_proof, 48, "zc_balance_proof");
|
|||
SET_VARIANT_TAGS(currency::asset_descriptor_operation, 49, "asset_descriptor_base");
|
||||
SET_VARIANT_TAGS(currency::asset_operation_proof, 50, "asset_operation_proof");
|
||||
SET_VARIANT_TAGS(currency::asset_operation_ownership_proof, 51, "asset_operation_ownership_proof");
|
||||
SET_VARIANT_TAGS(currency::asset_operation_ownership_proof_eth, 52, "asset_operation_ownership_proof_eth");
|
||||
|
||||
SET_VARIANT_TAGS(crypto::eth_public_key, 60, "eth_public_key");
|
||||
//SET_VARIANT_TAGS(crypto::eth_signature, 61, "eth_signature");s
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#define CURRENCY_MAX_BLOCK_NUMBER 500000000
|
||||
#define CURRENCY_MAX_BLOCK_SIZE 500000000 // block header blob limit, never used!
|
||||
#define CURRENCY_TX_MAX_ALLOWED_INPUTS 256 // limited primarily by asset surjection proof
|
||||
#define CURRENCY_TX_MAX_ALLOWED_OUTS 2000
|
||||
#define CURRENCY_TX_MIN_ALLOWED_OUTS 2 // effective starting HF4 Zarcanum
|
||||
#define CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX 0xc5 // addresses start with 'Zx'
|
||||
|
|
@ -257,25 +258,29 @@
|
|||
|
||||
#define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31)
|
||||
|
||||
//hard forks section
|
||||
#define BLOCK_MAJOR_VERSION_GENESIS 1
|
||||
#define BLOCK_MINOR_VERSION_GENESIS 0
|
||||
#define BLOCK_MAJOR_VERSION_INITIAL 0
|
||||
|
||||
/////// Hard forks setup //////////////////////////////
|
||||
#ifndef TESTNET
|
||||
// Mainnet
|
||||
#define ZANO_HARDFORK_01_AFTER_HEIGHT 194624 // 2019-09-21 20:25:16
|
||||
#define ZANO_HARDFORK_02_AFTER_HEIGHT 999999 // 2021-04-05 09:11:45
|
||||
#define ZANO_HARDFORK_03_AFTER_HEIGHT 1082577 // 2021-06-01 23:28:10
|
||||
#define ZANO_HARDFORK_04_AFTER_HEIGHT 2555000 // 2024-03-21 11:49:55
|
||||
#define ZANO_HARDFORK_05_AFTER_HEIGHT 999999999999999999
|
||||
#define ZANO_HARDFORK_04_TIMESTAMP_ACTUAL 1711021795ull // block 2555000, 2024-03-21 11:49:55 UTC
|
||||
#define ZANO_HARDFORK_05_AFTER_HEIGHT 999999999999999999
|
||||
#define ZANO_HARDFORK_05_MIN_BUILD_VER 343
|
||||
#else
|
||||
/////// Zarcanum Testnet //////////////////////////////
|
||||
// Testnet
|
||||
#define ZANO_HARDFORK_01_AFTER_HEIGHT 0
|
||||
#define ZANO_HARDFORK_02_AFTER_HEIGHT 0
|
||||
#define ZANO_HARDFORK_03_AFTER_HEIGHT 0
|
||||
#define ZANO_HARDFORK_04_AFTER_HEIGHT 200
|
||||
#define ZANO_HARDFORK_05_AFTER_HEIGHT 200
|
||||
#define ZANO_HARDFORK_04_TIMESTAMP_ACTUAL 1712785801ull // block 200, 2024-04-10 21:50:01 UTC
|
||||
#define ZANO_HARDFORK_05_AFTER_HEIGHT 241750
|
||||
#define ZANO_HARDFORK_05_MIN_BUILD_VER 343
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -552,6 +552,7 @@ namespace currency
|
|||
if (hardfork_id_for_prev_block != hardfork_id_for_curr_block)
|
||||
{
|
||||
LOG_PRINT_GREEN("Hardfork " << hardfork_id_for_curr_block << " has been activated after the block at height " << h, LOG_LEVEL_0);
|
||||
m_pprotocol->on_hardfork_activated(hardfork_id_for_curr_block);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ namespace currency
|
|||
secret_index = ring.size() - 1;
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(secret_index != SIZE_MAX, false, "out #" << j << ": can't find a corresponding asset id in inputs, asset id: " << H);
|
||||
CHECK_AND_ASSERT_MES(secret_index != SIZE_MAX, false, "out #" << j << ": cannot find a corresponding asset id in inputs or asset operations; asset id: " << H);
|
||||
|
||||
result.bge_proofs.emplace_back(crypto::BGE_proof_s{});
|
||||
uint8_t err = 0;
|
||||
|
|
@ -322,7 +322,7 @@ namespace currency
|
|||
CHECK_AND_ASSERT_MES(ogc.asset_id_blinding_mask_x_amount_sum.is_zero(), false, "it's expected that all asset ids for this tx are obvious and thus explicit"); // because this tx has no ZC inputs => all outs clearly have native asset id
|
||||
CHECK_AND_ASSERT_MES(ogc.ao_amount_blinding_mask.is_zero(), false, "asset emmission is not allowed for txs without ZC inputs");
|
||||
|
||||
// (sum(bare inputs' amounts) - fee) * H + sum(pseudo out amount commitments) - sum(outputs' commitments) = lin(G)
|
||||
// (sum(bare inputs' amounts) - fee) * H - sum(outputs' commitments) = lin(G)
|
||||
|
||||
crypto::point_t commitment_to_zero = (crypto::scalar_t(bare_inputs_sum) - crypto::scalar_t(fee)) * currency::native_coin_asset_id_pt - ogc.amount_commitments_sum;
|
||||
crypto::scalar_t secret_x = -ogc.amount_blinding_masks_sum;
|
||||
|
|
@ -336,6 +336,8 @@ namespace currency
|
|||
{
|
||||
// there're ZC inputs => in main balance equation we only need to cancel out X-component, because G-component cancelled out by choosing blinding mask for the last pseudo out amount commitment
|
||||
|
||||
// (sum(bare inputs' amounts) - fee) * H + sum(pseudo out amount commitments) + asset_op_commitment - sum(outputs' commitments) = lin(X)
|
||||
|
||||
crypto::point_t commitment_to_zero = (crypto::scalar_t(bare_inputs_sum) - crypto::scalar_t(fee)) * currency::native_coin_asset_id_pt + ogc.pseudo_out_amount_commitments_sum + (ogc.ao_commitment_in_outputs ? -ogc.ao_amount_commitment : ogc.ao_amount_commitment) - ogc.amount_commitments_sum;
|
||||
crypto::scalar_t secret_x = ogc.real_in_asset_id_blinding_mask_x_amount_sum - ogc.asset_id_blinding_mask_x_amount_sum;
|
||||
|
||||
|
|
@ -472,7 +474,7 @@ namespace currency
|
|||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS || height == 0, false, "Too many outs (" << destinations.size() << ")! Miner tx can't be constructed.");
|
||||
tx = AUTO_VAL_INIT_T(transaction);
|
||||
// tx is not cleared intentionally to allow passing additional args in the extra/attachments
|
||||
tx.version = tx_version;
|
||||
|
||||
tx_generation_context tx_gen_context{};
|
||||
|
|
@ -2182,8 +2184,10 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
|
||||
// otherwise, calculate asset id
|
||||
// otherwise, it must be a register operation
|
||||
CHECK_AND_ASSERT_MES(ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER, false, "unexpected asset operation type: " << (int)ado.operation_type << ", " << get_asset_operation_type_string(ado.operation_type));
|
||||
|
||||
// calculate asset id
|
||||
crypto::hash_helper_t::hs_t hsc;
|
||||
hsc.add_32_chars(CRYPTO_HDS_ASSET_ID);
|
||||
hsc.add_hash(crypto::hash_helper_t::h(ado.descriptor.ticker));
|
||||
|
|
@ -2192,6 +2196,8 @@ namespace currency
|
|||
hsc.add_scalar(crypto::scalar_t(ado.descriptor.total_max_supply));
|
||||
hsc.add_scalar(crypto::scalar_t(ado.descriptor.decimal_point));
|
||||
hsc.add_pub_key(ado.descriptor.owner);
|
||||
if (ado.descriptor.owner_eth_pub_key.has_value())
|
||||
hsc.add_eth_pub_key(ado.descriptor.owner_eth_pub_key.value());
|
||||
crypto::hash h = hsc.calc_hash_no_reduce();
|
||||
|
||||
// this hash function needs to be computationally expensive (s.a. the whitepaper)
|
||||
|
|
@ -2244,7 +2250,8 @@ namespace currency
|
|||
// asset_control_key = Hs(CRYPTO_HDS_ASSET_CONTROL_KEY, 8 * tx_key.sec * sender_account_keys.account_address.spend_public_key, 0)
|
||||
// ado.descriptor.owner = asset_control_key * G
|
||||
|
||||
ado.descriptor.owner = sender_account_keys.account_address.spend_public_key;
|
||||
if (!ado.descriptor.owner_eth_pub_key.has_value())
|
||||
ado.descriptor.owner = sender_account_keys.account_address.spend_public_key;
|
||||
|
||||
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id), false, "get_or_calculate_asset_id failed");
|
||||
|
||||
|
|
@ -2333,25 +2340,6 @@ namespace currency
|
|||
}
|
||||
if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation_before_seal{ &ado });
|
||||
|
||||
ftp.need_to_generate_ado_proof = true;
|
||||
/*
|
||||
//seal it with owners signature
|
||||
crypto::signature sig = currency::null_sig;
|
||||
crypto::hash h = get_signature_hash_for_asset_operation(ado);
|
||||
if (ftp.pthirdparty_sign_handler)
|
||||
{
|
||||
bool r = ftp.pthirdparty_sign_handler->sign(h, ftp.ado_current_asset_owner, sig);
|
||||
CHECK_AND_ASSERT_MES(r, false, "asset thirparty sign failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
crypto::public_key pub_k = currency::null_pkey;
|
||||
crypto::secret_key_to_public_key(sender_account_keys.spend_secret_key, pub_k);
|
||||
CHECK_AND_ASSERT_MES(ftp.ado_current_asset_owner == pub_k, false, "asset owner key not matched with provided private key for asset operation signing");
|
||||
crypto::generate_signature(h, pub_k, account_keys.spend_secret_key, sig);
|
||||
}
|
||||
ado.opt_proof = sig;
|
||||
*/
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2374,7 +2362,8 @@ namespace currency
|
|||
crypto::secret_key& one_time_tx_secret_key = result.one_time_key;
|
||||
|
||||
result.ftp = ftp;
|
||||
CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS, false, "Too many outs (" << destinations.size() << ")! Tx can't be constructed.");
|
||||
CHECK_AND_ASSERT_MES(sources.size() <= CURRENCY_TX_MAX_ALLOWED_INPUTS, false, "Too many inputs: " << sources.size() << ", max allowed: " << CURRENCY_TX_MAX_ALLOWED_INPUTS << ". Tx cannot be constructed.");
|
||||
CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS, false, "Too many outputs: " << destinations.size() << ", max allowed: " << CURRENCY_TX_MAX_ALLOWED_OUTS << ". Tx cannot be constructed.");
|
||||
|
||||
bool append_mode = false;
|
||||
if (flags&TX_FLAG_SIGNATURE_MODE_SEPARATE && tx.vin.size())
|
||||
|
|
@ -2600,8 +2589,7 @@ namespace currency
|
|||
// ASSET oprations handling
|
||||
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
|
||||
{
|
||||
asset_descriptor_operation* pado = nullptr;
|
||||
pado = get_type_in_variant_container<asset_descriptor_operation>(tx.extra);
|
||||
asset_descriptor_operation* pado = get_type_in_variant_container<asset_descriptor_operation>(tx.extra);
|
||||
if (pado)
|
||||
{
|
||||
bool r = construct_tx_handle_ado(sender_account_keys, ftp, *pado, gen_context, gen_context.tx_key, shuffled_dsts);
|
||||
|
|
@ -2714,7 +2702,8 @@ namespace currency
|
|||
// generate proofs and signatures
|
||||
// (any changes made below should only affect the signatures/proofs and should not impact the prefix hash calculation)
|
||||
//
|
||||
crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
|
||||
result.tx_id = get_transaction_prefix_hash(tx);
|
||||
const crypto::hash &tx_prefix_hash = result.tx_id;
|
||||
|
||||
// ring signatures (per-input proofs)
|
||||
r = false;
|
||||
|
|
@ -2770,35 +2759,30 @@ namespace currency
|
|||
CHECK_AND_ASSERT_MES(r, false, "generate_tx_balance_proof failed");
|
||||
tx.proofs.emplace_back(std::move(balance_proof));
|
||||
|
||||
// asset operation proof (if necessary)
|
||||
// optional asset operation proofs: amount commitment proof (required for register, emit, public burn)
|
||||
if (gen_context.ao_asset_id != currency::null_pkey)
|
||||
{
|
||||
// construct the asset operation proof
|
||||
// TODO @#@# add support for hidden supply
|
||||
// asset amount commitment g proof (TODO @#@# add support for hidden supply)
|
||||
crypto::signature aop_g_sig{};
|
||||
crypto::generate_signature(tx_prefix_hash, crypto::point_t(gen_context.ao_amount_blinding_mask * crypto::c_point_G).to_public_key(), gen_context.ao_amount_blinding_mask, aop_g_sig);
|
||||
asset_operation_proof aop{};
|
||||
aop.opt_amount_commitment_g_proof = aop_g_sig;
|
||||
tx.proofs.emplace_back(std::move(aop));
|
||||
}
|
||||
if(ftp.need_to_generate_ado_proof)
|
||||
{
|
||||
asset_operation_ownership_proof aoop = AUTO_VAL_INIT(aoop);
|
||||
|
||||
if (ftp.pthirdparty_sign_handler)
|
||||
// optional asset operation proofs: ownership proof for standard (non-eth) owner (using generic Shnorr signature with the spend secret key)
|
||||
const asset_descriptor_operation* pado = get_type_in_variant_container<asset_descriptor_operation>(tx.extra);
|
||||
if (pado != nullptr)
|
||||
{
|
||||
if ((pado->operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || pado->operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) &&
|
||||
!pado->descriptor.owner_eth_pub_key.has_value())
|
||||
{
|
||||
//ask third party to generate proof
|
||||
r = ftp.pthirdparty_sign_handler->sign(tx_prefix_hash, ftp.ado_current_asset_owner, aoop.gss);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to sign ado by thirdparty");
|
||||
}
|
||||
else
|
||||
{
|
||||
//generate signature by wallet account
|
||||
r = crypto::generate_schnorr_sig(tx_prefix_hash, ftp.ado_current_asset_owner, sender_account_keys.spend_secret_key, aoop.gss);
|
||||
asset_operation_ownership_proof aoop{};
|
||||
r = crypto::generate_schnorr_sig(tx_prefix_hash, sender_account_keys.spend_secret_key, aoop.gss);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to sign ado proof");
|
||||
if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_after_asset_ownership_proof_generated{ &aoop });
|
||||
tx.proofs.emplace_back(aoop);
|
||||
}
|
||||
if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_after_asset_ownership_proof_generated{ &aoop });
|
||||
tx.proofs.emplace_back(aoop);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2850,7 +2834,7 @@ namespace currency
|
|||
return reward;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
std::string get_word_from_timstamp(uint64_t timestamp, bool use_password)
|
||||
std::string get_word_from_timestamp(uint64_t timestamp, bool use_password)
|
||||
{
|
||||
uint64_t date_offset = timestamp > WALLET_BRAIN_DATE_OFFSET ? timestamp - WALLET_BRAIN_DATE_OFFSET : 0;
|
||||
uint64_t weeks_count = date_offset / WALLET_BRAIN_DATE_QUANTUM;
|
||||
|
|
@ -2865,7 +2849,7 @@ namespace currency
|
|||
return tools::mnemonic_encoding::word_by_num(weeks_count_32);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_timstamp_from_word(std::string word, bool& password_used)
|
||||
uint64_t get_timestamp_from_word(std::string word, bool& password_used)
|
||||
{
|
||||
uint64_t count_of_weeks = tools::mnemonic_encoding::num_by_word(word);
|
||||
if (count_of_weeks >= WALLET_BRAIN_DATE_MAX_WEEKS_COUNT)
|
||||
|
|
|
|||
|
|
@ -139,11 +139,13 @@ namespace currency
|
|||
bool hltc_our_out_is_before_expiration;
|
||||
};
|
||||
|
||||
struct thirdparty_sign_handler
|
||||
struct asset_eth_signer_i
|
||||
{
|
||||
virtual bool sign(const crypto::hash& h, const crypto::public_key& owner_public_key, crypto::generic_schnorr_sig& sig);
|
||||
virtual bool sign(const crypto::hash& h, const crypto::eth_public_key& asset_owner, crypto::eth_signature& sig) = 0;
|
||||
};
|
||||
|
||||
typedef boost::variant<crypto::public_key, crypto::eth_public_key> asset_owner_key_v;
|
||||
|
||||
struct finalize_tx_param
|
||||
{
|
||||
uint64_t unlock_time;
|
||||
|
|
@ -165,10 +167,6 @@ namespace currency
|
|||
epee::misc_utils::events_dispatcher* pevents_dispatcher;
|
||||
tx_generation_context gen_context{}; // solely for consolidated txs
|
||||
|
||||
//crypto::secret_key asset_control_key = currency::null_skey;
|
||||
crypto::public_key ado_current_asset_owner = null_pkey;
|
||||
thirdparty_sign_handler* pthirdparty_sign_handler = nullptr;
|
||||
mutable bool need_to_generate_ado_proof = false;
|
||||
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
|
|
@ -191,14 +189,13 @@ namespace currency
|
|||
{
|
||||
FIELD(gen_context);
|
||||
}
|
||||
FIELD(ado_current_asset_owner)
|
||||
FIELD(need_to_generate_ado_proof)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct finalized_tx
|
||||
{
|
||||
currency::transaction tx;
|
||||
crypto::hash tx_id;
|
||||
crypto::secret_key one_time_key;
|
||||
finalize_tx_param ftp;
|
||||
std::string htlc_origin;
|
||||
|
|
@ -208,6 +205,7 @@ namespace currency
|
|||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(tx)
|
||||
FIELD(tx_id)
|
||||
FIELD(one_time_key)
|
||||
FIELD(ftp)
|
||||
FIELD(htlc_origin)
|
||||
|
|
@ -457,9 +455,9 @@ namespace currency
|
|||
|
||||
bool fill_block_rpc_details(block_rpc_extended_info& pei_rpc, const block_extended_info& bei_chain, const crypto::hash& h);
|
||||
void append_per_block_increments_for_tx(const transaction& tx, std::unordered_map<uint64_t, uint32_t>& gindices);
|
||||
std::string get_word_from_timstamp(uint64_t timestamp, bool use_password);
|
||||
uint64_t get_timstamp_from_word(std::string word, bool& password_used, const std::string& buff);
|
||||
uint64_t get_timstamp_from_word(std::string word, bool& password_used);
|
||||
std::string get_word_from_timestamp(uint64_t timestamp, bool use_password);
|
||||
uint64_t get_timestamp_from_word(std::string word, bool& password_used, const std::string& buff);
|
||||
uint64_t get_timestamp_from_word(std::string word, bool& password_used);
|
||||
bool parse_vote(const std::string& buff, std::list<std::pair<std::string, bool>>& votes);
|
||||
|
||||
std::string generate_origin_for_htlc(const txout_htlc& htlc, const account_keys& acc_keys);
|
||||
|
|
@ -546,7 +544,7 @@ namespace currency
|
|||
{
|
||||
assets_list.push_back(currency::asset_descriptor_with_id());
|
||||
assets_list.back().asset_id = pr.first;
|
||||
epee::misc_utils::cast_assign_a_to_b(assets_list.back(), static_cast<currency::asset_descriptor_base>(pr.second));
|
||||
epee::misc_utils::cast_assign_a_to_b(static_cast<currency::asset_descriptor_base>(pr.second), assets_list.back());
|
||||
//*static_cast<currency::asset_descriptor_base*>(&assets_list.back()) = pr.second;
|
||||
}
|
||||
}
|
||||
|
|
@ -948,6 +946,12 @@ namespace currency
|
|||
}
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename invocable_t>
|
||||
typename std::enable_if_t<std::is_invocable_v<invocable_t, std::ostream&>, std::ostream&> operator<<(std::ostream& o, invocable_t callee)
|
||||
{
|
||||
callee(o);
|
||||
return o;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
std::ostream& operator <<(std::ostream& o, const ref_by_id& r);
|
||||
std::ostream& operator <<(std::ostream& o, const std::type_info& ti);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2024 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
|
||||
|
|
@ -135,7 +135,7 @@ namespace currency
|
|||
|
||||
struct CORE_SYNC_DATA
|
||||
{
|
||||
uint64_t current_height;
|
||||
uint64_t current_height; // height of the top block + 1
|
||||
crypto::hash top_id;
|
||||
uint64_t last_checkpoint_height;
|
||||
uint64_t core_time;
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ namespace currency
|
|||
//-----------------------------------------------------------------------------------
|
||||
void set_to_debug_mode(uint32_t ip);
|
||||
|
||||
bool is_remote_client_version_allowed(int build_number, size_t min_allowed_build_number = SIZE_MAX) const;
|
||||
bool is_remote_client_version_allowed(const std::string& client_version) const;
|
||||
void check_all_client_versions_are_okay();
|
||||
|
||||
private:
|
||||
//----------------- commands handlers ----------------------------------------------
|
||||
int handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, currency_connection_context& context);
|
||||
|
|
@ -86,11 +90,12 @@ namespace currency
|
|||
|
||||
|
||||
|
||||
//----------------- i_bc_protocol_layout ---------------------------------------
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, currency_connection_context& exclude_context);
|
||||
virtual bool relay_transactions(NOTIFY_OR_INVOKE_NEW_TRANSACTIONS::request& arg, currency_connection_context& exclude_context);
|
||||
//----------------- i_currency_protocol ---------------------------------------
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, currency_connection_context& exclude_context) override;
|
||||
virtual bool relay_transactions(NOTIFY_OR_INVOKE_NEW_TRANSACTIONS::request& arg, currency_connection_context& exclude_context) override;
|
||||
virtual void on_hardfork_activated(size_t hardfork_id) override;
|
||||
//----------------------------------------------------------------------------------
|
||||
//bool get_payload_sync_data(HANDSHAKE_DATA::request& hshd, currency_connection_context& context);
|
||||
|
||||
bool request_missing_objects(currency_connection_context& context, bool check_having_blocks);
|
||||
bool on_connection_synchronized();
|
||||
void relay_que_worker();
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2024 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
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <boost/interprocess/detail/atomic.hpp>
|
||||
#include "currency_protocol_handler.h"
|
||||
#include "currency_core/currency_format_utils.h"
|
||||
#include "profile_tools.h"
|
||||
#include <version.h>
|
||||
|
||||
namespace currency
|
||||
{
|
||||
|
||||
|
|
@ -95,7 +97,7 @@ namespace currency
|
|||
|
||||
ss << std::setw(29) << std::left << "Remote Host"
|
||||
<< std::setw(20) << "Peer id"
|
||||
<< std::setw(25) << "Recv/Sent (idle,sec)"
|
||||
<< std::setw(27) << "Recv/Sent (idle,sec)"
|
||||
<< std::setw(25) << "State"
|
||||
<< std::setw(20) << "Livetime"
|
||||
<< std::setw(20) << "Client version" << ENDL;
|
||||
|
|
@ -109,7 +111,7 @@ namespace currency
|
|||
conn_ss << std::setw(29) << std::left << std::string(cntxt.m_is_income ? "[INC]":"[OUT]") +
|
||||
epst::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port)
|
||||
<< std::setw(20) << std::hex << peer_id
|
||||
<< std::setw(25) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")"
|
||||
<< std::setw(27) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")"
|
||||
<< std::setw(25) << get_protocol_state_string(cntxt.m_state)
|
||||
<< std::setw(20) << epee::misc_utils::get_time_interval_string(livetime)
|
||||
<< std::setw(20) << cntxt.m_remote_version
|
||||
|
|
@ -128,9 +130,12 @@ namespace currency
|
|||
template<class t_core>
|
||||
bool t_currency_protocol_handler<t_core>::process_payload_sync_data(const CORE_SYNC_DATA& hshd, currency_connection_context& context, bool is_inital)
|
||||
{
|
||||
|
||||
|
||||
context.m_remote_version = hshd.client_version;
|
||||
if (!tools::parse_client_version_build_number(context.m_remote_version, context.m_build_number))
|
||||
{
|
||||
LOG_PRINT_RED_L0("Couldn't parse remote node's version: " << context.m_remote_version << ". Connection will be dropped.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(context.m_state == currency_connection_context::state_befor_handshake && !is_inital)
|
||||
return true;
|
||||
|
|
@ -988,7 +993,7 @@ namespace currency
|
|||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
bool t_currency_protocol_handler<t_core>::relay_transactions(NOTIFY_OR_INVOKE_NEW_TRANSACTIONS::request& arg, currency_connection_context& exclude_context)
|
||||
{
|
||||
{
|
||||
#ifdef ASYNC_RELAY_MODE
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_relay_que_lock);
|
||||
|
|
@ -1002,4 +1007,52 @@ namespace currency
|
|||
return relay_post_notify<NOTIFY_OR_INVOKE_NEW_TRANSACTIONS>(arg, exclude_context);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
void t_currency_protocol_handler<t_core>::on_hardfork_activated(size_t hardfork_id)
|
||||
{
|
||||
check_all_client_versions_are_okay();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
bool t_currency_protocol_handler<t_core>::is_remote_client_version_allowed(int build_number, size_t min_allowed_build_number /*= SIZE_MAX*/) const
|
||||
{
|
||||
if (min_allowed_build_number == SIZE_MAX)
|
||||
min_allowed_build_number = m_core.get_blockchain_storage().get_core_runtime_config().get_min_allowed_build_version_for_height(m_core.get_top_block_height() + 1);
|
||||
|
||||
if (build_number < static_cast<int>(min_allowed_build_number))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
bool t_currency_protocol_handler<t_core>::is_remote_client_version_allowed(const std::string& client_version) const
|
||||
{
|
||||
int major = -1, minor = -1, revision = -1, build_number = -1;
|
||||
std::string commit_id;
|
||||
bool dirty = false;
|
||||
if (!tools::parse_client_version(client_version, major, minor, revision, build_number, commit_id, dirty))
|
||||
return false;
|
||||
|
||||
return is_remote_client_version_allowed(build_number);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
void t_currency_protocol_handler<t_core>::check_all_client_versions_are_okay()
|
||||
{
|
||||
size_t min_allowed_build_number = m_core.get_blockchain_storage().get_core_runtime_config().get_min_allowed_build_version_for_height(m_core.get_top_block_height() + 1);
|
||||
|
||||
m_p2p->for_each_connection([&](const connection_context& cc, nodetool::peerid_type peer_id)
|
||||
{
|
||||
if (!is_remote_client_version_allowed(cc.m_build_number, min_allowed_build_number))
|
||||
{
|
||||
LOG_PRINT_CC_YELLOW(cc, "client's build number is " << cc.m_build_number << ", which is absolutely not okay in the current hardfork era, prompting us to adjust our connections accordingly.", LOG_LEVEL_0);
|
||||
m_p2p->drop_connection(cc);
|
||||
}
|
||||
return true; // = continue
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
} // namespace currency
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ namespace currency
|
|||
{
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, currency_connection_context& exclude_context)=0;
|
||||
virtual bool relay_transactions(NOTIFY_OR_INVOKE_NEW_TRANSACTIONS::request& arg, currency_connection_context& exclude_context)=0;
|
||||
virtual void on_hardfork_activated(size_t hardfork_id) {}
|
||||
//virtual bool request_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, currency_connection_context& context)=0;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ struct core_critical_error_handler_t : public currency::i_critical_error_handler
|
|||
if (dont_stop_on_time_error)
|
||||
return false; // ignore such errors
|
||||
|
||||
LOG_ERROR(ENDL << ENDL << "Serious time sync problem detected, daemon will stop immediately" << ENDL << ENDL);
|
||||
LOG_ERROR(ENDL << ENDL << "Serious TIME sync problem detected, daemon will stop immediately" << ENDL << ENDL);
|
||||
|
||||
// stop handling
|
||||
dch.stop_handling();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2024 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Boolberry developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -714,9 +714,12 @@ bool MainWindow::show_inital()
|
|||
{
|
||||
TRY_ENTRY();
|
||||
if (load_app_config())
|
||||
{
|
||||
restore_pos(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L1("set defaults values to config");
|
||||
m_config = AUTO_VAL_INIT(m_config);
|
||||
this->show();
|
||||
QSize sz = AUTO_VAL_INIT(sz);
|
||||
|
|
@ -976,6 +979,11 @@ QString MainWindow::start_backend(const QString& params)
|
|||
CATCH_ENTRY_FAIL_API_RESPONCE();
|
||||
}
|
||||
|
||||
void MainWindow::show_notification(const QString& title, const QString& message)
|
||||
{
|
||||
show_notification(title.toStdString(), message.toStdString());
|
||||
}
|
||||
|
||||
QString MainWindow::sync_call(const QString& func_name, const QString& params)
|
||||
{
|
||||
if (func_name == "test_call")
|
||||
|
|
@ -1107,6 +1115,7 @@ bool MainWindow::get_is_disabled_notifications(const QString& param)
|
|||
}
|
||||
bool MainWindow::set_is_disabled_notifications(const bool& param)
|
||||
{
|
||||
LOG_PRINT_L1("set_is_disabled_notifications: notifications were " << (m_config.disable_notifications ? "DISABLED" : "ENABLED") << " -> now " << (param ? "DISABLED" : "ENABLED"));
|
||||
m_config.disable_notifications = param;
|
||||
return m_config.disable_notifications;
|
||||
}
|
||||
|
|
@ -1712,7 +1721,7 @@ QString MainWindow::have_secure_app_data(const QString& param)
|
|||
CATCH_ENTRY_FAIL_API_RESPONCE();
|
||||
}
|
||||
|
||||
QString MainWindow::drop_secure_app_data(const QString& param)
|
||||
QString MainWindow::drop_secure_app_data()
|
||||
{
|
||||
TRY_ENTRY();
|
||||
LOG_API_TIMING();
|
||||
|
|
@ -2468,6 +2477,10 @@ QString MainWindow::print_log(const QString& param)
|
|||
void MainWindow::show_notification(const std::string& title, const std::string& message)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
if (m_config.disable_notifications)
|
||||
return;
|
||||
|
||||
LOG_PRINT_L1("system notification: \"" << title << "\", \"" << message << "\"");
|
||||
|
||||
// it's expected that title and message are utf-8 encoded!
|
||||
|
|
@ -2482,5 +2495,3 @@ void MainWindow::show_notification(const std::string& title, const std::string&
|
|||
#endif
|
||||
CATCH_ENTRY2(void());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ public:
|
|||
QString get_network_type(const QString& param);
|
||||
QString transfer(const QString& param);
|
||||
QString have_secure_app_data(const QString& param);
|
||||
QString drop_secure_app_data(const QString& param);
|
||||
QString drop_secure_app_data();
|
||||
QString get_secure_app_data(const QString& param);
|
||||
QString store_secure_app_data(const QString& param, const QString& password);
|
||||
QString set_master_password(const QString& param);
|
||||
|
|
@ -190,6 +190,7 @@ public:
|
|||
void on_menu_show(const QString& param);
|
||||
QString is_remnotenode_mode_preconfigured(const QString& param);
|
||||
QString start_backend(const QString& params);
|
||||
void show_notification(const QString& title, const QString& message);
|
||||
|
||||
QString async_call(const QString& func_name, const QString& params);
|
||||
QString sync_call(const QString& func_name, const QString& params);
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 2fb143cc67280f0e0cfcd3165e1c087ba8279edf
|
||||
Subproject commit 748e8e96d8f2653e6e698a11f67c172c1f84c2b2
|
||||
|
|
@ -523,7 +523,7 @@ namespace nodetool
|
|||
return;
|
||||
}
|
||||
|
||||
if (!tools::check_remote_client_version(rsp.payload_data.client_version))
|
||||
if (!m_payload_handler.is_remote_client_version_allowed(rsp.payload_data.client_version))
|
||||
{
|
||||
LOG_PRINT_CC_YELLOW(context, "COMMAND_HANDSHAKE Failed, wrong client version: " << rsp.payload_data.client_version << ", closing connection.", LOG_LEVEL_1);
|
||||
return;
|
||||
|
|
@ -1391,7 +1391,7 @@ namespace nodetool
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (!tools::check_remote_client_version(arg.payload_data.client_version))
|
||||
if (!m_payload_handler.is_remote_client_version_allowed(arg.payload_data.client_version))
|
||||
{
|
||||
LOG_PRINT_CCONTEXT_L2("COMMAND_HANDSHAKE: wrong client version: " << arg.payload_data.client_version << ", closing connection.");
|
||||
drop_connection(context);
|
||||
|
|
|
|||
|
|
@ -75,7 +75,8 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
#define check_core_ready() check_core_ready_(LOCAL_FUNCTION_DEF__)
|
||||
#define CHECK_CORE_READY() if(!check_core_ready()){res.status = API_RETURN_CODE_BUSY;return true;}
|
||||
#define CHECK_CORE_READY() if (!check_core_ready()) {res.status = API_RETURN_CODE_BUSY; return true; }
|
||||
#define CHECK_CORE_READY_WE() if (!check_core_ready()) {error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; error_resp.message = "Core is busy."; return false; }
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res, connection_context& cntx)
|
||||
{
|
||||
|
|
@ -575,7 +576,7 @@ namespace currency
|
|||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_get_pos_mining_details(const COMMAND_RPC_GET_POS_MINING_DETAILS::request& req, COMMAND_RPC_GET_POS_MINING_DETAILS::response& res, connection_context& cntx)
|
||||
{
|
||||
if (!m_p2p.get_connections_count())
|
||||
if (!m_ignore_status && !m_p2p.get_connections_count())
|
||||
{
|
||||
res.status = API_RETURN_CODE_DISCONNECTED;
|
||||
return true;
|
||||
|
|
@ -750,6 +751,74 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_decrypt_tx_details(const COMMAND_RPC_DECRYPT_TX_DETAILS::request& req, COMMAND_RPC_DECRYPT_TX_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
|
||||
{
|
||||
#define LOCAL_CHECK(cond, msg) if (!(cond)) { error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; error_resp.message = msg; LOG_PRINT_L1("on_decrypt_tx_details: " << error_resp.message); return false; }
|
||||
#define LOCAL_CHECK_INT_ERR(cond, msg) if (!(cond)) { error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; error_resp.message = msg; LOG_PRINT_L1("on_decrypt_tx_details: " << error_resp.message); return false; }
|
||||
|
||||
LOCAL_CHECK(req.tx_id.empty() != req.tx_blob.empty(), "One of either tx_id or tx_blob must be specified.");
|
||||
|
||||
transaction tx{};
|
||||
if (!req.tx_id.empty())
|
||||
{
|
||||
CHECK_CORE_READY_WE();
|
||||
|
||||
crypto::hash tx_id{};
|
||||
LOCAL_CHECK(crypto::parse_tpod_from_hex_string(req.tx_id, tx_id), "tx_id is given, but it's invalid");
|
||||
LOCAL_CHECK(m_core.get_transaction(tx_id, tx), "tx with the given tx_id could be found in the blockchain");
|
||||
}
|
||||
else
|
||||
{
|
||||
blobdata decoded_blob = string_encoding::base64_decode(req.tx_blob);
|
||||
if (!t_unserializable_object_from_blob(tx, decoded_blob))
|
||||
{
|
||||
// unable to decode tx_blob as base64, try once again as hex-encoding
|
||||
decoded_blob.clear();
|
||||
string_tools::parse_hexstr_to_binbuff(req.tx_blob, decoded_blob);
|
||||
LOCAL_CHECK(t_unserializable_object_from_blob(tx, decoded_blob), "tx_id is not given, and tx_blob is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
|
||||
crypto::point_t R{};
|
||||
LOCAL_CHECK(tx_pub_key != null_pkey && R.from_public_key(tx_pub_key) && R.is_in_main_subgroup(), "unsigned_tx: tx public key is missing or invalid");
|
||||
|
||||
LOCAL_CHECK(tx_pub_key == (crypto::scalar_t(req.tx_secret_key) * crypto::c_point_G).to_public_key(), "tx_secret_key doesn't match the transaction public key");
|
||||
|
||||
LOCAL_CHECK(req.outputs_addresses.size() == tx.vout.size(), "outputs_addresses count (" + epee::string_tools::num_to_string_fast(req.outputs_addresses.size()) + " doesn't match tx.vout size (" + epee::string_tools::num_to_string_fast(tx.vout.size()) + ")");
|
||||
|
||||
for(size_t i = 0; i < req.outputs_addresses.size(); ++i)
|
||||
{
|
||||
if (req.outputs_addresses[i].empty())
|
||||
continue; // skip this output if the given address is empty string
|
||||
|
||||
account_public_address addr{};
|
||||
payment_id_t payment_id{};
|
||||
LOCAL_CHECK(currency::get_account_address_and_payment_id_from_str(addr, payment_id, req.outputs_addresses[i]) && payment_id.empty(), "output address #" + epee::string_tools::num_to_string_fast(i) + " couldn't be parsed or it is an integrated address (which is not supported)");
|
||||
|
||||
tx_out_v& out_v = tx.vout[i];
|
||||
LOCAL_CHECK(out_v.type() == typeid(tx_out_zarcanum), "tx output #" + epee::string_tools::num_to_string_fast(i) + " has wrong type");
|
||||
const tx_out_zarcanum& zo = boost::get<tx_out_zarcanum>(out_v);
|
||||
|
||||
crypto::key_derivation derivation{};
|
||||
LOCAL_CHECK_INT_ERR(crypto::generate_key_derivation(addr.view_public_key, req.tx_secret_key, derivation), "output #" + epee::string_tools::num_to_string_fast(i) + ": generate_key_derivation failed");
|
||||
|
||||
auto& decoded_out = res.decoded_outputs.emplace_back();
|
||||
decoded_out.out_index = i;
|
||||
decoded_out.address = req.outputs_addresses[i];
|
||||
crypto::scalar_t amount_blinding_mask{}, asset_id_blinding_mask{};
|
||||
LOCAL_CHECK(currency::decode_output_amount_and_asset_id(zo, derivation, i, decoded_out.amount, decoded_out.asset_id, amount_blinding_mask, asset_id_blinding_mask), "output #" + epee::string_tools::num_to_string_fast(i) + ": cannot be decoded");
|
||||
}
|
||||
|
||||
res.tx_in_json = currency::obj_to_json_str(tx);
|
||||
res.verified_tx_id = get_transaction_hash(tx);
|
||||
|
||||
res.status = API_RETURN_CODE_OK;
|
||||
return true;
|
||||
#undef LOCAL_CHECK
|
||||
#undef LOCAL_CHECK_INT_ERR
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_get_main_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
|
||||
{
|
||||
if (!m_core.get_blockchain_storage().get_main_block_rpc_details(req.id, res.block_details))
|
||||
|
|
@ -793,7 +862,7 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!m_p2p.get_payload_object().get_synchronized_connections_count())
|
||||
if (!m_ignore_status && !m_p2p.get_payload_object().get_synchronized_connections_count())
|
||||
{
|
||||
LOG_PRINT_L0("[on_send_raw_tx]: Failed to send, daemon not connected to net");
|
||||
res.status = API_RETURN_CODE_DISCONNECTED;
|
||||
|
|
@ -1001,7 +1070,7 @@ namespace currency
|
|||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
|
||||
{
|
||||
CHECK_CORE_READY();
|
||||
CHECK_CORE_READY_WE();
|
||||
if(req.size()!=1)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
|
||||
|
|
@ -1044,8 +1113,7 @@ namespace currency
|
|||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_submitblock2(const COMMAND_RPC_SUBMITBLOCK2::request& req, COMMAND_RPC_SUBMITBLOCK2::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
|
||||
{
|
||||
CHECK_CORE_READY();
|
||||
|
||||
CHECK_CORE_READY_WE();
|
||||
|
||||
block b = AUTO_VAL_INIT(b);
|
||||
if (!parse_and_validate_block_from_blob(req.b, b))
|
||||
|
|
@ -1301,6 +1369,110 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_find_outs_in_recent_blocks(const COMMAND_RPC_FIND_OUTS_IN_RECENT_BLOCKS::request& req, COMMAND_RPC_FIND_OUTS_IN_RECENT_BLOCKS::response& resp, epee::json_rpc::error& error_resp, connection_context& cntx)
|
||||
{
|
||||
#define LOCAL_CHECK(cond, msg) if (!(cond)) { error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; error_resp.message = msg; LOG_PRINT_L1("on_find_outs_in_recent_blocks: " << msg); return false; }
|
||||
#define LOCAL_CHECK_INT_ERR(cond, msg) if (!(cond)) { error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; error_resp.message = msg; LOG_PRINT_L1("on_find_outs_in_recent_blocks: " << msg); return false; }
|
||||
|
||||
LOCAL_CHECK(req.address != account_public_address{}, "address is missing");
|
||||
LOCAL_CHECK(req.viewkey != null_skey, "viewkey is missing");
|
||||
LOCAL_CHECK(req.blocks_limit <= 5, "blocks_limit is out of allowed bounds");
|
||||
|
||||
// verify addess keys
|
||||
crypto::point_t view_pk, spend_pk;
|
||||
LOCAL_CHECK(view_pk.from_public_key(req.address.view_public_key), "cannon load point from address.view_public_key");
|
||||
LOCAL_CHECK(view_pk.is_in_main_subgroup(), "address.view_public_key isn't in main subgroup");
|
||||
LOCAL_CHECK(spend_pk.from_public_key(req.address.spend_public_key), "cannon load point from address.spend_public_key");
|
||||
LOCAL_CHECK(spend_pk.is_in_main_subgroup(), "address.spend_public_key isn't in main subgroup");
|
||||
|
||||
// verify viewkey
|
||||
crypto::scalar_t view_sc = req.viewkey;
|
||||
LOCAL_CHECK(view_sc.is_reduced(), "viewkey is invalid");
|
||||
LOCAL_CHECK(view_sc * crypto::c_point_G == view_pk, "viewkey doesn't correspond to the given address");
|
||||
|
||||
const blockchain_storage& bcs = m_core.get_blockchain_storage();
|
||||
resp.blockchain_top_block_height = bcs.get_top_block_height();
|
||||
resp.blocks_limit = req.blocks_limit;
|
||||
|
||||
// get blockchain transactions
|
||||
std::unordered_map<uint64_t, std::pair<std::vector<crypto::hash>, std::list<transaction>>> blockchain_txs; // block height -> (vector of tx_ids, list of txs)
|
||||
if (req.blocks_limit > 0)
|
||||
{
|
||||
uint64_t start_offset = resp.blockchain_top_block_height - req.blocks_limit + 1;
|
||||
std::list<block> recent_blocks;
|
||||
LOCAL_CHECK_INT_ERR(bcs.get_blocks(start_offset, static_cast<size_t>(req.blocks_limit), recent_blocks), "cannot get recent blocks");
|
||||
|
||||
std::vector<crypto::hash> blockchain_tx_ids, missed_tx;
|
||||
for(auto& b : recent_blocks)
|
||||
{
|
||||
blockchain_tx_ids.insert(blockchain_tx_ids.end(), b.tx_hashes.begin(), b.tx_hashes.end());
|
||||
uint64_t height = get_block_height(b);
|
||||
auto& el = blockchain_txs[height];
|
||||
el.first = b.tx_hashes;
|
||||
missed_tx.clear();
|
||||
LOCAL_CHECK_INT_ERR(bcs.get_transactions(b.tx_hashes, el.second, missed_tx), "bcs.get_transactions failed");
|
||||
LOCAL_CHECK_INT_ERR(missed_tx.empty(), "missed_tx is not empty");
|
||||
LOCAL_CHECK_INT_ERR(el.first.size() == el.second.size(), "el.first.size() != el.second.size()");
|
||||
}
|
||||
}
|
||||
|
||||
// get pool transactions
|
||||
std::list<transaction> pool_txs;
|
||||
LOCAL_CHECK_INT_ERR(m_core.get_tx_pool().get_transactions(pool_txs), "cannot get txs from pool");
|
||||
|
||||
// processor lambda
|
||||
auto process_tx = [&](const transaction& tx, const crypto::hash& tx_id, const int64_t height) {
|
||||
crypto::key_derivation derivation{};
|
||||
LOCAL_CHECK(generate_key_derivation(get_tx_pub_key_from_extra(tx), req.viewkey, derivation), "generate_key_derivation failed");
|
||||
|
||||
for(size_t i = 0, sz = tx.vout.size(); i < sz; ++i)
|
||||
{
|
||||
const tx_out_v& outv = tx.vout[i];
|
||||
if (outv.type() != typeid(tx_out_zarcanum))
|
||||
continue;
|
||||
|
||||
uint64_t decoded_amount = 0;
|
||||
crypto::public_key decoded_asset_id{};
|
||||
crypto::scalar_t amount_blinding_mask{}, asset_id_blinding_mask{};
|
||||
if (!is_out_to_acc(req.address, boost::get<tx_out_zarcanum>(outv), derivation, i, decoded_amount, decoded_asset_id, amount_blinding_mask, asset_id_blinding_mask))
|
||||
continue;
|
||||
|
||||
auto& el = resp.outputs.emplace_back();
|
||||
el.amount = decoded_amount;
|
||||
el.asset_id = decoded_asset_id;
|
||||
el.tx_id = tx_id;
|
||||
el.tx_block_height = height;
|
||||
el.output_tx_index = i;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// process blockchain txs
|
||||
for(auto& [height, pair] : blockchain_txs)
|
||||
{
|
||||
LOCAL_CHECK(pair.first.size() == pair.second.size(), "container size inconsistency");
|
||||
auto tx_it = pair.second.begin();
|
||||
for(size_t i = 0, sz = pair.first.size(); i < sz; ++i, ++tx_it)
|
||||
{
|
||||
const crypto::hash& tx_id = pair.first[i];
|
||||
LOCAL_CHECK(process_tx(*tx_it, tx_id, height), "process blockchain tx failed for tx " + crypto::pod_to_hex(tx_id));
|
||||
}
|
||||
}
|
||||
|
||||
// process pool txs
|
||||
for(auto& tx : pool_txs)
|
||||
{
|
||||
crypto::hash tx_id = get_transaction_hash(tx);
|
||||
LOCAL_CHECK(process_tx(tx, tx_id, -1), "process pool tx failed for tx " + crypto::pod_to_hex(tx_id));
|
||||
}
|
||||
|
||||
resp.status = resp.outputs.empty() ? API_RETURN_CODE_NOT_FOUND : API_RETURN_CODE_OK;
|
||||
return true;
|
||||
|
||||
#undef LOCAL_CHECK_INT_ERR
|
||||
#undef LOCAL_CHECK
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_aliases_by_address(const COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& req, COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
|
||||
{
|
||||
account_public_address addr = AUTO_VAL_INIT(addr);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2024 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
|
||||
|
|
@ -89,11 +89,13 @@ namespace currency
|
|||
bool on_get_votes(const COMMAND_RPC_GET_VOTES::request& req, COMMAND_RPC_GET_VOTES::response& res, connection_context& cntx);
|
||||
bool on_get_asset_info(const COMMAND_RPC_GET_ASSET_INFO::request& req, COMMAND_RPC_GET_ASSET_INFO::response& res, connection_context& cntx);
|
||||
bool on_get_assets_list(const COMMAND_RPC_GET_ASSETS_LIST::request& req, COMMAND_RPC_GET_ASSETS_LIST::response& res, connection_context& cntx);
|
||||
bool on_decrypt_tx_details(const COMMAND_RPC_DECRYPT_TX_DETAILS::request& req, COMMAND_RPC_DECRYPT_TX_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||
|
||||
bool on_get_main_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||
bool on_get_alt_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||
bool on_get_alt_blocks_details(const COMMAND_RPC_GET_ALT_BLOCKS_DETAILS::request& req, COMMAND_RPC_GET_ALT_BLOCKS_DETAILS::response& res, connection_context& cntx);
|
||||
bool on_get_est_height_from_date(const COMMAND_RPC_GET_EST_HEIGHT_FROM_DATE::request& req, COMMAND_RPC_GET_EST_HEIGHT_FROM_DATE::response& res, connection_context& cntx);
|
||||
bool on_find_outs_in_recent_blocks(const COMMAND_RPC_FIND_OUTS_IN_RECENT_BLOCKS::request& req, COMMAND_RPC_FIND_OUTS_IN_RECENT_BLOCKS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||
bool on_validate_signature(const COMMAND_VALIDATE_SIGNATURE::request& req, COMMAND_VALIDATE_SIGNATURE::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
|
||||
|
||||
|
|
@ -133,6 +135,8 @@ namespace currency
|
|||
MAP_JON_RPC_WE("get_alias_by_address", on_aliases_by_address, COMMAND_RPC_GET_ALIASES_BY_ADDRESS)
|
||||
MAP_JON_RPC_WE("get_alias_reward", on_get_alias_reward, COMMAND_RPC_GET_ALIAS_REWARD)
|
||||
MAP_JON_RPC ("get_est_height_from_date", on_get_est_height_from_date, COMMAND_RPC_GET_EST_HEIGHT_FROM_DATE)
|
||||
MAP_JON_RPC_WE("find_outs_in_recent_blocks", on_find_outs_in_recent_blocks, COMMAND_RPC_FIND_OUTS_IN_RECENT_BLOCKS)
|
||||
|
||||
//block explorer api
|
||||
MAP_JON_RPC ("get_blocks_details", on_rpc_get_blocks_details, COMMAND_RPC_GET_BLOCKS_DETAILS)
|
||||
MAP_JON_RPC_WE("get_tx_details", on_get_tx_details, COMMAND_RPC_GET_TX_DETAILS)
|
||||
|
|
@ -150,9 +154,11 @@ namespace currency
|
|||
MAP_JON_RPC ("getrandom_outs1", on_get_random_outs1, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS)
|
||||
MAP_JON_RPC ("getrandom_outs3", on_get_random_outs3, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3)
|
||||
MAP_JON_RPC ("get_votes", on_get_votes, COMMAND_RPC_GET_VOTES)
|
||||
|
||||
//assets api
|
||||
MAP_JON_RPC ("get_asset_info", on_get_asset_info, COMMAND_RPC_GET_ASSET_INFO)
|
||||
MAP_JON_RPC ("get_assets_list", on_get_assets_list, COMMAND_RPC_GET_ASSETS_LIST)
|
||||
MAP_JON_RPC_WE("decrypt_tx_details", on_decrypt_tx_details, COMMAND_RPC_DECRYPT_TX_DETAILS)
|
||||
|
||||
MAP_JON_RPC_WE("get_main_block_details", on_get_main_block_details, COMMAND_RPC_GET_BLOCK_DETAILS)
|
||||
MAP_JON_RPC_WE("get_alt_block_details", on_get_alt_block_details, COMMAND_RPC_GET_BLOCK_DETAILS)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <currency_core/account.h>
|
||||
//#include "currency_core/basic_api_response_codes.h"
|
||||
|
||||
namespace currency
|
||||
|
|
@ -178,6 +179,58 @@ namespace currency
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
struct COMMAND_RPC_DECRYPT_TX_DETAILS
|
||||
{
|
||||
DOC_COMMAND("Decrypts transaction private information. Should be used only with your own local daemon for security reasons.");
|
||||
|
||||
struct request
|
||||
{
|
||||
std::string tx_id;
|
||||
currency::blobdata tx_blob;
|
||||
crypto::secret_key tx_secret_key;
|
||||
std::vector<std::string> outputs_addresses;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tx_id) DOC_DSCR("[either] ID for a transaction if it is already in the blockchain. Can be ommited if tx_blob is provided.") DOC_EXMP("a6e8da986858e6825fce7a192097e6afae4e889cabe853a9c29b964985b23da8") DOC_END
|
||||
KV_SERIALIZE(tx_blob) DOC_DSCR("[or] base64-encoded or hex-encoded tx blob. Can be ommited if tx_id is provided.") DOC_EXMP("ewogICJ2ZXJzaW9uIjogMSwgC....iAgInZpbiI6IFsgewogICAgIC") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(tx_secret_key) DOC_DSCR("Hex-encoded transaction secret key.") DOC_EXMP("2e0b840e70dba386effd64c5d988622dea8c064040566e6bf035034cbb54a5c08") DOC_END
|
||||
KV_SERIALIZE(outputs_addresses) DOC_DSCR("Address of each of tx's output. Order is important and should correspond to order of tx's outputs. Empty strings are ignored.") DOC_EXMP_AGGR("ZxDNaMeZjwCjnHuU5gUNyrP1pM3U5vckbakzzV6dEHyDYeCpW8XGLBFTshcaY8LkG9RQn7FsQx8w2JeJzJwPwuDm2NfixPAXf", "ZxBvJDuQjMG9R2j4WnYUhBYNrwZPwuyXrC7FHdVmWqaESgowDvgfWtiXeNGu8Px9B24pkmjsA39fzSSiEQG1ekB225ZnrMTBp") DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
// TODO consider reusing existing structure transfer_destination -- sowle
|
||||
struct decoded_output
|
||||
{
|
||||
uint64_t amount = 0;
|
||||
std::string address;
|
||||
crypto::public_key asset_id;
|
||||
uint64_t out_index;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(amount) DOC_DSCR("Amount begin transferred.") DOC_EXMP(10000000000000) DOC_END
|
||||
KV_SERIALIZE(address) DOC_DSCR("Destination address.") DOC_EXMP("ZxBvJDuQjMG9R2j4WnYUhBYNrwZPwuyXrC7FHdVmWqaESgowDvgfWtiXeNGu8Px9B24pkmjsA39fzSSiEQG1ekB225ZnrMTBp") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) DOC_DSCR("Asset id.") DOC_EXMP("cc608f59f8080e2fbfe3c8c80eb6e6a953d47cf2d6aebd345bada3a1cab99852") DOC_END
|
||||
KV_SERIALIZE(out_index) DOC_DSCR("Index of the corresponding output in the transaction.") DOC_EXMP(1) DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
std::vector<decoded_output> decoded_outputs;
|
||||
std::string tx_in_json;
|
||||
crypto::hash verified_tx_id;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(status) DOC_DSCR("Status code of operation, OK if success") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
|
||||
KV_SERIALIZE(decoded_outputs) DOC_DSCR("Transaction's decoded outputs") DOC_EXMP_AUTO(1) DOC_END
|
||||
KV_SERIALIZE_BLOB_AS_BASE64_STRING(tx_in_json) DOC_DSCR("Serialized transaction represented in JSON, encoded in Base64.") DOC_EXMP("ewogICJ2ZXJzaW9uIjogMSwgC....iAgInZpbiI6IFsgewogICAgIC") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(verified_tx_id) DOC_DSCR("(Re)calculated transaction id. Can be used in third-party proof generation.") DOC_EXMP("a6e8da986858e6825fce7a192097e6afae4e889cabe853a9c29b964985b23da8") DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
struct COMMAND_RPC_GET_HEIGHT
|
||||
{
|
||||
DOC_COMMAND("Return current blockchain height");
|
||||
|
|
@ -289,6 +342,58 @@ namespace currency
|
|||
};
|
||||
};
|
||||
//-----------------------------------------------
|
||||
struct COMMAND_RPC_FIND_OUTS_IN_RECENT_BLOCKS
|
||||
{
|
||||
DOC_COMMAND("Retrieves information about outputs in recent blocks that are targeted for the given address with the corresponding secret view key.")
|
||||
|
||||
static constexpr uint64_t blocks_limit_default = 5;
|
||||
|
||||
struct request
|
||||
{
|
||||
account_public_address address;
|
||||
crypto::secret_key viewkey;
|
||||
uint64_t blocks_limit = blocks_limit_default;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_ADDRESS_AS_TEXT(address) DOC_DSCR("Target address for which outputs are being searched") DOC_EXMP("ZxCSpsGGeJsS8fwvQ4HktDU3qBeauoJTR6j73jAWWZxFXdF7XTbGm4YfS2kXJmAP4Rf5BVsSQ9iZ45XANXEYsrLN2L2W77dH7") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(viewkey) DOC_DSCR("Secret view key corresponding to the given address.") DOC_EXMP("5fa8eaaf231a305053260ff91d69c6ef1ecbd0f5") DOC_END
|
||||
KV_SERIALIZE(blocks_limit) DOC_DSCR("Block count limit. If 0, only the transaction pool will be searched. Maximum and default is " + epee::string_tools::num_to_string_fast(blocks_limit_default) + ".") DOC_EXMP(1711021795) DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct out_entry
|
||||
{
|
||||
uint64_t amount;
|
||||
crypto::public_key asset_id;
|
||||
crypto::hash tx_id;
|
||||
int64_t tx_block_height;
|
||||
uint64_t output_tx_index;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(amount) DOC_DSCR("The amount of the output.") DOC_EXMP(1000000000000) DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) DOC_DSCR("Asset ID of the output.") DOC_EXMP("cc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) DOC_DSCR("Transaction ID where the output is present, if found.") DOC_EXMP("a6e8da986858e6825fce7a192097e6afae4e889cabe853a9c29b964985b23da8") DOC_END
|
||||
KV_SERIALIZE(tx_block_height) DOC_DSCR("Block height where the transaction is present.") DOC_EXMP(2555000) DOC_END
|
||||
KV_SERIALIZE(output_tx_index) DOC_DSCR("Index of the output in the transaction.") DOC_EXMP(2) DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::vector<out_entry> outputs;
|
||||
uint64_t blockchain_top_block_height;
|
||||
uint64_t blocks_limit;
|
||||
std::string status;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(outputs) DOC_DSCR("List of found outputs.") DOC_EXMP_AUTO(1) DOC_END
|
||||
KV_SERIALIZE(blockchain_top_block_height) DOC_DSCR("Height of the most recent block in the blockchain.") DOC_EXMP(2555000) DOC_END
|
||||
KV_SERIALIZE(blocks_limit) DOC_DSCR("Used limit for block count.") DOC_EXMP(5) DOC_END
|
||||
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
//-----------------------------------------------
|
||||
struct COMMAND_RPC_GET_TX_POOL
|
||||
{
|
||||
DOC_COMMAND("Retreives transactions from tx pool (and other information).")
|
||||
|
|
@ -583,32 +688,32 @@ namespace currency
|
|||
};
|
||||
|
||||
//-----------------------------------------------
|
||||
struct COMMAND_RPC_SEND_RAW_TX
|
||||
{
|
||||
struct COMMAND_RPC_SEND_RAW_TX
|
||||
{
|
||||
DOC_COMMAND("Broadcasts a raw transaction encoded in hexadecimal format to the network.");
|
||||
|
||||
struct request
|
||||
{
|
||||
std::string tx_as_hex;
|
||||
{
|
||||
std::string tx_as_hex;
|
||||
|
||||
request() {}
|
||||
explicit request(const transaction &);
|
||||
request() {}
|
||||
explicit request(const transaction &);
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tx_as_hex) DOC_DSCR("The transaction data as a hexadecimal string, ready for network broadcast.") DOC_EXMP("00018ed1535b8b4862e.....368cdc5a86") DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(status) DOC_DSCR("Status of the call.") DOC_EXMP(API_RETURN_CODE_OK) DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
//-----------------------------------------------
|
||||
|
||||
|
|
@ -619,7 +724,7 @@ namespace currency
|
|||
std::vector<std::string> txs_as_hex;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(txs_as_hex) DOC_DSCR("List of transactions as a hexadecimal strings.") DOC_EXMP_AGGR("000535b8b2e.....3685a86", "00087368b2e.....349b77f") DOC_END
|
||||
KV_SERIALIZE(txs_as_hex) DOC_DSCR("List of transactions as a hexadecimal strings.") DOC_EXMP_AGGR("000535b8b2e.....3685a86", "00087368b2e.....349b77f") DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// Copyright (c) 2018-2024 Zano Project
|
||||
// Copyright (c) 2014-2017 The The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -7,7 +8,7 @@
|
|||
|
||||
#include <boost/serialization/optional.hpp>
|
||||
|
||||
|
||||
// boost::optional
|
||||
template <template <bool> class Archive, class T>
|
||||
bool do_serialize(Archive<false> &ar, boost::optional<T> &o)
|
||||
{
|
||||
|
|
@ -58,3 +59,55 @@ bool do_serialize(Archive<true> &ar, boost::optional<T> &v)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
// std::optional
|
||||
template <template <bool> class Archive, class T>
|
||||
bool do_serialize(Archive<false> &ar, std::optional<T> &o)
|
||||
{
|
||||
//reading flag
|
||||
bool is_none = false;
|
||||
if (!::do_serialize(ar, is_none))
|
||||
{
|
||||
ar.stream().setstate(std::ios::failbit);
|
||||
return false;
|
||||
}
|
||||
if (is_none)
|
||||
{
|
||||
o.reset();
|
||||
return true;
|
||||
}
|
||||
o = T();
|
||||
T& rval = o.value();
|
||||
//reading value
|
||||
if (!::do_serialize(ar, rval))
|
||||
{
|
||||
ar.stream().setstate(std::ios::failbit);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <template <bool> class Archive, class T>
|
||||
bool do_serialize(Archive<true> &ar, std::optional<T> &v)
|
||||
{
|
||||
//writing flag
|
||||
bool is_none = !v.has_value();
|
||||
if (!::do_serialize(ar, is_none))
|
||||
{
|
||||
ar.stream().setstate(std::ios::failbit);
|
||||
return false;
|
||||
}
|
||||
if (is_none)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!::do_serialize(ar, v.value()))
|
||||
{
|
||||
ar.stream().setstate(std::ios::failbit);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -238,8 +238,7 @@ bool t_unserializable_object_from_blob(t_object& to, const std::string& blob)
|
|||
ss << blob;
|
||||
binary_archive<false> ba(ss);
|
||||
bool r = ::serialization::serialize(ba, to);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob");
|
||||
return true;
|
||||
return r;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include "include_base_utils.h"
|
||||
#include "common/command_line.h"
|
||||
#include "common/util.h"
|
||||
|
|
@ -26,7 +27,7 @@
|
|||
#include "string_coding.h"
|
||||
#include "wallet/wrap_service.h"
|
||||
#include "common/general_purpose_commands_defs.h"
|
||||
|
||||
#include "common/mnemonic-encoding.h"
|
||||
#include "wallet/wallet_helpers.h"
|
||||
|
||||
|
||||
|
|
@ -87,9 +88,7 @@ namespace ph = boost::placeholders;
|
|||
} \
|
||||
catch (const tools::error::tx_too_big& e) \
|
||||
{ \
|
||||
currency::transaction tx = e.tx(); \
|
||||
fail_msg_writer() << "transaction " << get_transaction_hash(e.tx()) << " is too big. Transaction size: " << \
|
||||
get_object_blobsize(e.tx()) << " bytes, transaction size limit: " << e.tx_size_limit() << " bytes. Try to separate this payment into few smaller transfers."; \
|
||||
fail_msg_writer() << "transaction is too big. " << e.get_message() << " Try to split this payment into a few smaller transfers."; \
|
||||
} \
|
||||
catch (const tools::error::zero_destination&) \
|
||||
{ \
|
||||
|
|
@ -126,6 +125,7 @@ namespace
|
|||
{
|
||||
const command_line::arg_descriptor<std::string> arg_wallet_file ("wallet-file", "Use wallet <arg>", "");
|
||||
const command_line::arg_descriptor<std::string> arg_generate_new_wallet ("generate-new-wallet", "Generate new wallet and save it to <arg> or <address>.wallet by default", "");
|
||||
const command_line::arg_descriptor<bool> arg_derive_custom_seed("derive_custom_seed", "Derive seed phrase from custom 24-words secret(advanced option, do it on your own risk)", "");
|
||||
const command_line::arg_descriptor<std::string> arg_generate_new_auditable_wallet ("generate-new-auditable-wallet", "Generate new auditable wallet and store it to <arg>", "");
|
||||
const command_line::arg_descriptor<std::string> arg_daemon_address ("daemon-address", "Use daemon instance at <host>:<port>", "");
|
||||
const command_line::arg_descriptor<std::string> arg_daemon_host ("daemon-host", "Use daemon instance at host <arg> instead of localhost", "");
|
||||
|
|
@ -144,6 +144,7 @@ namespace
|
|||
const command_line::arg_descriptor<unsigned int> arg_set_timeout("set-timeout", "Set timeout for the wallet");
|
||||
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< std::vector<std::string> > arg_command ("command", "");
|
||||
|
||||
|
|
@ -2093,11 +2094,11 @@ bool simple_wallet::deploy_new_asset(const std::vector<std::string> &args)
|
|||
td.asset_id = currency::null_pkey;
|
||||
std::vector<currency::tx_destination_entry> destinations;
|
||||
destinations.push_back(td);
|
||||
currency::transaction result_tx = AUTO_VAL_INIT(result_tx);
|
||||
currency::finalized_tx ft{};
|
||||
crypto::public_key result_asset_id = currency::null_pkey;
|
||||
m_wallet->deploy_new_asset(adb, destinations, result_tx, result_asset_id);
|
||||
m_wallet->deploy_new_asset(adb, destinations, ft, result_asset_id);
|
||||
|
||||
success_msg_writer(true) << "New asset successfully deployed with tx " << get_transaction_hash(result_tx) << " (unconfirmed) : " << ENDL
|
||||
success_msg_writer(true) << "New asset successfully deployed with tx " << ft.tx_id << " (unconfirmed) : " << ENDL
|
||||
<< "Asset ID: " << result_asset_id << ENDL
|
||||
<< "Title: " << adb.full_name << ENDL
|
||||
<< "Ticker: " << adb.ticker << ENDL
|
||||
|
|
@ -2872,6 +2873,266 @@ bool search_for_wallet_file(const std::wstring &search_here/*, const std::string
|
|||
return false;
|
||||
}
|
||||
|
||||
int custom_seed_builder()
|
||||
{
|
||||
success_msg_writer() <<
|
||||
"**********************************************************************\n" <<
|
||||
"This is an experimental tool that helps you create a custom seed phrase \n"
|
||||
"based on your own 24 words. It can be extremely unsafe, so only use it \n"
|
||||
"if you're confident in what you're doing.\n"
|
||||
"**********************************************************************";
|
||||
|
||||
success_msg_writer() << "Please enter 24 words that you want to use as base for the seed:";
|
||||
std::string seed_24;
|
||||
std::getline(std::cin, seed_24);
|
||||
|
||||
|
||||
std::list<std::string> words;
|
||||
std::string trimed_seed_24 = epee::string_tools::trim(seed_24);
|
||||
boost::split(words, trimed_seed_24, boost::is_space(), boost::token_compress_on);
|
||||
seed_24 = boost::algorithm::join(words, " ");
|
||||
|
||||
std::string passphrase;
|
||||
success_msg_writer() << "Please enter seed passphrase(it's highly recommended to use passphrase for custom seed):";
|
||||
std::getline(std::cin, passphrase);
|
||||
if (passphrase.empty())
|
||||
{
|
||||
success_msg_writer() << "Using unsecured seed(no passphrase)";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string passphrase_confirmation;
|
||||
success_msg_writer() << "Please confirm passphrase:";
|
||||
std::getline(std::cin, passphrase_confirmation);
|
||||
if (passphrase_confirmation != passphrase)
|
||||
{
|
||||
success_msg_writer() << "Passphrase mismatched, try again";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
account_base acc;
|
||||
acc.generate();
|
||||
std::string pass_protected_or_not = "";
|
||||
std::vector<unsigned char> binary_from_seed = tools::mnemonic_encoding::text2binary(seed_24);
|
||||
std::vector<unsigned char> processed_binary_from_seed = binary_from_seed;
|
||||
if (!passphrase.empty())
|
||||
{
|
||||
//encrypt seed phrase binary data
|
||||
account_base::crypt_with_pass(&binary_from_seed[0], binary_from_seed.size(), &processed_binary_from_seed[0], passphrase);
|
||||
pass_protected_or_not = "(secured with passphrase)";
|
||||
}
|
||||
{
|
||||
pass_protected_or_not = "(!without passphrase!)";
|
||||
}
|
||||
const std::string new_seed = acc.get_seed_phrase(passphrase, processed_binary_from_seed);
|
||||
|
||||
success_msg_writer() << "Here is your seed" << pass_protected_or_not << "\n " << new_seed;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int seed_doctor()
|
||||
{
|
||||
success_msg_writer() <<
|
||||
"**********************************************************************\n" <<
|
||||
"This is experimental tool that might help you to recover your wallet's corrupted seed phrase. \n" <<
|
||||
"It might help to sort out only trivial situations where one word was written wrong or \n" <<
|
||||
"two word was written in wrong order\n" <<
|
||||
"**********************************************************************";
|
||||
|
||||
|
||||
success_msg_writer() << "Please enter problematic seed phrase:";
|
||||
std::string seed;
|
||||
std::getline(std::cin, seed);
|
||||
|
||||
success_msg_writer() << "Please enter wallet address if you have it(press enter if you don't know it):";
|
||||
std::string address;
|
||||
std::getline(std::cin, address);
|
||||
address = epee::string_tools::trim(address);
|
||||
|
||||
std::string passphrase;
|
||||
bool check_summ_available = false;
|
||||
|
||||
//cut the last timestamp word from restore_dats
|
||||
std::vector<std::string> words;
|
||||
boost::split(words, seed, boost::is_space());
|
||||
|
||||
std::set<size_t> failed_words;
|
||||
size_t i = 0;
|
||||
//let's validate each word
|
||||
for (const auto& w : words)
|
||||
{
|
||||
if (!tools::mnemonic_encoding::valid_word(w))
|
||||
{
|
||||
success_msg_writer() << "Word " << i << " '" << w << "' is invalid, attempting to restore it";
|
||||
failed_words.insert(i);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (words.size() == SEED_PHRASE_V1_WORDS_COUNT)
|
||||
{
|
||||
// 24 seed words + one timestamp word = 25 total
|
||||
success_msg_writer() << "SEED_PHRASE_V1_WORDS_COUNT, checksum is unavailable";
|
||||
if (address.empty())
|
||||
{
|
||||
success_msg_writer() << "With SEED_PHRASE_V1_WORDS_COUNT and address unknown it's not enough information to recover it, sorry";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
else if (words.size() == SEED_PHRASE_V2_WORDS_COUNT)
|
||||
{
|
||||
// 24 seed words + one timestamp word + one flags & checksum = 26 total
|
||||
|
||||
success_msg_writer() << "SEED_PHRASE_V2_WORDS_COUNT, checksum is available";
|
||||
check_summ_available = true;
|
||||
}
|
||||
else if (words.size() == 24)
|
||||
{
|
||||
//seed only with no date, add date to it
|
||||
std::string zero_word = tools::mnemonic_encoding::word_by_num(0); //zero_word is likely to be "like"
|
||||
words.push_back(zero_word); //
|
||||
}
|
||||
else
|
||||
{
|
||||
success_msg_writer() << "Impossible to recover something with " << words.size() << " words only";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
bool pass_protected = false;
|
||||
bool success = account_base::is_seed_password_protected(seed, pass_protected);
|
||||
success_msg_writer() << "SECURED_SEED: " << (pass_protected ? "true" : "false");
|
||||
|
||||
if (pass_protected)
|
||||
{
|
||||
success_msg_writer() << "Please enter seed passphrase(if passphrase is wrong then chances to correct seed recovery is nearly zero):";
|
||||
std::getline(std::cin, passphrase);
|
||||
}
|
||||
|
||||
size_t global_candidates_count = 0;
|
||||
|
||||
auto brute_force_func = [&](size_t word_index) -> bool {
|
||||
const map<string, uint32_t>& all_words = tools::mnemonic_encoding::get_words_map();
|
||||
success_msg_writer() << "Brute forcing word " << word_index << " ....";
|
||||
size_t candidates_count = 0;
|
||||
std::vector<std::string> words_local = words;
|
||||
|
||||
for (auto it = all_words.begin(); it != all_words.end(); it++)
|
||||
{
|
||||
words_local[word_index] = it->first;
|
||||
|
||||
std::string result = boost::algorithm::join(words_local, " ");
|
||||
account_base acc;
|
||||
bool r = acc.restore_from_seed_phrase(result, passphrase);
|
||||
if (r)
|
||||
{
|
||||
if (!address.empty())
|
||||
{
|
||||
//check against address
|
||||
if (acc.get_public_address_str() == address)
|
||||
{
|
||||
success_msg_writer(true) << "!!!SUCCESS!!!";
|
||||
success_msg_writer() << "Seed recovered, please write down recovered seed and use it to restore the wallet:\n" << result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
success_msg_writer() << "Potential seed candidate:\n" << result << "\nAddress: " << acc.get_public_address_str();
|
||||
candidates_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
global_candidates_count += candidates_count;
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
auto swap_func = [&](size_t word_index) -> bool {
|
||||
size_t candidates_count = 0;
|
||||
std::vector<std::string> words_local = words;
|
||||
|
||||
std::string tmp = words_local[word_index];
|
||||
words_local[word_index] = words_local[word_index + 1];
|
||||
words_local[word_index + 1] = tmp;
|
||||
std::string result = boost::algorithm::join(words_local, " ");
|
||||
account_base acc;
|
||||
bool r = acc.restore_from_seed_phrase(result, passphrase);
|
||||
if (r)
|
||||
{
|
||||
if (!address.empty())
|
||||
{
|
||||
//check against address
|
||||
if (acc.get_public_address_str() == address)
|
||||
{
|
||||
success_msg_writer(true) << "!!!SUCCESS!!!";
|
||||
success_msg_writer() << "Seed recovered, please write down recovered seed and use it to restore the wallet:\n" << result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
success_msg_writer() << "Potential seed candidate:\n" << result << "\nAddress: " << acc.get_public_address_str();
|
||||
candidates_count++;
|
||||
}
|
||||
}
|
||||
global_candidates_count += candidates_count;
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
if (failed_words.size())
|
||||
{
|
||||
if (failed_words.size() > 1)
|
||||
{
|
||||
success_msg_writer() << "Restoring more then 1 broken words not implemented yet, sorry";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!check_summ_available && address.empty())
|
||||
{
|
||||
success_msg_writer() << "No address and no checksum, recovery is impossible, sorry";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
size_t broken_word_index = *failed_words.begin();
|
||||
bool r = brute_force_func(broken_word_index);
|
||||
success_msg_writer() << "Brute forcing finished, " << global_candidates_count << " potential candidates found";
|
||||
return r ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!check_summ_available && address.empty())
|
||||
{
|
||||
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);
|
||||
success_msg_writer() << "Potential seed candidate:\n" << result << "\nAddress: " << acc.get_public_address_str();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
success_msg_writer() << "Brute forcing all each word";
|
||||
for (size_t i = 0; i != words.size() && i != 24; i++)
|
||||
{
|
||||
bool r = brute_force_func(i);
|
||||
if(r)
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
success_msg_writer() << "Brute forcing finished, " << global_candidates_count << " potential candidates found";
|
||||
|
||||
success_msg_writer() << "Swap check...";
|
||||
|
||||
for (size_t i = 0; i != words.size() && i != 23; i++)
|
||||
{
|
||||
bool r = swap_func(i);
|
||||
if (r)
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
#ifdef WIN32
|
||||
int wmain( int argc, wchar_t* argv_w[ ], wchar_t* envp[ ] )
|
||||
|
|
@ -2936,7 +3197,10 @@ int main(int argc, char* argv[])
|
|||
command_line::add_arg(desc_params, arg_set_timeout);
|
||||
command_line::add_arg(desc_params, arg_voting_config_file);
|
||||
command_line::add_arg(desc_params, arg_no_password_confirmations);
|
||||
command_line::add_arg(desc_params, command_line::arg_generate_rpc_autodoc);
|
||||
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);
|
||||
|
||||
|
||||
tools::wallet_rpc_server::init_options(desc_params);
|
||||
|
||||
|
|
@ -3014,6 +3278,16 @@ int main(int argc, char* argv[])
|
|||
|
||||
bool offline_mode = command_line::get_arg(vm, arg_offline_mode);
|
||||
|
||||
if (command_line::has_arg(vm, arg_seed_doctor))
|
||||
{
|
||||
return seed_doctor();
|
||||
}
|
||||
|
||||
if (command_line::has_arg(vm, arg_derive_custom_seed))
|
||||
{
|
||||
return custom_seed_builder();
|
||||
}
|
||||
|
||||
if (command_line::has_arg(vm, tools::wallet_rpc_server::arg_rpc_bind_port))
|
||||
{
|
||||
// runs wallet as RPC server
|
||||
|
|
@ -3224,3 +3498,4 @@ int main(int argc, char* argv[])
|
|||
CATCH_ENTRY_L0(__func__, EXIT_FAILURE);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -590,7 +590,8 @@ namespace
|
|||
error_str << "wallet address " << user_str << " doesn't match the address previously set in daemon and/or other workers.";
|
||||
}
|
||||
|
||||
set_miner_address(address);
|
||||
if (!error)
|
||||
set_miner_address(address);
|
||||
}
|
||||
|
||||
if (error)
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
#define PROJECT_MAJOR_VERSION "2"
|
||||
#define PROJECT_MINOR_VERSION "0"
|
||||
#define PROJECT_REVISION "0"
|
||||
#define PROJECT_REVISION "1"
|
||||
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
|
||||
|
||||
#define PROJECT_VERSION_BUILD_NO 333
|
||||
#define PROJECT_VERSION_BUILD_NO 346
|
||||
#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 "]"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
#include <boost/serialization/deque.hpp>
|
||||
#include <boost/serialization/singleton.hpp>
|
||||
#include <boost/serialization/extended_type_info.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/optional.hpp>
|
||||
#include <atomic>
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ namespace tools
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
std::string wallet2::transfer_flags_to_str(uint32_t flags)
|
||||
{
|
||||
std::string result(5, ' ');
|
||||
std::string result(7, ' ');
|
||||
if (flags & WALLET_TRANSFER_DETAIL_FLAG_SPENT)
|
||||
result[0] = 's';
|
||||
if (flags & WALLET_TRANSFER_DETAIL_FLAG_BLOCKED)
|
||||
|
|
@ -140,6 +140,10 @@ std::string wallet2::transfer_flags_to_str(uint32_t flags)
|
|||
result[3] = 'm';
|
||||
if (flags & WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION)
|
||||
result[4] = 'c';
|
||||
if (flags & WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM)
|
||||
result[5] = 'h';
|
||||
if (flags & WALLET_TRANSFER_DETAIL_FLAG_ASSET_OP_RESERVATION)
|
||||
result[6] = 'a';
|
||||
return result;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -147,7 +151,12 @@ void wallet2::init(const std::string& daemon_address)
|
|||
{
|
||||
//m_miner_text_info = PROJECT_VERSION_LONG;
|
||||
m_core_proxy->set_connection_addr(daemon_address);
|
||||
m_core_proxy->check_connection();
|
||||
bool connected = m_core_proxy->check_connection();
|
||||
if (!daemon_address.empty())
|
||||
{
|
||||
WLT_LOG_L0("daemon address: " << daemon_address);
|
||||
WLT_LOG_L1((connected ? "" : "not ") << "connected to daemon");
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
const tools::wallet_public::wallet_vote_config& votes = this->get_current_votes();
|
||||
|
|
@ -158,9 +167,8 @@ void wallet2::init(const std::string& daemon_address)
|
|||
{
|
||||
ss << "\t\t" << e.proposal_id << "\t\t" << (e.vote ? "1" : "0") << "\t\t(" << e.h_start << " - " << e.h_end << ")";
|
||||
}
|
||||
WLT_LOG_L0(ss.str());
|
||||
}
|
||||
WLT_LOG_L0(ss.str());
|
||||
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::set_core_proxy(const std::shared_ptr<i_core_proxy>& proxy)
|
||||
|
|
@ -386,6 +394,10 @@ const crypto::public_key& wallet2::out_get_pub_key(const currency::tx_out_v& out
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_operation& ado, process_transaction_context& ptc)
|
||||
{
|
||||
auto print_ado_owner = [ado](std::ostream& o){
|
||||
ado.descriptor.owner_eth_pub_key.has_value() ? o << ado.descriptor.owner_eth_pub_key.get() << " (ETH)" : o << ado.descriptor.owner;
|
||||
};
|
||||
|
||||
do
|
||||
{
|
||||
crypto::public_key asset_id{};
|
||||
|
|
@ -394,17 +406,22 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
|
|||
|
||||
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
|
||||
{
|
||||
if (ado.descriptor.owner != m_account.get_public_address().spend_public_key)
|
||||
// Add an asset to ownership list if either:
|
||||
// 1) we're the owner of the asset;
|
||||
// or
|
||||
// 2) we spent native coins in the tx (i.e. we sent it) AND it registers an asset with third-party ownership.
|
||||
if (ado.descriptor.owner != m_account.get_public_address().spend_public_key &&
|
||||
(!ado.descriptor.owner_eth_pub_key.has_value() || !ptc.spent_own_native_inputs))
|
||||
break;
|
||||
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(m_own_asset_descriptors.count(asset_id) == 0, "asset with asset_id " << asset_id << " has already been registered in the wallet as own asset");
|
||||
wallet_own_asset_context& asset_context = m_own_asset_descriptors[asset_id];
|
||||
epee::misc_utils::cast_assign_a_to_b(asset_context, ado.descriptor);
|
||||
//*static_cast<asset_descriptor_base*>(&asset_context) = ado.descriptor;
|
||||
epee::misc_utils::cast_assign_a_to_b(ado.descriptor, asset_context);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "New Asset Registered:"
|
||||
<< ENDL << "asset id: " << asset_id
|
||||
<< ENDL << "Owner: " << print_ado_owner
|
||||
<< ENDL << "Name: " << asset_context.full_name
|
||||
<< ENDL << "Ticker: " << asset_context.ticker
|
||||
<< ENDL << "Total Max Supply: " << print_asset_money(asset_context.total_max_supply, asset_context.decimal_point)
|
||||
|
|
@ -424,7 +441,7 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
|
|||
break;
|
||||
//asset had been updated
|
||||
add_rollback_event(ptc.height, asset_update_event{ it->first, it->second });
|
||||
epee::misc_utils::cast_assign_a_to_b(it->second, ado.descriptor);
|
||||
epee::misc_utils::cast_assign_a_to_b(ado.descriptor, it->second);
|
||||
|
||||
}
|
||||
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE )
|
||||
|
|
@ -437,7 +454,7 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
|
|||
// ownership of the asset acquired
|
||||
|
||||
wallet_own_asset_context& asset_context = m_own_asset_descriptors[asset_id];
|
||||
epee::misc_utils::cast_assign_a_to_b(asset_context, ado.descriptor);
|
||||
epee::misc_utils::cast_assign_a_to_b(ado.descriptor, asset_context);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "Asset ownership acquired:"
|
||||
|
|
@ -462,8 +479,8 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
|
|||
}
|
||||
else
|
||||
{
|
||||
//update event for asset that we control, check if ownership is still ours
|
||||
if (ado.descriptor.owner != m_account.get_public_address().spend_public_key && !it->second.thirdparty_custody)
|
||||
// check our ownership status: we lost it if the asset has new non-null owner (null means a third-party ownership, and in such a case we retain it in the own list whatever happens)
|
||||
if (ado.descriptor.owner != null_pkey && ado.descriptor.owner != m_account.get_public_address().spend_public_key)
|
||||
{
|
||||
//ownership of the asset had been transfered
|
||||
add_rollback_event(ptc.height, asset_unown_event{ it->first, it->second });
|
||||
|
|
@ -472,7 +489,7 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
|
|||
std::stringstream ss;
|
||||
ss << "Asset ownership lost:"
|
||||
<< ENDL << "asset id: " << asset_id
|
||||
<< ENDL << "New owner: " << ado.descriptor.owner
|
||||
<< ENDL << "New owner: " << print_ado_owner
|
||||
<< ENDL << "Name: " << ado.descriptor.full_name
|
||||
<< ENDL << "Ticker: " << ado.descriptor.ticker
|
||||
<< ENDL << "Total Max Supply: " << print_asset_money(ado.descriptor.total_max_supply, ado.descriptor.decimal_point)
|
||||
|
|
@ -488,8 +505,7 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
|
|||
{
|
||||
//just an update of the asset
|
||||
add_rollback_event(ptc.height, asset_update_event{ it->first, it->second });
|
||||
epee::misc_utils::cast_assign_a_to_b(it->second, ado.descriptor);
|
||||
|
||||
epee::misc_utils::cast_assign_a_to_b(ado.descriptor, it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1147,7 +1163,7 @@ void wallet2::accept_proposal(const crypto::hash& contract_id, uint64_t b_accept
|
|||
throw;
|
||||
}
|
||||
|
||||
print_tx_sent_message(tx, "(contract <" + epee::string_tools::pod_to_hex(contract_id) + ">)", construct_param.fee);
|
||||
print_tx_sent_message(tx, "contract <" + epee::string_tools::pod_to_hex(contract_id) + ">", true, construct_param.fee);
|
||||
|
||||
if (p_acceptance_tx != nullptr)
|
||||
*p_acceptance_tx = tx;
|
||||
|
|
@ -1286,7 +1302,7 @@ void wallet2::request_cancel_contract(const crypto::hash& contract_id, uint64_t
|
|||
throw;
|
||||
}
|
||||
|
||||
print_tx_sent_message(tx, "(transport for cancel proposal)", fee);
|
||||
print_tx_sent_message(tx, "transport for cancel proposal", true, fee);
|
||||
|
||||
if (p_cancellation_proposal_tx != nullptr)
|
||||
*p_cancellation_proposal_tx = tx;
|
||||
|
|
@ -3433,8 +3449,8 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password)
|
|||
m_current_wallet_file_size = boost::filesystem::file_size(wallet_, ec);
|
||||
|
||||
WLT_LOG_L0("Loaded wallet file" << (m_watch_only ? " (WATCH ONLY) " : " ") << string_encoding::convert_to_ansii(m_wallet_file)
|
||||
<< " with public address: " << m_account.get_public_address_str()
|
||||
<< ", file_size=" << m_current_wallet_file_size
|
||||
<< " with public address " << m_account.get_public_address_str()
|
||||
<< ", file_size: " << m_current_wallet_file_size
|
||||
<< ", blockchain_size: " << m_chain.get_blockchain_current_size()
|
||||
);
|
||||
WLT_LOG_L1("[LOADING]Blockchain shortener state: " << ENDL << m_chain.get_internal_state_text());
|
||||
|
|
@ -3703,12 +3719,13 @@ bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asse
|
|||
m_has_bare_unspent_outputs = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<crypto::public_key, bool> subtransfers_by_assets_map;
|
||||
for(auto& utx : m_unconfirmed_txs)
|
||||
{
|
||||
for (auto& subtransfer : utx.second.subtransfers)
|
||||
{
|
||||
wallet_public::asset_balance_entry_base& e = balances[subtransfer.asset_id];
|
||||
subtransfers_by_assets_map[subtransfer.asset_id] = subtransfer.is_income;
|
||||
if (subtransfer.is_income)
|
||||
{
|
||||
e.total += subtransfer.amount;
|
||||
|
|
@ -3729,16 +3746,27 @@ bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asse
|
|||
}
|
||||
}
|
||||
}
|
||||
if (utx.second.has_outgoing_entries())
|
||||
{
|
||||
|
||||
//has outgoing entries for each asset
|
||||
//if (utx.second.has_outgoing_entries())
|
||||
//{
|
||||
//collect change to unconfirmed
|
||||
for (const auto& emp_entry : utx.second.employed_entries.receive)
|
||||
{
|
||||
wallet_public::asset_balance_entry_base& e = balances[emp_entry.asset_id];
|
||||
e.total += emp_entry.amount;
|
||||
auto it_employed_entry = subtransfers_by_assets_map.find(emp_entry.asset_id);
|
||||
if (it_employed_entry == subtransfers_by_assets_map.end())
|
||||
{
|
||||
LOG_ERROR("Intenral error, check the wallet code at give location");
|
||||
continue;
|
||||
}
|
||||
if (!(it_employed_entry->second)) // if is_incoming == false, then we need to check for change and add it to total
|
||||
{
|
||||
wallet_public::asset_balance_entry_base& e = balances[emp_entry.asset_id];
|
||||
e.total += emp_entry.amount;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -3988,7 +4016,7 @@ bool wallet2::generate_utxo_defragmentation_transaction_if_needed(currency::tran
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool include_unspent /*= true*/, bool show_only_unknown /*= false*/, const std::string& filter_asset_ticker /*= std::string{}*/) const
|
||||
{
|
||||
static const char* header = " index amount ticker g_index flags block tx out# asset id";
|
||||
static const char* header = " index amount ticker g_index flags block tx out# asset id";
|
||||
std::stringstream ss;
|
||||
ss << header << ENDL;
|
||||
size_t count = 0;
|
||||
|
|
@ -4020,7 +4048,7 @@ std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool inclu
|
|||
std::setw(6) << std::left << (native_coin ? std::string(" ") : adb.ticker) << " " << std::right <<
|
||||
std::setw(7) << td.m_global_output_index << " " <<
|
||||
std::setw(2) << std::setfill('0') << td.m_flags << std::setfill(' ') << ":" <<
|
||||
std::setw(5) << transfer_flags_to_str(td.m_flags) << " " <<
|
||||
std::setw(7) << transfer_flags_to_str(td.m_flags) << " " <<
|
||||
std::setw(7) << td.m_ptx_wallet_info->m_block_height << " " <<
|
||||
get_transaction_hash(td.m_ptx_wallet_info->m_tx) << " " <<
|
||||
std::setw(4) << td.m_internal_output_index << " ";
|
||||
|
|
@ -4050,13 +4078,21 @@ std::string wallet2::get_balance_str() const
|
|||
// 98.0 BGTVUW af2b12f3033337f9aea1845a6bc3fc966ed4d13227a3ace7706fca7dbcdaa7e2
|
||||
// 1000.034 DP3 d4aba1020f26927571771e04b585b4ffb211f52708d5e4c465bbdfa4a12e6271
|
||||
|
||||
static const char* header = " balance unlocked / [balance total] ticker asset id";
|
||||
static const char* header = " balance unlocked / [balance total] ticker asset id";
|
||||
std::stringstream ss;
|
||||
ss << header << ENDL;
|
||||
|
||||
std::list<tools::wallet_public::asset_balance_entry> balances;
|
||||
uint64_t mined = 0;
|
||||
balance(balances, mined);
|
||||
|
||||
auto native_coin_it = std::find_if(balances.begin(), balances.end(), [&](auto& v){ return v.asset_info.asset_id == currency::native_coin_asset_id; });
|
||||
if (native_coin_it != balances.end())
|
||||
{
|
||||
balances.push_front(*native_coin_it);
|
||||
balances.erase(native_coin_it);
|
||||
}
|
||||
|
||||
for (const tools::wallet_public::asset_balance_entry& b : balances)
|
||||
{
|
||||
ss << " " << std::left << std::setw(21) << print_fixed_decimal_point_with_trailing_spaces(b.unlocked, b.asset_info.decimal_point);
|
||||
|
|
@ -4064,7 +4100,10 @@ std::string wallet2::get_balance_str() const
|
|||
ss << std::string(21 + 3, ' ');
|
||||
else
|
||||
ss << " / " << std::setw(21) << print_fixed_decimal_point_with_trailing_spaces(b.total, b.asset_info.decimal_point);
|
||||
ss << " " << std::setw(8) << std::left << b.asset_info.ticker << " " << b.asset_info.asset_id << ENDL;
|
||||
ss << " " << std::setw(8) << std::left << b.asset_info.ticker << " " << b.asset_info.asset_id;
|
||||
if (b.asset_info.asset_id == native_coin_asset_id)
|
||||
ss << " NATIVE";
|
||||
ss << ENDL;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
|
|
@ -4081,33 +4120,63 @@ std::string wallet2::get_balance_str_raw() const
|
|||
// 7d3f348fbebfffc4e61a3686189cf870ea393e1c88b8f636acbfdacf9e4b2db2 CT
|
||||
// ...
|
||||
|
||||
static const char* header = " balance unlocked / [balance total] DP asset id";
|
||||
static const char* header = " balance unlocked / [balance total] ticker asset id DP flags";
|
||||
std::stringstream ss;
|
||||
ss << header << ENDL;
|
||||
|
||||
uint64_t dummy = 0;
|
||||
std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base> balances_map;
|
||||
typedef std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base> balances_map_t;
|
||||
balances_map_t balances_map;
|
||||
this->balance(balances_map, dummy);
|
||||
|
||||
for(const auto& entry : balances_map)
|
||||
auto print_map = [&](const balances_map_t& map){
|
||||
for(const auto& entry : map)
|
||||
{
|
||||
uint32_t asset_flags = 0;
|
||||
asset_descriptor_base asset_info{};
|
||||
bool has_info = get_asset_info(entry.first, asset_info, asset_flags);
|
||||
ss << " " << std::left << std::setw(21) << print_fixed_decimal_point_with_trailing_spaces(entry.second.unlocked, asset_info.decimal_point);
|
||||
if(entry.second.total == entry.second.unlocked)
|
||||
ss << std::string(21 + 3, ' ');
|
||||
else
|
||||
ss << " / " << std::setw(21) << print_fixed_decimal_point_with_trailing_spaces(entry.second.total, asset_info.decimal_point);
|
||||
|
||||
ss << " " << std::setw(8) << std::left << asset_info.ticker;
|
||||
ss << " " << entry.first << " ";
|
||||
|
||||
if (has_info)
|
||||
ss << std::setw(2) << std::right << (int)asset_info.decimal_point;
|
||||
else
|
||||
ss << "??";
|
||||
|
||||
ss << " ";
|
||||
|
||||
if (entry.first == native_coin_asset_id)
|
||||
{
|
||||
ss << "NATIVE";
|
||||
}
|
||||
else if (asset_flags != aif_none)
|
||||
{
|
||||
if (asset_flags & aif_own)
|
||||
ss << "own,";
|
||||
if (asset_flags & aif_whitelisted)
|
||||
ss << "whitelisted,";
|
||||
ss.seekp(-1, ss.cur); // trim comma
|
||||
}
|
||||
ss << ENDL;
|
||||
}
|
||||
};
|
||||
|
||||
auto balances_map_it = balances_map.find(native_coin_asset_id);
|
||||
if (balances_map_it != balances_map.end())
|
||||
{
|
||||
size_t decimal_point = 0;
|
||||
bool has_known_decimal_point = get_asset_decimal_point(entry.first, &decimal_point);
|
||||
ss << " " << std::left << std::setw(21) << print_fixed_decimal_point_with_trailing_spaces(entry.second.unlocked, decimal_point);
|
||||
if(entry.second.total == entry.second.unlocked)
|
||||
ss << std::string(21 + 3, ' ');
|
||||
else
|
||||
ss << " / " << std::setw(21) << print_fixed_decimal_point_with_trailing_spaces(entry.second.total, decimal_point);
|
||||
|
||||
ss << " ";
|
||||
|
||||
if (has_known_decimal_point)
|
||||
ss << std::setw(2) << std::right << decimal_point;
|
||||
else
|
||||
ss << "??";
|
||||
|
||||
ss << " " << entry.first << ENDL;
|
||||
balances_map_t native_coin_map;
|
||||
native_coin_map.insert(*balances_map_it);
|
||||
balances_map.erase(balances_map_it);
|
||||
print_map(native_coin_map);
|
||||
}
|
||||
print_map(balances_map);
|
||||
|
||||
|
||||
//print whitelist
|
||||
ss << "WHITELIST: " << ENDL;
|
||||
|
|
@ -4243,6 +4312,39 @@ bool wallet2::get_utxo_distribution(std::map<uint64_t, uint64_t>& distribution)
|
|||
return false;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::submit_externally_signed_asset_tx(const finalized_tx& ft, const crypto::eth_signature& eth_sig, bool unlock_transfers_on_fail, currency::transaction& result_tx, bool& transfers_unlocked)
|
||||
{
|
||||
transaction tx = ft.tx;
|
||||
|
||||
currency::asset_operation_ownership_proof_eth aoop_eth{};
|
||||
aoop_eth.eth_sig = eth_sig;
|
||||
tx.proofs.push_back(std::move(aoop_eth));
|
||||
|
||||
// foolproof
|
||||
WLT_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: " << ft.tx_id);
|
||||
|
||||
try
|
||||
{
|
||||
send_transaction_to_network(tx);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// clear transfers flags if smth went wrong and it was requested
|
||||
if (unlock_transfers_on_fail)
|
||||
{
|
||||
uint32_t flag = WALLET_TRANSFER_DETAIL_FLAG_SPENT | WALLET_TRANSFER_DETAIL_FLAG_ASSET_OP_RESERVATION;
|
||||
clear_transfers_from_flag(ft.ftp.selected_transfers, flag, "broadcasting tx " + epee::string_tools::pod_to_hex(ft.tx_id) + " was unsuccessful");
|
||||
transfers_unlocked = true;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
m_tx_keys.insert(std::make_pair(ft.tx_id, ft.one_time_key));
|
||||
add_sent_tx_detailed_info(tx, ft.ftp.attachments, ft.ftp.prepared_destinations, ft.ftp.selected_transfers);
|
||||
|
||||
print_tx_sent_message(tx, "from submit_externally_signed_asset_tx", true, get_tx_fee(tx));
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::transaction& tx)
|
||||
{
|
||||
// decrypt sources
|
||||
|
|
@ -4333,7 +4435,7 @@ void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::trans
|
|||
}
|
||||
|
||||
// TODO: print inputs' key images
|
||||
print_tx_sent_message(tx, "(from submit_transfer)");
|
||||
print_tx_sent_message(tx, "from submit_transfer", true);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::submit_transfer_files(const std::string& signed_tx_file, currency::transaction& tx)
|
||||
|
|
@ -5052,7 +5154,7 @@ bool wallet2::build_minted_block(const mining_context& cxt, const currency::acco
|
|||
WLT_LOG_GREEN("Note: " << udtx.vin.size() << " inputs were aggregated into UTXO defragmentation tx " << get_transaction_hash(udtx), LOG_LEVEL_0);
|
||||
}
|
||||
m_core_proxy->call_COMMAND_RPC_GETBLOCKTEMPLATE(tmpl_req, tmpl_rsp);
|
||||
WLT_CHECK_AND_ASSERT_MES(tmpl_rsp.status == API_RETURN_CODE_OK, false, "Failed to create block template after kernel hash found!");
|
||||
WLT_CHECK_AND_ASSERT_MES(tmpl_rsp.status == API_RETURN_CODE_OK, false, "Failed to create block template after kernel hash found! Status: " << tmpl_rsp.status);
|
||||
|
||||
currency::block b = AUTO_VAL_INIT(b);
|
||||
currency::blobdata block_blob;
|
||||
|
|
@ -5303,126 +5405,159 @@ void wallet2::request_alias_registration(currency::extra_alias_entry& ai, curren
|
|||
transfer(destinations, 0, 0, fee, extra, attachments, get_current_split_strategy(), tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx, CURRENCY_TO_KEY_OUT_RELAXED, false);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector<currency::tx_destination_entry>& destinations, currency::transaction& result_tx, crypto::public_key& new_asset_id)
|
||||
void wallet2::deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector<currency::tx_destination_entry>& destinations, currency::finalized_tx& ft, crypto::public_key& new_asset_id)
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(asset_info.decimal_point <= 18, "too big decimal point: " << asset_info.decimal_point);
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(asset_info.decimal_point <= 18, "too big decimal point: " << (int)asset_info.decimal_point);
|
||||
|
||||
asset_descriptor_operation asset_reg_info = AUTO_VAL_INIT(asset_reg_info);
|
||||
asset_descriptor_operation asset_reg_info{};
|
||||
asset_reg_info.descriptor = asset_info;
|
||||
asset_reg_info.operation_type = ASSET_DESCRIPTOR_OPERATION_REGISTER;
|
||||
construct_tx_param ctp = get_default_construct_tx_param();
|
||||
ctp.dsts = destinations;
|
||||
ctp.extra.push_back(asset_reg_info);
|
||||
ctp.need_at_least_1_zc = true;
|
||||
ctp.tx_meaning_for_logs = "asset registration";
|
||||
|
||||
finalized_tx ft = AUTO_VAL_INIT(ft);
|
||||
this->transfer(ctp, ft, true, nullptr);
|
||||
result_tx = ft.tx;
|
||||
//get generated asset id
|
||||
currency::asset_descriptor_operation ado = AUTO_VAL_INIT(ado);
|
||||
bool r = get_type_in_variant_container(result_tx.extra, ado);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed find asset info in tx");
|
||||
currency::asset_descriptor_operation ado{};
|
||||
bool r = get_type_in_variant_container(ft.tx.extra, ado);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "asset_descriptor_operation cannot be found in tx extra as expected");
|
||||
CHECK_AND_ASSERT_THROW_MES(get_or_calculate_asset_id(ado, nullptr, &new_asset_id), "get_or_calculate_asset_id failed");
|
||||
|
||||
m_custom_assets[new_asset_id] = ado.descriptor;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::emit_asset(const crypto::public_key asset_id, std::vector<currency::tx_destination_entry>& destinations, currency::transaction& result_tx)
|
||||
void wallet2::deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector<currency::tx_destination_entry>& destinations, currency::transaction& result_tx, crypto::public_key& new_asset_id)
|
||||
{
|
||||
finalized_tx ft{};
|
||||
deploy_new_asset(asset_info, destinations, ft, new_asset_id);
|
||||
result_tx = ft.tx;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::emit_asset(const crypto::public_key& asset_id, const std::vector<currency::tx_destination_entry>& destinations, currency::finalized_tx& ft)
|
||||
{
|
||||
|
||||
auto own_asset_entry_it = m_own_asset_descriptors.find(asset_id);
|
||||
CHECK_AND_ASSERT_THROW_MES(own_asset_entry_it != m_own_asset_descriptors.end(), "Failed find asset_id " << asset_id << " in own assets list");
|
||||
COMMAND_RPC_GET_ASSET_INFO::request req;
|
||||
req.asset_id = asset_id;
|
||||
COMMAND_RPC_GET_ASSET_INFO::response rsp;
|
||||
bool r = m_core_proxy->call_COMMAND_RPC_GET_ASSET_INFO(req, rsp);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to call_COMMAND_RPC_GET_ASSET_INFO");
|
||||
|
||||
asset_descriptor_operation asset_emmit_info = AUTO_VAL_INIT(asset_emmit_info);
|
||||
asset_emmit_info.descriptor = rsp.asset_descriptor;
|
||||
currency::asset_descriptor_base last_adb{};
|
||||
bool r = daemon_get_asset_info(asset_id, last_adb);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon");
|
||||
|
||||
asset_descriptor_operation asset_emmit_info{};
|
||||
asset_emmit_info.descriptor = last_adb;
|
||||
asset_emmit_info.operation_type = ASSET_DESCRIPTOR_OPERATION_EMIT;
|
||||
asset_emmit_info.opt_asset_id = asset_id;
|
||||
construct_tx_param ctp = get_default_construct_tx_param();
|
||||
ctp.dsts = destinations;
|
||||
ctp.extra.push_back(asset_emmit_info);
|
||||
ctp.need_at_least_1_zc = true;
|
||||
ctp.ado_current_asset_owner = rsp.asset_descriptor.owner;
|
||||
//ctp.asset_deploy_control_key = own_asset_entry_it->second.control_key;
|
||||
ctp.tx_meaning_for_logs = "asset emission";
|
||||
|
||||
for(auto& dst : ctp.dsts)
|
||||
bool send_to_network = true;
|
||||
if (last_adb.owner_eth_pub_key.has_value())
|
||||
{
|
||||
if (dst.asset_id == asset_id)
|
||||
dst.asset_id = null_pkey; // emit operation requires null_pkey for emitting asset outputs, fix it ad-hoc here
|
||||
send_to_network = false;
|
||||
ctp.additional_transfer_flags_to_mark = WALLET_TRANSFER_DETAIL_FLAG_ASSET_OP_RESERVATION;
|
||||
ctp.tx_meaning_for_logs = "asset eth emission";
|
||||
}
|
||||
|
||||
finalized_tx ft = AUTO_VAL_INIT(ft);
|
||||
this->transfer(ctp, ft, true, nullptr);
|
||||
this->transfer(ctp, ft, send_to_network, nullptr);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::emit_asset(const crypto::public_key& asset_id, std::vector<currency::tx_destination_entry>& destinations, currency::transaction& result_tx)
|
||||
{
|
||||
finalized_tx ft{};
|
||||
emit_asset(asset_id, destinations, ft);
|
||||
result_tx = ft.tx;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::update_asset(const crypto::public_key asset_id, const currency::asset_descriptor_base new_descriptor, currency::transaction& result_tx)
|
||||
void wallet2::update_asset(const crypto::public_key& asset_id, const currency::asset_descriptor_base& new_descriptor, currency::finalized_tx& ft)
|
||||
{
|
||||
auto own_asset_entry_it = m_own_asset_descriptors.find(asset_id);
|
||||
CHECK_AND_ASSERT_THROW_MES(own_asset_entry_it != m_own_asset_descriptors.end(), "Failed find asset_id " << asset_id << " in own assets list");
|
||||
currency::asset_descriptor_base last_adb{};
|
||||
bool r = daemon_get_asset_info(asset_id, last_adb);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon");
|
||||
|
||||
asset_descriptor_operation asset_update_info = AUTO_VAL_INIT(asset_update_info);
|
||||
asset_descriptor_operation asset_update_info{};
|
||||
asset_update_info.descriptor = new_descriptor;
|
||||
asset_update_info.operation_type = ASSET_DESCRIPTOR_OPERATION_UPDATE;
|
||||
asset_update_info.opt_asset_id = asset_id;
|
||||
construct_tx_param ctp = get_default_construct_tx_param();
|
||||
ctp.extra.push_back(asset_update_info);
|
||||
ctp.need_at_least_1_zc = true;
|
||||
currency::asset_descriptor_base adb = AUTO_VAL_INIT(adb);
|
||||
bool r = this->daemon_get_asset_info(asset_id, adb);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon");
|
||||
ctp.ado_current_asset_owner = adb.owner;
|
||||
ctp.tx_meaning_for_logs = "asset update";
|
||||
|
||||
finalized_tx ft = AUTO_VAL_INIT(ft);
|
||||
this->transfer(ctp, ft, true, nullptr);
|
||||
bool send_to_network = true;
|
||||
if (last_adb.owner_eth_pub_key.has_value())
|
||||
{
|
||||
send_to_network = false;
|
||||
ctp.additional_transfer_flags_to_mark = WALLET_TRANSFER_DETAIL_FLAG_ASSET_OP_RESERVATION;
|
||||
ctp.tx_meaning_for_logs = "asset eth update";
|
||||
}
|
||||
|
||||
this->transfer(ctp, ft, send_to_network, nullptr);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::update_asset(const crypto::public_key& asset_id, const currency::asset_descriptor_base new_descriptor, currency::transaction& result_tx)
|
||||
{
|
||||
currency::finalized_tx ft{};
|
||||
update_asset(asset_id, new_descriptor, ft);
|
||||
result_tx = ft.tx;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::transfer_asset_ownership(const crypto::public_key asset_id, const crypto::public_key& new_owner, currency::transaction& result_tx)
|
||||
void wallet2::transfer_asset_ownership(const crypto::public_key& asset_id, const currency::asset_owner_pub_key_v& new_owner_v, currency::finalized_tx& ft)
|
||||
{
|
||||
auto own_asset_entry_it = m_own_asset_descriptors.find(asset_id);
|
||||
CHECK_AND_ASSERT_THROW_MES(own_asset_entry_it != m_own_asset_descriptors.end(), "Failed find asset_id " << asset_id << " in own assets list");
|
||||
|
||||
currency::asset_descriptor_base adb = AUTO_VAL_INIT(adb);
|
||||
bool r = this->daemon_get_asset_info(asset_id, adb);
|
||||
currency::asset_descriptor_base last_adb{};
|
||||
bool r = this->daemon_get_asset_info(asset_id, last_adb);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon");
|
||||
|
||||
asset_descriptor_operation asset_update_info = AUTO_VAL_INIT(asset_update_info);
|
||||
asset_update_info.descriptor = adb;
|
||||
asset_descriptor_operation asset_update_info{};
|
||||
asset_update_info.descriptor = last_adb;
|
||||
asset_update_info.operation_type = ASSET_DESCRIPTOR_OPERATION_UPDATE;
|
||||
asset_update_info.opt_asset_id = asset_id;
|
||||
asset_update_info.descriptor.owner = new_owner;
|
||||
construct_tx_param ctp = get_default_construct_tx_param();
|
||||
ctp.ado_current_asset_owner = adb.owner;
|
||||
ctp.extra.push_back(asset_update_info);
|
||||
|
||||
finalized_tx ft = AUTO_VAL_INIT(ft);
|
||||
this->transfer(ctp, ft, true, nullptr);
|
||||
if (new_owner_v.type() == typeid(crypto::public_key))
|
||||
asset_update_info.descriptor.owner = boost::get<crypto::public_key>(new_owner_v);
|
||||
else
|
||||
asset_update_info.descriptor.owner_eth_pub_key = boost::get<crypto::eth_public_key>(new_owner_v);
|
||||
|
||||
construct_tx_param ctp = get_default_construct_tx_param();
|
||||
ctp.extra.push_back(asset_update_info);
|
||||
ctp.tx_meaning_for_logs = "transfer asset ownership";
|
||||
|
||||
bool send_to_network = true;
|
||||
if (last_adb.owner_eth_pub_key.has_value())
|
||||
{
|
||||
send_to_network = false;
|
||||
ctp.additional_transfer_flags_to_mark = WALLET_TRANSFER_DETAIL_FLAG_ASSET_OP_RESERVATION;
|
||||
ctp.tx_meaning_for_logs = "transfer asset eth ownership";
|
||||
}
|
||||
|
||||
this->transfer(ctp, ft, send_to_network, nullptr);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::transfer_asset_ownership(const crypto::public_key& asset_id, const currency::asset_owner_pub_key_v& new_owner_v, currency::transaction& result_tx)
|
||||
{
|
||||
finalized_tx ft{};
|
||||
transfer_asset_ownership(asset_id, new_owner_v, ft);
|
||||
result_tx = ft.tx;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::burn_asset(const crypto::public_key asset_id, uint64_t amount_to_burn, currency::transaction& result_tx)
|
||||
void wallet2::burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::finalized_tx& ft)
|
||||
{
|
||||
//auto own_asset_entry_it = m_own_asset_descriptors.find(asset_id);
|
||||
//CHECK_AND_ASSERT_THROW_MES(own_asset_entry_it != m_own_asset_descriptors.end(), "Failed find asset_id " << asset_id << " in own assets list");
|
||||
COMMAND_RPC_GET_ASSET_INFO::request req;
|
||||
req.asset_id = asset_id;
|
||||
COMMAND_RPC_GET_ASSET_INFO::response rsp;
|
||||
bool r = m_core_proxy->call_COMMAND_RPC_GET_ASSET_INFO(req, rsp);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to call_COMMAND_RPC_GET_ASSET_INFO");
|
||||
currency::asset_descriptor_base last_adb{};
|
||||
bool r = this->daemon_get_asset_info(asset_id, last_adb);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon");
|
||||
|
||||
asset_descriptor_operation asset_burn_info{};
|
||||
asset_burn_info.descriptor = last_adb;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(last_adb.current_supply >= amount_to_burn, "amount_to_burn is incorrect: " << print_money_brief(amount_to_burn, last_adb.decimal_point) << ", current_supply: " << print_money_brief(last_adb.current_supply, last_adb.decimal_point));
|
||||
|
||||
asset_descriptor_operation asset_burn_info = AUTO_VAL_INIT(asset_burn_info);
|
||||
asset_burn_info.descriptor = rsp.asset_descriptor;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(asset_burn_info.descriptor.current_supply >= amount_to_burn, "Wrong amount to burn (current_supply" << asset_burn_info.descriptor.current_supply << " is less then " << amount_to_burn << ")");
|
||||
|
||||
currency::tx_destination_entry dst_to_burn = AUTO_VAL_INIT(dst_to_burn);
|
||||
currency::tx_destination_entry dst_to_burn{};
|
||||
dst_to_burn.amount = amount_to_burn;
|
||||
dst_to_burn.asset_id = asset_id;
|
||||
|
||||
|
|
@ -5431,11 +5566,16 @@ void wallet2::burn_asset(const crypto::public_key asset_id, uint64_t amount_to_b
|
|||
construct_tx_param ctp = get_default_construct_tx_param();
|
||||
ctp.extra.push_back(asset_burn_info);
|
||||
ctp.need_at_least_1_zc = true;
|
||||
ctp.ado_current_asset_owner = rsp.asset_descriptor.owner;
|
||||
ctp.dsts.push_back(dst_to_burn);
|
||||
ctp.tx_meaning_for_logs = "asset burn";
|
||||
|
||||
finalized_tx ft = AUTO_VAL_INIT(ft);
|
||||
this->transfer(ctp, ft, true, nullptr);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::transaction& result_tx)
|
||||
{
|
||||
finalized_tx ft{};
|
||||
burn_asset(asset_id, amount_to_burn, ft);
|
||||
result_tx = ft.tx;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -5905,7 +6045,7 @@ void wallet2::send_escrow_proposal(const bc_services::contract_private_details&
|
|||
mark_transfers_as_spent(ftp.selected_transfers, std::string("escrow proposal sent, tx <") + epee::string_tools::pod_to_hex(get_transaction_hash(tx)) + ">, contract: " + epee::string_tools::pod_to_hex(ms_id));
|
||||
add_sent_tx_detailed_info(tx, ftp.attachments, ftp.prepared_destinations, ftp.selected_transfers);
|
||||
|
||||
print_tx_sent_message(tx, "(from multisig)", fee);
|
||||
print_tx_sent_message(tx, "from multisig", true, fee);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::create_htlc_proposal(uint64_t amount, const currency::account_public_address& addr, uint64_t lock_blocks_count, currency::transaction &tx, const crypto::hash& htlc_hash, std::string &origin)
|
||||
|
|
@ -6253,7 +6393,7 @@ bool wallet2::accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposa
|
|||
{
|
||||
if (balances[item.asset_id].unlocked < item.amount)
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_EX_MES(false, error::not_enough_money, "", balances[item.asset_id].unlocked, item.amount, 0 /*fee*/, item.asset_id, get_asset_decimal_point(item.asset_id));
|
||||
THROW_IF_FALSE_WALLET_EX(false, error::not_enough_money, balances[item.asset_id].unlocked, item.amount, 0 /*fee*/, item.asset_id, get_asset_decimal_point(item.asset_id));
|
||||
}
|
||||
if (item.asset_id == currency::native_coin_asset_id)
|
||||
{
|
||||
|
|
@ -6268,7 +6408,7 @@ bool wallet2::accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposa
|
|||
additional_fee = m_core_runtime_config.tx_default_fee - msc.proposal_info.fee_paid_by_a;
|
||||
if (balances[currency::native_coin_asset_id].unlocked < additional_fee + native_amount_required)
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_EX_MES(false, error::not_enough_money, "", balances[currency::native_coin_asset_id].unlocked, native_amount_required, additional_fee, currency::native_coin_asset_id);
|
||||
THROW_IF_FALSE_WALLET_EX(false, error::not_enough_money, balances[currency::native_coin_asset_id].unlocked, native_amount_required, additional_fee, currency::native_coin_asset_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7116,9 +7256,9 @@ bool wallet2::select_indices_for_transfer(assets_selection_context& needed_money
|
|||
WLT_LOG_L1("select_indices_for_transfer: unknown asset id: " << asset_id);
|
||||
|
||||
auto asset_cache_it = m_found_free_amounts.find(asset_id);
|
||||
WLT_THROW_IF_FALSE_WALLET_EX_MES(asset_cache_it != m_found_free_amounts.end(), error::not_enough_money, "", item.second.found_amount, item.second.needed_amount, 0, asset_id, asset_info.decimal_point);
|
||||
THROW_IF_FALSE_WALLET_EX(asset_cache_it != m_found_free_amounts.end(), error::not_enough_money, item.second.found_amount, item.second.needed_amount, (uint64_t)0, asset_id, asset_info.decimal_point);
|
||||
item.second.found_amount = select_indices_for_transfer(selected_indexes, asset_cache_it->second, item.second.needed_amount, fake_outputs_count, asset_id, asset_info.decimal_point);
|
||||
WLT_THROW_IF_FALSE_WALLET_EX_MES(item.second.found_amount >= item.second.needed_amount, error::not_enough_money, "", item.second.found_amount, item.second.needed_amount, 0, asset_id, asset_info.decimal_point);
|
||||
THROW_IF_FALSE_WALLET_EX(item.second.found_amount >= item.second.needed_amount, error::not_enough_money, item.second.found_amount, item.second.needed_amount, (uint64_t)0, asset_id, asset_info.decimal_point);
|
||||
}
|
||||
if (m_current_context.pconstruct_tx_param && m_current_context.pconstruct_tx_param->need_at_least_1_zc)
|
||||
{
|
||||
|
|
@ -7362,20 +7502,20 @@ void wallet2::set_genesis(const crypto::hash& genesis_hash)
|
|||
m_chain.set_genesis(genesis_hash);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::print_tx_sent_message(const currency::transaction& tx, const std::string& description, uint64_t fee /* = UINT64_MAX */)
|
||||
void wallet2::print_tx_sent_message(const currency::transaction& tx, const std::string& description, bool broadcasted, uint64_t fee /* = UINT64_MAX */)
|
||||
{
|
||||
//uint64_t balance_unlocked = 0;
|
||||
//uint64_t balance_total = balance(balance_unlocked);
|
||||
|
||||
std::stringstream ss;
|
||||
if (fee != UINT64_MAX)
|
||||
ss << "Commission: " << std::setw(21) << std::right << print_money(fee) << ENDL;
|
||||
ss << "Fee: " << std::setw(21) << std::right << print_money_brief(fee) << ENDL;
|
||||
|
||||
WLT_LOG_CYAN("Transaction " << get_transaction_hash(tx) << " was successfully sent " << description << ENDL
|
||||
WLT_LOG_CYAN("Transaction " << get_transaction_hash(tx) << " was successfully " << (broadcasted ? "sent" : "created") << " (" << description << ")" << ENDL
|
||||
<< ss.str()
|
||||
// << "Balance: " << std::setw(21) << print_money(balance_total) << ENDL
|
||||
// << "Unlocked: " << std::setw(21) << print_money(balance_unlocked) << ENDL
|
||||
<< "Please, wait for confirmation for your balance to be unlocked.",
|
||||
<< (broadcasted ? "Please wait for the transaction to be confirmed before your balance is unlocked." : ""),
|
||||
LOG_LEVEL_0);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -7542,8 +7682,12 @@ bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx
|
|||
|
||||
const currency::transaction& tx_for_mode_separate = msc.tx_for_mode_separate;
|
||||
assets_selection_context needed_money_map = get_needed_money(ctp.fee, ctp.dsts);
|
||||
ftp.ado_current_asset_owner = ctp.ado_current_asset_owner;
|
||||
ftp.pthirdparty_sign_handler = ctp.pthirdparty_sign_handler;
|
||||
if (this->is_auditable() && ctp.fake_outputs_count > 0)
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WITH_CODE(false, "WALLET_RPC_ERROR_CODE_WRONG_MIXINS_FOR_AUDITABLE_WALLET", "WALLET_RPC_ERROR_CODE_WRONG_MIXINS_FOR_AUDITABLE_WALLET");
|
||||
}
|
||||
//ftp.asset_owner = ctp.asset_owner;
|
||||
//ftp.p_eth_signer = ctp.p_eth_signer;
|
||||
//
|
||||
// TODO @#@# need to do refactoring over this part to support hidden amounts and asset_id
|
||||
//
|
||||
|
|
@ -7649,12 +7793,14 @@ void wallet2::finalize_transaction(currency::finalize_tx_param& ftp, currency::f
|
|||
// broadcasting tx without secret key storing is forbidden to avoid lost key issues
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!broadcast_tx || store_tx_secret_key, "finalize_tx is requested to broadcast a tx without storing the key");
|
||||
|
||||
THROW_IF_FALSE_WALLET_EX_MES(ftp.sources.size() <= CURRENCY_TX_MAX_ALLOWED_INPUTS, error::tx_too_big, "Too many inputs: " << ftp.sources.size() << ", maximum allowed is " << CURRENCY_TX_MAX_ALLOWED_INPUTS << ".");
|
||||
|
||||
bool r = currency::construct_tx(m_account.get_keys(),
|
||||
ftp, result);
|
||||
//TIME_MEASURE_FINISH_MS(construct_tx_time);
|
||||
THROW_IF_FALSE_WALLET_EX(r, error::tx_not_constructed, ftp.sources, ftp.prepared_destinations, ftp.unlock_time);
|
||||
uint64_t effective_fee = 0;
|
||||
THROW_IF_FALSE_WALLET_CMN_ERR_EX(!get_tx_fee(result.tx, effective_fee) || effective_fee <= WALLET_TX_MAX_ALLOWED_FEE, "tx fee is WAY too big: " << print_money_brief(effective_fee) << ", max allowed is " << print_money_brief(WALLET_TX_MAX_ALLOWED_FEE));
|
||||
THROW_IF_FALSE_WALLET_CMN_ERR_EX(!get_tx_fee(result.tx, effective_fee) || effective_fee <= WALLET_TX_MAX_ALLOWED_FEE, "tx fee is WAY too big: " << print_money_brief(effective_fee) << ", maximum allowed is " << print_money_brief(WALLET_TX_MAX_ALLOWED_FEE) << ".");
|
||||
|
||||
//TIME_MEASURE_START_MS(sign_ms_input_time);
|
||||
if (ftp.multisig_id != currency::null_hash)
|
||||
|
|
@ -7671,10 +7817,10 @@ void wallet2::finalize_transaction(currency::finalize_tx_param& ftp, currency::f
|
|||
//TIME_MEASURE_FINISH_MS(sign_ms_input_time);
|
||||
|
||||
size_t tx_blob_size = tx_to_blob(result.tx).size();
|
||||
THROW_IF_FALSE_WALLET_EX(tx_blob_size < CURRENCY_MAX_TRANSACTION_BLOB_SIZE, error::tx_too_big, result.tx, m_upper_transaction_size_limit);
|
||||
THROW_IF_FALSE_WALLET_EX_MES(tx_blob_size < CURRENCY_MAX_TRANSACTION_BLOB_SIZE, error::tx_too_big, "Transaction size: " << tx_blob_size << " bytes, transaction size limit: " << CURRENCY_MAX_TRANSACTION_BLOB_SIZE << " bytes.");
|
||||
|
||||
if (store_tx_secret_key)
|
||||
m_tx_keys.insert(std::make_pair(get_transaction_hash(result.tx), result.one_time_key));
|
||||
m_tx_keys.insert(std::make_pair(result.tx_id, result.one_time_key));
|
||||
|
||||
//TIME_MEASURE_START(send_transaction_to_network_time);
|
||||
if (broadcast_tx)
|
||||
|
|
@ -7686,13 +7832,7 @@ void wallet2::finalize_transaction(currency::finalize_tx_param& ftp, currency::f
|
|||
add_sent_tx_detailed_info(result.tx, ftp.attachments, ftp.prepared_destinations, ftp.selected_transfers);
|
||||
//TIME_MEASURE_FINISH(add_sent_tx_detailed_info_time);
|
||||
|
||||
/* TODO
|
||||
WLT_LOG_GREEN("[prepare_transaction]: get_needed_money_time: " << get_needed_money_time << " ms"
|
||||
<< ", prepare_tx_sources_time: " << prepare_tx_sources_time << " ms"
|
||||
<< ", prepare_tx_destinations_time: " << prepare_tx_destinations_time << " ms"
|
||||
<< ", construct_tx_time: " << construct_tx_time << " ms"
|
||||
<< ", sign_ms_input_time: " << sign_ms_input_time << " ms",
|
||||
LOG_LEVEL_0);*/
|
||||
// not logging success here because it's the caller's responsibility
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::transfer(const std::vector<currency::tx_destination_entry>& dsts, size_t fake_outputs_count,
|
||||
|
|
@ -7858,8 +7998,11 @@ void wallet2::transfer(construct_tx_param& ctp,
|
|||
return;
|
||||
}
|
||||
|
||||
std::string tx_description = ctp.tx_meaning_for_logs.empty() ? std::string("transfer") : ctp.tx_meaning_for_logs;
|
||||
uint32_t transfers_flags = ctp.additional_transfer_flags_to_mark | WALLET_TRANSFER_DETAIL_FLAG_SPENT;
|
||||
|
||||
TIME_MEASURE_START(mark_transfers_as_spent_time);
|
||||
mark_transfers_as_spent(ftp.selected_transfers, std::string("money transfer, tx: ") + epee::string_tools::pod_to_hex(get_transaction_hash(result.tx)));
|
||||
mark_transfers_with_flag(ftp.selected_transfers, transfers_flags, std::string("preparing for ") + tx_description);
|
||||
TIME_MEASURE_FINISH(mark_transfers_as_spent_time);
|
||||
|
||||
TIME_MEASURE_START(finalize_transaction_time);
|
||||
|
|
@ -7869,7 +8012,7 @@ void wallet2::transfer(construct_tx_param& ctp,
|
|||
}
|
||||
catch (...)
|
||||
{
|
||||
clear_transfers_from_flag(ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_SPENT, std::string("exception on money transfer, tx: ") + epee::string_tools::pod_to_hex(get_transaction_hash(result.tx)));
|
||||
clear_transfers_from_flag(ftp.selected_transfers, transfers_flags, std::string("exception during") + tx_description + ", tx (maybe incorrect if tx is incomplete): " + epee::string_tools::pod_to_hex(get_transaction_hash(result.tx)));
|
||||
throw;
|
||||
}
|
||||
TIME_MEASURE_FINISH(finalize_transaction_time);
|
||||
|
|
@ -7882,17 +8025,13 @@ void wallet2::transfer(construct_tx_param& ctp,
|
|||
<< ", mark_transfers_as_spent_time: " << print_fixed_decimal_point(mark_transfers_as_spent_time, 3)
|
||||
, LOG_LEVEL_0);
|
||||
|
||||
print_tx_sent_message(result.tx, std::string() + "(transfer)", ctp.fee);
|
||||
print_tx_sent_message(result.tx, tx_description, send_to_network, ctp.fee);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::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 */)
|
||||
{
|
||||
static const size_t estimated_bytes_per_input = 85;
|
||||
const size_t estimated_max_inputs = static_cast<size_t>(CURRENCY_MAX_TRANSACTION_BLOB_SIZE / (estimated_bytes_per_input * (fake_outs_count + 1.5))); // estimated number of maximum tx inputs under the tx size limit
|
||||
const size_t tx_sources_for_querying_random_outs_max = estimated_max_inputs * 2;
|
||||
|
||||
bool r = false;
|
||||
outs_total = 0;
|
||||
amount_total = 0;
|
||||
|
|
@ -7900,8 +8039,10 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
|
|||
amount_swept = 0;
|
||||
|
||||
std::vector<uint64_t> selected_transfers;
|
||||
std::unordered_map<size_t, size_t> fake_outs_for_selected_transfers; // tr index -> fake outs count
|
||||
selected_transfers.reserve(m_transfers.size());
|
||||
for (uint64_t i = 0; i < m_transfers.size(); ++i)
|
||||
fake_outs_for_selected_transfers.reserve(m_transfers.size());
|
||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||
{
|
||||
const transfer_details& td = m_transfers[i];
|
||||
size_t fake_outs_count_for_td = is_auditable() ? 0 : (td.is_zc() ? m_core_runtime_config.hf4_minimum_mixins : fake_outs_count);
|
||||
|
|
@ -7910,6 +8051,8 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
|
|||
is_transfer_ready_to_go(td, fake_outs_count_for_td))
|
||||
{
|
||||
selected_transfers.push_back(i);
|
||||
r = fake_outs_for_selected_transfers.insert(std::make_pair(i, fake_outs_count_for_td)).second;
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "unable to insert: " << i << ", " << fake_outs_count_for_td);
|
||||
outs_total += 1;
|
||||
amount_total += amount;
|
||||
}
|
||||
|
|
@ -7921,21 +8064,29 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
|
|||
std::sort(selected_transfers.begin(), selected_transfers.end(), [this](uint64_t a, uint64_t b) { return m_transfers[b].amount() < m_transfers[a].amount(); });
|
||||
|
||||
// limit RPC request with reasonable number of sources
|
||||
if (selected_transfers.size() > tx_sources_for_querying_random_outs_max)
|
||||
selected_transfers.erase(selected_transfers.begin() + tx_sources_for_querying_random_outs_max, selected_transfers.end());
|
||||
if (selected_transfers.size() > CURRENCY_TX_MAX_ALLOWED_INPUTS)
|
||||
selected_transfers.erase(selected_transfers.begin() + CURRENCY_TX_MAX_ALLOWED_INPUTS, selected_transfers.end());
|
||||
|
||||
prefetch_global_indicies_if_needed(selected_transfers);
|
||||
|
||||
size_t max_fake_outs_count = 0;
|
||||
for(auto tr_idx : selected_transfers)
|
||||
if (max_fake_outs_count < fake_outs_for_selected_transfers[tr_idx])
|
||||
max_fake_outs_count = fake_outs_for_selected_transfers[tr_idx];
|
||||
|
||||
static const size_t estimated_bytes_per_input = 85;
|
||||
const size_t estimated_max_inputs = static_cast<size_t>(CURRENCY_MAX_TRANSACTION_BLOB_SIZE / (estimated_bytes_per_input * (max_fake_outs_count + 1.5))); // estimated number of maximum tx inputs under the tx size limit
|
||||
|
||||
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry;
|
||||
typedef currency::tx_source_entry::output_entry tx_output_entry;
|
||||
|
||||
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response rpc_get_random_outs_resp = AUTO_VAL_INIT(rpc_get_random_outs_resp);
|
||||
if (fake_outs_count > 0)
|
||||
if (max_fake_outs_count > 0)
|
||||
{
|
||||
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req = AUTO_VAL_INIT(req);
|
||||
req.height_upper_limit = m_last_pow_block_h;
|
||||
req.use_forced_mix_outs = false;
|
||||
req.decoys_count = fake_outs_count + 1;
|
||||
req.decoys_count = max_fake_outs_count + 1;
|
||||
for (uint64_t i : selected_transfers)
|
||||
req.amounts.push_back(m_transfers[i].is_zc() ? 0 : m_transfers[i].m_amount);
|
||||
|
||||
|
|
@ -7950,10 +8101,10 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
|
|||
std::vector<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount> scanty_outs;
|
||||
for (COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs : rpc_get_random_outs_resp.outs)
|
||||
{
|
||||
if (amount_outs.outs.size() < fake_outs_count)
|
||||
if (amount_outs.outs.size() < max_fake_outs_count)
|
||||
scanty_outs.push_back(amount_outs);
|
||||
}
|
||||
THROW_IF_FALSE_WALLET_EX(scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outs_count);
|
||||
THROW_IF_FALSE_WALLET_EX(scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, max_fake_outs_count);
|
||||
}
|
||||
|
||||
currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp);
|
||||
|
|
@ -7980,7 +8131,7 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
|
|||
auto get_result_t_str = [](try_construct_result_t t) -> const char*
|
||||
{ return t == rc_ok ? "rc_ok" : t == rc_too_few_outputs ? "rc_too_few_outputs" : t == rc_too_many_outputs ? "rc_too_many_outputs" : t == rc_create_tx_failed ? "rc_create_tx_failed" : "unknown"; };
|
||||
|
||||
auto try_construct_tx = [this, &selected_transfers, &rpc_get_random_outs_resp, &fake_outs_count, &fee, &destination_addr]
|
||||
auto try_construct_tx = [this, &selected_transfers, &rpc_get_random_outs_resp, &fake_outs_for_selected_transfers, &fee, &destination_addr]
|
||||
(size_t st_index_upper_boundary, currency::finalize_tx_param& ftp, uint64_t& amount_swept) -> try_construct_result_t
|
||||
{
|
||||
amount_swept = 0;
|
||||
|
|
@ -8009,7 +8160,7 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
|
|||
if (td.m_global_output_index == daemon_oe.global_amount_index)
|
||||
continue;
|
||||
src.outputs.emplace_back(daemon_oe.global_amount_index, daemon_oe.stealth_address, daemon_oe.concealing_point, daemon_oe.amount_commitment, daemon_oe.blinded_asset_id);
|
||||
if (src.outputs.size() >= fake_outs_count)
|
||||
if (src.outputs.size() >= fake_outs_for_selected_transfers[tr_index])
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -8162,6 +8313,7 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
|
|||
{
|
||||
crypto::secret_key sk{};
|
||||
finalize_transaction(ftp, *p_tx, sk, true);
|
||||
print_tx_sent_message(*p_tx, "sweep_below", true, get_tx_fee(*p_tx));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -420,10 +420,16 @@ namespace tools
|
|||
bool check_available_sources(std::list<uint64_t>& amounts);
|
||||
|
||||
void deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector<currency::tx_destination_entry>& destinations, currency::transaction& result_tx, crypto::public_key& new_asset_id);
|
||||
void emit_asset(const crypto::public_key asset_id, std::vector<currency::tx_destination_entry>& destinations, currency::transaction& result_tx);
|
||||
void update_asset(const crypto::public_key asset_id, const currency::asset_descriptor_base new_descriptor, currency::transaction& result_tx);
|
||||
void burn_asset(const crypto::public_key asset_id, uint64_t amount_to_burn, currency::transaction& result_tx);
|
||||
void transfer_asset_ownership(const crypto::public_key asset_id, const crypto::public_key& new_owner, currency::transaction& result_tx);
|
||||
void emit_asset(const crypto::public_key& asset_id, std::vector<currency::tx_destination_entry>& destinations, currency::transaction& result_tx);
|
||||
void update_asset(const crypto::public_key& asset_id, const currency::asset_descriptor_base new_descriptor, currency::transaction& result_tx);
|
||||
void burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::transaction& result_tx);
|
||||
void transfer_asset_ownership(const crypto::public_key& asset_id, const currency::asset_owner_pub_key_v& new_owner_v, currency::transaction& result_tx);
|
||||
|
||||
void deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector<currency::tx_destination_entry>& destinations, currency::finalized_tx& ft, crypto::public_key& new_asset_id);
|
||||
void emit_asset(const crypto::public_key& asset_id, const std::vector<currency::tx_destination_entry>& destinations, currency::finalized_tx& ft);
|
||||
void update_asset(const crypto::public_key& asset_id, const currency::asset_descriptor_base& new_descriptor, currency::finalized_tx& ft);
|
||||
void burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::finalized_tx& ft);
|
||||
void transfer_asset_ownership(const crypto::public_key& asset_id, const currency::asset_owner_pub_key_v& new_owner_v, currency::finalized_tx& ft);
|
||||
|
||||
bool daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb);
|
||||
bool set_core_proxy(const std::shared_ptr<i_core_proxy>& proxy);
|
||||
|
|
@ -589,6 +595,7 @@ namespace tools
|
|||
void sign_transfer_files(const std::string& tx_sources_file, const std::string& signed_tx_file, currency::transaction& tx);
|
||||
void submit_transfer(const std::string& signed_tx_blob, currency::transaction& tx);
|
||||
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::eth_signature& eth_sig, bool unlock_transfers_on_fail, currency::transaction& result_tx, bool& transfers_unlocked);
|
||||
|
||||
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);
|
||||
|
|
@ -836,7 +843,7 @@ private:
|
|||
|
||||
uint64_t get_tx_expiration_median() const;
|
||||
|
||||
void print_tx_sent_message(const currency::transaction& tx, const std::string& description, uint64_t fee = UINT64_MAX);
|
||||
void print_tx_sent_message(const currency::transaction& tx, const std::string& description, bool broadcasted, uint64_t fee = UINT64_MAX);
|
||||
|
||||
// Validates escrow template tx in assumption it's related to wallet's account (wallet's account is either A or B party in escrow process)
|
||||
bool validate_escrow_proposal(const wallet_public::wallet_transfer_info& wti, const bc_services::proposal_body& prop,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#include <boost/serialization/deque.hpp>
|
||||
#include <boost/serialization/singleton.hpp>
|
||||
#include <boost/serialization/extended_type_info.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/optional.hpp>
|
||||
#include <atomic>
|
||||
|
||||
|
|
@ -52,6 +51,7 @@
|
|||
#define WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER uint32_t(1 << 3)
|
||||
#define WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION uint32_t(1 << 4) // transfer is reserved for cold-signing (unsigned tx was created and passed for signing)
|
||||
#define WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM uint32_t(1 << 5) // for htlc keeps info if this htlc belong as redeem or as refund
|
||||
#define WALLET_TRANSFER_DETAIL_FLAG_ASSET_OP_RESERVATION uint32_t(1 << 6) // transfer is reserved for an ongoing asset operation with external signing
|
||||
|
||||
|
||||
|
||||
|
|
@ -224,9 +224,10 @@ namespace tools
|
|||
bool shuffle = false;
|
||||
bool create_utxo_defragmentation_tx = false;
|
||||
bool need_at_least_1_zc = false;
|
||||
//crypto::secret_key asset_deploy_control_key = currency::null_skey;
|
||||
currency::thirdparty_sign_handler* pthirdparty_sign_handler = nullptr;
|
||||
crypto::public_key ado_current_asset_owner = currency::null_pkey;
|
||||
|
||||
// misc
|
||||
std::string tx_meaning_for_logs; // used to correctly log things, e.g. "escrow" or "asset emission".
|
||||
uint32_t additional_transfer_flags_to_mark = 0;
|
||||
};
|
||||
|
||||
struct mode_separate_context
|
||||
|
|
@ -356,7 +357,7 @@ namespace tools
|
|||
uint64_t m_spent_height = 0;
|
||||
uint32_t m_flags = 0;
|
||||
uint64_t m_amount = 0;
|
||||
boost::shared_ptr<ZC_out_info> m_zc_info_ptr;
|
||||
std::shared_ptr<ZC_out_info> m_zc_info_ptr;
|
||||
|
||||
uint64_t amount() const { return m_amount; }
|
||||
uint64_t amount_for_global_output_index() const { return is_zc() ? 0 : m_amount; } // amount value for global outputs index, it's zero for outputs with hidden amounts
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#include <boost/serialization/deque.hpp>
|
||||
#include <boost/serialization/singleton.hpp>
|
||||
#include <boost/serialization/extended_type_info.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
|
||||
|
|
|
|||
|
|
@ -30,3 +30,7 @@ struct wde_construct_tx_after_asset_ownership_proof_generated
|
|||
currency::asset_operation_ownership_proof* pownership_proof;
|
||||
};
|
||||
|
||||
struct wde_construct_tx_after_asset_ownership_eth_proof_generated
|
||||
{
|
||||
currency::asset_operation_ownership_proof_eth* pownership_proof_eth;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2024 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
|
||||
|
|
@ -350,7 +350,7 @@ namespace tools
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
struct not_enough_money : public transfer_error
|
||||
{
|
||||
not_enough_money(std::string&& loc, uint64_t availbable, uint64_t tx_amount, uint64_t fee, const crypto::public_key& asset_id, size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT)
|
||||
not_enough_money(std::string&& loc, uint64_t availbable, uint64_t tx_amount, uint64_t fee, const crypto::public_key& asset_id, uint8_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT)
|
||||
: transfer_error(std::move(loc), "")
|
||||
, m_available(availbable)
|
||||
, m_tx_amount(tx_amount)
|
||||
|
|
@ -381,12 +381,13 @@ namespace tools
|
|||
uint64_t m_tx_amount;
|
||||
uint64_t m_fee;
|
||||
crypto::public_key m_asset_id;
|
||||
size_t m_decimal_point;
|
||||
uint8_t m_decimal_point;
|
||||
};
|
||||
|
||||
struct no_zc_inputs : public transfer_error
|
||||
{
|
||||
no_zc_inputs(const std::string& /*v*/): transfer_error(std::string(""), API_RETURN_CODE_MISSING_ZC_INPUTS)
|
||||
no_zc_inputs(std::string&& loc, const std::string&)
|
||||
: transfer_error(std::move(loc), API_RETURN_CODE_MISSING_ZC_INPUTS)
|
||||
{}
|
||||
|
||||
virtual const char* what() const noexcept
|
||||
|
|
@ -566,34 +567,25 @@ namespace tools
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
struct tx_too_big : public transfer_error
|
||||
{
|
||||
explicit tx_too_big(std::string&& loc, const currency::transaction& tx, uint64_t tx_size_limit)
|
||||
: transfer_error(std::move(loc), "transaction is too big")
|
||||
, m_tx(tx)
|
||||
, m_tx_size_limit(tx_size_limit)
|
||||
explicit tx_too_big(std::string&& loc, const std::string& message)
|
||||
: transfer_error(std::move(loc), API_RETURN_CODE_TX_IS_TOO_BIG)
|
||||
, m_message(message)
|
||||
{
|
||||
}
|
||||
|
||||
const currency::transaction& tx() const { return m_tx; }
|
||||
uint64_t tx_size_limit() const { return m_tx_size_limit; }
|
||||
const std::string get_message() const { return m_message; }
|
||||
|
||||
// TODO the following overrides need to be redesigned (seems to be necessary for API, consider writing API tests and then refactor this) -- sowle
|
||||
std::string to_string() const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << API_RETURN_CODE_TX_IS_TOO_BIG;
|
||||
//currency::transaction tx = m_tx;
|
||||
//ss << transfer_error::to_string() <<
|
||||
// ", tx_size_limit = " << m_tx_size_limit <<
|
||||
// ", tx size = " << get_object_blobsize(m_tx) <<
|
||||
// ", tx:\n" << currency::obj_to_json_str(tx);
|
||||
return ss.str();
|
||||
return API_RETURN_CODE_TX_IS_TOO_BIG;
|
||||
}
|
||||
virtual const char* what() const noexcept
|
||||
{
|
||||
return API_RETURN_CODE_TX_IS_TOO_BIG;
|
||||
}
|
||||
private:
|
||||
currency::transaction m_tx;
|
||||
uint64_t m_tx_size_limit;
|
||||
std::string m_message;
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
struct zero_destination : public transfer_error
|
||||
|
|
@ -668,8 +660,6 @@ namespace tools
|
|||
};
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
|
||||
template<typename TException, typename... TArgs>
|
||||
void throw_wallet_ex(std::string&& loc, const TArgs&... args)
|
||||
{
|
||||
|
|
@ -677,31 +667,6 @@ namespace tools
|
|||
LOG_PRINT_L0(e.to_string());
|
||||
throw e;
|
||||
}
|
||||
|
||||
#else
|
||||
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
||||
|
||||
template<typename TException>
|
||||
void throw_wallet_ex(std::string&& loc)
|
||||
{
|
||||
TException e(std::move(loc));
|
||||
LOG_PRINT_L0(e.to_string());
|
||||
throw e;
|
||||
}
|
||||
|
||||
#define GEN_throw_wallet_ex(z, n, data) \
|
||||
template<typename TException, BOOST_PP_ENUM_PARAMS(n, typename TArg)> \
|
||||
void throw_wallet_ex(std::string&& loc, BOOST_PP_ENUM_BINARY_PARAMS(n, const TArg, &arg)) \
|
||||
{ \
|
||||
TException e(std::move(loc), BOOST_PP_ENUM_PARAMS(n, arg)); \
|
||||
LOG_PRINT_L0(e.to_string()); \
|
||||
throw e; \
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(1, 6, GEN_throw_wallet_ex, ~)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -739,14 +704,14 @@ if (!(cond))
|
|||
}
|
||||
|
||||
|
||||
#define THROW_IF_FALSE_WALLET_EX_MES(cond, err_type, mess, ...) \
|
||||
#define THROW_IF_FALSE_WALLET_EX_MES(cond, err_type, mes, ...) \
|
||||
if (!(cond)) \
|
||||
{ \
|
||||
exception_handler(); \
|
||||
std::stringstream ss; \
|
||||
ss << std::endl << mess; \
|
||||
LOG_ERROR(#cond << ". THROW EXCEPTION: " << #err_type); \
|
||||
tools::error::throw_wallet_ex<err_type>(std::string(__FILE__ ":" STRINGIZE(__LINE__)) + ss.str(), ## __VA_ARGS__); \
|
||||
ss << mes; \
|
||||
LOG_ERROR(#cond << ". THROW EXCEPTION: " << #err_type << " : " << ss.str()); \
|
||||
tools::error::throw_wallet_ex<err_type>(std::string(__FILE__ ":" STRINGIZE(__LINE__)), ss.str(), ## __VA_ARGS__); \
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
#include "currency_core/offers_service_basics.h"
|
||||
#include "currency_core/bc_escrow_service.h"
|
||||
#include "rpc/core_rpc_server_commands_defs.h"
|
||||
|
||||
#include "currency_protocol/blobdatatype.h"
|
||||
|
||||
|
||||
const uint64_t WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED = std::numeric_limits<uint64_t>::max();
|
||||
|
|
@ -690,7 +690,7 @@ namespace wallet_public
|
|||
KV_SERIALIZE(destinations) DOC_DSCR("List of destinations") DOC_EXMP_AUTO(1) DOC_END
|
||||
KV_SERIALIZE(fee) DOC_DSCR("Fee to be paid on behalf of sender's wallet(paid in native coins)") DOC_EXMP_AUTO(10000000000) DOC_END
|
||||
KV_SERIALIZE(mixin) DOC_DSCR("Specifies number of mixins(decoys) that would be used to create input, actual for pre-zarcanum outputs, for post-zarcanum outputs instead of this option, number that is defined by network hard rules(15+)") DOC_EXMP(15) DOC_END
|
||||
KV_SERIALIZE(payment_id) DOC_DSCR("Hex-encoded payment_id, that normally used for user database by exchanges") DOC_EXMP_AUTO("1dfe5a88ff9effb3") DOC_END
|
||||
KV_SERIALIZE(payment_id) DOC_DSCR("Hex-encoded payment_id, that normally used for user database by exchanges") DOC_EXMP_AUTO("") DOC_END
|
||||
KV_SERIALIZE(comment) DOC_DSCR("Text comment that is displayed in UI") DOC_EXMP_AUTO("Thanks for the coffe") DOC_END
|
||||
KV_SERIALIZE(push_payer) DOC_DSCR("Reveal information about sender of this transaction, basically add sender address to transaction in encrypted way, so only receiver can see who sent transaction") DOC_EXMP(false) DOC_END
|
||||
KV_SERIALIZE(hide_receiver) DOC_DSCR("This add to transaction information about remote address(destination), might be needed when the wallet restored from seed phrase and fully resynched, if this option were true, then sender won't be able to see remote address for sent transactions anymore.") DOC_EXMP(true) DOC_END
|
||||
|
|
@ -706,9 +706,9 @@ namespace wallet_public
|
|||
uint64_t tx_size;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tx_hash)
|
||||
KV_SERIALIZE(tx_hash) DOC_DSCR("Has of the generated transaction(if succeded)") DOC_EXMP("01220e8304d46b940a86e383d55ca5887b34f158a7365bbcdd17c5a305814a93") DOC_END
|
||||
KV_SERIALIZE(tx_unsigned_hex)
|
||||
KV_SERIALIZE(tx_size)
|
||||
KV_SERIALIZE(tx_size) DOC_DSCR("Transaction size in bytes") DOC_EXMP(1234) DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
|
@ -1982,31 +1982,49 @@ namespace wallet_public
|
|||
struct COMMAND_ASSETS_DEPLOY
|
||||
{
|
||||
DOC_COMMAND("Deploy new asset in the system.");
|
||||
|
||||
|
||||
struct request
|
||||
{
|
||||
std::list<transfer_destination> destinations;
|
||||
currency::asset_descriptor_base asset_descriptor;
|
||||
bool do_not_split_destinations = false;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(destinations) DOC_DSCR("Addresses where to receive emitted coins. Asset id in the destinations is irreleant and can be omitted.") DOC_EXMP_AUTO(1) DOC_END
|
||||
KV_SERIALIZE(asset_descriptor) DOC_DSCR("Descriptor that holds all information about asset - ticker, emission, description etc") DOC_END
|
||||
KV_SERIALIZE(destinations) DOC_DSCR("Addresses where to receive emitted coins. Asset id in the destinations is irreleant and can be omitted.") DOC_EXMP_AUTO(1) DOC_END
|
||||
KV_SERIALIZE(asset_descriptor) DOC_DSCR("Descriptor that holds all information about asset - ticker, emission, description etc") DOC_END
|
||||
KV_SERIALIZE(do_not_split_destinations) DOC_DSCR("If true, the provided destinations will be used as-is and won't be splitted (or altered) to avoid common issues. Default is false.") DOC_EXMP(false) DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
||||
struct response
|
||||
{
|
||||
crypto::hash result_tx;
|
||||
crypto::hash tx_id;
|
||||
crypto::public_key new_asset_id;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(result_tx) DOC_DSCR("Id of transaction that carries asset registration command, asset would be registered as soon as transaction got confirmed") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) DOC_DSCR("Id of transaction that carries asset registration command, asset would be registered as soon as transaction got confirmed") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(new_asset_id) DOC_DSCR("Issued asset id") DOC_EXMP("40fa6db923728b38962718c61b4dc3af1acaa1967479c73703e260dc3609c58d") DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
// contains data for external checking & signing asset-emitting/-updating transaction by a third-party
|
||||
struct data_for_external_asset_signing_tx
|
||||
{
|
||||
currency::blobdata unsigned_tx;
|
||||
crypto::secret_key tx_secret_key;
|
||||
std::vector<std::string> outputs_addresses;
|
||||
currency::blobdata finalized_tx;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_BLOB_AS_BASE64_STRING(unsigned_tx) DOC_DSCR("Base64-encoded unsigned transaction blob.") DOC_EXMP("ewogICJ2ZXJzaW9uIjogMSwgC....iAgInZpbiI6IFsgewogICAgIC") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(tx_secret_key) DOC_DSCR("Hex-encoded transaction secret key.") DOC_EXMP("2e0b840e70dba386effd64c5d988622dea8c064040566e6bf035034cbb54a5c08") DOC_END
|
||||
KV_SERIALIZE(outputs_addresses) DOC_DSCR("Target address for each of the transaction zoutput.") DOC_EXMP_AGGR("ZxDNaMeZjwCjnHuU5gUNyrP1pM3U5vckbakzzV6dEHyDYeCpW8XGLBFTshcaY8LkG9RQn7FsQx8w2JeJzJwPwuDm2NfixPAXf", "ZxBvJDuQjMG9R2j4WnYUhBYNrwZPwuyXrC7FHdVmWqaESgowDvgfWtiXeNGu8Px9B24pkmjsA39fzSSiEQG1ekB225ZnrMTBp") DOC_END
|
||||
KV_SERIALIZE_BLOB_AS_BASE64_STRING(finalized_tx)DOC_DSCR("Base64-encoded finalized_tx data structure, which should be passed along with submitting the transaction.") DOC_EXMP("ewogICJ2ZXJzaW9uIjogMSwgC....iAgInZpbiI6IFsgewogICAgIC") DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct COMMAND_ASSETS_EMIT
|
||||
{
|
||||
DOC_COMMAND("Emmit new coins of the the asset, that is controlled by this wallet.");
|
||||
|
|
@ -2015,20 +2033,23 @@ namespace wallet_public
|
|||
{
|
||||
crypto::public_key asset_id;
|
||||
std::list<transfer_destination> destinations;
|
||||
bool do_not_split_destinations = false;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) DOC_DSCR("Id of the asset to emit more coins") DOC_EXMP("40fa6db923728b38962718c61b4dc3af1acaa1967479c73703e260dc3609c58d") DOC_END
|
||||
KV_SERIALIZE(destinations) DOC_DSCR("Addresses where to receive emitted coins. Asset id in the destinations is irreleant and can be omitted.") DOC_EXMP_AUTO(1) DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) DOC_DSCR("Id of the asset to emit more coins") DOC_EXMP("40fa6db923728b38962718c61b4dc3af1acaa1967479c73703e260dc3609c58d") DOC_END
|
||||
KV_SERIALIZE(destinations) DOC_DSCR("Addresses where to receive emitted coins. Asset id in the destinations is irreleant and can be omitted.") DOC_EXMP_AUTO(1) DOC_END
|
||||
KV_SERIALIZE(do_not_split_destinations) DOC_DSCR("If true, the provided destinations will be used as-is and won't be splitted (or altered) to avoid common issues. Default is false.") DOC_EXMP(false) DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
||||
struct response
|
||||
{
|
||||
crypto::hash result_tx;
|
||||
|
||||
crypto::hash tx_id;
|
||||
std::optional<data_for_external_asset_signing_tx> data_for_external_signing;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(result_tx) DOC_DSCR("Id of transaction that carries asset registration command, asset would be registered as soon as transaction got confirmed") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) DOC_DSCR("Id of transaction that emits the required asset.") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
KV_SERIALIZE(data_for_external_signing) DOC_DSCR("[optional] Additional data for external asset tx signing.") DOC_EXMP_AGGR() DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
|
@ -2050,10 +2071,12 @@ namespace wallet_public
|
|||
|
||||
struct response
|
||||
{
|
||||
crypto::hash result_tx;
|
||||
crypto::hash tx_id;
|
||||
std::optional<data_for_external_asset_signing_tx> data_for_external_signing;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(result_tx) DOC_DSCR("Id of transaction that carries asset registration command, asset would be registered as soon as transaction got confirmed") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) DOC_DSCR("Id of transaction that carries asset registration command, asset would be registered as soon as transaction got confirmed") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
KV_SERIALIZE(data_for_external_signing) DOC_DSCR("[optional] Hex-encoded transaction for external signing. ") DOC_EXMP_AGGR() DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
|
@ -2075,13 +2098,47 @@ namespace wallet_public
|
|||
|
||||
struct response
|
||||
{
|
||||
crypto::hash result_tx;
|
||||
crypto::hash tx_id;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(result_tx) DOC_DSCR("Id of transaction that carries asset burn operation") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) DOC_DSCR("Id of transaction that carries asset burn operation") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
struct COMMAND_ASSET_SEND_EXT_SIGNED_TX
|
||||
{
|
||||
DOC_COMMAND("Inserts externally made asset ownership signature into the given transaction and broadcasts it.");
|
||||
|
||||
struct request
|
||||
{
|
||||
currency::blobdata finalized_tx;
|
||||
currency::blobdata unsigned_tx;
|
||||
crypto::eth_signature eth_sig;
|
||||
crypto::hash expected_tx_id;
|
||||
bool unlock_transfers_on_fail = false;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_BLOB_AS_BASE64_STRING(finalized_tx)DOC_DSCR("Base64-encoded finalized_tx data structure, which was received from emit_asset call.") DOC_EXMP("ewogICJ2ZXJzaW9uIjogMSwgC....iAgInZpbiI6IFsgewogICAgIC") DOC_END
|
||||
KV_SERIALIZE_BLOB_AS_BASE64_STRING(unsigned_tx) DOC_DSCR("Base64-encoded unsigned transaction blob, which was received from emit_asset call.") DOC_EXMP("083737bcfd826a973f74bb56a52b4fa562e6579ccaadd2697463498a66de4f1760b2cd40f11c3a00a7a80000") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(eth_sig) DOC_DSCR("HEX-encoded ETH signature (64 bytes)") DOC_EXMP("674bb56a5b4fa562e679ccacc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6add697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
|
||||
KV_SERIALIZE_POD_AS_HEX_STRING(expected_tx_id) DOC_DSCR("The expected transaction id. Tx won't be sent if the calculated one doesn't match this one. Consider using 'verified_tx_id' returned by 'decrypt_tx_details' call.") DOC_EXMP("40fa6db923728b38962718c61b4dc3af1acaa1967479c73703e260dc3609c58d") DOC_END
|
||||
KV_SERIALIZE(unlock_transfers_on_fail) DOC_DSCR("If true, all locked wallet transfers, corresponding to the transaction, will be unlocked on sending failure. False by default.") DOC_EXMP(false) DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
bool transfers_were_unlocked;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(status) DOC_DSCR("Status of the call") DOC_EXMP("OK") DOC_END
|
||||
KV_SERIALIZE(transfers_were_unlocked) DOC_DSCR("If true, all input transfers that were locked when preparing this transaction, are now unlocked and may be spent. Can be true only upon sending failure and if requested.") DOC_EXMP(false) DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
} // namespace wallet_rpc
|
||||
} // namespace tools
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2024 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
|
||||
|
|
@ -1260,13 +1260,46 @@ namespace tools
|
|||
WALLET_RPC_CATCH_TRY_ENTRY();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
void wallet_rpc_server::rpc_destinations_to_currency_destination(const std::list<wallet_public::transfer_destination>& rpc_destinations, std::vector<currency::tx_destination_entry>& currency_destinations)
|
||||
#define DESTINATIONS_COUNT_FOR_DEPLOY_OR_EMIT 10
|
||||
static_assert(DESTINATIONS_COUNT_FOR_DEPLOY_OR_EMIT >= CURRENCY_TX_MIN_ALLOWED_OUTS, "DESTINATIONS_COUNT_FOR_DEPLOY_OR_EMIT must be >= min allowed tx outs");
|
||||
void wallet_rpc_server::rpc_destinations_to_currency_destinations(const std::list<wallet_public::transfer_destination>& rpc_destinations, bool nullify_asset_id, bool try_to_split, std::vector<currency::tx_destination_entry>& result_destinations)
|
||||
{
|
||||
GET_WALLET();
|
||||
std::vector<currency::tx_destination_entry>& dsts = currency_destinations;
|
||||
for (auto it = rpc_destinations.begin(); it != rpc_destinations.end(); it++)
|
||||
|
||||
WLT_THROW_IF_FALSE_WITH_CODE(!rpc_destinations.empty(), "WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT", "WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT");
|
||||
|
||||
std::list<wallet_public::transfer_destination> local_destinations;
|
||||
if (nullify_asset_id && try_to_split)
|
||||
{
|
||||
currency::tx_destination_entry de;
|
||||
bool do_split = true;
|
||||
uint64_t total_amount = rpc_destinations.front().amount;
|
||||
std::string first_address = rpc_destinations.front().address;
|
||||
for(auto it = std::next(rpc_destinations.begin()); it != rpc_destinations.end(); ++it)
|
||||
{
|
||||
total_amount += it->amount;
|
||||
if (first_address != it->address)
|
||||
{
|
||||
do_split = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (do_split)
|
||||
{
|
||||
const uint64_t el_amount = total_amount / DESTINATIONS_COUNT_FOR_DEPLOY_OR_EMIT; // approximation, see below
|
||||
wallet_public::transfer_destination td{};
|
||||
td.address = first_address;
|
||||
td.amount = el_amount;
|
||||
for(size_t i = 0; i < DESTINATIONS_COUNT_FOR_DEPLOY_OR_EMIT - 1; ++i)
|
||||
local_destinations.push_back(td);
|
||||
td.amount = total_amount - (DESTINATIONS_COUNT_FOR_DEPLOY_OR_EMIT - 1) * el_amount; // the last element must account for division error
|
||||
local_destinations.push_back(td);
|
||||
}
|
||||
}
|
||||
const std::list<wallet_public::transfer_destination>& destinations = local_destinations.size() != 0 ? local_destinations : rpc_destinations;
|
||||
|
||||
for (auto it = destinations.begin(); it != destinations.end(); ++it)
|
||||
{
|
||||
currency::tx_destination_entry de{};
|
||||
de.addr.resize(1);
|
||||
std::string embedded_payment_id;
|
||||
//check if address looks like wrapped address
|
||||
|
|
@ -1274,66 +1307,133 @@ namespace tools
|
|||
WLT_THROW_IF_FALSE_WITH_CODE(w.get_wallet()->get_transfer_address(it->address, de.addr.back(), embedded_payment_id), "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS", "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS");
|
||||
WLT_THROW_IF_FALSE_WITH_CODE(embedded_payment_id.size() == 0, "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS", "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS");
|
||||
de.amount = it->amount;
|
||||
de.asset_id = it->asset_id;
|
||||
dsts.push_back(de);
|
||||
de.asset_id = nullify_asset_id ? currency::null_pkey : it->asset_id;
|
||||
result_destinations.push_back(de);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::on_assets_deploy(const wallet_public::COMMAND_ASSETS_DEPLOY::request& req, wallet_public::COMMAND_ASSETS_DEPLOY::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
bool wallet_rpc_server::on_asset_deploy(const wallet_public::COMMAND_ASSETS_DEPLOY::request& req, wallet_public::COMMAND_ASSETS_DEPLOY::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
WALLET_RPC_BEGIN_TRY_ENTRY();
|
||||
|
||||
currency::transaction result_tx;
|
||||
std::vector<currency::tx_destination_entry> currency_destinations;
|
||||
rpc_destinations_to_currency_destination(req.destinations, currency_destinations);
|
||||
//fix for default asset_id
|
||||
for (auto& d : currency_destinations)
|
||||
{
|
||||
d.asset_id = currency::null_pkey;
|
||||
}
|
||||
rpc_destinations_to_currency_destinations(req.destinations, true, !req.do_not_split_destinations, currency_destinations);
|
||||
|
||||
currency::finalized_tx ft{};
|
||||
w.get_wallet()->deploy_new_asset(req.asset_descriptor, currency_destinations, ft, res.new_asset_id);
|
||||
res.tx_id = ft.tx_id;
|
||||
|
||||
w.get_wallet()->deploy_new_asset(req.asset_descriptor, currency_destinations, result_tx, res.new_asset_id);
|
||||
res.result_tx = currency::get_transaction_hash(result_tx);
|
||||
return true;
|
||||
WALLET_RPC_CATCH_TRY_ENTRY();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::on_assets_emit(const wallet_public::COMMAND_ASSETS_EMIT::request& req, wallet_public::COMMAND_ASSETS_EMIT::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
bool wallet_rpc_server::on_asset_emit(const wallet_public::COMMAND_ASSETS_EMIT::request& req, wallet_public::COMMAND_ASSETS_EMIT::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
WALLET_RPC_BEGIN_TRY_ENTRY();
|
||||
currency::transaction result_tx;
|
||||
currency::asset_descriptor_base last_adb{};
|
||||
CHECK_AND_ASSERT_THROW_MES(w.get_wallet()->daemon_get_asset_info(req.asset_id, last_adb), "unknown asset_id"); // TODO: bad design, consider refactoring -- sowle
|
||||
|
||||
std::vector<currency::tx_destination_entry> currency_destinations;
|
||||
rpc_destinations_to_currency_destination(req.destinations, currency_destinations);
|
||||
//fix for default asset_id
|
||||
for (auto& d : currency_destinations)
|
||||
rpc_destinations_to_currency_destinations(req.destinations, true, !req.do_not_split_destinations, currency_destinations);
|
||||
|
||||
currency::finalized_tx ft{};
|
||||
w.get_wallet()->emit_asset(req.asset_id, currency_destinations, ft);
|
||||
res.tx_id = ft.tx_id;
|
||||
|
||||
if (last_adb.owner_eth_pub_key.has_value())
|
||||
{
|
||||
d.asset_id = currency::null_pkey;
|
||||
// include additonal info into response, if it's an external signing asset operation
|
||||
wallet_public::data_for_external_asset_signing_tx data{};
|
||||
data.unsigned_tx = t_serializable_object_to_blob(ft.tx);
|
||||
data.tx_secret_key = ft.one_time_key;
|
||||
std::vector<std::string>& outs_addr = data.outputs_addresses;
|
||||
for(auto d : ft.ftp.prepared_destinations)
|
||||
outs_addr.push_back(currency::get_account_address_as_str(d.addr.back()));
|
||||
data.finalized_tx = t_serializable_object_to_blob(ft);
|
||||
|
||||
res.data_for_external_signing = data;
|
||||
}
|
||||
|
||||
w.get_wallet()->emit_asset(req.asset_id, currency_destinations, result_tx);
|
||||
res.result_tx = currency::get_transaction_hash(result_tx);
|
||||
return true;
|
||||
|
||||
WALLET_RPC_CATCH_TRY_ENTRY();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::on_assets_update(const wallet_public::COMMAND_ASSETS_UPDATE::request& req, wallet_public::COMMAND_ASSETS_UPDATE::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
bool wallet_rpc_server::on_asset_update(const wallet_public::COMMAND_ASSETS_UPDATE::request& req, wallet_public::COMMAND_ASSETS_UPDATE::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
WALLET_RPC_BEGIN_TRY_ENTRY();
|
||||
currency::transaction result_tx;
|
||||
w.get_wallet()->update_asset(req.asset_id, req.asset_descriptor, result_tx);
|
||||
res.result_tx = currency::get_transaction_hash(result_tx);
|
||||
return true;
|
||||
currency::finalized_tx ft{};
|
||||
w.get_wallet()->update_asset(req.asset_id, req.asset_descriptor, ft);
|
||||
res.tx_id = ft.tx_id;
|
||||
|
||||
if (req.asset_descriptor.owner_eth_pub_key.has_value())
|
||||
{
|
||||
// include additonal info into response, if it's an external signing asset operation
|
||||
wallet_public::data_for_external_asset_signing_tx data{};
|
||||
data.unsigned_tx = t_serializable_object_to_blob(ft.tx);
|
||||
data.tx_secret_key = ft.one_time_key;
|
||||
std::vector<std::string>& outs_addr = data.outputs_addresses;
|
||||
for(auto d : ft.ftp.prepared_destinations)
|
||||
outs_addr.push_back(currency::get_account_address_as_str(d.addr.back()));
|
||||
data.finalized_tx = t_serializable_object_to_blob(ft);
|
||||
|
||||
res.data_for_external_signing = data;
|
||||
}
|
||||
|
||||
return true;
|
||||
WALLET_RPC_CATCH_TRY_ENTRY();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::on_assets_burn(const wallet_public::COMMAND_ASSETS_BURN::request& req, wallet_public::COMMAND_ASSETS_BURN::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
bool wallet_rpc_server::on_asset_burn(const wallet_public::COMMAND_ASSETS_BURN::request& req, wallet_public::COMMAND_ASSETS_BURN::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
WALLET_RPC_BEGIN_TRY_ENTRY();
|
||||
currency::transaction result_tx;
|
||||
w.get_wallet()->burn_asset(req.asset_id, req.burn_amount, result_tx);
|
||||
res.result_tx = currency::get_transaction_hash(result_tx);
|
||||
|
||||
currency::finalized_tx ft{};
|
||||
w.get_wallet()->burn_asset(req.asset_id, req.burn_amount, ft);
|
||||
res.tx_id = ft.tx_id;
|
||||
|
||||
return true;
|
||||
WALLET_RPC_CATCH_TRY_ENTRY();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::on_asset_send_ext_signed_tx(const wallet_public::COMMAND_ASSET_SEND_EXT_SIGNED_TX::request& req, wallet_public::COMMAND_ASSET_SEND_EXT_SIGNED_TX::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
WALLET_RPC_BEGIN_TRY_ENTRY();
|
||||
|
||||
currency::finalized_tx ft{};
|
||||
if (!t_unserializable_object_from_blob(ft, req.finalized_tx))
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
|
||||
er.message = "finalized_tx couldn't be deserialized";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t_serializable_object_to_blob(ft.tx) != req.unsigned_tx)
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
|
||||
er.message = "unsigned_tx doesn't match finalized_tx";
|
||||
return false;
|
||||
}
|
||||
|
||||
crypto::hash tx_id = currency::get_transaction_hash(ft.tx);
|
||||
if (req.expected_tx_id != tx_id)
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
|
||||
er.message = std::string("expected_tx_id mismatch, real tx id is ") + epee::string_tools::pod_to_hex(tx_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
currency::transaction result_tx{};
|
||||
w.get_wallet()->submit_externally_signed_asset_tx(ft, req.eth_sig, req.unlock_transfers_on_fail, result_tx, res.transfers_were_unlocked);
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
// doing this to be able to return 'transfers_were_unlocked' to the caller even in the case of exception
|
||||
res.status = e.what();
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
WALLET_RPC_CATCH_TRY_ENTRY();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,11 +146,11 @@ namespace tools
|
|||
MAP_JON_RPC_WE("assets_whitelist_add", on_assets_whitelist_add, wallet_public::COMMAND_ASSETS_WHITELIST_ADD)
|
||||
MAP_JON_RPC_WE("assets_whitelist_remove", on_assets_whitelist_remove, wallet_public::COMMAND_ASSETS_WHITELIST_REMOVE)
|
||||
|
||||
MAP_JON_RPC_WE("deploy_asset", on_assets_deploy, wallet_public::COMMAND_ASSETS_DEPLOY)
|
||||
MAP_JON_RPC_WE("emit_asset", on_assets_emit, wallet_public::COMMAND_ASSETS_EMIT)
|
||||
MAP_JON_RPC_WE("update_asset", on_assets_update, wallet_public::COMMAND_ASSETS_UPDATE)
|
||||
MAP_JON_RPC_WE("burn_asset", on_assets_burn, wallet_public::COMMAND_ASSETS_BURN)
|
||||
|
||||
MAP_JON_RPC_WE("deploy_asset", on_asset_deploy, wallet_public::COMMAND_ASSETS_DEPLOY)
|
||||
MAP_JON_RPC_WE("emit_asset", on_asset_emit, wallet_public::COMMAND_ASSETS_EMIT)
|
||||
MAP_JON_RPC_WE("update_asset", on_asset_update, wallet_public::COMMAND_ASSETS_UPDATE)
|
||||
MAP_JON_RPC_WE("burn_asset", on_asset_burn, wallet_public::COMMAND_ASSETS_BURN)
|
||||
MAP_JON_RPC_WE("send_ext_signed_asset_tx", on_asset_send_ext_signed_tx, wallet_public::COMMAND_ASSET_SEND_EXT_SIGNED_TX)
|
||||
|
||||
//MULTIWALLET APIs
|
||||
MAP_JON_RPC_WE("mw_get_wallets", on_mw_get_wallets, wallet_public::COMMAND_MW_GET_WALLETS)
|
||||
|
|
@ -218,10 +218,11 @@ namespace tools
|
|||
bool on_assets_whitelist_add(const wallet_public::COMMAND_ASSETS_WHITELIST_ADD::request& req, wallet_public::COMMAND_ASSETS_WHITELIST_ADD::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_assets_whitelist_remove(const wallet_public::COMMAND_ASSETS_WHITELIST_REMOVE::request& req, wallet_public::COMMAND_ASSETS_WHITELIST_REMOVE::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
|
||||
bool on_assets_deploy(const wallet_public::COMMAND_ASSETS_DEPLOY::request& req, wallet_public::COMMAND_ASSETS_DEPLOY::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_assets_emit(const wallet_public::COMMAND_ASSETS_EMIT::request& req, wallet_public::COMMAND_ASSETS_EMIT::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_assets_update(const wallet_public::COMMAND_ASSETS_UPDATE::request& req, wallet_public::COMMAND_ASSETS_UPDATE::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_assets_burn(const wallet_public::COMMAND_ASSETS_BURN::request& req, wallet_public::COMMAND_ASSETS_BURN::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_asset_deploy(const wallet_public::COMMAND_ASSETS_DEPLOY::request& req, wallet_public::COMMAND_ASSETS_DEPLOY::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_asset_emit(const wallet_public::COMMAND_ASSETS_EMIT::request& req, wallet_public::COMMAND_ASSETS_EMIT::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_asset_update(const wallet_public::COMMAND_ASSETS_UPDATE::request& req, wallet_public::COMMAND_ASSETS_UPDATE::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_asset_burn(const wallet_public::COMMAND_ASSETS_BURN::request& req, wallet_public::COMMAND_ASSETS_BURN::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_asset_send_ext_signed_tx(const wallet_public::COMMAND_ASSET_SEND_EXT_SIGNED_TX::request& req, wallet_public::COMMAND_ASSET_SEND_EXT_SIGNED_TX::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
|
||||
bool on_mw_get_wallets(const wallet_public::COMMAND_MW_GET_WALLETS::request& req, wallet_public::COMMAND_MW_GET_WALLETS::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_mw_select_wallet(const wallet_public::COMMAND_MW_SELECT_WALLET::request& req, wallet_public::COMMAND_MW_SELECT_WALLET::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
|
|
@ -238,7 +239,8 @@ namespace tools
|
|||
//bool reset_active_wallet(std::shared_ptr<wallet2> w);
|
||||
|
||||
bool handle_command_line(const boost::program_options::variables_map& vm);
|
||||
void rpc_destinations_to_currency_destination(const std::list<wallet_public::transfer_destination>& rpc_destinations, std::vector<currency::tx_destination_entry>& currency_destinations);
|
||||
void rpc_destinations_to_currency_destinations(const std::list<wallet_public::transfer_destination>& rpc_destinations, bool nullify_asset_id, bool try_to_split, std::vector<currency::tx_destination_entry>& currency_destinations);
|
||||
|
||||
|
||||
private:
|
||||
std::shared_ptr<i_wallet_provider> m_pwallet_provider_sh_ptr;
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#define WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR -1
|
||||
#define WALLET_RPC_ERROR_CODE_WRONG_ADDRESS -2
|
||||
#define WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY -3
|
||||
#define WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR -4
|
||||
#define WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID -5
|
||||
#define WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT -6
|
||||
#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY -7
|
||||
#define WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR -1
|
||||
#define WALLET_RPC_ERROR_CODE_WRONG_ADDRESS -2
|
||||
#define WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY -3
|
||||
#define WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR -4
|
||||
#define WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID -5
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -817,3 +817,241 @@ bool chain_switching_when_out_spent_in_alt_chain_ref_id::generate(std::vector<te
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
alt_chain_and_block_tx_fee_median::alt_chain_and_block_tx_fee_median()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(alt_chain_and_block_tx_fee_median, check_after_hf4);
|
||||
REGISTER_CALLBACK_METHOD(alt_chain_and_block_tx_fee_median, check_before_hf4);
|
||||
}
|
||||
|
||||
bool alt_chain_and_block_tx_fee_median::generate(
|
||||
std::vector<test_event_entry>& events) const
|
||||
{
|
||||
/* Test idea: check chain switching rules.
|
||||
Rules before and after HF4 for PoW blocks are different. There're only PoW
|
||||
blocks in the test situation. If the last blocks contain transactions (non
|
||||
empty blocks), then the chain with the largest this_block_tx_fee_median on its
|
||||
head becomes the main.
|
||||
0 10 11 21 22
|
||||
(0 ) - ... - (0r) - (1 ) - ... - (1r) - (2 )
|
||||
| main | \
|
||||
| | [tx_0]
|
||||
| |
|
||||
| | main
|
||||
\ - (1a) \ - (2a)
|
||||
\
|
||||
[tx_1]
|
||||
Chain with head blk_1 versus chain with head blk_1a: chain with head blk_1
|
||||
is the main, because blocks 1, 1a are empty.
|
||||
Chain with head blk_2 versus chain with head blk_2a: chain with head blk_2a
|
||||
is the main, because blocks 2, 2a aren't empty and the fee of tx_1 is larger
|
||||
than the fee of tx_0.
|
||||
*/
|
||||
|
||||
bool success{};
|
||||
bool hf4_active{};
|
||||
std::vector<tx_source_entry> sources{};
|
||||
std::vector<tx_destination_entry> destinations{};
|
||||
transaction tx_0{}, tx_1{};
|
||||
uint64_t tx_version{};
|
||||
crypto::hash top_block{};
|
||||
|
||||
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);
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner);
|
||||
MAKE_NEXT_BLOCK(events, blk_1a, blk_0r, miner);
|
||||
|
||||
/* It is decided which chain will be the main: with the head blk_1 or with the
|
||||
head blk_1a.
|
||||
0 10 11
|
||||
/ - (1 )
|
||||
|
|
||||
(0 ) - ... - (0r)
|
||||
|
|
||||
\ - (1a)
|
||||
*/
|
||||
|
||||
CHECK_AND_ASSERT_EQ(is_pos_block(blk_1), false);
|
||||
CHECK_AND_ASSERT_EQ(is_pos_block(blk_1a), false);
|
||||
CHECK_AND_ASSERT_EQ(get_block_height(blk_1), 11);
|
||||
CHECK_AND_ASSERT_EQ(get_block_height(blk_1), get_block_height(blk_1a));
|
||||
|
||||
/* Blocks blk_1, blk_1a do not contain transactions (they are empty blocks).
|
||||
Switching to the alternative chain with head blk_1a will not occur. The main
|
||||
chain is the chain with the head blk_1. */
|
||||
|
||||
DO_CALLBACK_PARAMS(events,
|
||||
"check_top_block",
|
||||
params_top_block(get_block_height(blk_1),
|
||||
get_block_hash(blk_1)));
|
||||
|
||||
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner,
|
||||
CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
// Transaction tx_0 is constructed and placed in block blk_2.
|
||||
|
||||
success = fill_tx_sources_and_destinations(
|
||||
events,
|
||||
/* head = */ blk_1r,
|
||||
/* from = */ miner.get_keys(),
|
||||
/* to = */ miner.get_public_address(),
|
||||
/* amount = */ MK_TEST_COINS(10),
|
||||
/* fee = */ m_fee_tx_0_blk_2,
|
||||
/* nmix = */ 0,
|
||||
sources,
|
||||
destinations);
|
||||
|
||||
CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations");
|
||||
|
||||
tx_version = get_tx_version(get_block_height(blk_1r),
|
||||
m_hardforks);
|
||||
|
||||
success = construct_tx(miner.get_keys(),
|
||||
sources,
|
||||
destinations,
|
||||
empty_attachment,
|
||||
tx_0,
|
||||
tx_version,
|
||||
0);
|
||||
|
||||
CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_0");
|
||||
|
||||
ADD_CUSTOM_EVENT(events, tx_0);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner, tx_0);
|
||||
|
||||
sources.clear();
|
||||
destinations.clear();
|
||||
|
||||
// Transaction tx_1 is constructed and placed in block blk_2a.
|
||||
|
||||
tx_version = get_tx_version(get_block_height(blk_1r),
|
||||
m_hardforks);
|
||||
|
||||
success = fill_tx_sources_and_destinations(
|
||||
events,
|
||||
/* head = */ blk_1r,
|
||||
/* from = */ miner.get_keys(),
|
||||
/* to = */ miner.get_public_address(),
|
||||
/* amount = */ MK_TEST_COINS(10),
|
||||
/* fee = */ m_fee_tx_1_blk_2a,
|
||||
/* nmix = */ 0,
|
||||
sources,
|
||||
destinations);
|
||||
|
||||
CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations");
|
||||
|
||||
success = construct_tx(miner.get_keys(),
|
||||
sources,
|
||||
destinations,
|
||||
empty_attachment,
|
||||
tx_1,
|
||||
tx_version,
|
||||
0);
|
||||
|
||||
CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_1");
|
||||
|
||||
ADD_CUSTOM_EVENT(events, tx_1);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_2a, blk_1r, miner, tx_1);
|
||||
|
||||
/* It is decided which chain will be the main: with the head blk_2 or with the
|
||||
head blk_2a.
|
||||
0 21 22
|
||||
/ - (2 )
|
||||
| \
|
||||
| [tx_0]
|
||||
|
|
||||
(0 ) - ... - (1r)
|
||||
|
|
||||
|
|
||||
|
|
||||
\ - (2a)
|
||||
\
|
||||
[tx_1]
|
||||
*/
|
||||
|
||||
CHECK_AND_ASSERT_EQ(is_pos_block(blk_2), false);
|
||||
CHECK_AND_ASSERT_EQ(is_pos_block(blk_2a), false);
|
||||
CHECK_AND_ASSERT_GREATER(m_fee_tx_1_blk_2a, m_fee_tx_0_blk_2);
|
||||
CHECK_AND_ASSERT_EQ(get_block_height(blk_2), 22);
|
||||
CHECK_AND_ASSERT_EQ(get_block_height(blk_2), get_block_height(blk_2a));
|
||||
|
||||
hf4_active =
|
||||
m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM,
|
||||
get_block_height(blk_2) + 1);
|
||||
|
||||
if (hf4_active)
|
||||
{
|
||||
/* With HF4 active, the chain with head blk_2a wins because transaction tx_1
|
||||
has a greater fee than transaction tx_0. The main chain is the chain with
|
||||
the head blk_2a. */
|
||||
|
||||
DO_CALLBACK(events, "check_after_hf4");
|
||||
top_block = get_block_hash(blk_2a);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* The chains have the same commulative difficulty. Therefore, with HF4
|
||||
inactive, switching to the chain with the blk_2a head will not occur. The
|
||||
main chain is the chain with the head blk_2. */
|
||||
|
||||
DO_CALLBACK(events, "check_before_hf4");
|
||||
top_block = get_block_hash(blk_2);
|
||||
}
|
||||
|
||||
DO_CALLBACK_PARAMS(events,
|
||||
"check_top_block",
|
||||
params_top_block(/* height = */ 22, top_block));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool alt_chain_and_block_tx_fee_median::check_after_hf4(
|
||||
currency::core& c,
|
||||
size_t ev_index,
|
||||
const std::vector<test_event_entry>& events)
|
||||
{
|
||||
block_extended_info bei{};
|
||||
const uint64_t height_block{22};
|
||||
|
||||
CHECK_AND_ASSERT_EQ(
|
||||
m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM,
|
||||
height_block),
|
||||
true);
|
||||
|
||||
c.get_blockchain_storage().get_block_extended_info_by_height(height_block,
|
||||
bei);
|
||||
CHECK_AND_ASSERT_EQ(bei.this_block_tx_fee_median, m_fee_tx_1_blk_2a);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool alt_chain_and_block_tx_fee_median::check_before_hf4(
|
||||
currency::core& c,
|
||||
size_t ev_index,
|
||||
const std::vector<test_event_entry>& events)
|
||||
{
|
||||
block_extended_info bei{};
|
||||
const uint64_t height_block{22};
|
||||
|
||||
CHECK_AND_ASSERT_EQ(
|
||||
m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM,
|
||||
height_block),
|
||||
false);
|
||||
|
||||
c.get_blockchain_storage().get_block_extended_info_by_height(height_block,
|
||||
bei);
|
||||
CHECK_AND_ASSERT_EQ(bei.this_block_tx_fee_median, m_fee_tx_0_blk_2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,3 +82,21 @@ struct chain_switching_when_out_spent_in_alt_chain_ref_id : public test_chain_un
|
|||
{
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct alt_chain_and_block_tx_fee_median : public test_chain_unit_enchanced
|
||||
{
|
||||
alt_chain_and_block_tx_fee_median();
|
||||
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool check_after_hf4(currency::core& c,
|
||||
size_t ev_index,
|
||||
const std::vector<test_event_entry>& events);
|
||||
|
||||
bool check_before_hf4(currency::core& c,
|
||||
size_t ev_index,
|
||||
const std::vector<test_event_entry>& events);
|
||||
|
||||
private:
|
||||
const uint64_t m_fee_tx_0_blk_2{TESTS_DEFAULT_FEE};
|
||||
const uint64_t m_fee_tx_1_blk_2a{2 * m_fee_tx_0_blk_2};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1814,6 +1814,48 @@ bool construct_tx_with_many_outputs(const currency::hard_forks_descriptor& hf, s
|
|||
return construct_tx(keys_from, sources, destinations, empty_attachment, tx, tx_version, 0);
|
||||
}
|
||||
|
||||
bool construct_tx(const account_keys& sender_account_keys,
|
||||
const std::vector<tx_source_entry>& sources,
|
||||
const std::vector<tx_destination_entry>& destinations,
|
||||
const std::vector<extra_v>& extra,
|
||||
const std::vector<attachment_v>& attachments,
|
||||
transaction& tx,
|
||||
uint64_t tx_version,
|
||||
crypto::secret_key& one_time_secret_key,
|
||||
uint64_t unlock_time,
|
||||
uint64_t expiration_time,
|
||||
uint8_t tx_outs_attr,
|
||||
bool shuffle,
|
||||
uint64_t flags,
|
||||
uint64_t explicit_consolidated_tx_fee,
|
||||
tx_generation_context& gen_context)
|
||||
{
|
||||
// extra copy operation, but creating transaction is not sensitive to this
|
||||
finalize_tx_param ftp {};
|
||||
ftp.tx_version = tx_version;
|
||||
ftp.sources = sources;
|
||||
ftp.prepared_destinations = destinations;
|
||||
ftp.extra = extra;
|
||||
ftp.attachments = attachments;
|
||||
ftp.unlock_time = unlock_time;
|
||||
// ftp.crypt_address = crypt_destination_addr;
|
||||
ftp.expiration_time = expiration_time;
|
||||
ftp.tx_outs_attr = tx_outs_attr;
|
||||
ftp.shuffle = shuffle;
|
||||
ftp.flags = flags;
|
||||
ftp.mode_separate_fee = explicit_consolidated_tx_fee;
|
||||
|
||||
finalized_tx ft = AUTO_VAL_INIT(ft);
|
||||
ft.tx = tx;
|
||||
ft.one_time_key = one_time_secret_key;
|
||||
ftp.gen_context = gen_context; // ftp, not ft here, this is UGLY -- sowle
|
||||
bool r = construct_tx(sender_account_keys, ftp, ft);
|
||||
tx = ft.tx;
|
||||
one_time_secret_key = ft.one_time_key;
|
||||
gen_context = ft.ftp.gen_context;
|
||||
return r;
|
||||
}
|
||||
|
||||
uint64_t get_balance(const currency::account_keys& addr, const std::vector<currency::block>& blockchain, const map_hash2tx_t& mtx, bool dbg_log)
|
||||
{
|
||||
uint64_t res = 0;
|
||||
|
|
@ -1945,22 +1987,27 @@ void balance_via_wallet(const tools::wallet2& w, const crypto::public_key& asset
|
|||
}
|
||||
|
||||
bool check_balance_via_wallet(const tools::wallet2& w, const char* account_name,
|
||||
uint64_t expected_total, uint64_t expected_mined, uint64_t expected_unlocked, uint64_t expected_awaiting_in, uint64_t expected_awaiting_out, const crypto::public_key& asset_id /* = currency::native_coin_asset_id */)
|
||||
uint64_t expected_total, uint64_t expected_mined, uint64_t expected_unlocked, uint64_t expected_awaiting_in, uint64_t expected_awaiting_out,
|
||||
const crypto::public_key& asset_id /* = currency::native_coin_asset_id */, size_t asset_decimal_point /* = CURRENCY_DISPLAY_DECIMAL_POINT */)
|
||||
{
|
||||
uint64_t total, unlocked, awaiting_in, awaiting_out, mined;
|
||||
balance_via_wallet(w, asset_id, &total, &unlocked, &awaiting_in, &awaiting_out, &mined);
|
||||
|
||||
std::string asset_id_str;
|
||||
if (asset_id != currency::native_coin_asset_id)
|
||||
{
|
||||
asset_id_str = std::string(", asset_id: ") + epee::string_tools::pod_to_hex(asset_id).erase(4, 56).insert(4, "...");
|
||||
if (asset_decimal_point == CURRENCY_DISPLAY_DECIMAL_POINT)
|
||||
asset_decimal_point = w.get_asset_decimal_point(asset_id, asset_decimal_point);
|
||||
}
|
||||
|
||||
LOG_PRINT_CYAN("Balance for wallet " << account_name << " @ height " << w.get_top_block_height() << asset_id_str << ":" << ENDL <<
|
||||
"unlocked: " << print_money(unlocked) << ENDL <<
|
||||
"awaiting in: " << print_money(awaiting_in) << ENDL <<
|
||||
"awaiting out: " << print_money(awaiting_out) << ENDL <<
|
||||
"mined: " << print_money(mined) << ENDL <<
|
||||
"unlocked: " << print_money(unlocked, asset_decimal_point) << ENDL <<
|
||||
"awaiting in: " << print_money(awaiting_in, asset_decimal_point) << ENDL <<
|
||||
"awaiting out: " << print_money(awaiting_out, asset_decimal_point) << ENDL <<
|
||||
"mined: " << print_money(mined, asset_decimal_point) << ENDL <<
|
||||
"-----------------------------------------" << ENDL <<
|
||||
"total: " << print_money(total) << ENDL,
|
||||
"total: " << print_money(total, asset_decimal_point) << ENDL,
|
||||
LOG_LEVEL_0);
|
||||
|
||||
bool r = true;
|
||||
|
|
@ -1981,6 +2028,12 @@ bool check_balance_via_wallet(const tools::wallet2& w, const char* account_name,
|
|||
return r;
|
||||
}
|
||||
|
||||
bool check_balance_via_wallet(const tools::wallet2& w, const char* account_name, uint64_t expected_total, const crypto::public_key& asset_id, size_t asset_decimal_point /* = CURRENCY_DISPLAY_DECIMAL_POINT */)
|
||||
{
|
||||
return check_balance_via_wallet(w, account_name, expected_total, INVALID_BALANCE_VAL, INVALID_BALANCE_VAL, INVALID_BALANCE_VAL, INVALID_BALANCE_VAL, asset_id, asset_decimal_point);
|
||||
}
|
||||
|
||||
|
||||
// In assumption we have only genesis and few blocks with the same reward (==first_blocks_reward),
|
||||
// this function helps to calculate such amount that many outputs have it, and amount, no output has it.
|
||||
// It can fail, so check the returning value.
|
||||
|
|
|
|||
|
|
@ -673,6 +673,22 @@ bool construct_tx_with_many_outputs(const currency::hard_forks_descriptor& hf, s
|
|||
const currency::account_keys& keys_from, const currency::account_public_address& addr_to,
|
||||
uint64_t total_amount, size_t outputs_count, uint64_t fee, currency::transaction& tx, bool use_ref_by_id = false);
|
||||
|
||||
bool construct_tx(const currency::account_keys& sender_account_keys,
|
||||
const std::vector<currency::tx_source_entry>& sources,
|
||||
const std::vector<currency::tx_destination_entry>& destinations,
|
||||
const std::vector<currency::extra_v>& extra,
|
||||
const std::vector<currency::attachment_v>& attachments,
|
||||
currency::transaction& tx,
|
||||
uint64_t tx_version,
|
||||
crypto::secret_key& one_time_secret_key,
|
||||
uint64_t unlock_time,
|
||||
uint64_t expiration_time,
|
||||
uint8_t tx_outs_attr,
|
||||
bool shuffle,
|
||||
uint64_t flags,
|
||||
uint64_t explicit_consolidated_tx_fee,
|
||||
currency::tx_generation_context& gen_context);
|
||||
|
||||
void get_confirmed_txs(const std::vector<currency::block>& blockchain, const map_hash2tx_t& mtx, map_hash2tx_t& confirmed_txs);
|
||||
bool find_block_chain(const std::vector<test_event_entry>& events, std::vector<currency::block>& blockchain, map_hash2tx_t& mtx, const crypto::hash& head);
|
||||
bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std::vector<test_event_entry>& events,
|
||||
|
|
@ -715,7 +731,9 @@ bool check_balance_via_wallet(const tools::wallet2& w, const char* account_name,
|
|||
uint64_t expected_unlocked = INVALID_BALANCE_VAL,
|
||||
uint64_t expected_awaiting_in = INVALID_BALANCE_VAL,
|
||||
uint64_t expected_awaiting_out = INVALID_BALANCE_VAL,
|
||||
const crypto::public_key& asset_id = currency::native_coin_asset_id);
|
||||
const crypto::public_key& asset_id = currency::native_coin_asset_id,
|
||||
size_t asset_decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT);
|
||||
bool check_balance_via_wallet(const tools::wallet2& w, const char* account_name, uint64_t expected_total, const crypto::public_key& asset_id, size_t asset_decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT);
|
||||
|
||||
bool calculate_amounts_many_outs_have_and_no_outs_have(const uint64_t first_blocks_reward, uint64_t& amount_many_outs_have, uint64_t& amount_no_outs_have);
|
||||
bool find_global_index_for_output(const std::vector<test_event_entry>& events, const crypto::hash& head_block_hash, const currency::transaction& reference_tx, const size_t reference_tx_out_index, uint64_t& global_index);
|
||||
|
|
|
|||
|
|
@ -264,13 +264,13 @@ bool generate_and_play(const char* const genclass_name, size_t hardfork_id = SIZ
|
|||
|
||||
if (result)
|
||||
{
|
||||
LOG_PRINT_GREEN(std::string(100, '=') << std::endl <<
|
||||
LOG_PRINT_GREEN(std::string(72, '=') << std::endl <<
|
||||
"#TEST# >>>> " << genclass_name << " <<<< Succeeded" << std::endl <<
|
||||
std::string(100, '=') << std::endl, LOG_LEVEL_0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_RED( std::string(100, '=') << std::endl <<
|
||||
LOG_PRINT_RED( std::string(72, '=') << std::endl <<
|
||||
"#TEST# >>>> " << genclass_name << " <<<< FAILED" << std::endl <<
|
||||
std::string(100, '=') << std::endl, LOG_LEVEL_0);
|
||||
result = false;
|
||||
|
|
@ -1070,7 +1070,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(gen_wallet_refreshing_on_chain_switch_2);
|
||||
GENERATE_AND_PLAY(gen_wallet_unconfirmed_tx_from_tx_pool);
|
||||
GENERATE_AND_PLAY_HF(gen_wallet_save_load_and_balance, "*");
|
||||
GENERATE_AND_PLAY_HF(gen_wallet_mine_pos_block, "3");
|
||||
GENERATE_AND_PLAY_HF(gen_wallet_mine_pos_block, "3-*");
|
||||
GENERATE_AND_PLAY(gen_wallet_unconfirmed_outdated_tx);
|
||||
GENERATE_AND_PLAY(gen_wallet_unlock_by_block_and_by_time);
|
||||
GENERATE_AND_PLAY(gen_wallet_payment_id);
|
||||
|
|
@ -1102,6 +1102,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(wallet_rpc_transfer);
|
||||
GENERATE_AND_PLAY(wallet_rpc_alias_tests);
|
||||
GENERATE_AND_PLAY_HF(wallet_rpc_exchange_suite, "3,4");
|
||||
GENERATE_AND_PLAY_HF(wallet_true_rpc_pos_mining, "4-*");
|
||||
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-*");
|
||||
|
|
@ -1139,7 +1140,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY_HF(alt_blocks_with_the_same_txs, "3-*");
|
||||
GENERATE_AND_PLAY_HF(chain_switching_when_out_spent_in_alt_chain_mixin, "3-*");
|
||||
GENERATE_AND_PLAY_HF(chain_switching_when_out_spent_in_alt_chain_ref_id, "3-*");
|
||||
|
||||
GENERATE_AND_PLAY_HF(alt_chain_and_block_tx_fee_median, "3-*");
|
||||
|
||||
// miscellaneous tests
|
||||
GENERATE_AND_PLAY(test_blockchain_vs_spent_keyimges);
|
||||
|
|
@ -1216,6 +1217,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(tx_expiration_time_and_block_template);
|
||||
GENERATE_AND_PLAY(tx_expiration_time_and_chain_switching);
|
||||
GENERATE_AND_PLAY(tx_key_image_pool_conflict);
|
||||
//GENERATE_AND_PLAY_HF(tx_version_against_hardfork, "4-*");
|
||||
|
||||
// Double spend
|
||||
GENERATE_AND_PLAY(gen_double_spend_in_tx<false>);
|
||||
|
|
@ -1288,14 +1290,17 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(zarcanum_block_with_txs);
|
||||
GENERATE_AND_PLAY(asset_depoyment_and_few_zc_utxos);
|
||||
GENERATE_AND_PLAY_HF(assets_and_pos_mining, "4-*");
|
||||
// GENERATE_AND_PLAY_HF(asset_emission_and_unconfirmed_balance, "4-*");
|
||||
|
||||
GENERATE_AND_PLAY_HF(asset_emission_and_unconfirmed_balance, "4-*");
|
||||
GENERATE_AND_PLAY_HF(asset_operation_in_consolidated_tx, "4-*");
|
||||
GENERATE_AND_PLAY_HF(asset_operation_and_hardfork_checks, "4-*");
|
||||
GENERATE_AND_PLAY_HF(eth_signed_asset_basics, "5-*"); // TODO: make HF4 version
|
||||
GENERATE_AND_PLAY_HF(eth_signed_asset_via_rpc, "5-*"); // TODO: make HF4 version
|
||||
|
||||
GENERATE_AND_PLAY_HF(pos_fuse_test, "4-*");
|
||||
|
||||
|
||||
|
||||
GENERATE_AND_PLAY_HF(attachment_isolation_test, "4-*");
|
||||
|
||||
|
||||
// GENERATE_AND_PLAY(gen_block_reward);
|
||||
// END OF TESTS */
|
||||
|
|
|
|||
|
|
@ -7,51 +7,7 @@
|
|||
|
||||
using namespace currency;
|
||||
|
||||
namespace currency
|
||||
{
|
||||
bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources,
|
||||
const std::vector<tx_destination_entry>& destinations,
|
||||
const std::vector<extra_v>& extra,
|
||||
const std::vector<attachment_v>& attachments,
|
||||
transaction& tx,
|
||||
uint64_t tx_version,
|
||||
crypto::secret_key& one_time_secret_key,
|
||||
uint64_t unlock_time,
|
||||
uint64_t expiration_time,
|
||||
uint8_t tx_outs_attr,
|
||||
bool shuffle,
|
||||
uint64_t flags,
|
||||
uint64_t explicit_consolidated_tx_fee,
|
||||
tx_generation_context& gen_context)
|
||||
{
|
||||
//extra copy operation, but creating transaction is not sensitive to this
|
||||
finalize_tx_param ftp{};
|
||||
ftp.tx_version = tx_version;
|
||||
ftp.sources = sources;
|
||||
ftp.prepared_destinations = destinations;
|
||||
ftp.extra = extra;
|
||||
ftp.attachments = attachments;
|
||||
ftp.unlock_time = unlock_time;
|
||||
// ftp.crypt_address = crypt_destination_addr;
|
||||
ftp.expiration_time = expiration_time;
|
||||
ftp.tx_outs_attr = tx_outs_attr;
|
||||
ftp.shuffle = shuffle;
|
||||
ftp.flags = flags;
|
||||
ftp.mode_separate_fee = explicit_consolidated_tx_fee;
|
||||
|
||||
finalized_tx ft = AUTO_VAL_INIT(ft);
|
||||
ft.tx = tx;
|
||||
ft.one_time_key = one_time_secret_key;
|
||||
ftp.gen_context = gen_context; // ftp, not ft here, this is UGLY -- sowle
|
||||
bool r = construct_tx(sender_account_keys, ftp, ft);
|
||||
tx = ft.tx;
|
||||
one_time_secret_key = ft.one_time_key;
|
||||
gen_context = ft.ftp.gen_context;
|
||||
return r;
|
||||
}
|
||||
} // namespace currency
|
||||
|
||||
void add_flags_to_all_destination_entries(const uint64_t flags, std::vector<currency::tx_destination_entry>& destinations)
|
||||
static void add_flags_to_all_destination_entries(const uint64_t flags, std::vector<currency::tx_destination_entry>& destinations)
|
||||
{
|
||||
for(auto& de : destinations)
|
||||
de.flags |= flags;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2023 Zano Project
|
||||
// Copyright (c) 2014-2024 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.
|
||||
|
|
@ -47,3 +47,51 @@ struct asset_emission_and_unconfirmed_balance : 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 asset_operation_and_hardfork_checks : public wallet_test
|
||||
{
|
||||
public:
|
||||
asset_operation_and_hardfork_checks();
|
||||
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool c1(currency::core& c,
|
||||
size_t ev_index,
|
||||
const std::vector<test_event_entry>& events);
|
||||
|
||||
bool c2(currency::core& c,
|
||||
size_t ev_index,
|
||||
const std::vector<test_event_entry>& events);
|
||||
|
||||
private:
|
||||
mutable currency::asset_descriptor_base m_adb_hello{};
|
||||
mutable currency::asset_descriptor_operation m_ado_hello{};
|
||||
mutable currency::asset_descriptor_base m_adb_bye{};
|
||||
mutable currency::asset_descriptor_operation m_ado_bye{};
|
||||
};
|
||||
|
||||
struct asset_operation_in_consolidated_tx : public wallet_test
|
||||
{
|
||||
public:
|
||||
asset_operation_in_consolidated_tx();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool assert_balances(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool assert_alice_currency_not_registered(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
private:
|
||||
mutable currency::asset_descriptor_base m_adb_alice_currency{};
|
||||
mutable currency::asset_descriptor_operation m_ado_alice_currency{};
|
||||
};
|
||||
|
||||
struct eth_signed_asset_basics : public wallet_test
|
||||
{
|
||||
eth_signed_asset_basics();
|
||||
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 eth_signed_asset_via_rpc : public wallet_test
|
||||
{
|
||||
eth_signed_asset_via_rpc();
|
||||
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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
|
|||
uint64_t block_reward_without_fee = 0;
|
||||
m_block_reward = 0;
|
||||
size_t estimated_block_size = m_txs_total_size;
|
||||
m_block.miner_tx = transaction{};
|
||||
bool r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee,
|
||||
reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, m_block_reward, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "construct_miner_tx failed");
|
||||
|
|
@ -177,6 +178,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
|
|||
size_t cumulative_size = 0;
|
||||
for (size_t try_count = 0; try_count != 10; ++try_count)
|
||||
{
|
||||
m_block.miner_tx = transaction{};
|
||||
r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee,
|
||||
reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, m_block_reward, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed");
|
||||
|
|
|
|||
|
|
@ -1620,3 +1620,84 @@ bool tx_key_image_pool_conflict::generate(std::vector<test_event_entry>& events)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
bool tx_version_against_hardfork::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
// Test idea: make sure that tx with incorrect for the activated HF version won't be accepted.
|
||||
|
||||
bool r = false;
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
// 0 ... 10 11 12 13 14 <- height
|
||||
// (0 )- (0r)- (1 )- !2b!- <- chain A, block 2b is invalid
|
||||
// tx_0 tx_1 tx_0 is accepted, tx_1 is rejected
|
||||
// \
|
||||
// \(2 ) <- chain B
|
||||
// tx_1 tx_1 is accepted
|
||||
|
||||
uint64_t tx_version_good = 0, tx_version_bad = 0;
|
||||
|
||||
// select good and bad tx versions based on active hardfork
|
||||
size_t most_recent_hardfork_id = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_0r));
|
||||
switch(most_recent_hardfork_id)
|
||||
{
|
||||
case ZANO_HARDFORK_04_ZARCANUM:
|
||||
case ZANO_HARDFORK_05:
|
||||
tx_version_good = TRANSACTION_VERSION_POST_HF4;
|
||||
tx_version_bad = TRANSACTION_VERSION_PRE_HF4;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("hardfork " << most_recent_hardfork_id << " is not supported by this test");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<tx_source_entry> sources;
|
||||
std::vector<tx_destination_entry> destinations;
|
||||
|
||||
//
|
||||
// 1/2 tx with good version, should go okay
|
||||
//
|
||||
r = fill_tx_sources_and_destinations(events, blk_0r, miner_acc.get_keys(), miner_acc.get_public_address(), MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
|
||||
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed");
|
||||
transaction tx_0{};
|
||||
r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, tx_version_good, 0);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
events.push_back(tx_0);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0);
|
||||
|
||||
sources.clear();
|
||||
destinations.clear();
|
||||
|
||||
//
|
||||
// 2/2 tx with bad version, should be rejected by tx pool and by the core
|
||||
//
|
||||
r = fill_tx_sources_and_destinations(events, blk_0, miner_acc.get_keys(), miner_acc.get_public_address(), MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
|
||||
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed");
|
||||
transaction tx_1{};
|
||||
r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, tx_version_bad, 0);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
// check tx pool rejection
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
events.push_back(tx_1);
|
||||
|
||||
// now add tx_1 as onboard transaction (directly to a block, skipping tx pool)
|
||||
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true));
|
||||
events.push_back(tx_1);
|
||||
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false));
|
||||
|
||||
// make sure the block with tx_1 is invalid
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_2b, blk_1, miner_acc, tx_1);
|
||||
|
||||
|
||||
// just one more block to make sure everyting is okay
|
||||
MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,3 +155,8 @@ struct tx_key_image_pool_conflict : public test_chain_unit_enchanced
|
|||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
mutable currency::account_base m_miner_acc;
|
||||
};
|
||||
|
||||
struct tx_version_against_hardfork : public test_chain_unit_enchanced
|
||||
{
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -801,3 +801,126 @@ bool wallet_rpc_exchange_suite::c1(currency::core& c, size_t ev_index, const std
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
wallet_true_rpc_pos_mining::wallet_true_rpc_pos_mining()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(wallet_true_rpc_pos_mining, c1);
|
||||
}
|
||||
|
||||
bool wallet_true_rpc_pos_mining::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
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);
|
||||
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
|
||||
DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
|
||||
|
||||
DO_CALLBACK(events, "c1");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#include <boost/program_options/detail/parsers.hpp>
|
||||
|
||||
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);
|
||||
|
||||
/*currency::t_currency_protocol_handler<currency::core> m_cprotocol(c, nullptr);
|
||||
nodetool::node_server<currency::t_currency_protocol_handler<currency::core> > p2p(m_cprotocol);
|
||||
bc_services::bc_offers_service bos(nullptr);
|
||||
bos.set_disabled(true);
|
||||
currency::core_rpc_server core_rpc_wrapper(c, p2p, bos);
|
||||
core_rpc_wrapper.set_ignore_connectivity_status(true);
|
||||
|
||||
boost::program_options::options_description desc_options;
|
||||
currency::core_rpc_server::init_options(desc_options);
|
||||
boost::program_options::variables_map vm{};
|
||||
char* argv[] = {"--rpc-bind-ip=127.0.0.1", "--rpc-bind-port=33777"};
|
||||
boost::program_options::store(boost::program_options::parse_command_line(sizeof argv / sizeof argv[0], argv, desc_options), vm);
|
||||
r = core_rpc_wrapper.init(vm);
|
||||
CHECK_AND_ASSERT_MES(r, false, "rpc server init failed");
|
||||
r = core_rpc_wrapper.run(1, false);
|
||||
CHECK_AND_ASSERT_MES(r, 1, "rpc server run failed");
|
||||
auto slh = epee::misc_utils::create_scope_leave_handler([&](){
|
||||
core_rpc_wrapper.deinit();
|
||||
});
|
||||
|
||||
|
||||
auto http_core_proxy = std::shared_ptr<tools::i_core_proxy>(new tools::default_http_core_proxy());
|
||||
http_core_proxy->set_connectivity(5000, 1);
|
||||
CHECK_AND_ASSERT_MES(http_core_proxy->set_connection_addr("127.0.0.1:33777"), false, "");
|
||||
CHECK_AND_ASSERT_MES(http_core_proxy->check_connection(), false, "no connection");
|
||||
|
||||
miner_wlt->set_core_proxy(http_core_proxy);*/
|
||||
|
||||
uint64_t top_height = c.get_top_block_height();
|
||||
|
||||
size_t blocks_fetched = 0;
|
||||
miner_wlt->refresh(blocks_fetched);
|
||||
CHECK_AND_ASSERT_EQ(blocks_fetched, top_height);
|
||||
|
||||
alice_wlt->refresh(blocks_fetched);
|
||||
CHECK_AND_ASSERT_EQ(blocks_fetched, top_height);
|
||||
|
||||
//uint64_t balance_unlocked = 1, balance_awaiting_in = 1, balance_awaiting_out = 1, balance_mined = 1;
|
||||
//uint64_t miner_initial_balance = miner_wlt->balance(balance_unlocked, balance_awaiting_in, balance_awaiting_out, balance_mined);
|
||||
//CHECK_AND_ASSERT_EQ(miner_initial_balance, PREMINE_AMOUNT + CURRENCY_BLOCK_REWARD * top_height);
|
||||
uint64_t miner_amount = PREMINE_AMOUNT + CURRENCY_BLOCK_REWARD * top_height;
|
||||
uint64_t expected_unlocked = miner_amount - (CURRENCY_MINED_MONEY_UNLOCK_WINDOW - 1) * COIN;
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*miner_wlt, "miner", miner_amount, INVALID_BALANCE_VAL, expected_unlocked, 0, 0), false, "");
|
||||
|
||||
CHECK_AND_ASSERT_MES(miner_wlt->try_mint_pos(), false, "try_mint_pos failed");
|
||||
|
||||
CHECK_AND_ASSERT_EQ(c.get_top_block_height(), top_height + 1);
|
||||
|
||||
miner_wlt->refresh(blocks_fetched);
|
||||
CHECK_AND_ASSERT_EQ(blocks_fetched, 1);
|
||||
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*miner_wlt, "miner", miner_amount + COIN), false, "");
|
||||
|
||||
uint64_t amount_to_alice = MK_TEST_COINS(500);
|
||||
miner_wlt->transfer(amount_to_alice, m_accounts[ALICE_ACC_IDX].get_public_address());
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "enexpected pool txs count: " << c.get_pool_transactions_count());
|
||||
CHECK_AND_ASSERT_MES(miner_wlt->try_mint_pos(), false, "try_mint_pos failed");
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "enexpected pool txs count: " << c.get_pool_transactions_count());
|
||||
|
||||
miner_wlt->refresh(blocks_fetched);
|
||||
CHECK_AND_ASSERT_EQ(blocks_fetched, 1);
|
||||
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*miner_wlt, "miner", miner_amount + 2 * COIN - amount_to_alice - TESTS_DEFAULT_FEE), false, "");
|
||||
|
||||
// Alice
|
||||
|
||||
//alice_wlt->refresh(blocks_fetched);
|
||||
//CHECK_AND_ASSERT_EQ(blocks_fetched, 2);
|
||||
|
||||
//CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", amount_to_alice, 0, 0, 0, 0), false, "");
|
||||
|
||||
//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_blocks_in_playtime failed");
|
||||
|
||||
//alice_wlt->refresh(blocks_fetched);
|
||||
//CHECK_AND_ASSERT_EQ(blocks_fetched, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
//
|
||||
//CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", amount_to_alice, 0, amount_to_alice, 0, 0), false, "");
|
||||
|
||||
//std::this_thread::yield();
|
||||
//std::this_thread::sleep_for( std::chrono::milliseconds(1) );
|
||||
//CHECK_AND_ASSERT_MES(alice_wlt->try_mint_pos(), false, "try_mint_pos failed");
|
||||
|
||||
//alice_wlt->refresh(blocks_fetched);
|
||||
//CHECK_AND_ASSERT_EQ(blocks_fetched, 1);
|
||||
|
||||
//CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", amount_to_alice + CURRENCY_BLOCK_REWARD, 0, 0, 0, 0), false, "");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,3 +49,9 @@ struct wallet_rpc_exchange_suite : public wallet_test
|
|||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
};
|
||||
|
||||
struct wallet_true_rpc_pos_mining : public wallet_test
|
||||
{
|
||||
wallet_true_rpc_pos_mining();
|
||||
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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -639,8 +639,19 @@ bool gen_wallet_mine_pos_block::c1(currency::core& c, size_t ev_index, const std
|
|||
block top_block = AUTO_VAL_INIT(top_block);
|
||||
bool r = c.get_blockchain_storage().get_top_block(top_block);
|
||||
CHECK_AND_ASSERT_MES(r && is_pos_block(top_block), false, "get_top_block failed or smth goes wrong");
|
||||
uint64_t top_block_reward = get_outs_money_amount(top_block.miner_tx);
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", top_block_reward, top_block_reward - MK_TEST_COINS(2000), 0, 0, 0), false, "");
|
||||
|
||||
uint64_t top_block_reward = 0, expected_mined = 0;
|
||||
if (c.get_blockchain_storage().is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM))
|
||||
{
|
||||
top_block_reward = MK_TEST_COINS(2000) + CURRENCY_BLOCK_REWARD;
|
||||
expected_mined = INVALID_BALANCE_VAL; // Don't check mined balace for post-HF4 due to a lack of mined balance correctness TODO -- sowle
|
||||
}
|
||||
else
|
||||
{
|
||||
top_block_reward = get_outs_money_amount(top_block.miner_tx);
|
||||
expected_mined = top_block_reward - MK_TEST_COINS(2000);
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", top_block_reward, expected_mined, 0, 0, 0), false, "");
|
||||
|
||||
alice_wlt->reset_password(g_wallet_password);
|
||||
alice_wlt->store(g_wallet_filename);
|
||||
|
|
|
|||
|
|
@ -99,3 +99,8 @@ std::shared_ptr<tools::wallet2> wallet_test::init_playtime_test_wallet(const std
|
|||
return init_playtime_test_wallet(events, c, m_accounts[account_index]);
|
||||
}
|
||||
|
||||
std::shared_ptr<tools::wallet2> wallet_test::init_playtime_test_wallet_with_true_http_rpc(const std::vector<test_event_entry>& events, currency::core& c, size_t account_index) const
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(account_index < m_accounts.size(), "Invalid account index");
|
||||
return init_playtime_test_wallet_t<tools::wallet2>(events, c, m_accounts[account_index], true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2024 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.
|
||||
|
||||
#pragma once
|
||||
#include "chaingen.h"
|
||||
#include "currency_protocol/currency_protocol_handler.h"
|
||||
#include "currency_core/currency_core.h"
|
||||
#include "p2p/net_node.h"
|
||||
#include "currency_core/bc_offers_service.h"
|
||||
#include "rpc/core_rpc_server.h"
|
||||
|
||||
struct wallet_test : virtual public test_chain_unit_enchanced
|
||||
{
|
||||
|
|
@ -22,11 +27,33 @@ struct wallet_test : virtual public test_chain_unit_enchanced
|
|||
static std::string get_test_account_name_by_id(size_t acc_id);
|
||||
|
||||
template<typename wallet_t>
|
||||
std::shared_ptr<wallet_t> init_playtime_test_wallet_t(const std::vector<test_event_entry>& events, currency::core& c, const currency::account_base& acc) const
|
||||
std::shared_ptr<wallet_t> init_playtime_test_wallet_t(const std::vector<test_event_entry>& events, currency::core& c, const currency::account_base& acc, bool true_http_rpc = false) const
|
||||
{
|
||||
#define LOCAL_HOST_CSTR "127.0.0.1"
|
||||
#define LOCAL_PORT_CSTR "33777"
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(events.size() > 0 && events[0].type() == typeid(currency::block), "Invalid events queue, can't find genesis block at the beginning");
|
||||
crypto::hash genesis_hash = get_block_hash(boost::get<currency::block>(events[0]));
|
||||
|
||||
if (true_http_rpc)
|
||||
{
|
||||
m_core_proxy = std::make_shared<tools::default_http_core_proxy>();
|
||||
m_core_proxy->set_connectivity(100, 1);
|
||||
CHECK_AND_ASSERT_THROW_MES(m_core_proxy->set_connection_addr(LOCAL_HOST_CSTR ":" LOCAL_PORT_CSTR), "set_connection_addr failed");
|
||||
if (!m_core_proxy->check_connection())
|
||||
{
|
||||
// if there's not http rpc core server yet, create one
|
||||
boost::program_options::options_description desc_options;
|
||||
currency::core_rpc_server::init_options(desc_options);
|
||||
boost::program_options::variables_map vm{};
|
||||
const char* const argv[] = {"--rpc-bind-ip=" LOCAL_HOST_CSTR, "--rpc-bind-port=" LOCAL_PORT_CSTR};
|
||||
boost::program_options::store(boost::program_options::parse_command_line(sizeof argv / sizeof argv[0], argv, desc_options), vm);
|
||||
m_http_rpc_server = std::make_shared<core_http_rpc_server_details>(c, vm);
|
||||
}
|
||||
m_core_proxy->set_connectivity(30000, 1);
|
||||
CHECK_AND_ASSERT_THROW_MES(m_core_proxy->check_connection(), "m_core_proxy: no connection");
|
||||
}
|
||||
|
||||
std::shared_ptr<wallet_t> w(new wallet_t);
|
||||
w->set_core_runtime_config(c.get_blockchain_storage().get_core_runtime_config());
|
||||
w->assign_account(acc);
|
||||
|
|
@ -34,6 +61,9 @@ struct wallet_test : virtual public test_chain_unit_enchanced
|
|||
w->set_core_proxy(m_core_proxy);
|
||||
w->set_disable_tor_relay(true);
|
||||
return w;
|
||||
|
||||
#undef LOCAL_HOST_CSTR
|
||||
#undef LOCAL_PORT_CSTR
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -64,12 +94,42 @@ protected:
|
|||
size_t account_index;
|
||||
};
|
||||
|
||||
struct core_http_rpc_server_details
|
||||
{
|
||||
currency::t_currency_protocol_handler<currency::core> cph;
|
||||
nodetool::node_server<currency::t_currency_protocol_handler<currency::core> > p2p;
|
||||
bc_services::bc_offers_service bos;
|
||||
currency::core_rpc_server core_rpc_server;
|
||||
|
||||
core_http_rpc_server_details(currency::core& c, const boost::program_options::variables_map& vm)
|
||||
: cph(c, nullptr)
|
||||
, p2p(cph)
|
||||
, bos(nullptr)
|
||||
, core_rpc_server(c, p2p, bos)
|
||||
{
|
||||
bos.set_disabled(true);
|
||||
core_rpc_server.set_ignore_connectivity_status(true);
|
||||
|
||||
bool r = core_rpc_server.init(vm);
|
||||
CRYPTO_CHECK_AND_THROW_MES(r, "core_http_rpc_server_details: rpc server init failed");
|
||||
r = core_rpc_server.run(2, false);
|
||||
CRYPTO_CHECK_AND_THROW_MES(r, "core_http_rpc_server_details: rpc server run failed");
|
||||
}
|
||||
|
||||
~core_http_rpc_server_details()
|
||||
{
|
||||
core_rpc_server.deinit();
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<tools::wallet2> init_playtime_test_wallet(const std::vector<test_event_entry>& events, currency::core& c, size_t account_index) const;
|
||||
std::shared_ptr<tools::wallet2> init_playtime_test_wallet(const std::vector<test_event_entry>& events, currency::core& c, const currency::account_base& acc) const;
|
||||
std::shared_ptr<tools::wallet2> init_playtime_test_wallet_with_true_http_rpc(const std::vector<test_event_entry>& events, currency::core& c, size_t account_index) const;
|
||||
|
||||
mutable std::vector<currency::account_base> m_accounts;
|
||||
mutable test_generator generator;
|
||||
std::shared_ptr<tools::i_core_proxy> m_core_proxy;
|
||||
mutable std::shared_ptr<tools::i_core_proxy> m_core_proxy;
|
||||
mutable std::shared_ptr<core_http_rpc_server_details> m_http_rpc_server; // "True" RPC via http on localhost
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "crypto/range_proofs.h"
|
||||
#include "../core_tests/random_helper.h"
|
||||
#include "crypto_torsion_elements.h"
|
||||
#include "crypto/eth_signature.h"
|
||||
|
||||
using namespace crypto;
|
||||
|
||||
|
|
@ -1896,6 +1897,93 @@ TEST(crypto, generators_precomp)
|
|||
#undef CHECK_PRECOMP
|
||||
}
|
||||
|
||||
#include "bitcoin-secp256k1/include/secp256k1.h"
|
||||
TEST(crypto, secp256k1_ecdsa_native)
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
uint8_t randomness[32];
|
||||
crypto::generate_random_bytes(sizeof randomness, randomness);
|
||||
secp256k1_context_randomize(ctx, randomness);
|
||||
|
||||
uint8_t seckey[32] = {};
|
||||
while(true)
|
||||
{
|
||||
crypto::generate_random_bytes(sizeof seckey, seckey);
|
||||
if (secp256k1_ec_seckey_verify(ctx, seckey))
|
||||
break;
|
||||
}
|
||||
|
||||
secp256k1_pubkey pubkey{};
|
||||
ASSERT_TRUE(secp256k1_ec_pubkey_create(ctx, &pubkey, seckey));
|
||||
|
||||
uint8_t compressed_pubkey[33] = {};
|
||||
size_t output_len = sizeof compressed_pubkey;
|
||||
ASSERT_TRUE(secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey, &output_len, &pubkey, SECP256K1_EC_COMPRESSED));
|
||||
ASSERT_TRUE(output_len == sizeof compressed_pubkey);
|
||||
|
||||
|
||||
secp256k1_ecdsa_signature secp256k1_ecdsa_sig{};
|
||||
hash msg_hash = hash_helper_t::h("message");
|
||||
ASSERT_TRUE(secp256k1_ecdsa_sign(ctx, &secp256k1_ecdsa_sig, (const unsigned char*)&msg_hash, seckey, NULL, NULL));
|
||||
|
||||
// Serialize the signature in a compact form.
|
||||
unsigned char secp256k1_ecdsa_sig_serialized[64] = {};
|
||||
ASSERT_TRUE(secp256k1_ecdsa_signature_serialize_compact(ctx, secp256k1_ecdsa_sig_serialized, &secp256k1_ecdsa_sig));
|
||||
|
||||
//
|
||||
// Verification
|
||||
//
|
||||
|
||||
secp256k1_ecdsa_sig = secp256k1_ecdsa_signature{};
|
||||
pubkey = secp256k1_pubkey{};
|
||||
|
||||
// Deserialize the signature.
|
||||
ASSERT_TRUE(secp256k1_ecdsa_signature_parse_compact(ctx, &secp256k1_ecdsa_sig, secp256k1_ecdsa_sig_serialized));
|
||||
|
||||
// Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */
|
||||
ASSERT_TRUE(secp256k1_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey)));
|
||||
|
||||
// verify a signature
|
||||
ASSERT_TRUE(secp256k1_ecdsa_verify(ctx, &secp256k1_ecdsa_sig, (const unsigned char*)&msg_hash, &pubkey));
|
||||
|
||||
// verify using a static context
|
||||
ASSERT_TRUE(secp256k1_ecdsa_verify(secp256k1_context_static, &secp256k1_ecdsa_sig, (const unsigned char*)&msg_hash, &pubkey));
|
||||
|
||||
|
||||
// Epilogue
|
||||
secp256k1_context_destroy(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
TEST(crypto, eth_signature_basics)
|
||||
{
|
||||
eth_secret_key sk{};
|
||||
eth_public_key pk{};
|
||||
|
||||
ASSERT_TRUE(generate_eth_key_pair(sk, pk));
|
||||
|
||||
eth_signature sig{};
|
||||
hash m = hash_helper_t::h("How many of you have ever felt personally victimized by elliptic curves?");
|
||||
|
||||
ASSERT_TRUE(generate_eth_signature(m, sk, sig));
|
||||
|
||||
const eth_signature const_sig = sig;
|
||||
ASSERT_TRUE(verify_eth_signature(m, pk, const_sig));
|
||||
|
||||
for(size_t i = 0; i < sizeof sig; ++i)
|
||||
{
|
||||
eth_signature bad_sig = sig;
|
||||
bad_sig.data[i] ^= 1 + (rand() % 254); // xor with a number fom [1; 255] to make sure this byte will change
|
||||
ASSERT_FALSE(verify_eth_signature(m, pk, bad_sig));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -312,139 +312,139 @@ TEST(decompose_amount_randomly, 1)
|
|||
TEST(print_money_brief, 1)
|
||||
{
|
||||
// decimal point 12 (default)
|
||||
ASSERT_EQ(print_money_brief( 0), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1), "0.000000000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000), "1.0");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000), "1.9");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000), "1.0000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001), "1.000000000001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999), "9.999999999999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900), "90.0099900099");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000), "10109010.0");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000), "10109010.01");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610), "18446744.07370955161");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614), "18446744.073709551614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615), "18446744.073709551615");
|
||||
ASSERT_EQ(print_money_brief( 0ull), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1ull), "0.000000000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000ull), "1.0");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000ull), "1.9");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000ull), "1.0000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001ull), "1.000000000001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999ull), "9.999999999999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900ull), "90.0099900099");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000ull), "10109010.0");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000ull), "10109010.01");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610ull), "18446744.07370955161");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614ull), "18446744.073709551614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615ull), "18446744.073709551615");
|
||||
|
||||
// decimal point 0
|
||||
ASSERT_EQ(print_money_brief( 0, 0), "0");
|
||||
ASSERT_EQ(print_money_brief( 1, 0), "1");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000, 0), "1000000000000");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000, 0), "1900000000000");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000, 0), "1000000100000");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001, 0), "1000000000001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999, 0), "9999999999999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900, 0), "90009990009900");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000, 0), "10109010000000000000");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000, 0), "10109010010000000000");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610, 0), "18446744073709551610");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614, 0), "18446744073709551614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615, 0), "18446744073709551615");
|
||||
ASSERT_EQ(print_money_brief( 0ull, 0), "0");
|
||||
ASSERT_EQ(print_money_brief( 1ull, 0), "1");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000ull, 0), "1000000000000");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000ull, 0), "1900000000000");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000ull, 0), "1000000100000");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001ull, 0), "1000000000001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999ull, 0), "9999999999999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900ull, 0), "90009990009900");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000ull, 0), "10109010000000000000");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000ull, 0), "10109010010000000000");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610ull, 0), "18446744073709551610");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614ull, 0), "18446744073709551614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615ull, 0), "18446744073709551615");
|
||||
|
||||
// decimal point 1
|
||||
ASSERT_EQ(print_money_brief( 0, 1), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1, 1), "0.1");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000, 1), "100000000000.0");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000, 1), "190000000000.0");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000, 1), "100000010000.0");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001, 1), "100000000000.1");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999, 1), "999999999999.9");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900, 1), "9000999000990.0");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000, 1), "1010901000000000000.0");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000, 1), "1010901001000000000.0");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610, 1), "1844674407370955161.0");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614, 1), "1844674407370955161.4");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615, 1), "1844674407370955161.5");
|
||||
ASSERT_EQ(print_money_brief( 0ull, 1), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1ull, 1), "0.1");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000ull, 1), "100000000000.0");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000ull, 1), "190000000000.0");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000ull, 1), "100000010000.0");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001ull, 1), "100000000000.1");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999ull, 1), "999999999999.9");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900ull, 1), "9000999000990.0");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000ull, 1), "1010901000000000000.0");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000ull, 1), "1010901001000000000.0");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610ull, 1), "1844674407370955161.0");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614ull, 1), "1844674407370955161.4");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615ull, 1), "1844674407370955161.5");
|
||||
|
||||
// decimal point 2
|
||||
ASSERT_EQ(print_money_brief( 0, 2), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1, 2), "0.01");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000, 2), "10000000000.0");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000, 2), "19000000000.0");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000, 2), "10000001000.0");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001, 2), "10000000000.01");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999, 2), "99999999999.99");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900, 2), "900099900099.0");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000, 2), "101090100000000000.0");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000, 2), "101090100100000000.0");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610, 2), "184467440737095516.1");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614, 2), "184467440737095516.14");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615, 2), "184467440737095516.15");
|
||||
ASSERT_EQ(print_money_brief( 0ull, 2), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1ull, 2), "0.01");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000ull, 2), "10000000000.0");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000ull, 2), "19000000000.0");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000ull, 2), "10000001000.0");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001ull, 2), "10000000000.01");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999ull, 2), "99999999999.99");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900ull, 2), "900099900099.0");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000ull, 2), "101090100000000000.0");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000ull, 2), "101090100100000000.0");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610ull, 2), "184467440737095516.1");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614ull, 2), "184467440737095516.14");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615ull, 2), "184467440737095516.15");
|
||||
|
||||
// decimal point 3
|
||||
ASSERT_EQ(print_money_brief( 0, 3), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1, 3), "0.001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000, 3), "1000000000.0");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000, 3), "1900000000.0");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000, 3), "1000000100.0");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001, 3), "1000000000.001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999, 3), "9999999999.999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900, 3), "90009990009.9");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000, 3), "10109010000000000.0");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000, 3), "10109010010000000.0");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610, 3), "18446744073709551.61");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614, 3), "18446744073709551.614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615, 3), "18446744073709551.615");
|
||||
ASSERT_EQ(print_money_brief( 0ull, 3), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1ull, 3), "0.001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000ull, 3), "1000000000.0");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000ull, 3), "1900000000.0");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000ull, 3), "1000000100.0");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001ull, 3), "1000000000.001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999ull, 3), "9999999999.999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900ull, 3), "90009990009.9");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000ull, 3), "10109010000000000.0");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000ull, 3), "10109010010000000.0");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610ull, 3), "18446744073709551.61");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614ull, 3), "18446744073709551.614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615ull, 3), "18446744073709551.615");
|
||||
|
||||
// decimal point 18
|
||||
ASSERT_EQ(print_money_brief( 0, 18), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1, 18), "0.000000000000000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000, 18), "0.000001");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000, 18), "0.0000019");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000, 18), "0.0000010000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001, 18), "0.000001000000000001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999, 18), "0.000009999999999999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900, 18), "0.0000900099900099");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000, 18), "10.10901");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000, 18), "10.10901001");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610, 18), "18.44674407370955161");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614, 18), "18.446744073709551614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615, 18), "18.446744073709551615");
|
||||
ASSERT_EQ(print_money_brief( 0ull, 18), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1ull, 18), "0.000000000000000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000ull, 18), "0.000001");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000ull, 18), "0.0000019");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000ull, 18), "0.0000010000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001ull, 18), "0.000001000000000001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999ull, 18), "0.000009999999999999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900ull, 18), "0.0000900099900099");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000ull, 18), "10.10901");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000ull, 18), "10.10901001");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610ull, 18), "18.44674407370955161");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614ull, 18), "18.446744073709551614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615ull, 18), "18.446744073709551615");
|
||||
|
||||
// decimal point 19
|
||||
ASSERT_EQ(print_money_brief( 0, 19), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1, 19), "0.0000000000000000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000, 19), "0.0000001");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000, 19), "0.00000019");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000, 19), "0.00000010000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001, 19), "0.0000001000000000001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999, 19), "0.0000009999999999999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900, 19), "0.00000900099900099");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000, 19), "1.010901");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000, 19), "1.010901001");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610, 19), "1.844674407370955161");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614, 19), "1.8446744073709551614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615, 19), "1.8446744073709551615");
|
||||
ASSERT_EQ(print_money_brief( 0ull, 19), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1ull, 19), "0.0000000000000000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000ull, 19), "0.0000001");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000ull, 19), "0.00000019");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000ull, 19), "0.00000010000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001ull, 19), "0.0000001000000000001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999ull, 19), "0.0000009999999999999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900ull, 19), "0.00000900099900099");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000ull, 19), "1.010901");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000ull, 19), "1.010901001");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610ull, 19), "1.844674407370955161");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614ull, 19), "1.8446744073709551614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615ull, 19), "1.8446744073709551615");
|
||||
|
||||
// TODO: remove it after setting reasonable limit of 18
|
||||
// decimal point 20
|
||||
ASSERT_EQ(print_money_brief( 0, 20), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1, 20), "0.00000000000000000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000, 20), "0.00000001");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000, 20), "0.000000019");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000, 20), "0.000000010000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001, 20), "0.00000001000000000001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999, 20), "0.00000009999999999999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900, 20), "0.000000900099900099");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000, 20), "0.1010901");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000, 20), "0.1010901001");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610, 20), "0.1844674407370955161");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614, 20), "0.18446744073709551614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615, 20), "0.18446744073709551615");
|
||||
ASSERT_EQ(print_money_brief( 0ull, 20), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1ull, 20), "0.00000000000000000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000ull, 20), "0.00000001");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000ull, 20), "0.000000019");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000ull, 20), "0.000000010000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001ull, 20), "0.00000001000000000001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999ull, 20), "0.00000009999999999999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900ull, 20), "0.000000900099900099");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000ull, 20), "0.1010901");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000ull, 20), "0.1010901001");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610ull, 20), "0.1844674407370955161");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614ull, 20), "0.18446744073709551614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615ull, 20), "0.18446744073709551615");
|
||||
|
||||
// TODO: remove it after setting reasonable limit of 18
|
||||
// decimal point 21
|
||||
ASSERT_EQ(print_money_brief( 0, 21), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1, 21), "0.000000000000000000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000, 21), "0.000000001");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000, 21), "0.0000000019");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000, 21), "0.0000000010000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001, 21), "0.000000001000000000001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999, 21), "0.000000009999999999999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900, 21), "0.0000000900099900099");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000, 21), "0.01010901");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000, 21), "0.01010901001");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610, 21), "0.01844674407370955161");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614, 21), "0.018446744073709551614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615, 21), "0.018446744073709551615");
|
||||
ASSERT_EQ(print_money_brief( 0ull, 21), "0.0");
|
||||
ASSERT_EQ(print_money_brief( 1ull, 21), "0.000000000000000000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000000ull, 21), "0.000000001");
|
||||
ASSERT_EQ(print_money_brief( 1900000000000ull, 21), "0.0000000019");
|
||||
ASSERT_EQ(print_money_brief( 1000000100000ull, 21), "0.0000000010000001");
|
||||
ASSERT_EQ(print_money_brief( 1000000000001ull, 21), "0.000000001000000000001");
|
||||
ASSERT_EQ(print_money_brief( 9999999999999ull, 21), "0.000000009999999999999");
|
||||
ASSERT_EQ(print_money_brief( 90009990009900ull, 21), "0.0000000900099900099");
|
||||
ASSERT_EQ(print_money_brief(10109010000000000000ull, 21), "0.01010901");
|
||||
ASSERT_EQ(print_money_brief(10109010010000000000ull, 21), "0.01010901001");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551610ull, 21), "0.01844674407370955161");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551614ull, 21), "0.018446744073709551614");
|
||||
ASSERT_EQ(print_money_brief(18446744073709551615ull, 21), "0.018446744073709551615");
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -26,14 +26,20 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
#define TEST_pos(int_type, expected, str) \
|
||||
TEST(get_xtype_from_string, handles_pos_ ## int_type ## _ ## expected) \
|
||||
{ \
|
||||
do_pos_test<int_type>(expected, str); \
|
||||
}
|
||||
#define MAKE_TEST_NAME(prefix, int_type, ln, test_type) \
|
||||
test_type ## _ ## prefix ## _ ## int_type ## _ ## ln
|
||||
|
||||
#define DO_MAKE_NEG_TEST_NAME(prefix, int_type, ln) prefix ## int_type ## _ ## ln
|
||||
#define MAKE_NEG_TEST_NAME(prefix, int_type, ln) DO_MAKE_NEG_TEST_NAME(prefix, int_type, ln)
|
||||
#define MAKE_POS_TEST_NAME(prefix, int_type, ln) \
|
||||
MAKE_TEST_NAME(prefix, int_type, ln, POS)
|
||||
|
||||
#define MAKE_NEG_TEST_NAME(prefix, int_type, ln) \
|
||||
MAKE_TEST_NAME(prefix, int_type, ln, NEG)
|
||||
|
||||
#define TEST_pos(int_type, expected, str) \
|
||||
TEST(get_xtype_from_string, MAKE_POS_TEST_NAME(handles_pos, int_type, __LINE__)) \
|
||||
{ \
|
||||
do_pos_test<int_type>(expected, str); \
|
||||
}
|
||||
|
||||
#define TEST_neg(int_type, str) \
|
||||
TEST(get_xtype_from_string, MAKE_NEG_TEST_NAME(handles_neg, int_type, __LINE__)) \
|
||||
|
|
@ -134,3 +140,31 @@ TEST_neg(uint64_t, "1w1");
|
|||
TEST_neg(uint64_t, "18446744073709551615w");
|
||||
|
||||
TEST_neg(uint64_t, "18446744073709551616");
|
||||
|
||||
TEST_pos(int16_t, 32'767, "32767"); // 2^15 - 1
|
||||
TEST_pos(int16_t, -32'768, "-32768"); // -2^15
|
||||
TEST_pos(int16_t, 0, "-0");
|
||||
TEST_pos(int16_t, 0, "+0");
|
||||
|
||||
TEST_neg(int16_t, "32768"); // 2^15
|
||||
TEST_neg(int16_t, "+32768"); // 2^15
|
||||
TEST_neg(int16_t, "-32769"); // -2^15 - 1
|
||||
TEST_neg(int16_t, "");
|
||||
|
||||
TEST_pos(int32_t, 2'147'483'647, "2147483647"); // 2^31 - 1
|
||||
TEST_pos(int32_t, -2'147'483'648, "-2147483648"); // -2^31
|
||||
TEST_pos(int32_t, 0, "-0");
|
||||
TEST_pos(int32_t, 0, "+0");
|
||||
|
||||
TEST_neg(int32_t, "-2147483649");
|
||||
TEST_neg(int32_t, "2147483648");
|
||||
TEST_neg(int32_t, "");
|
||||
|
||||
TEST_pos(int64_t, 9'223'372'036'854'775'807LL, "9223372036854775807"); // 2^63 - 1
|
||||
TEST_pos(int64_t, -9'223'372'036'854'775'807LL - 1LL, "-9223372036854775808"); // -2^63
|
||||
TEST_pos(int64_t, 0LL, "-0");
|
||||
TEST_pos(int64_t, 0LL, "+0");
|
||||
|
||||
TEST_neg(int64_t, "-9223372036854775809"); // -2^63 - 1
|
||||
TEST_neg(int64_t, "9223372036854775808"); // 2^63
|
||||
TEST_neg(int64_t, "");
|
||||
|
|
|
|||
1314
tests/unit_tests/multiassets_test.cpp
Normal file
1314
tests/unit_tests/multiassets_test.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -5,6 +5,24 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include "common/util.h"
|
||||
|
||||
bool check_parse_client_version(const std::string& str, int expected_major, int expected_minor, int expected_revision, int expected_build_number, const std::string& expected_commit_id, bool expected_dirty)
|
||||
{
|
||||
int major = -1, minor = -1, revision = -1, build_number = -1;
|
||||
std::string commit_id;
|
||||
bool dirty = false;
|
||||
if (!tools::parse_client_version(str, major, minor, revision, build_number, commit_id, dirty))
|
||||
return false;
|
||||
|
||||
return major == expected_major && minor == expected_minor && revision == expected_revision && build_number == expected_build_number && commit_id == expected_commit_id && dirty == expected_dirty;
|
||||
}
|
||||
|
||||
|
||||
TEST(p2p_client_version, test_0)
|
||||
{
|
||||
ASSERT_TRUE(check_parse_client_version("10.101.999.28391[deadbeef31337-dirty]", 10, 101, 999, 28391, "deadbeef31337", true));
|
||||
}
|
||||
|
||||
|
||||
TEST(p2p_client_version, test_1)
|
||||
{
|
||||
using namespace tools;
|
||||
|
|
|
|||
|
|
@ -757,30 +757,30 @@ struct A
|
|||
struct A_v1 : public A
|
||||
{
|
||||
std::vector<std::string> vector_two;
|
||||
|
||||
uint8_t current_version = 1;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(one)
|
||||
FIELD(two)
|
||||
FIELD(vector_one)
|
||||
VERSION(1)
|
||||
if (s_version < 1) return true;
|
||||
VERSION_TO_MEMBER(1, current_version)
|
||||
FIELD(vector_two)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
||||
struct A_v2 : public A_v1
|
||||
{
|
||||
std::vector<std::string> vector_3;
|
||||
std::vector<std::string> vector_4;
|
||||
|
||||
uint8_t current_version = 2;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
//CURRENT_VERSION(2)
|
||||
FIELD(one)
|
||||
FIELD(two)
|
||||
FIELD(vector_one)
|
||||
VERSION(2)
|
||||
VERSION_TO_MEMBER(2, current_version)
|
||||
if (s_version < 1) return true;
|
||||
FIELD(vector_two)
|
||||
if (s_version < 2) return true;
|
||||
|
|
@ -792,13 +792,14 @@ struct A_v2 : public A_v1
|
|||
struct A_v3 : public A_v2
|
||||
{
|
||||
std::vector<std::string> vector_5;
|
||||
uint8_t current_version = 3;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
//CURRENT_VERSION(3)
|
||||
FIELD(one)
|
||||
FIELD(two)
|
||||
FIELD(vector_one)
|
||||
VERSION(3)
|
||||
VERSION_TO_MEMBER(3, current_version)
|
||||
if (s_version < 1) return true;
|
||||
FIELD(vector_two)
|
||||
if (s_version < 2) return true;
|
||||
|
|
|
|||
|
|
@ -2,10 +2,13 @@
|
|||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <exception>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "currency_core/account.h"
|
||||
#include "currency_core/currency_format_utils.h"
|
||||
|
||||
TEST(wallet_seed, store_restore_test)
|
||||
{
|
||||
|
|
@ -211,3 +214,151 @@ TEST(wallet_seed, basic_test)
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
TEST(wallet_seed, word_from_timestamp)
|
||||
{
|
||||
//timestamp = 0; use_password = false
|
||||
ASSERT_EQ("like", currency::get_word_from_timestamp(0, false));
|
||||
|
||||
// timestamp = 0; use_password = true
|
||||
ASSERT_EQ("among", currency::get_word_from_timestamp(0, true));
|
||||
|
||||
// timestamp = WALLET_BRAIN_DATE_OFFSET = 1543622400; use_password = false
|
||||
ASSERT_EQ("like", currency::get_word_from_timestamp(1543622400, false));
|
||||
|
||||
// timestamp = WALLET_BRAIN_DATE_OFFSET = 1543622400; use_password = true
|
||||
ASSERT_EQ("among", currency::get_word_from_timestamp(1543622400, true));
|
||||
|
||||
// timestamp = WALLET_BRAIN_DATE_OFFSET - 1 = 1543622399; use_password = false
|
||||
ASSERT_EQ("like", currency::get_word_from_timestamp(1543622399, false));
|
||||
|
||||
// timestamp = WALLET_BRAIN_DATE_OFFSET + 1 = 1543622401; use_password = false
|
||||
ASSERT_EQ("like", currency::get_word_from_timestamp(1543622401, false));
|
||||
|
||||
// timestamp = WALLET_BRAIN_DATE_OFFSET + 1 = 1543622401; use_password = true
|
||||
ASSERT_EQ("among", currency::get_word_from_timestamp(1543622401, true));
|
||||
|
||||
/*
|
||||
Values get_word_from_timestamp(1, true),
|
||||
get_word_from_timestamp(1543622401, true) must be equal.
|
||||
*/
|
||||
|
||||
ASSERT_EQ("among", currency::get_word_from_timestamp(1, true));
|
||||
ASSERT_EQ(currency::get_word_from_timestamp(1, true),
|
||||
currency::get_word_from_timestamp(1543622401, true));
|
||||
|
||||
/*
|
||||
2027462399 is the largest timestamp argument value under which the
|
||||
inequality weeks_count < WALLET_BRAIN_DATE_MAX_WEEKS_COUNT is satisfied.
|
||||
|
||||
timestamp = 2027462399
|
||||
date_offset = timestamp - WALLET_BRAIN_DATE_OFFSET = 483839999
|
||||
weeks_count = date_offset / WALLET_BRAIN_DATE_QUANTUM = 799
|
||||
WALLET_BRAIN_DATE_MAX_WEEKS_COUNT = 800
|
||||
WALLET_BRAIN_DATE_QUANTUM = 604800
|
||||
|
||||
floor(483839999 / 604800) = 799
|
||||
floor(483840000 / 604800) = 800
|
||||
*/
|
||||
|
||||
// weeks_count_32 = 799; wordsArray[799] = "ugly"
|
||||
ASSERT_EQ("ugly", currency::get_word_from_timestamp(2027462399, false));
|
||||
|
||||
// weeks_count_32 = 799 + 800 = 1599; wordsArray[1599] = "moan"
|
||||
ASSERT_EQ("moan", currency::get_word_from_timestamp(2027462399, true));
|
||||
|
||||
/*
|
||||
If you pass values >= 2027462399 + 1, then the inequality
|
||||
weeks_count < WALLET_BRAIN_DATE_MAX_WEEKS_COUNT is not satisfied. The
|
||||
function throws an exception.
|
||||
*/
|
||||
|
||||
EXPECT_THROW(currency::get_word_from_timestamp(2027462400, false),
|
||||
std::runtime_error);
|
||||
|
||||
EXPECT_THROW(currency::get_word_from_timestamp(2027462400, true),
|
||||
std::runtime_error);
|
||||
}
|
||||
|
||||
TEST(wallet_seed, timestamp_from_word)
|
||||
{
|
||||
{
|
||||
// WALLET_BRAIN_DATE_OFFSET = 1543622400
|
||||
|
||||
{
|
||||
bool password_used{false};
|
||||
|
||||
ASSERT_EQ(1543622400,
|
||||
currency::get_timestamp_from_word("like", password_used));
|
||||
ASSERT_FALSE(password_used);
|
||||
}
|
||||
|
||||
{
|
||||
bool password_used{true};
|
||||
|
||||
ASSERT_EQ(1543622400,
|
||||
currency::get_timestamp_from_word("like", password_used));
|
||||
ASSERT_FALSE(password_used);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// WALLET_BRAIN_DATE_OFFSET = 1543622400
|
||||
|
||||
{
|
||||
bool password_used{true};
|
||||
|
||||
ASSERT_EQ(1543622400,
|
||||
currency::get_timestamp_from_word("among", password_used));
|
||||
ASSERT_TRUE(password_used);
|
||||
}
|
||||
|
||||
{
|
||||
bool password_used{false};
|
||||
|
||||
ASSERT_EQ(1543622400,
|
||||
currency::get_timestamp_from_word("among", password_used));
|
||||
ASSERT_TRUE(password_used);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// (1625 - 800) * 604800 + 1543622400 = 2042582400
|
||||
|
||||
{
|
||||
bool password_used{false};
|
||||
|
||||
ASSERT_EQ(2026857600,
|
||||
currency::get_timestamp_from_word("ugly", password_used));
|
||||
ASSERT_FALSE(password_used);
|
||||
}
|
||||
|
||||
{
|
||||
bool password_used{true};
|
||||
|
||||
ASSERT_EQ(2026857600,
|
||||
currency::get_timestamp_from_word("ugly", password_used));
|
||||
ASSERT_FALSE(password_used);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// (1625 - 800) * 604800 + 1543622400 = 2042582400
|
||||
|
||||
{
|
||||
bool password_used{false};
|
||||
|
||||
ASSERT_EQ(2042582400,
|
||||
currency::get_timestamp_from_word("weary", password_used));
|
||||
ASSERT_TRUE(password_used);
|
||||
}
|
||||
|
||||
{
|
||||
bool password_used{true};
|
||||
|
||||
ASSERT_EQ(2042582400,
|
||||
currency::get_timestamp_from_word("weary", password_used));
|
||||
ASSERT_TRUE(password_used);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue