forked from lthn/blockchain
Merge branch 'develop' into concise
# Conflicts: # src/wallet/wallet2.cpp # src/wallet/wallet2_base.h
This commit is contained in:
commit
3a6e0c0f2f
77 changed files with 3750 additions and 434 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
//
|
||||
|
||||
#pragma once
|
||||
#include <type_traits>
|
||||
#include <optional>
|
||||
#include "misc_language.h"
|
||||
namespace epee
|
||||
{
|
||||
|
|
@ -51,24 +53,73 @@ namespace epee
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_std_optional : std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct is_std_optional<std::optional<T>> : std::true_type {};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_std_optional<boost::optional<T>> : std::true_type {};
|
||||
|
||||
|
||||
//basic helpers for pod-to-hex serialization
|
||||
template<class t_pod_type>
|
||||
std::string transform_t_pod_to_str_internal(const t_pod_type& a)
|
||||
{
|
||||
return epee::string_tools::pod_to_hex(a);
|
||||
}
|
||||
|
||||
template<class t_pod_type>
|
||||
std::string transform_t_pod_to_str_internal(const std::optional<t_pod_type>& a)
|
||||
{
|
||||
if (a.has_value())
|
||||
return epee::string_tools::pod_to_hex(*a);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
template<class t_pod_type>
|
||||
std::string transform_t_pod_to_str_internal(const boost::optional<t_pod_type>& a)
|
||||
{
|
||||
if (a.has_value())
|
||||
return epee::string_tools::pod_to_hex(*a);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
//basic helpers for pod-to-hex serialization
|
||||
template<class t_pod_type>
|
||||
std::string transform_t_pod_to_str(const t_pod_type & a)
|
||||
{
|
||||
return epee::string_tools::pod_to_hex(a);
|
||||
return transform_t_pod_to_str_internal(a);
|
||||
}
|
||||
template<class t_pod_type>
|
||||
|
||||
|
||||
|
||||
template<class t_pod_type>
|
||||
t_pod_type transform_str_to_t_pod(const std::string& a)
|
||||
{
|
||||
t_pod_type res = AUTO_VAL_INIT(res);
|
||||
t_pod_type res = AUTO_VAL_INIT(res);
|
||||
if (a.empty())
|
||||
return res;
|
||||
if constexpr (is_std_optional<t_pod_type>::value)
|
||||
{
|
||||
typename t_pod_type::value_type v = AUTO_VAL_INIT(v);
|
||||
if (!epee::string_tools::hex_to_pod(a, v))
|
||||
throw std::runtime_error(std::string("Unable to transform \"") + a + "\" to pod type " + typeid(typename t_pod_type::value_type).name());
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
if (!epee::string_tools::hex_to_pod(a, res))
|
||||
throw std::runtime_error(std::string("Unable to transform \"") + a + "\" to pod type " + typeid(t_pod_type).name());
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//basic helpers for blob-to-hex serialization
|
||||
|
||||
inline std::string transform_binbuf_to_hexstr(const std::string& a)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ namespace tools
|
|||
};
|
||||
|
||||
#ifndef TESTNET
|
||||
static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2500000.pak", "8ffa2cb4213f4f96f97033c65a9e52bc350f683237808597784e79b24d5bfee7", 3242348793, 5905489920 };
|
||||
static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2500000.pak", "5509650e12c8f901e6731a2bfaf3abfd64409e3e1366d3d94cd11db8beddb0c3", 4239505801, 5893566464 };
|
||||
static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2829200.pak", "ea874a67934f22d500658fe603f6a25e85f6a64c51669ae78bf9e1c5be6d6d87", 5824475897, 9663528960 };
|
||||
static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2829200.pak", "d8d50c2aa832ed4ae8ca00ef9a0de0eb72a402791ebf8b3f64e546036879545e", 7204761982, 9414295552 };
|
||||
#else
|
||||
static constexpr pre_download_entry c_pre_download_mdbx = { "", "", 0, 0 };
|
||||
static constexpr pre_download_entry c_pre_download_lmdb = { "", "", 0, 0 };
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
166
src/crypto/eth_signature.cpp
Normal file
166
src/crypto/eth_signature.cpp
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
// 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);
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& o, const eth_signature& v)
|
||||
{
|
||||
return o << epee::string_tools::pod_to_hex(v);
|
||||
}
|
||||
|
||||
|
||||
} // namespace crypto
|
||||
67
src/crypto/eth_signature.h
Normal file
67
src/crypto/eth_signature.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// 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);
|
||||
std::ostream& operator<<(std::ostream& o, const eth_signature& v);
|
||||
|
||||
} // namespace crypto
|
||||
|
|
@ -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,16 +71,23 @@ 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);
|
||||
|
|
@ -92,7 +99,7 @@ namespace currency
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -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,38 @@ 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");
|
||||
if (!crypto::verify_eth_signature(avc.tx_id, last_ado.descriptor.owner_eth_pub_key.value(), aoop_eth.eth_sig))
|
||||
{
|
||||
LOG_ERROR("Failed to validate secp256k1 signature for hash: " << avc.tx_id << ", signature: " << aoop_eth.eth_sig);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 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 +4145,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 +4158,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 +5825,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 +5955,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_POD_AS_HEX_STRING(owner_eth_pub_key) DOC_DSCR("[Optional] Owner's key in the case when ETH signature is used.") DOC_END
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
@ -840,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
|
||||
|
|
@ -943,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
|
||||
|
|
@ -1202,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
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -258,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{};
|
||||
|
|
@ -2194,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)
|
||||
|
|
@ -2246,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");
|
||||
|
||||
|
|
@ -2335,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;
|
||||
}
|
||||
|
|
@ -2603,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);
|
||||
|
|
@ -2717,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;
|
||||
|
|
@ -2773,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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,13 +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
|
||||
{
|
||||
|
||||
|
|
@ -96,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;
|
||||
|
|
@ -110,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
|
||||
|
|
@ -129,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;
|
||||
|
|
@ -989,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);
|
||||
|
|
@ -1003,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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 748e8e96d8f2653e6e698a11f67c172c1f84c2b2
|
||||
Subproject commit 5c878005ace55484eafe2985d204cd51e90b203b
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
@ -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))
|
||||
|
|
@ -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))
|
||||
|
|
@ -1308,7 +1376,7 @@ namespace currency
|
|||
|
||||
LOCAL_CHECK(req.address != account_public_address{}, "address is missing");
|
||||
LOCAL_CHECK(req.viewkey != null_skey, "viewkey is missing");
|
||||
LOCAL_CHECK(0 <= req.blocks_limit && req.blocks_limit <= 5, "blocks_limit is out of allowed bounds");
|
||||
LOCAL_CHECK(req.blocks_limit <= 5, "blocks_limit is out of allowed bounds");
|
||||
|
||||
// verify addess keys
|
||||
crypto::point_t view_pk, spend_pk;
|
||||
|
|
@ -1332,7 +1400,7 @@ namespace currency
|
|||
{
|
||||
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, req.blocks_limit, recent_blocks), "cannot get 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)
|
||||
|
|
|
|||
|
|
@ -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,6 +89,7 @@ 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);
|
||||
|
|
@ -153,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)
|
||||
|
|
|
|||
|
|
@ -179,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");
|
||||
|
|
@ -636,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()
|
||||
};
|
||||
};
|
||||
|
||||
//-----------------------------------------------
|
||||
|
||||
|
|
@ -672,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>
|
||||
|
|
|
|||
|
|
@ -125,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", "");
|
||||
|
|
@ -2095,11 +2096,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
|
||||
|
|
@ -2874,7 +2875,63 @@ 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()
|
||||
{
|
||||
|
|
@ -3144,6 +3201,8 @@ int main(int argc, char* argv[])
|
|||
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, arg_seed_doctor);
|
||||
command_line::add_arg(desc_params, arg_derive_custom_seed);
|
||||
|
||||
|
||||
tools::wallet_rpc_server::init_options(desc_params);
|
||||
|
||||
|
|
@ -3221,12 +3280,15 @@ 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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -194,7 +194,6 @@ namespace currency
|
|||
std::string m_restore_wallet;
|
||||
std::string m_voting_config_file;
|
||||
bool m_no_password_confirmations = false;
|
||||
|
||||
|
||||
crypto::hash m_password_hash;
|
||||
uint64_t m_password_salt;
|
||||
|
|
|
|||
|
|
@ -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 337
|
||||
#define PROJECT_VERSION_BUILD_NO 349
|
||||
#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;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -390,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.value() << " (ETH)" : o << ado.descriptor.owner;
|
||||
};
|
||||
|
||||
do
|
||||
{
|
||||
crypto::public_key asset_id{};
|
||||
|
|
@ -398,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)
|
||||
|
|
@ -428,8 +441,8 @@ 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)
|
||||
{
|
||||
|
|
@ -441,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:"
|
||||
|
|
@ -466,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 });
|
||||
|
|
@ -476,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)
|
||||
|
|
@ -492,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1151,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;
|
||||
|
|
@ -1290,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;
|
||||
|
|
@ -3800,13 +3812,10 @@ bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asse
|
|||
for (const auto& emp_entry : utx.second.employed_entries.receive)
|
||||
{
|
||||
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
|
||||
if (it_employed_entry == subtransfers_by_assets_map.end() || !(it_employed_entry->second)) // if is_incoming == false, then we need to check for change and add it to total
|
||||
{
|
||||
//it_employed_entry == subtransfers_by_assets_map.end() is a case when amount sent exactly equal amount received (someone producing more outputs for example)
|
||||
//still need to add to total as it is a change
|
||||
wallet_public::asset_balance_entry_base& e = balances[emp_entry.asset_id];
|
||||
e.total += emp_entry.amount;
|
||||
}
|
||||
|
|
@ -4103,7 +4112,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;
|
||||
|
|
@ -4136,7 +4145,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 << " ";
|
||||
|
|
@ -4400,6 +4409,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
|
||||
|
|
@ -4490,7 +4532,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)
|
||||
|
|
@ -5461,125 +5503,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");
|
||||
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 = AUTO_VAL_INIT(asset_emmit_info);
|
||||
asset_emmit_info.descriptor = rsp.asset_descriptor;
|
||||
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())
|
||||
{
|
||||
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;
|
||||
|
||||
|
|
@ -5588,11 +5664,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;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -6069,7 +6150,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)
|
||||
|
|
@ -7540,20 +7621,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.",
|
||||
// << "Balance: " << std::setw(21) << print_money(balance_total) << ENDL
|
||||
// << "Unlocked: " << std::setw(21) << print_money(balance_unlocked) << ENDL
|
||||
<< (broadcasted ? "Please wait for the transaction to be confirmed before your balance is unlocked." : ""),
|
||||
LOG_LEVEL_0);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -7724,8 +7805,8 @@ bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx
|
|||
{
|
||||
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.ado_current_asset_owner = ctp.ado_current_asset_owner;
|
||||
ftp.pthirdparty_sign_handler = ctp.pthirdparty_sign_handler;
|
||||
//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
|
||||
//
|
||||
|
|
@ -7858,7 +7939,7 @@ void wallet2::finalize_transaction(currency::finalize_tx_param& ftp, currency::f
|
|||
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)
|
||||
|
|
@ -8036,8 +8117,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);
|
||||
|
|
@ -8047,7 +8131,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);
|
||||
|
|
@ -8060,7 +8144,7 @@ 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);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -8349,7 +8433,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)", get_tx_fee(*p_tx));
|
||||
print_tx_sent_message(*p_tx, "sweep_below", true, get_tx_fee(*p_tx));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -438,10 +438,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);
|
||||
|
|
@ -609,6 +615,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);
|
||||
|
|
@ -859,7 +866,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>
|
||||
|
||||
|
|
@ -53,6 +52,7 @@
|
|||
#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_CONCISE_MODE_PRESERVE uint32_t(1 << 6) // do not truncate this output with CONCISE mode
|
||||
#define WALLET_TRANSFER_DETAIL_FLAG_ASSET_OP_RESERVATION uint32_t(1 << 7) // transfer is reserved for an ongoing asset operation with external signing
|
||||
|
||||
|
||||
|
||||
|
|
@ -225,9 +225,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
|
||||
|
|
@ -357,7 +358,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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
@ -1982,7 +1982,7 @@ namespace wallet_public
|
|||
struct COMMAND_ASSETS_DEPLOY
|
||||
{
|
||||
DOC_COMMAND("Deploy new asset in the system.");
|
||||
|
||||
|
||||
struct request
|
||||
{
|
||||
std::list<transfer_destination> destinations;
|
||||
|
|
@ -1999,16 +1999,32 @@ namespace wallet_public
|
|||
|
||||
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.");
|
||||
|
|
@ -2026,13 +2042,14 @@ namespace wallet_public
|
|||
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()
|
||||
};
|
||||
};
|
||||
|
|
@ -2054,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()
|
||||
};
|
||||
};
|
||||
|
|
@ -2079,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
|
||||
|
|
@ -1312,51 +1312,128 @@ namespace tools
|
|||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
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_destinations(req.destinations, true, !req.do_not_split_destinations, currency_destinations);
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
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_destinations(req.destinations, true, !req.do_not_split_destinations, currency_destinations);
|
||||
|
||||
w.get_wallet()->emit_asset(req.asset_id, currency_destinations, result_tx);
|
||||
res.result_tx = currency::get_transaction_hash(result_tx);
|
||||
return true;
|
||||
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())
|
||||
{
|
||||
// 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_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;
|
||||
}
|
||||
res.status = API_RETURN_CODE_OK;
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1816,6 +1816,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;
|
||||
|
|
@ -1947,22 +1989,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;
|
||||
|
|
@ -1983,6 +2030,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.
|
||||
|
|
|
|||
|
|
@ -675,6 +675,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,
|
||||
|
|
@ -717,7 +733,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;
|
||||
|
|
@ -1140,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);
|
||||
|
|
@ -1218,6 +1218,7 @@ int main(int argc, char* argv[])
|
|||
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-*");
|
||||
GENERATE_AND_PLAY_HF(tx_pool_semantic_validation, "4-*");
|
||||
|
||||
// Double spend
|
||||
GENERATE_AND_PLAY(gen_double_spend_in_tx<false>);
|
||||
|
|
@ -1291,14 +1292,17 @@ int main(int argc, char* argv[])
|
|||
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_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(wallet_reorganize_and_trim_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");
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "offers_tests_common.h"
|
||||
#include "tx_builder.h"
|
||||
#include "chaingen_helpers.h"
|
||||
#include "../../src/currency_core/tx_semantic_validation.h"
|
||||
|
||||
using namespace epee;
|
||||
using namespace crypto;
|
||||
|
|
@ -1701,3 +1702,214 @@ bool tx_version_against_hardfork::generate(std::vector<test_event_entry>& events
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tx_pool_semantic_validation::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
// Test idea: ensure that the checks contained in the function "validate_tx_semantic" body are performed.
|
||||
|
||||
GENERATE_ACCOUNT(miner);
|
||||
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time());
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
|
||||
CHECK_AND_ASSERT_EQ(validate_tx_semantic(transaction{}, CURRENCY_MAX_TRANSACTION_BLOB_SIZE), false);
|
||||
|
||||
// No inputs.
|
||||
{
|
||||
transaction tx{};
|
||||
|
||||
tx.vin = {};
|
||||
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
ADD_CUSTOM_EVENT(events, tx);
|
||||
}
|
||||
|
||||
// Unsupported input type.
|
||||
{
|
||||
transaction tx{};
|
||||
|
||||
tx.vin.emplace_back();
|
||||
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
ADD_CUSTOM_EVENT(events, tx);
|
||||
}
|
||||
|
||||
// Unsupported output type.
|
||||
{
|
||||
transaction tx{};
|
||||
|
||||
tx.vin.push_back(txin_to_key{});
|
||||
tx.vout.emplace_back();
|
||||
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
ADD_CUSTOM_EVENT(events, tx);
|
||||
}
|
||||
|
||||
// Inputs amount overflow.
|
||||
{
|
||||
point_t point_public_key{};
|
||||
txout_to_key target{};
|
||||
std::array<txin_to_key, 2> inputs{};
|
||||
tx_out_bare output{};
|
||||
transaction tx{};
|
||||
|
||||
CHECK_AND_ASSERT_EQ(point_public_key.from_string("499790c3302b9f0514e2db09b390679283d43d971383d33dc24c7991ea4cf6d7"), true);
|
||||
target.key = point_public_key.to_public_key();
|
||||
inputs.at(0).amount = 1;
|
||||
inputs.at(1).amount = UINT64_MAX;
|
||||
|
||||
for (const auto& input : inputs)
|
||||
{
|
||||
tx.vin.push_back(input);
|
||||
}
|
||||
|
||||
output.amount = 1;
|
||||
output.target = target;
|
||||
tx.vout.push_back(output);
|
||||
|
||||
CHECK_AND_ASSERT_GREATER(inputs.at(0).amount, inputs.at(0).amount + inputs.at(1).amount);
|
||||
CHECK_AND_ASSERT_GREATER(inputs.at(1).amount, inputs.at(0).amount + inputs.at(1).amount);
|
||||
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
ADD_CUSTOM_EVENT(events, tx);
|
||||
}
|
||||
|
||||
// Outputs amount overflow.
|
||||
{
|
||||
point_t point_public_key{};
|
||||
txout_to_key target{};
|
||||
std::array<tx_out_bare, 2> outputs{};
|
||||
transaction tx{};
|
||||
|
||||
CHECK_AND_ASSERT_EQ(point_public_key.from_string("78ef3d9af7b5e3d09556d57820cf68c2b3553a9d8205c01fe40fc70aae86bb4f"), true);
|
||||
target.key = point_public_key.to_public_key();
|
||||
outputs.at(0).amount = 1;
|
||||
outputs.at(1).amount = UINT64_MAX;
|
||||
|
||||
for (auto& output : outputs)
|
||||
{
|
||||
output.target = target;
|
||||
tx.vout.push_back(output);
|
||||
}
|
||||
|
||||
tx.vin.push_back(txin_to_key{});
|
||||
|
||||
CHECK_AND_ASSERT_GREATER(outputs.at(0).amount, outputs.at(0).amount + outputs.at(1).amount);
|
||||
CHECK_AND_ASSERT_GREATER(outputs.at(1).amount, outputs.at(0).amount + outputs.at(1).amount);
|
||||
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
ADD_CUSTOM_EVENT(events, tx);
|
||||
}
|
||||
|
||||
// Equal key images in inputs.
|
||||
{
|
||||
tx_out_bare output;
|
||||
transaction tx{};
|
||||
std::array<txin_to_key, 2> inputs{};
|
||||
point_t key_image_point{};
|
||||
key_image image{};
|
||||
|
||||
output.amount = 1;
|
||||
tx.vout.push_back(output);
|
||||
CHECK_AND_ASSERT_EQ(key_image_point.from_string("8fc7cbfd1054690767d0c20917a68371b34b190aac5997581641f064b93d1b96"), true);
|
||||
image = key_image_point.to_key_image();
|
||||
|
||||
for (int position{}; position < 2; ++position)
|
||||
{
|
||||
inputs.at(position).k_image = image;
|
||||
tx.vin.push_back(inputs.at(position));
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_EQ(tx.vin.at(0).type(), typeid(txin_to_key));
|
||||
CHECK_AND_ASSERT_EQ(tx.vin.at(0).type(), tx.vin.at(1).type());
|
||||
CHECK_AND_ASSERT_EQ(boost::get<txin_to_key>(tx.vin.at(0)).k_image, boost::get<txin_to_key>(tx.vin.at(1)).k_image);
|
||||
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
ADD_CUSTOM_EVENT(events, tx);
|
||||
}
|
||||
|
||||
// Two entries of the same type in extra.
|
||||
{
|
||||
tx_out_bare output;
|
||||
transaction tx{};
|
||||
std::array<txin_to_key, 2> inputs{};
|
||||
std::array<point_t, 2> key_image_points{};
|
||||
key_image image{};
|
||||
|
||||
output.amount = 1;
|
||||
tx.vout.push_back(output);
|
||||
CHECK_AND_ASSERT_EQ(key_image_points.at(0).from_string("de3c22a62f15e6de8abe6b217085b2aead196daf5ddd67d9c4b366330736fbeb"), true);
|
||||
CHECK_AND_ASSERT_EQ(key_image_points.at(1).from_string("9f3eef913921ca35239e696725595e3686bb0d69e3e805791c5aa93d5754aa5c"), true);
|
||||
|
||||
for (int position{}; position < 2; ++position)
|
||||
{
|
||||
inputs.at(position).k_image = key_image_points.at(position).to_key_image();
|
||||
tx.vin.push_back(inputs.at(position));
|
||||
}
|
||||
|
||||
tx.extra.push_back(null_pkey);
|
||||
tx.extra.push_back(null_pkey);
|
||||
|
||||
CHECK_AND_ASSERT_EQ(tx.extra.size(), 2);
|
||||
CHECK_AND_ASSERT_EQ(typeid(tx.extra.front()), typeid(tx.extra.back()));
|
||||
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
ADD_CUSTOM_EVENT(events, tx);
|
||||
}
|
||||
|
||||
// tx.version <= TRANSACTION_VERSION_PRE_HF4. Balance check fail: sum of inputs <= sum of outputs.
|
||||
{
|
||||
transaction tx{};
|
||||
tx_out_bare output;
|
||||
std::array<point_t, 2> key_image_points{};
|
||||
std::array<txin_to_key, 2> inputs{};
|
||||
|
||||
output.amount = 3;
|
||||
tx.vout.push_back(output);
|
||||
tx.version = 0;
|
||||
CHECK_AND_ASSERT_EQ(key_image_points.at(0).from_string("8fc7cbfd1054690767d0c20917a68371b34b190aac5997581641f064b93d1b96"), true);
|
||||
CHECK_AND_ASSERT_EQ(key_image_points.at(1).from_string("dc48b741dacda5ac026ad0a7d193b816049eb08724907a1ff6f95839cfb0efa5"), true);
|
||||
|
||||
for (int position{}; position < 2; ++position)
|
||||
{
|
||||
auto& input{inputs.at(position)};
|
||||
|
||||
input.amount = 1;
|
||||
input.k_image = key_image_points.at(position).to_key_image();
|
||||
tx.vin.push_back(input);
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_GREATER(output.amount, std::accumulate(inputs.begin(), inputs.end(), std::uint64_t{}, [](uint64_t sum, const txin_to_key& input) { return sum + input.amount; }));
|
||||
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
ADD_CUSTOM_EVENT(events, tx);
|
||||
}
|
||||
|
||||
// Semantically valid transaction.
|
||||
{
|
||||
tx_out_bare output;
|
||||
transaction tx{};
|
||||
std::array<point_t, 2> key_image_points{};
|
||||
std::array<txin_to_key, 2> inputs{};
|
||||
|
||||
output.amount = 3'000'000'000'000;
|
||||
tx.version = 0;
|
||||
tx.vout.push_back(output);
|
||||
CHECK_AND_ASSERT_EQ(key_image_points.at(0).from_string("fe1ef4a48a69804652324dc071cb72f49c22cd97479583950eaff746c936f72c"), true);
|
||||
CHECK_AND_ASSERT_EQ(key_image_points.at(1).from_string("0bf1d8bb0988069f2c2b4f0dc89c81830c1178e04450d1da31ef020660732279"), true);
|
||||
for (int position{}; position < 2; ++position)
|
||||
{
|
||||
auto& input{inputs.at(position)};
|
||||
|
||||
input.amount = 2'000'000'000'000;
|
||||
input.k_image = key_image_points.at(position).to_key_image();
|
||||
tx.vin.push_back(input);
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true);
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
ADD_CUSTOM_EVENT(events, tx);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,3 +160,8 @@ struct tx_version_against_hardfork : public test_chain_unit_enchanced
|
|||
{
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
struct tx_pool_semantic_validation : public test_chain_unit_enchanced
|
||||
{
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ struct wallet_test : virtual public test_chain_unit_enchanced
|
|||
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, 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]));
|
||||
|
||||
|
|
@ -36,14 +39,14 @@ struct wallet_test : virtual public test_chain_unit_enchanced
|
|||
{
|
||||
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("127.0.0.1:33777"), "set_connection_addr failed");
|
||||
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{};
|
||||
char* argv[] = {"--rpc-bind-ip=127.0.0.1", "--rpc-bind-port=33777"};
|
||||
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);
|
||||
}
|
||||
|
|
@ -60,6 +63,9 @@ struct wallet_test : virtual public test_chain_unit_enchanced
|
|||
w->set_concise_mode(true);
|
||||
w->set_concise_mode_reorg_max_reorg_blocks(TESTS_CONCISE_MODE_REORG_MAX_REORG_BLOCK);
|
||||
return w;
|
||||
|
||||
#undef LOCAL_HOST_CSTR
|
||||
#undef LOCAL_PORT_CSTR
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ TEST(multiassets, get_or_calculate_asset_id_public_burn)
|
|||
|
||||
TEST(multiassets, get_or_calculate_asset_id_undefined)
|
||||
{
|
||||
bool success{false};
|
||||
bool success{false};
|
||||
|
||||
crypto::point_t pt_public_key{};
|
||||
success = pt_public_key.from_string(
|
||||
|
|
@ -448,8 +448,6 @@ TEST(multiassets, get_or_calculate_asset_id_undefined)
|
|||
&calculated_asset_id_key);
|
||||
|
||||
ASSERT_FALSE(success);
|
||||
ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt);
|
||||
ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key);
|
||||
}
|
||||
|
||||
TEST(multiassets, get_or_calculate_asset_id_register_serialization)
|
||||
|
|
@ -680,18 +678,6 @@ TEST(multiassets, get_or_calculate_asset_id_undefined_serialization)
|
|||
&calculated_asset_id_pt,
|
||||
&calculated_asset_id_key);
|
||||
ASSERT_FALSE(success);
|
||||
|
||||
const std::string expected_asset_id_str{
|
||||
"979eb706ace2eb83f9125658b23fb352208480cb3b90c43e2df0d298f9754ebc"};
|
||||
|
||||
crypto::point_t expected_asset_id_pt{};
|
||||
success = expected_asset_id_pt.from_string(expected_asset_id_str);
|
||||
ASSERT_TRUE(success);
|
||||
|
||||
crypto::public_key expected_asset_id_key{};
|
||||
expected_asset_id_pt.to_public_key(expected_asset_id_key);
|
||||
ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt);
|
||||
ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key);
|
||||
}
|
||||
|
||||
TEST(multiassets, get_or_calculate_asset_id_register_boost_serialization)
|
||||
|
|
@ -940,7 +926,7 @@ TEST(multiassets, get_or_calculate_asset_id_undefined_boost_serialization)
|
|||
'i', 'o', 'n', ':', ':', 'a', 'r', 'c', 'h',
|
||||
'i', 'v', 'e', '\x11', '\x00', '\x04', '\x08', '\x04', '\x08',
|
||||
'\x01', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00',
|
||||
'\x04', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x03', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', 'H', 'L', 'O', '\x0b', '\x00',
|
||||
|
|
@ -949,20 +935,20 @@ TEST(multiassets, get_or_calculate_asset_id_undefined_boost_serialization)
|
|||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'e',
|
||||
'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l',
|
||||
'd', '!', '\x00', '\x00', '\x00', '\x00', '\x00', ' ', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x0c', '@', '\x8c',
|
||||
'\xf8', '\xb7', '\xfb', '\x80', '\x8f', '@', 'Y', '=', 'n',
|
||||
'\xb7', 'X', '\x90', '\xe2', '\xab', '=', '\x0c', '\xcd', '\xc7',
|
||||
'\x01', 'J', '\x7f', '\xc6', '\xb6', '\xab', '\x05', '\x16', ';',
|
||||
'\xe0', '`', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xe9', '\x1b', '\x9a',
|
||||
's', ')', '-', 'n', '\xa4', 'o', '\xb3', '\xd4', '\xf4',
|
||||
'\xcc', 'y', '\xc3', 'K', '\xfb', '}', '\x14', '\xc2', '\xe6',
|
||||
'\x84', '\xe5', '\x80', '\x93', '\xa2', 'G', '\x1c', '\x92', '\xe5',
|
||||
'\x1c', '\x16', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x01',
|
||||
'\x00', '\x00', '\x00', '\x01', ' ', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', 'T', '\xf3', '\xf7', ',', 'r', '\xe5',
|
||||
'\xb0', '\x14', '\xad', '+', '+', '\x90', '\x01', '\xac', '\xef',
|
||||
'\x95', 'O', '\xe8', '-', '\xd3', '\xed', 'V', '\xa3', '\x8c',
|
||||
'\xd9', '\xdd', '\xc5', '\xdb', 'W', 'g', '?', '\x8f'};
|
||||
'\x00', '\x00', '\x00', '\x97', '\x9e', '\xb7', '\x06', '\xac', '\xe2',
|
||||
'\xeb', '\x83', '\xf9', '\x12', 'V', 'X', '\xb2', '?', '\xb3',
|
||||
'R', ' ', '\x84', '\x80', '\xcb', ';', '\x90', '\xc4', '>',
|
||||
'-', '\xf0', '\xd2', '\x98', '\xf9', 'u', 'N', '\xbc'};
|
||||
|
||||
success = tools::unserialize_obj_from_buff(
|
||||
asset_descriptor_operation,
|
||||
|
|
|
|||
|
|
@ -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
utils/JS/.gitignore
vendored
Normal file
2
utils/JS/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/node_modules*
|
||||
.vscode
|
||||
77
utils/JS/decrypt_response.json
Normal file
77
utils/JS/decrypt_response.json
Normal file
File diff suppressed because one or more lines are too long
25
utils/JS/emmit_response.json
Normal file
25
utils/JS/emmit_response.json
Normal file
File diff suppressed because one or more lines are too long
192
utils/JS/package-lock.json
generated
Normal file
192
utils/JS/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
{
|
||||
"name": "JS",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"axios": "^1.7.7",
|
||||
"ethers": "^6.13.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@adraffy/ens-normalize": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz",
|
||||
"integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw=="
|
||||
},
|
||||
"node_modules/@noble/curves": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
|
||||
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.3.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
|
||||
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.15.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz",
|
||||
"integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q=="
|
||||
},
|
||||
"node_modules/aes-js": {
|
||||
"version": "4.0.0-beta.5",
|
||||
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz",
|
||||
"integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q=="
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.7.7",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
|
||||
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ethers": {
|
||||
"version": "6.13.2",
|
||||
"resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.2.tgz",
|
||||
"integrity": "sha512-9VkriTTed+/27BGuY1s0hf441kqwHJ1wtN2edksEtiRvXx+soxRX3iSXTfFqq2+YwrOqbDoTHjIhQnjJRlzKmg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/ethers-io/"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@adraffy/ens-normalize": "1.10.1",
|
||||
"@noble/curves": "1.2.0",
|
||||
"@noble/hashes": "1.3.2",
|
||||
"@types/node": "18.15.13",
|
||||
"aes-js": "4.0.0-beta.5",
|
||||
"tslib": "2.4.0",
|
||||
"ws": "8.17.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
utils/JS/package.json
Normal file
6
utils/JS/package.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"axios": "^1.7.7",
|
||||
"ethers": "^6.13.2"
|
||||
}
|
||||
}
|
||||
8
utils/JS/sign_response.json
Normal file
8
utils/JS/sign_response.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"id": 0,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"status": "",
|
||||
"transfers_were_unlocked": false
|
||||
}
|
||||
}
|
||||
248
utils/JS/test_eth_sig.js
Normal file
248
utils/JS/test_eth_sig.js
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
|
||||
|
||||
const axios = require('axios');
|
||||
const { ethers } = require("ethers");
|
||||
const { exit } = require('process');
|
||||
const fs = require('fs');
|
||||
|
||||
/// Define an async function that takes method name and parameters
|
||||
async function callJsonRpc(requestData, port = 22222) {
|
||||
try {
|
||||
const response = await axios.post('http://127.0.0.1:' + port +'/json_rpc', requestData, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// Return the result from the JSON-RPC response
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
throw error; // Optionally rethrow the error to handle it in the calling function
|
||||
}
|
||||
}
|
||||
|
||||
function reverseHexBytes(hexString) {
|
||||
// Ensure the hex string length is even
|
||||
if (hexString.length % 2 !== 0) {
|
||||
throw new Error("Invalid hex string length");
|
||||
}
|
||||
|
||||
// Split the hex string into chunks of 2 characters (1 byte)
|
||||
const bytes = hexString.match(/.{1,2}/g);
|
||||
|
||||
// Reverse the array of bytes and join them back into a string
|
||||
const reversedHex = bytes.reverse().join('');
|
||||
|
||||
return reversedHex;
|
||||
}
|
||||
|
||||
async function deploy_asset()
|
||||
{
|
||||
try {
|
||||
//Generated Private Key: 0x17a938099954cee510d7fc9eb2366f0762b093d9be547acabf8be85f774ef154
|
||||
//Generated Address: 0x0886bA9F5b117D2A3C1ce18106F2Ce759f5D34C8
|
||||
|
||||
const loadedWallet = new ethers.Wallet("0x17a938099954cee510d7fc9eb2366f0762b093d9be547acabf8be85f774ef154");
|
||||
console.log("Loaded Address:", loadedWallet.address);
|
||||
console.log("Public key:", loadedWallet.signingKey.compressedPublicKey);
|
||||
const owner_eth_pub_key = loadedWallet.signingKey.compressedPublicKey.substring(2);
|
||||
console.log("Generated Public key HEX:", owner_eth_pub_key);
|
||||
const jsonObject = {
|
||||
id: 0,
|
||||
jsonrpc: "2.0",
|
||||
method: "deploy_asset",
|
||||
params: {
|
||||
asset_descriptor: {
|
||||
//current_supply: 1000000000000000,
|
||||
decimal_point: 12,
|
||||
full_name: "Zano wrapped ABC",
|
||||
hidden_supply: false,
|
||||
meta_info: "Stable and private",
|
||||
owner: "",
|
||||
ticker: "ZABC",
|
||||
total_max_supply: 1000000000000000000,
|
||||
owner_eth_pub_key: owner_eth_pub_key
|
||||
},
|
||||
destinations: [
|
||||
{
|
||||
address: "ZxC1U6hoCRM9PBSwrBTrWD8XgcHqLNJN9NWqXs9o994eZuHHBvSAyBpQ4TbWSNoabUDPdD8iEM5ZjPoMM7jE48mp2iKcVHLSK",
|
||||
amount: 1000000000000000,
|
||||
asset_id: ""
|
||||
},
|
||||
{
|
||||
address: "ZxC1U6hoCRM9PBSwrBTrWD8XgcHqLNJN9NWqXs9o994eZuHHBvSAyBpQ4TbWSNoabUDPdD8iEM5ZjPoMM7jE48mp2iKcVHLSK",
|
||||
amount: 1000000000000000,
|
||||
asset_id: ""
|
||||
}
|
||||
],
|
||||
do_not_split_destinations: false
|
||||
}
|
||||
};
|
||||
|
||||
const res = await callJsonRpc(jsonObject);
|
||||
console.log("deploy_asset response: " + JSON.stringify(res, null, 2));
|
||||
/*
|
||||
deploy_asset response:
|
||||
{
|
||||
"id": 0,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"new_asset_id": "7d51ecaad2e3458e0d62b146f33079c6ea307841b09a44b777e0c01eb11b98bf",
|
||||
"tx_id": "73ff52bf4d85153f2b25033dd76e9e92e63214ed983682182e6e2b2ce0ecf46c"
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
catch (error) {
|
||||
console.error('Error occurred:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function emmit_asset()
|
||||
{
|
||||
try {
|
||||
|
||||
//Generated Private Key: 0x17a938099954cee510d7fc9eb2366f0762b093d9be547acabf8be85f774ef154
|
||||
//Generated Address: 0x0886bA9F5b117D2A3C1ce18106F2Ce759f5D34C8
|
||||
// asset_id 7d51ecaad2e3458e0d62b146f33079c6ea307841b09a44b777e0c01eb11b98bf
|
||||
|
||||
//var use_pregenerated_files = false;
|
||||
|
||||
const loadedWallet = new ethers.Wallet("0x17a938099954cee510d7fc9eb2366f0762b093d9be547acabf8be85f774ef154");
|
||||
|
||||
console.log("Loaded Address:", loadedWallet.address);
|
||||
console.log("Public key:", loadedWallet.signingKey.compressedPublicKey);
|
||||
const owner_eth_pub_key = loadedWallet.signingKey.compressedPublicKey.substring(2);
|
||||
console.log("Generated Public key HEX:", owner_eth_pub_key);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//this part is performed on coordinator node:
|
||||
|
||||
var res_emmit;
|
||||
//if(!use_pregenerated_files)
|
||||
//{
|
||||
const requestDataEmit = {
|
||||
id: 0,
|
||||
jsonrpc: "2.0",
|
||||
method: "emit_asset",
|
||||
params: {
|
||||
asset_id: "7d51ecaad2e3458e0d62b146f33079c6ea307841b09a44b777e0c01eb11b98bf",
|
||||
destinations: [{
|
||||
address: "ZxC1U6hoCRM9PBSwrBTrWD8XgcHqLNJN9NWqXs9o994eZuHHBvSAyBpQ4TbWSNoabUDPdD8iEM5ZjPoMM7jE48mp2iKcVHLSK",
|
||||
amount: 100000000000,
|
||||
asset_id: ""
|
||||
}],
|
||||
do_not_split_destinations: false
|
||||
}
|
||||
};
|
||||
|
||||
res_emmit = await callJsonRpc(requestDataEmit);
|
||||
fs.writeFileSync('emmit_response.json', JSON.stringify(res_emmit, null, 2));
|
||||
console.log("emmit_response response: " + JSON.stringify(res_emmit, null, 2));
|
||||
//}else
|
||||
//{
|
||||
// const data = fs.readFileSync('emmit_response.json', 'utf8');
|
||||
// res_emmit = JSON.parse(data);
|
||||
//}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//this part is performed on validator node:
|
||||
|
||||
|
||||
var res_decrypt;
|
||||
//if(!use_pregenerated_files)
|
||||
//{
|
||||
const requestDataDecrypt = {
|
||||
id: 0,
|
||||
jsonrpc: "2.0",
|
||||
method: "decrypt_tx_details",
|
||||
params: {
|
||||
outputs_addresses: res_emmit.result.data_for_external_signing.outputs_addresses,
|
||||
tx_blob: res_emmit.result.data_for_external_signing.unsigned_tx,
|
||||
tx_id: "",
|
||||
tx_secret_key: res_emmit.result.data_for_external_signing.tx_secret_key
|
||||
}
|
||||
};
|
||||
|
||||
res_decrypt = await callJsonRpc(requestDataDecrypt, 12111); //request to daemon
|
||||
fs.writeFileSync('decrypt_response.json', JSON.stringify(res_decrypt, null, 2));
|
||||
console.log("decrypt_response : " + JSON.stringify(res_decrypt, null, 2));
|
||||
|
||||
//TODO: response holds all information about what this transaction actually transfer and to what addresses
|
||||
|
||||
//}else
|
||||
//{
|
||||
// const data = fs.readFileSync('decrypt_response.json', 'utf8');
|
||||
// res_decrypt = JSON.parse(data);
|
||||
//}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//this part is performed with TSS scheme:
|
||||
const bytesToSign = ethers.getBytes('0x' + res_decrypt.result.verified_tx_id);
|
||||
const signature = loadedWallet.signingKey.sign(bytesToSign).serialized;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//this part is performed on coordinator node with given signature:
|
||||
|
||||
const signature_without_0x = signature.substring(2);
|
||||
console.log("Generated signature: " + signature_without_0x);
|
||||
// Strip the last byte (recovery parameter) to get 64 bytes
|
||||
const strippedSignature = signature_without_0x.slice(0, -2); // Remove the last byte (2 hex chars)
|
||||
|
||||
const requestSendSigned = {
|
||||
id: 0,
|
||||
jsonrpc: "2.0",
|
||||
method: "send_ext_signed_asset_tx",
|
||||
params: {
|
||||
eth_sig: strippedSignature,
|
||||
expected_tx_id: res_decrypt.result.verified_tx_id,
|
||||
finalized_tx: res_emmit.result.data_for_external_signing.finalized_tx,
|
||||
unlock_transfers_on_fail: false,
|
||||
unsigned_tx: res_emmit.result.data_for_external_signing.unsigned_tx
|
||||
}
|
||||
}
|
||||
|
||||
const res_sign = await callJsonRpc(requestSendSigned);
|
||||
fs.writeFileSync('sign_response.json', JSON.stringify(res_sign, null, 2));
|
||||
console.log("sign_response response: " + JSON.stringify(res_sign, null, 2));
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error occurred:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function main()
|
||||
{
|
||||
try {
|
||||
|
||||
/*
|
||||
await deploy_asset();
|
||||
TODO: wait for 10 confirmations
|
||||
//wait for 10 confirmations
|
||||
|
||||
//asset id 7d51ecaad2e3458e0d62b146f33079c6ea307841b09a44b777e0c01eb11b98bf
|
||||
*/
|
||||
await emmit_asset();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error occurred:', error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
main();
|
||||
Loading…
Add table
Reference in a new issue