forked from lthn/blockchain
Merge branch 'auditability' into predevelop
This commit is contained in:
commit
ab1ef9cf5e
41 changed files with 2523 additions and 386 deletions
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2020 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Copyright (c) 2012-2013 The Boolberry developers
|
||||
|
|
@ -37,3 +37,21 @@ namespace std { \
|
|||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
// this allows using std::pair<> as a key in unordered std containers
|
||||
template <class T1, class T2>
|
||||
struct hash<pair<T1, T2>>
|
||||
{
|
||||
size_t operator()(const pair<T1, T2>& p) const
|
||||
{
|
||||
auto hash1 = hash<T1>{}(p.first);
|
||||
auto hash2 = hash<T2>{}(p.second);
|
||||
return hash1 ^ hash2;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
|
|
|||
|
|
@ -48,8 +48,6 @@ namespace tools
|
|||
{
|
||||
using namespace std;
|
||||
|
||||
const int NUMWORDS = 1626;
|
||||
|
||||
const map<string,uint32_t> wordsMap = {
|
||||
{"like", 0},
|
||||
{"just", 1},
|
||||
|
|
@ -3358,7 +3356,7 @@ namespace tools
|
|||
throw runtime_error("Invalid binary data size for mnemonic encoding");
|
||||
// 4 bytes -> 3 words. 8 digits base 16 -> 3 digits base 1626
|
||||
string res;
|
||||
for (unsigned int i=0; i < binary.size() / 4; i++, res += ' ')
|
||||
for (unsigned int i=0; i < binary.size() / 4; i++)
|
||||
{
|
||||
const uint32_t* val =
|
||||
reinterpret_cast<const uint32_t*>(&binary[i * 4]);
|
||||
|
|
@ -3369,8 +3367,9 @@ namespace tools
|
|||
|
||||
res += wordsArray[w1] + " ";
|
||||
res += wordsArray[w2] + " ";
|
||||
res += wordsArray[w3];
|
||||
res += wordsArray[w3] + " ";
|
||||
}
|
||||
res.erase(--res.end()); // remove trailing space
|
||||
return res;
|
||||
}
|
||||
std::string word_by_num(uint32_t n)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ namespace tools
|
|||
{
|
||||
namespace mnemonic_encoding
|
||||
{
|
||||
constexpr int NUMWORDS = 1626;
|
||||
|
||||
std::vector<unsigned char> text2binary(const std::string& text);
|
||||
std::string binary2text(const std::vector<unsigned char>& binary);
|
||||
std::string word_by_num(uint32_t n);
|
||||
|
|
|
|||
|
|
@ -85,34 +85,31 @@ namespace crypto {
|
|||
memcpy(&res, tmp, 32);
|
||||
}
|
||||
|
||||
void crypto_ops::keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec, size_t brain_wallet_seed_size)
|
||||
{
|
||||
unsigned char tmp[64] = { 0 };
|
||||
|
||||
if (!(sizeof(tmp) >= brain_wallet_seed_size))
|
||||
{
|
||||
throw std::runtime_error("size mismatch");
|
||||
}
|
||||
|
||||
memcpy(tmp, a_part, brain_wallet_seed_size);
|
||||
|
||||
cn_fast_hash(tmp, 32, (char*)&tmp[32]);
|
||||
|
||||
sc_reduce(tmp);
|
||||
memcpy(&sec, tmp, 32);
|
||||
ge_p3 point;
|
||||
ge_scalarmult_base(&point, &sec);
|
||||
ge_p3_tobytes(&pub, &point);
|
||||
}
|
||||
|
||||
void crypto_ops::generate_brain_keys(public_key &pub, secret_key &sec, std::string& seed, size_t brain_wallet_seed_size)
|
||||
void crypto_ops::keys_from_default(const unsigned char* a_part, public_key &pub, secret_key &sec, size_t keys_seed_binary_size)
|
||||
{
|
||||
std::vector<unsigned char> tmp_vector;
|
||||
tmp_vector.resize(brain_wallet_seed_size, 0);
|
||||
unsigned char *tmp = &tmp_vector[0];
|
||||
generate_random_bytes(brain_wallet_seed_size, tmp);
|
||||
seed.assign((const char*)tmp, brain_wallet_seed_size);
|
||||
keys_from_default(tmp, pub, sec, brain_wallet_seed_size);
|
||||
unsigned char tmp[64] = { 0 };
|
||||
|
||||
if (!(sizeof(tmp) >= keys_seed_binary_size))
|
||||
{
|
||||
throw std::runtime_error("size mismatch");
|
||||
}
|
||||
|
||||
memcpy(tmp, a_part, keys_seed_binary_size);
|
||||
|
||||
cn_fast_hash(tmp, 32, (char*)&tmp[32]);
|
||||
|
||||
sc_reduce(tmp);
|
||||
memcpy(&sec, tmp, 32);
|
||||
ge_p3 point;
|
||||
ge_scalarmult_base(&point, &sec);
|
||||
ge_p3_tobytes(&pub, &point);
|
||||
}
|
||||
|
||||
void crypto_ops::generate_seed_keys(public_key &pub, secret_key &sec, std::vector<unsigned char>& keys_seed_binary, size_t keys_seed_binary_size)
|
||||
{
|
||||
keys_seed_binary.resize(keys_seed_binary_size, 0);
|
||||
generate_random_bytes(keys_seed_binary_size, keys_seed_binary.data());
|
||||
keys_from_default(keys_seed_binary.data(), pub, sec, keys_seed_binary_size);
|
||||
}
|
||||
|
||||
static inline void hash_to_scalar(const void *data, size_t length, ec_scalar &res)
|
||||
|
|
|
|||
|
|
@ -74,10 +74,10 @@ namespace crypto {
|
|||
|
||||
static void generate_keys(public_key &, secret_key &);
|
||||
friend void generate_keys(public_key &, secret_key &);
|
||||
static void generate_brain_keys(public_key &, secret_key &, std::string& seed, size_t brain_wallet_seed_size);
|
||||
friend void generate_brain_keys(public_key &, secret_key &, std::string& seed, size_t brain_wallet_seed_size);
|
||||
static void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec, size_t brain_wallet_seed_size);
|
||||
friend void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec, size_t brain_wallet_seed_size);
|
||||
static void generate_seed_keys(public_key &pub, secret_key &sec, std::vector<unsigned char>& keys_seed_binary, size_t keys_seed_binary_size);
|
||||
friend void generate_seed_keys(public_key &pub, secret_key &sec, std::vector<unsigned char>& keys_seed_binary, size_t keys_seed_binary_size);
|
||||
static void keys_from_default(const unsigned char* a_part, public_key &pub, secret_key &sec, size_t keys_seed_binary_size);
|
||||
friend void keys_from_default(const unsigned char* a_part, public_key &pub, secret_key &sec, size_t keys_seed_binary_size);
|
||||
static void dependent_key(const secret_key& first, secret_key& second);
|
||||
friend void dependent_key(const secret_key& first, secret_key& second);
|
||||
static bool check_key(const public_key &);
|
||||
|
|
@ -136,14 +136,14 @@ namespace crypto {
|
|||
crypto_ops::generate_keys(pub, sec);
|
||||
}
|
||||
|
||||
inline void generate_brain_keys(public_key &pub, secret_key &sec, std::string& seed, size_t brain_wallet_seed_size) {
|
||||
crypto_ops::generate_brain_keys(pub, sec, seed, brain_wallet_seed_size);
|
||||
inline void generate_seed_keys(public_key &pub, secret_key &sec, std::vector<unsigned char>& keys_seed_binary, size_t keys_seed_binary_size)
|
||||
{
|
||||
crypto_ops::generate_seed_keys(pub, sec, keys_seed_binary, keys_seed_binary_size);
|
||||
}
|
||||
|
||||
|
||||
inline void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec, size_t brain_wallet_seed_size)
|
||||
inline void keys_from_default(const unsigned char* a_part, public_key &pub, secret_key &sec, size_t keys_seed_binary_size)
|
||||
{
|
||||
crypto_ops::keys_from_default(a_part, pub, sec, brain_wallet_seed_size);
|
||||
crypto_ops::keys_from_default(a_part, pub, sec, keys_seed_binary_size);
|
||||
}
|
||||
|
||||
inline void dependent_key(const secret_key& first, secret_key& second){
|
||||
|
|
@ -290,8 +290,7 @@ namespace crypto {
|
|||
bool m_ready;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // namespace crypto
|
||||
|
||||
POD_MAKE_HASHABLE(crypto, public_key)
|
||||
POD_MAKE_COMPARABLE(crypto, secret_key)
|
||||
|
|
|
|||
|
|
@ -17,15 +17,10 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
DISABLE_VS_WARNINGS(4244 4345)
|
||||
|
||||
|
||||
//DISABLE_VS_WARNINGS(4244 4345)
|
||||
|
||||
namespace currency
|
||||
{
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
account_base::account_base()
|
||||
{
|
||||
|
|
@ -37,18 +32,22 @@ namespace currency
|
|||
// fill sensitive data with random bytes
|
||||
crypto::generate_random_bytes(sizeof m_keys.spend_secret_key, &m_keys.spend_secret_key);
|
||||
crypto::generate_random_bytes(sizeof m_keys.view_secret_key, &m_keys.view_secret_key);
|
||||
crypto::generate_random_bytes(m_seed.size(), &m_seed[0]);
|
||||
if (m_keys_seed_binary.size())
|
||||
crypto::generate_random_bytes(m_keys_seed_binary.size(), &m_keys_seed_binary[0]);
|
||||
|
||||
// clear
|
||||
m_keys = account_keys();
|
||||
m_creation_timestamp = 0;
|
||||
m_seed.clear();
|
||||
m_keys_seed_binary.clear();
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::generate()
|
||||
void account_base::generate(bool auditable /* = false */)
|
||||
{
|
||||
generate_brain_keys(m_keys.account_address.spend_public_key, m_keys.spend_secret_key, m_seed, BRAINWALLET_DEFAULT_SEED_SIZE);
|
||||
dependent_key(m_keys.spend_secret_key, m_keys.view_secret_key);
|
||||
if (auditable)
|
||||
m_keys.account_address.flags = ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE;
|
||||
|
||||
crypto::generate_seed_keys(m_keys.account_address.spend_public_key, m_keys.spend_secret_key, m_keys_seed_binary, BRAINWALLET_DEFAULT_SEED_SIZE);
|
||||
crypto::dependent_key(m_keys.spend_secret_key, m_keys.view_secret_key);
|
||||
if (!crypto::secret_key_to_public_key(m_keys.view_secret_key, m_keys.account_address.view_public_key))
|
||||
throw std::runtime_error("Failed to create public view key");
|
||||
|
||||
|
|
@ -61,68 +60,122 @@ namespace currency
|
|||
return m_keys;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
std::string account_base::get_restore_data() const
|
||||
{
|
||||
return m_seed;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
std::string account_base::get_restore_braindata() const
|
||||
{
|
||||
std::string restore_buff = get_restore_data();
|
||||
if (restore_buff.empty())
|
||||
if (m_keys_seed_binary.empty())
|
||||
return "";
|
||||
std::vector<unsigned char> v;
|
||||
v.assign((unsigned char*)restore_buff.data(), (unsigned char*)restore_buff.data() + restore_buff.size());
|
||||
std::string seed_brain_data = tools::mnemonic_encoding::binary2text(v);
|
||||
std::string keys_seed_text = tools::mnemonic_encoding::binary2text(m_keys_seed_binary);
|
||||
std::string timestamp_word = currency::get_word_from_timstamp(m_creation_timestamp);
|
||||
seed_brain_data = seed_brain_data + timestamp_word;
|
||||
return seed_brain_data;
|
||||
|
||||
// floor creation time to WALLET_BRAIN_DATE_QUANTUM to make checksum calculation stable
|
||||
uint64_t creation_timestamp_rounded = get_timstamp_from_word(timestamp_word);
|
||||
|
||||
constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum
|
||||
crypto::hash h = crypto::cn_fast_hash(m_keys_seed_binary.data(), m_keys_seed_binary.size());
|
||||
*reinterpret_cast<uint64_t*>(&h) = creation_timestamp_rounded;
|
||||
h = crypto::cn_fast_hash(&h, sizeof h);
|
||||
uint64_t h_64 = *reinterpret_cast<uint64_t*>(&h);
|
||||
uint16_t checksum = h_64 % (checksum_max + 1);
|
||||
|
||||
uint8_t auditable_flag = 0;
|
||||
if (m_keys.account_address.flags & ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE)
|
||||
auditable_flag = 1;
|
||||
|
||||
uint64_t auditable_flag_and_checksum = (auditable_flag & 1) | (checksum << 1);
|
||||
std::string auditable_flag_and_checksum_word = tools::mnemonic_encoding::word_by_num(auditable_flag_and_checksum);
|
||||
|
||||
return keys_seed_text + " " + timestamp_word + " " + auditable_flag_and_checksum_word;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::restore_keys(const std::string& restore_data)
|
||||
std::string account_base::get_awo_blob() const
|
||||
{
|
||||
//CHECK_AND_ASSERT_MES(restore_data.size() == ACCOUNT_RESTORE_DATA_SIZE, false, "wrong restore data size");
|
||||
if (restore_data.size() == BRAINWALLET_DEFAULT_SEED_SIZE)
|
||||
{
|
||||
crypto::keys_from_default((unsigned char*)restore_data.data(), m_keys.account_address.spend_public_key, m_keys.spend_secret_key, BRAINWALLET_DEFAULT_SEED_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("wrong restore data size=" << restore_data.size());
|
||||
return false;
|
||||
}
|
||||
m_seed = restore_data;
|
||||
return get_public_address_str() + ":" +
|
||||
epee::string_tools::pod_to_hex(m_keys.view_secret_key) +
|
||||
(m_creation_timestamp ? ":" : "") + (m_creation_timestamp ? epee::string_tools::num_to_string_fast(m_creation_timestamp) : "");
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::restore_keys(const std::vector<unsigned char>& keys_seed_binary)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(keys_seed_binary.size() == BRAINWALLET_DEFAULT_SEED_SIZE, false, "wrong restore data size: " << keys_seed_binary.size());
|
||||
crypto::keys_from_default(keys_seed_binary.data(), m_keys.account_address.spend_public_key, m_keys.spend_secret_key, keys_seed_binary.size());
|
||||
crypto::dependent_key(m_keys.spend_secret_key, m_keys.view_secret_key);
|
||||
bool r = crypto::secret_key_to_public_key(m_keys.view_secret_key, m_keys.account_address.view_public_key);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to secret_key_to_public_key for view key");
|
||||
set_createtime(0);
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::restore_keys_from_braindata(const std::string& restore_data_)
|
||||
bool account_base::restore_from_braindata(const std::string& seed_phrase)
|
||||
{
|
||||
//cut the last timestamp word from restore_dats
|
||||
std::list<std::string> words;
|
||||
boost::split(words, restore_data_, boost::is_space());
|
||||
CHECK_AND_ASSERT_MES(words.size() == BRAINWALLET_DEFAULT_WORDS_COUNT, false, "Words count missmatch: " << words.size());
|
||||
|
||||
std::string timestamp_word = words.back();
|
||||
words.erase(--words.end());
|
||||
|
||||
std::string restore_data_local = boost::algorithm::join(words, " ");
|
||||
boost::split(words, seed_phrase, boost::is_space());
|
||||
|
||||
std::vector<unsigned char> bin = tools::mnemonic_encoding::text2binary(restore_data_local);
|
||||
if (!bin.size())
|
||||
std::string keys_seed_text, timestamp_word, auditable_flag_and_checksum_word;
|
||||
if (words.size() == SEED_PHRASE_V1_WORDS_COUNT)
|
||||
{
|
||||
// 24 seed words + one timestamp word = 25 total
|
||||
timestamp_word = words.back();
|
||||
words.erase(--words.end());
|
||||
keys_seed_text = boost::algorithm::join(words, " ");
|
||||
}
|
||||
else if (words.size() == SEED_PHRASE_V2_WORDS_COUNT)
|
||||
{
|
||||
// 24 seed words + one timestamp word + one flags & checksum = 26 total
|
||||
auditable_flag_and_checksum_word = words.back();
|
||||
words.erase(--words.end());
|
||||
timestamp_word = words.back();
|
||||
words.erase(--words.end());
|
||||
keys_seed_text = boost::algorithm::join(words, " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Invalid seed words count: " << words.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t auditable_flag_and_checksum = UINT64_MAX;
|
||||
if (!auditable_flag_and_checksum_word.empty())
|
||||
auditable_flag_and_checksum = tools::mnemonic_encoding::num_by_word(auditable_flag_and_checksum_word);
|
||||
|
||||
std::vector<unsigned char> keys_seed_binary = tools::mnemonic_encoding::text2binary(keys_seed_text);
|
||||
CHECK_AND_ASSERT_MES(keys_seed_binary.size(), false, "text2binary failed to convert the given text"); // don't prints event incorrect seed into the log for security
|
||||
|
||||
std::string restore_buff((const char*)&bin[0], bin.size());
|
||||
bool r = restore_keys(restore_buff);
|
||||
CHECK_AND_ASSERT_MES(r, false, "restore_keys failed");
|
||||
m_creation_timestamp = get_timstamp_from_word(timestamp_word);
|
||||
|
||||
bool auditable_flag = false;
|
||||
|
||||
// check the checksum if checksum word provided
|
||||
if (auditable_flag_and_checksum != UINT64_MAX)
|
||||
{
|
||||
auditable_flag = (auditable_flag_and_checksum & 1) != 0; // auditable flag is the lower 1 bit
|
||||
uint16_t checksum = auditable_flag_and_checksum >> 1; // checksum -- everything else
|
||||
constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum
|
||||
crypto::hash h = crypto::cn_fast_hash(keys_seed_binary.data(), keys_seed_binary.size());
|
||||
*reinterpret_cast<uint64_t*>(&h) = m_creation_timestamp;
|
||||
h = crypto::cn_fast_hash(&h, sizeof h);
|
||||
uint64_t h_64 = *reinterpret_cast<uint64_t*>(&h);
|
||||
uint16_t checksum_calculated = h_64 % (checksum_max + 1);
|
||||
CHECK_AND_ASSERT_MES(checksum == checksum_calculated, false, "seed phase has invalid checksum: " << checksum_calculated << ", while " << checksum << " is expected, check your words");
|
||||
}
|
||||
|
||||
bool r = restore_keys(keys_seed_binary);
|
||||
CHECK_AND_ASSERT_MES(r, false, "restore_keys failed");
|
||||
|
||||
m_keys_seed_binary = keys_seed_binary;
|
||||
|
||||
if (auditable_flag)
|
||||
m_keys.account_address.flags |= ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE;
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::restore_from_awo_blob(const std::string& awo_blob)
|
||||
{
|
||||
set_null();
|
||||
bool r = parse_awo_blob(awo_blob, m_keys.account_address, m_keys.view_secret_key, m_creation_timestamp);
|
||||
return r;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
std::string account_base::get_public_address_str() const
|
||||
{
|
||||
//TODO: change this code into base 58
|
||||
|
|
@ -133,7 +186,7 @@ namespace currency
|
|||
{
|
||||
// keep only:
|
||||
// timestamp
|
||||
// view pub & spend pub (public address)
|
||||
// view pub & spend pub + flags (public address)
|
||||
// view sec
|
||||
|
||||
// store to local tmp
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@
|
|||
|
||||
#define BRAINWALLET_DEFAULT_SEED_SIZE 32
|
||||
#define ACCOUNT_RESTORE_DATA_SIZE BRAINWALLET_DEFAULT_SEED_SIZE
|
||||
#define BRAINWALLET_DEFAULT_WORDS_COUNT 25
|
||||
#define SEED_PHRASE_V1_WORDS_COUNT 25
|
||||
#define SEED_PHRASE_V2_WORDS_COUNT 26
|
||||
|
||||
|
||||
|
||||
|
|
@ -47,15 +48,15 @@ namespace currency
|
|||
{
|
||||
public:
|
||||
account_base();
|
||||
void generate();
|
||||
void generate(bool auditable = false);
|
||||
const account_keys& get_keys() const;
|
||||
const account_public_address& get_public_address() const { return m_keys.account_address; };
|
||||
std::string get_public_address_str() const;
|
||||
std::string get_restore_data() const;
|
||||
|
||||
std::string get_restore_braindata() const;
|
||||
|
||||
bool restore_keys(const std::string& restore_data);
|
||||
bool restore_keys_from_braindata(const std::string& restore_data);
|
||||
std::string get_awo_blob() const;
|
||||
bool restore_from_braindata(const std::string& seed_phrase);
|
||||
bool restore_from_awo_blob(const std::string& awo_blob);
|
||||
|
||||
uint64_t get_createtime() const { return m_creation_timestamp; }
|
||||
void set_createtime(uint64_t val) { m_creation_timestamp = val; }
|
||||
|
|
@ -70,20 +71,26 @@ namespace currency
|
|||
{
|
||||
a & m_keys;
|
||||
a & m_creation_timestamp;
|
||||
a & m_seed;
|
||||
a & m_keys_seed_binary;
|
||||
}
|
||||
|
||||
static std::string vector_of_chars_to_string(const std::vector<unsigned char>& v) { return std::string(v.begin(), v.end()); }
|
||||
static std::vector<unsigned char> string_to_vector_of_chars(const std::string& v) { return std::vector<unsigned char>(v.begin(), v.end()); }
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_keys)
|
||||
KV_SERIALIZE(m_creation_timestamp)
|
||||
KV_SERIALIZE(m_seed)
|
||||
KV_SERIALIZE_CUSTOM_N(m_keys_seed_binary, std::string, vector_of_chars_to_string, string_to_vector_of_chars, "m_seed")
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
private:
|
||||
void set_null();
|
||||
bool restore_keys(const std::vector<unsigned char>& keys_seed_binary);
|
||||
|
||||
account_keys m_keys;
|
||||
uint64_t m_creation_timestamp;
|
||||
std::string m_seed;
|
||||
|
||||
std::vector<unsigned char> m_keys_seed_binary;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4671,6 +4671,26 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
|
|||
return true;
|
||||
}
|
||||
|
||||
if (block_height <= m_core_runtime_config.hard_fork_02_starts_after_height)
|
||||
{
|
||||
// before hardfork 2
|
||||
|
||||
auto check_lambda = [&](const std::vector<payload_items_v>& container) -> bool
|
||||
{
|
||||
for (const auto& el : container)
|
||||
{
|
||||
const auto& type = el.type();
|
||||
CHECK_AND_ASSERT_MES(type != typeid(tx_payer), false, "tx " << tx_id << " contains tx_payer which is not allowed on height " << block_height);
|
||||
CHECK_AND_ASSERT_MES(type != typeid(tx_receiver), false, "tx " << tx_id << " contains tx_receiver which is not allowed on height " << block_height);
|
||||
CHECK_AND_ASSERT_MES(type != typeid(extra_alias_entry), false, "tx " << tx_id << " contains extra_alias_entry which is not allowed on height " << block_height);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
return check_lambda(tx.extra) && check_lambda(tx.attachment);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
#include <boost/mpl/unique.hpp>
|
||||
#include <boost/mpl/list.hpp>
|
||||
#include <boost/mpl/equal.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#include <boost/mpl/vector/vector30.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
|
@ -60,9 +60,9 @@ namespace currency
|
|||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
//since structure used in blockchain as a key accessor, then be sure that there is no padding inside
|
||||
//since structure used in blockchain as a key accessor, then be sure that there is no padding inside
|
||||
#pragma pack(push, 1)
|
||||
struct account_public_address
|
||||
struct account_public_address_old
|
||||
{
|
||||
crypto::public_key spend_public_key;
|
||||
crypto::public_key view_public_key;
|
||||
|
|
@ -72,13 +72,63 @@ namespace currency
|
|||
FIELD(view_public_key)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(spend_public_key, "m_spend_public_key")
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(view_public_key, "m_view_public_key")
|
||||
END_KV_SERIALIZE_MAP()
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(spend_public_key, "m_spend_public_key")
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(view_public_key, "m_view_public_key")
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
#define ACCOUNT_PUBLIC_ADDRESS_SERIZALIZATION_VER 1
|
||||
|
||||
#define ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE 0x01 // auditable address
|
||||
|
||||
//since structure used in blockchain as a key accessor, then be sure that there is no padding inside
|
||||
#pragma pack(push, 1)
|
||||
struct account_public_address
|
||||
{
|
||||
crypto::public_key spend_public_key;
|
||||
crypto::public_key view_public_key;
|
||||
uint8_t flags;
|
||||
|
||||
DEFINE_SERIALIZATION_VERSION(ACCOUNT_PUBLIC_ADDRESS_SERIZALIZATION_VER)
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(spend_public_key)
|
||||
FIELD(view_public_key)
|
||||
FIELD(flags)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(spend_public_key, "m_spend_public_key")
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(view_public_key, "m_view_public_key")
|
||||
KV_SERIALIZE(flags)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
bool is_auditable() const
|
||||
{
|
||||
return (flags & ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE) != 0;
|
||||
}
|
||||
|
||||
static account_public_address from_old(const account_public_address_old& rhs)
|
||||
{
|
||||
account_public_address result = AUTO_VAL_INIT(result);
|
||||
result.spend_public_key = rhs.spend_public_key;
|
||||
result.view_public_key = rhs.view_public_key;
|
||||
return result;
|
||||
}
|
||||
|
||||
account_public_address_old to_old() const
|
||||
{
|
||||
account_public_address_old result = AUTO_VAL_INIT(result);
|
||||
result.spend_public_key = spend_public_key;
|
||||
result.view_public_key = view_public_key;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
const static account_public_address null_pub_addr = AUTO_VAL_INIT(null_pub_addr);
|
||||
|
||||
typedef std::vector<crypto::signature> ring_signature;
|
||||
|
|
@ -226,9 +276,30 @@ namespace currency
|
|||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_payer_old
|
||||
{
|
||||
account_public_address_old acc_addr;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(acc_addr)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_payer
|
||||
{
|
||||
account_public_address acc_addr;
|
||||
tx_payer() = default;
|
||||
tx_payer(const tx_payer_old& old) : acc_addr(account_public_address::from_old(old.acc_addr)) {}
|
||||
|
||||
account_public_address acc_addr{};
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(acc_addr)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_receiver_old
|
||||
{
|
||||
account_public_address_old acc_addr;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(acc_addr)
|
||||
|
|
@ -237,7 +308,10 @@ namespace currency
|
|||
|
||||
struct tx_receiver
|
||||
{
|
||||
account_public_address acc_addr;
|
||||
tx_receiver() = default;
|
||||
tx_receiver(const tx_receiver_old& old) : acc_addr(account_public_address::from_old(old.acc_addr)) {}
|
||||
|
||||
account_public_address acc_addr{};
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(acc_addr)
|
||||
|
|
@ -299,8 +373,42 @@ namespace currency
|
|||
};
|
||||
|
||||
|
||||
struct extra_alias_entry_base_old
|
||||
{
|
||||
account_public_address_old m_address;
|
||||
std::string m_text_comment;
|
||||
std::vector<crypto::secret_key> m_view_key; // only one or zero elments expected (std::vector is using as memory efficient container for such a case)
|
||||
std::vector<crypto::signature> m_sign; // only one or zero elments expected (std::vector is using as memory efficient container for such a case)
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(m_address)
|
||||
FIELD(m_text_comment)
|
||||
FIELD(m_view_key)
|
||||
FIELD(m_sign)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct extra_alias_entry_old : public extra_alias_entry_base_old
|
||||
{
|
||||
std::string m_alias;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(m_alias)
|
||||
FIELDS(*static_cast<extra_alias_entry_base_old*>(this))
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct extra_alias_entry_base
|
||||
{
|
||||
extra_alias_entry_base() = default;
|
||||
extra_alias_entry_base(const extra_alias_entry_base_old& old)
|
||||
: m_address(account_public_address::from_old(old.m_address))
|
||||
, m_text_comment(old.m_text_comment)
|
||||
, m_view_key(old.m_view_key)
|
||||
, m_sign(old.m_sign)
|
||||
{
|
||||
}
|
||||
|
||||
account_public_address m_address;
|
||||
std::string m_text_comment;
|
||||
std::vector<crypto::secret_key> m_view_key; // only one or zero elments expected (std::vector is using as memory efficient container for such a case)
|
||||
|
|
@ -314,14 +422,32 @@ namespace currency
|
|||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct extra_alias_entry: public extra_alias_entry_base
|
||||
struct extra_alias_entry : public extra_alias_entry_base
|
||||
{
|
||||
extra_alias_entry() = default;
|
||||
extra_alias_entry(const extra_alias_entry_old& old)
|
||||
: extra_alias_entry_base(old)
|
||||
, m_alias(old.m_alias)
|
||||
{
|
||||
}
|
||||
|
||||
std::string m_alias;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(m_alias)
|
||||
FIELDS(*static_cast<extra_alias_entry_base *>(this))
|
||||
END_SERIALIZE()
|
||||
FIELDS(*static_cast<extra_alias_entry_base*>(this))
|
||||
END_SERIALIZE()
|
||||
|
||||
extra_alias_entry_old to_old() const
|
||||
{
|
||||
extra_alias_entry_old result = AUTO_VAL_INIT(result);
|
||||
result.m_address = m_address.to_old();
|
||||
result.m_text_comment = m_text_comment;
|
||||
result.m_view_key = m_view_key;
|
||||
result.m_sign = m_sign;
|
||||
result.m_alias = m_alias;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -390,9 +516,10 @@ namespace currency
|
|||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
typedef boost::mpl::vector<
|
||||
tx_service_attachment, tx_comment, tx_payer, tx_receiver, tx_derivation_hint, std::string, tx_crypto_checksum, etc_tx_time, etc_tx_details_unlock_time, etc_tx_details_expiration_time,
|
||||
etc_tx_details_flags, crypto::public_key, extra_attachment_info, extra_alias_entry, extra_user_data, extra_padding, etc_tx_uint16_t, etc_tx_details_unlock_time2
|
||||
typedef boost::mpl::vector21<
|
||||
tx_service_attachment, tx_comment, tx_payer_old, tx_receiver_old, tx_derivation_hint, std::string, tx_crypto_checksum, etc_tx_time, etc_tx_details_unlock_time, etc_tx_details_expiration_time,
|
||||
etc_tx_details_flags, crypto::public_key, extra_attachment_info, extra_alias_entry_old, extra_user_data, extra_padding, etc_tx_uint16_t, etc_tx_details_unlock_time2,
|
||||
tx_payer, tx_receiver, extra_alias_entry
|
||||
> all_payload_types;
|
||||
|
||||
typedef boost::make_variant_over<all_payload_types>::type payload_items_v;
|
||||
|
|
@ -604,7 +731,7 @@ SET_VARIANT_TAGS(currency::transaction, 5, "tx");
|
|||
SET_VARIANT_TAGS(currency::block, 6, "block");
|
||||
//attachment_v definitions
|
||||
SET_VARIANT_TAGS(currency::tx_comment, 7, "comment");
|
||||
SET_VARIANT_TAGS(currency::tx_payer, 8, "payer");
|
||||
SET_VARIANT_TAGS(currency::tx_payer_old, 8, "payer");
|
||||
SET_VARIANT_TAGS(std::string, 9, "string");
|
||||
SET_VARIANT_TAGS(currency::tx_crypto_checksum, 10, "checksum");
|
||||
SET_VARIANT_TAGS(currency::tx_derivation_hint, 11, "derivation_hint");
|
||||
|
|
@ -618,7 +745,7 @@ SET_VARIANT_TAGS(currency::signed_parts, 17, "signed_outs");
|
|||
//extra_v definitions
|
||||
SET_VARIANT_TAGS(currency::extra_attachment_info, 18, "extra_attach_info");
|
||||
SET_VARIANT_TAGS(currency::extra_user_data, 19, "user_data");
|
||||
SET_VARIANT_TAGS(currency::extra_alias_entry, 20, "alias_entry");
|
||||
SET_VARIANT_TAGS(currency::extra_alias_entry_old, 20, "alias_entry");
|
||||
SET_VARIANT_TAGS(currency::extra_padding, 21, "extra_padding");
|
||||
SET_VARIANT_TAGS(crypto::public_key, 22, "pub_key");
|
||||
SET_VARIANT_TAGS(currency::etc_tx_uint16_t, 23, "etc_tx_uint16");
|
||||
|
|
@ -629,7 +756,16 @@ SET_VARIANT_TAGS(uint64_t, 26, "uint64_t");
|
|||
//etc
|
||||
SET_VARIANT_TAGS(currency::etc_tx_time, 27, "etc_tx_time");
|
||||
SET_VARIANT_TAGS(uint32_t, 28, "uint32_t");
|
||||
SET_VARIANT_TAGS(currency::tx_receiver, 29, "payer");
|
||||
SET_VARIANT_TAGS(currency::tx_receiver_old, 29, "payer"); // -- original
|
||||
//SET_VARIANT_TAGS(currency::tx_receiver_old, 29, "receiver");
|
||||
SET_VARIANT_TAGS(currency::etc_tx_details_unlock_time2, 30, "unlock_time2");
|
||||
|
||||
SET_VARIANT_TAGS(currency::tx_payer, 31, "payer2");
|
||||
SET_VARIANT_TAGS(currency::tx_receiver, 32, "receiver2");
|
||||
|
||||
// @#@ TODO @#@
|
||||
SET_VARIANT_TAGS(currency::extra_alias_entry, 33, "alias_entry2");
|
||||
|
||||
|
||||
|
||||
#undef SET_VARIANT_TAGS
|
||||
|
|
|
|||
|
|
@ -29,10 +29,18 @@ namespace boost
|
|||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::account_public_address &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
//a & x.version;
|
||||
a & x.flags;
|
||||
a & x.spend_public_key;
|
||||
a & x.view_public_key;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::account_public_address_old &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.spend_public_key;
|
||||
a & x.view_public_key;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::txout_to_key &x, const boost::serialization::version_type ver)
|
||||
|
|
@ -90,11 +98,24 @@ namespace boost
|
|||
a & x.comment;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::tx_payer_old &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.acc_addr;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::tx_payer &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.acc_addr;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::tx_receiver_old &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.acc_addr;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::tx_receiver &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
|
|
@ -136,14 +157,6 @@ namespace boost
|
|||
a & x.m_sign;
|
||||
}
|
||||
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::signed_parts &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.n_outs;
|
||||
a & x.n_extras;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::extra_alias_entry &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
|
|
@ -151,6 +164,29 @@ namespace boost
|
|||
a & static_cast<currency::extra_alias_entry_base&>(x);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::extra_alias_entry_base_old &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.m_address;
|
||||
a & x.m_text_comment;
|
||||
a & x.m_view_key;
|
||||
a & x.m_sign;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::extra_alias_entry_old &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.m_alias;
|
||||
a & static_cast<currency::extra_alias_entry_base_old&>(x);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::signed_parts &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.n_outs;
|
||||
a & x.n_extras;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, currency::extra_padding &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,8 +20,11 @@
|
|||
#define CURRENCY_MAX_BLOCK_NUMBER 500000000
|
||||
#define CURRENCY_MAX_BLOCK_SIZE 500000000 // block header blob limit, never used!
|
||||
#define CURRENCY_TX_MAX_ALLOWED_OUTS 2000
|
||||
#define CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX 197 // addresses start with 'Z'
|
||||
#define CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX 0xc5 // addresses start with 'Zx'
|
||||
#define CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX 0x3678 // integrated addresses start with 'iZ'
|
||||
#define CURRENCY_PUBLIC_INTEG_ADDRESS_V2_BASE58_PREFIX 0x36f8 // integrated addresses start with 'iZ' (new format)
|
||||
#define CURRENCY_PUBLIC_AUDITABLE_ADDRESS_BASE58_PREFIX 0x98c8 // auditable addresses start with 'aZx'
|
||||
#define CURRENCY_PUBLIC_AUDITABLE_INTEG_ADDRESS_BASE58_PREFIX 0x8a49 // auditable integrated addresses start with 'aiZX'
|
||||
#define CURRENCY_MINED_MONEY_UNLOCK_WINDOW 10
|
||||
#define CURRENT_TRANSACTION_VERSION 1
|
||||
#define CURRENT_BLOCK_MAJOR_VERSION 1
|
||||
|
|
@ -141,7 +144,8 @@
|
|||
#define POS_MINIMUM_COINSTAKE_AGE 10 // blocks count
|
||||
|
||||
|
||||
#define WALLET_FILE_SIGNATURE 0x1111012101101011LL //Bender's nightmare
|
||||
#define WALLET_FILE_SIGNATURE_OLD 0x1111012101101011LL // Bender's nightmare
|
||||
#define WALLET_FILE_SIGNATURE_V2 0x1111011201101011LL // another Bender's nightmare
|
||||
#define WALLET_FILE_MAX_BODY_SIZE 0x88888888L //2GB
|
||||
#define WALLET_FILE_MAX_KEYS_SIZE 10000 //
|
||||
#define WALLET_BRAIN_DATE_OFFSET 1543622400
|
||||
|
|
@ -216,7 +220,7 @@
|
|||
#define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin"
|
||||
|
||||
|
||||
#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+66)
|
||||
#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+67)
|
||||
|
||||
|
||||
#define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31)
|
||||
|
|
|
|||
|
|
@ -493,7 +493,17 @@ namespace currency
|
|||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::add_new_block(const block& b, block_verification_context& bvc)
|
||||
{
|
||||
return m_blockchain_storage.add_new_block(b, bvc);
|
||||
bool r = m_blockchain_storage.add_new_block(b, bvc);
|
||||
if (r && bvc.m_added_to_main_chain)
|
||||
{
|
||||
uint64_t h = get_block_height(b);
|
||||
auto& crc = m_blockchain_storage.get_core_runtime_config();
|
||||
if (h == crc.hard_fork_01_starts_after_height + 1)
|
||||
{ LOG_PRINT_GREEN("Hardfork 1 activated at height " << h, LOG_LEVEL_0); }
|
||||
else if (h == crc.hard_fork_02_starts_after_height + 1)
|
||||
{ LOG_PRINT_GREEN("Hardfork 2 activated at height " << h, LOG_LEVEL_0); }
|
||||
}
|
||||
return r;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::parse_block(const blobdata& block_blob, block& b, block_verification_context& bvc)
|
||||
|
|
|
|||
|
|
@ -313,6 +313,46 @@ namespace currency
|
|||
return string_tools::get_xtype_from_string(amount, str_amount);
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool parse_awo_blob(const std::string& awo_blob, account_public_address& address, crypto::secret_key& view_sec_key, uint64_t& creation_timestamp)
|
||||
{
|
||||
std::vector<std::string> parts;
|
||||
boost::split(parts, awo_blob, [](char x){ return x == ':'; } );
|
||||
if (parts.size() != 2 && parts.size() != 3)
|
||||
return false;
|
||||
|
||||
if (!get_account_address_from_str(address, parts[0]))
|
||||
return false;
|
||||
|
||||
if (!address.is_auditable())
|
||||
return false;
|
||||
|
||||
if (!epee::string_tools::parse_tpod_from_hex_string(parts[1], view_sec_key))
|
||||
return false;
|
||||
|
||||
crypto::public_key view_pub_key = AUTO_VAL_INIT(view_pub_key);
|
||||
if (!crypto::secret_key_to_public_key(view_sec_key, view_pub_key))
|
||||
return false;
|
||||
|
||||
if (view_pub_key != address.view_public_key)
|
||||
return false;
|
||||
|
||||
creation_timestamp = 0;
|
||||
if (parts.size() == 3)
|
||||
{
|
||||
// parse timestamp
|
||||
int64_t ts = 0;
|
||||
if (!epee::string_tools::string_to_num_fast(parts[2], ts))
|
||||
return false;
|
||||
|
||||
if (ts < WALLET_BRAIN_DATE_OFFSET)
|
||||
return false;
|
||||
|
||||
creation_timestamp = ts;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
std::string print_stake_kernel_info(const stake_kernel& sk)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
|
@ -421,13 +461,16 @@ namespace currency
|
|||
rei.m_attachment_info = ai;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator()(const extra_alias_entry& ae) const
|
||||
{
|
||||
ENSURE_ONETIME(was_alias, "alias");
|
||||
rei.m_alias = ae;
|
||||
return true;
|
||||
}
|
||||
bool operator()(const extra_alias_entry_old& ae) const
|
||||
{
|
||||
return operator()(static_cast<const extra_alias_entry&>(ae));
|
||||
}
|
||||
bool operator()(const extra_user_data& ud) const
|
||||
{
|
||||
ENSURE_ONETIME(was_userdata, "userdata");
|
||||
|
|
@ -589,7 +632,12 @@ namespace currency
|
|||
//out to key
|
||||
txout_to_key tk;
|
||||
tk.key = target_keys.back();
|
||||
tk.mix_attr = tx_outs_attr;
|
||||
|
||||
if (de.addr.front().is_auditable()) // check only the first address because there's only one in this branch
|
||||
tk.mix_attr = CURRENCY_TO_KEY_OUT_FORCED_NO_MIX; // override mix_attr to 1 for auditable target addresses
|
||||
else
|
||||
tk.mix_attr = tx_outs_attr;
|
||||
|
||||
out.target = tk;
|
||||
}
|
||||
else
|
||||
|
|
@ -1106,7 +1154,7 @@ namespace currency
|
|||
//fill outputs
|
||||
size_t output_index = tx.vout.size(); // in case of append mode we need to start output indexing from the last one + 1
|
||||
std::set<uint16_t> deriv_cache;
|
||||
BOOST_FOREACH(const tx_destination_entry& dst_entr, shuffled_dsts)
|
||||
for(const tx_destination_entry& dst_entr : shuffled_dsts)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(dst_entr.amount > 0, false, "Destination with wrong amount: " << dst_entr.amount);
|
||||
bool r = construct_tx_out(dst_entr, txkey.sec, output_index, tx, deriv_cache, tx_outs_attr);
|
||||
|
|
@ -1251,7 +1299,7 @@ namespace currency
|
|||
{
|
||||
uint64_t date_offset = timestamp > WALLET_BRAIN_DATE_OFFSET ? timestamp - WALLET_BRAIN_DATE_OFFSET : 0;
|
||||
uint64_t weeks_count = date_offset / WALLET_BRAIN_DATE_QUANTUM;
|
||||
CHECK_AND_ASSERT_THROW_MES(weeks_count < std::numeric_limits<uint32_t>::max(), "internal error: unable to converto to uint32, val = " << weeks_count);
|
||||
CHECK_AND_ASSERT_THROW_MES(weeks_count < std::numeric_limits<uint32_t>::max(), "internal error: unable to convert to uint32, val = " << weeks_count);
|
||||
uint32_t weeks_count_32 = static_cast<uint32_t>(weeks_count);
|
||||
|
||||
return tools::mnemonic_encoding::word_by_num(weeks_count_32);
|
||||
|
|
@ -2026,7 +2074,7 @@ namespace currency
|
|||
//---------------------------------------------------------------
|
||||
bool is_showing_sender_addres(const transaction& tx)
|
||||
{
|
||||
return have_type_in_variant_container<tx_payer>(tx.attachment);
|
||||
return have_type_in_variant_container<tx_payer>(tx.attachment) || have_type_in_variant_container<tx_payer_old>(tx.attachment);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool is_mixin_tx(const transaction& tx)
|
||||
|
|
@ -2181,6 +2229,10 @@ namespace currency
|
|||
|
||||
return true;
|
||||
}
|
||||
bool operator()(const extra_alias_entry_old& ee)
|
||||
{
|
||||
return operator()(static_cast<const extra_alias_entry&>(ee));
|
||||
}
|
||||
bool operator()(const extra_user_data& ee)
|
||||
{
|
||||
tv.type = "user_data";
|
||||
|
|
@ -2214,7 +2266,13 @@ namespace currency
|
|||
|
||||
return true;
|
||||
}
|
||||
bool operator()(const tx_payer_old&)
|
||||
{
|
||||
tv.type = "payer_old";
|
||||
tv.short_view = "(encrypted)";
|
||||
|
||||
return true;
|
||||
}
|
||||
bool operator()(const tx_receiver& ee)
|
||||
{
|
||||
//const tx_payer& ee = boost::get<tx_payer>(extra);
|
||||
|
|
@ -2223,6 +2281,13 @@ namespace currency
|
|||
|
||||
return true;
|
||||
}
|
||||
bool operator()(const tx_receiver_old& ee)
|
||||
{
|
||||
tv.type = "receiver_old";
|
||||
tv.short_view = "(encrypted)";
|
||||
|
||||
return true;
|
||||
}
|
||||
bool operator()(const tx_derivation_hint& ee)
|
||||
{
|
||||
tv.type = "derivation_hint";
|
||||
|
|
@ -2511,12 +2576,24 @@ namespace currency
|
|||
//-----------------------------------------------------------------------
|
||||
std::string get_account_address_as_str(const account_public_address& addr)
|
||||
{
|
||||
return tools::base58::encode_addr(CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr));
|
||||
if (addr.flags == 0)
|
||||
return tools::base58::encode_addr(CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr.to_old())); // classic Zano address
|
||||
|
||||
if (addr.flags & ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE)
|
||||
return tools::base58::encode_addr(CURRENCY_PUBLIC_AUDITABLE_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr)); // new format Zano address (auditable)
|
||||
|
||||
return tools::base58::encode_addr(CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr)); // new format Zano address (normal)
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
std::string get_account_address_and_payment_id_as_str(const account_public_address& addr, const payment_id_t& payment_id)
|
||||
{
|
||||
return tools::base58::encode_addr(CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr) + payment_id);
|
||||
if (addr.flags == 0)
|
||||
return tools::base58::encode_addr(CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr.to_old()) + payment_id); // classic integrated Zano address
|
||||
|
||||
if (addr.flags & ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE)
|
||||
return tools::base58::encode_addr(CURRENCY_PUBLIC_AUDITABLE_INTEG_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(addr) + payment_id); // new format integrated Zano address (auditable)
|
||||
|
||||
return tools::base58::encode_addr(CURRENCY_PUBLIC_INTEG_ADDRESS_V2_BASE58_PREFIX, t_serializable_object_to_blob(addr) + payment_id); // new format integrated Zano address (normal)
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
bool get_account_address_from_str(account_public_address& addr, const std::string& str)
|
||||
|
|
@ -2527,7 +2604,7 @@ namespace currency
|
|||
//-----------------------------------------------------------------------
|
||||
bool get_account_address_and_payment_id_from_str(account_public_address& addr, payment_id_t& payment_id, const std::string& str)
|
||||
{
|
||||
static const size_t addr_blob_size = sizeof(account_public_address);
|
||||
payment_id.clear();
|
||||
blobdata blob;
|
||||
uint64_t prefix;
|
||||
if (!tools::base58::decode_addr(str, prefix, blob))
|
||||
|
|
@ -2536,42 +2613,88 @@ namespace currency
|
|||
return false;
|
||||
}
|
||||
|
||||
if (blob.size() < addr_blob_size)
|
||||
if (blob.size() < sizeof(account_public_address_old))
|
||||
{
|
||||
LOG_PRINT_L1("Address " << str << " has invalid format: blob size is " << blob.size() << " which is less, than expected " << addr_blob_size);
|
||||
LOG_PRINT_L1("Address " << str << " has invalid format: blob size is " << blob.size() << " which is less, than expected " << sizeof(account_public_address_old));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (blob.size() > addr_blob_size + BC_PAYMENT_ID_SERVICE_SIZE_MAX)
|
||||
if (blob.size() > sizeof(account_public_address) + BC_PAYMENT_ID_SERVICE_SIZE_MAX)
|
||||
{
|
||||
LOG_PRINT_L1("Address " << str << " has invalid format: blob size is " << blob.size() << " which is more, than allowed " << addr_blob_size + BC_PAYMENT_ID_SERVICE_SIZE_MAX);
|
||||
LOG_PRINT_L1("Address " << str << " has invalid format: blob size is " << blob.size() << " which is more, than allowed " << sizeof(account_public_address) + BC_PAYMENT_ID_SERVICE_SIZE_MAX);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_as_old_format = false;
|
||||
|
||||
if (prefix == CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX)
|
||||
{
|
||||
// nothing
|
||||
// normal address
|
||||
if (blob.size() == sizeof(account_public_address_old))
|
||||
{
|
||||
parse_as_old_format = true;
|
||||
}
|
||||
else if (blob.size() == sizeof(account_public_address))
|
||||
{
|
||||
parse_as_old_format = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L1("Account public address cannot be parsed from \"" << str << "\", incorrect size");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (prefix == CURRENCY_PUBLIC_AUDITABLE_ADDRESS_BASE58_PREFIX)
|
||||
{
|
||||
// auditable, parse as new format
|
||||
parse_as_old_format = false;
|
||||
}
|
||||
else if (prefix == CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX)
|
||||
{
|
||||
payment_id = blob.substr(addr_blob_size);
|
||||
blob = blob.substr(0, addr_blob_size);
|
||||
payment_id = blob.substr(sizeof(account_public_address_old));
|
||||
blob = blob.substr(0, sizeof(account_public_address_old));
|
||||
parse_as_old_format = true;
|
||||
}
|
||||
else if (prefix == CURRENCY_PUBLIC_AUDITABLE_INTEG_ADDRESS_BASE58_PREFIX || prefix == CURRENCY_PUBLIC_INTEG_ADDRESS_V2_BASE58_PREFIX)
|
||||
{
|
||||
payment_id = blob.substr(sizeof(account_public_address));
|
||||
blob = blob.substr(0, sizeof(account_public_address));
|
||||
parse_as_old_format = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L1("Address " << str << " has wrong prefix " << prefix << ", expected " << CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX << " or " << CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX);
|
||||
LOG_PRINT_L1("Address " << str << " has wrong prefix " << prefix);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!::serialization::parse_binary(blob, addr))
|
||||
if (parse_as_old_format)
|
||||
{
|
||||
LOG_PRINT_L1("Account public address keys can't be parsed for address \"" << str << "\"");
|
||||
account_public_address_old addr_old = AUTO_VAL_INIT(addr_old);
|
||||
if (!::serialization::parse_binary(blob, addr_old))
|
||||
{
|
||||
LOG_PRINT_L1("Account public address (old) cannot be parsed from \"" << str << "\"");
|
||||
return false;
|
||||
}
|
||||
addr = account_public_address::from_old(addr_old);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!::serialization::parse_binary(blob, addr))
|
||||
{
|
||||
LOG_PRINT_L1("Account public address cannot be parsed from \"" << str << "\"");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (payment_id.size() > BC_PAYMENT_ID_SERVICE_SIZE_MAX)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to parse address from \"" << str << "\": payment id size exceeded: " << payment_id.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!crypto::check_key(addr.spend_public_key) || !crypto::check_key(addr.view_public_key))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to validate address keys for address \"" << str << "\"");
|
||||
LOG_PRINT_L1("Failed to validate address keys for public address \"" << str << "\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "blockchain_storage_basic.h"
|
||||
#include "currency_format_utils_blocks.h"
|
||||
#include "currency_format_utils_transactions.h"
|
||||
#include "core_runtime_config.h"
|
||||
|
||||
|
||||
// ------ get_tx_type_definition -------------
|
||||
|
|
@ -238,6 +239,7 @@ namespace currency
|
|||
bool check_inputs_types_supported(const transaction& tx);
|
||||
bool check_outs_valid(const transaction& tx);
|
||||
bool parse_amount(uint64_t& amount, const std::string& str_amount);
|
||||
bool parse_awo_blob(const std::string& awo_blob, account_public_address& address, crypto::secret_key& view_sec_key, uint64_t& creation_timestamp);
|
||||
|
||||
|
||||
|
||||
|
|
@ -589,6 +591,51 @@ namespace currency
|
|||
return boost::apply_visitor(input_amount_getter(), v);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template <typename container_t>
|
||||
void create_and_add_tx_payer_to_container_from_address(container_t& container, const account_public_address& addr, uint64_t top_block_height, const core_runtime_config& crc)
|
||||
{
|
||||
if (top_block_height > crc.hard_fork_02_starts_after_height)
|
||||
{
|
||||
// after hardfork 2
|
||||
tx_payer result = AUTO_VAL_INIT(result);
|
||||
result.acc_addr = addr;
|
||||
container.push_back(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// before hardfork 2 -- add only if addr is not auditable
|
||||
if (!addr.is_auditable())
|
||||
{
|
||||
tx_payer_old result = AUTO_VAL_INIT(result);
|
||||
result.acc_addr = addr.to_old();
|
||||
container.push_back(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template <typename container_t>
|
||||
void create_and_add_tx_receiver_to_container_from_address(container_t& container, const account_public_address& addr, uint64_t top_block_height, const core_runtime_config& crc)
|
||||
{
|
||||
if (top_block_height > crc.hard_fork_02_starts_after_height)
|
||||
{
|
||||
// after hardfork 2
|
||||
tx_receiver result = AUTO_VAL_INIT(result);
|
||||
result.acc_addr = addr;
|
||||
container.push_back(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// before hardfork 2 -- add only if addr is not auditable
|
||||
if (!addr.is_auditable())
|
||||
{
|
||||
tx_receiver_old result = AUTO_VAL_INIT(result);
|
||||
result.acc_addr = addr.to_old();
|
||||
container.push_back(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
//---------------------------------------------------------------
|
||||
std::ostream& operator <<(std::ostream& o, const ref_by_id& r);
|
||||
//---------------------------------------------------------------
|
||||
#ifndef ANDROID_BUILD
|
||||
|
|
|
|||
|
|
@ -107,8 +107,9 @@ namespace currency
|
|||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// callback should return true to continue iterating through the container
|
||||
template <typename A, typename B, typename container_t, typename callback_t>
|
||||
bool handle_2_alternative_types_in_variant_container(const container_t& container, callback_t& cb)
|
||||
bool handle_2_alternative_types_in_variant_container(const container_t& container, callback_t cb)
|
||||
{
|
||||
bool found = false;
|
||||
for (auto& item : container)
|
||||
|
|
@ -122,7 +123,7 @@ namespace currency
|
|||
else if (item.type() == typeid(B))
|
||||
{
|
||||
found = true;
|
||||
if (!cb(boost::get<A>(item)))
|
||||
if (!cb(boost::get<B>(item)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1587,7 +1587,7 @@ QString MainWindow::restore_wallet(const QString& param)
|
|||
//return que_call2<view::restore_wallet_request>("restore_wallet", param, [this](const view::restore_wallet_request& owd, view::api_response& ar){
|
||||
PREPARE_ARG_FROM_JSON(view::restore_wallet_request, owd);
|
||||
PREPARE_RESPONSE(view::open_wallet_response, ar);
|
||||
ar.error_code = m_backend.restore_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, owd.restore_key, ar.response_data);
|
||||
ar.error_code = m_backend.restore_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, owd.restore_key, owd.auditable_watch_only, ar.response_data);
|
||||
return MAKE_RESPONSE(ar);
|
||||
CATCH_ENTRY_FAIL_API_RESPONCE();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,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<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", ""};
|
||||
const command_line::arg_descriptor<std::string> arg_password = {"password", "Wallet password", "", true};
|
||||
|
|
@ -51,6 +52,7 @@ namespace
|
|||
const command_line::arg_descriptor<bool> arg_do_pos_mining = { "do-pos-mining", "Do PoS mining", false, false };
|
||||
const command_line::arg_descriptor<std::string> arg_pos_mining_reward_address = { "pos-mining-reward-address", "Block reward will be sent to the giving address if specified", "" };
|
||||
const command_line::arg_descriptor<std::string> arg_restore_wallet = { "restore-wallet", "Restore wallet from the seed phrase and save it to <arg>", "" };
|
||||
const command_line::arg_descriptor<std::string> arg_restore_awo_wallet = { "restore-awo-wallet", "Restore auditable watch-only wallet from address and view key. Use \"address:viewkey\" as argument", "" };
|
||||
const command_line::arg_descriptor<bool> arg_offline_mode = { "offline-mode", "Don't connect to daemon, work offline (for cold-signing process)", false, true };
|
||||
|
||||
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
|
||||
|
|
@ -219,6 +221,8 @@ simple_wallet::simple_wallet()
|
|||
|
||||
m_cmd_binder.set_handler("get_tx_key", boost::bind(&simple_wallet::get_tx_key, this, _1), "Get transaction one-time secret key (r) for a given <txid>");
|
||||
|
||||
m_cmd_binder.set_handler("awo_blob", boost::bind(&simple_wallet::awo_blob, this, _1), "For auditable wallets: prints auditable watch-only blob for wallet's audit by a third party");
|
||||
|
||||
m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data");
|
||||
m_cmd_binder.set_handler("save_watch_only", boost::bind(&simple_wallet::save_watch_only, this, _1), "save_watch_only <filename> <password> - save as watch-only wallet file.");
|
||||
|
||||
|
|
@ -270,9 +274,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (m_wallet_file.empty() && m_generate_new.empty() && m_restore_wallet.empty())
|
||||
if (m_wallet_file.empty() && m_generate_new.empty() && m_restore_wallet.empty() && m_restore_awo_wallet.empty() && m_generate_new_aw.empty())
|
||||
{
|
||||
fail_msg_writer() << "you must specify --wallet-file, --generate-new-wallet or --restore-wallet";
|
||||
fail_msg_writer() << "you must specify --wallet-file, --generate-new-wallet, --generate-new-auditable-wallet, --restore-wallet or --restore-awo-wallet";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -311,9 +315,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
|
|||
|
||||
if (!m_generate_new.empty())
|
||||
{
|
||||
bool r = new_wallet(m_generate_new, pwd_container.password());
|
||||
CHECK_AND_ASSERT_MES(r, false, "account creation failed");
|
||||
|
||||
bool r = new_wallet(m_generate_new, pwd_container.password(), false);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to create new wallet");
|
||||
}
|
||||
else if (!m_generate_new_aw.empty())
|
||||
{
|
||||
bool r = new_wallet(m_generate_new_aw, pwd_container.password(), true);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to create new auditable wallet");
|
||||
}
|
||||
else if (!m_restore_wallet.empty())
|
||||
{
|
||||
|
|
@ -330,7 +338,25 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool r = restore_wallet(m_restore_wallet, restore_seed_container.password(), pwd_container.password());
|
||||
bool r = restore_wallet(m_restore_wallet, restore_seed_container.password(), pwd_container.password(), false);
|
||||
CHECK_AND_ASSERT_MES(r, false, "wallet restoring failed");
|
||||
}
|
||||
else if (!m_restore_awo_wallet.empty())
|
||||
{
|
||||
if (boost::filesystem::exists(m_restore_awo_wallet))
|
||||
{
|
||||
fail_msg_writer() << "file " << m_restore_awo_wallet << " already exists";
|
||||
return false;
|
||||
}
|
||||
|
||||
tools::password_container restore_addr_and_viewkey_container;
|
||||
if (!restore_addr_and_viewkey_container.read_password("please, enter wallet auditable address, viewkey and timestamp, separated by a colon (\"address:viewkey:timestamp\"):\n"))
|
||||
{
|
||||
fail_msg_writer() << "failed to read seed phrase";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool r = restore_wallet(m_restore_awo_wallet, restore_addr_and_viewkey_container.password(), pwd_container.password(), true);
|
||||
CHECK_AND_ASSERT_MES(r, false, "wallet restoring failed");
|
||||
}
|
||||
else
|
||||
|
|
@ -354,12 +380,14 @@ void simple_wallet::handle_command_line(const boost::program_options::variables_
|
|||
{
|
||||
m_wallet_file = command_line::get_arg(vm, arg_wallet_file);
|
||||
m_generate_new = command_line::get_arg(vm, arg_generate_new_wallet);
|
||||
m_generate_new_aw = command_line::get_arg(vm, arg_generate_new_auditable_wallet);
|
||||
m_daemon_address = command_line::get_arg(vm, arg_daemon_address);
|
||||
m_daemon_host = command_line::get_arg(vm, arg_daemon_host);
|
||||
m_daemon_port = command_line::get_arg(vm, arg_daemon_port);
|
||||
m_do_not_set_date = command_line::get_arg(vm, arg_dont_set_date);
|
||||
m_do_pos_mining = command_line::get_arg(vm, arg_do_pos_mining);
|
||||
m_restore_wallet = command_line::get_arg(vm, arg_restore_wallet);
|
||||
m_restore_awo_wallet = command_line::get_arg(vm, arg_restore_awo_wallet);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::try_connect_to_daemon()
|
||||
|
|
@ -374,7 +402,7 @@ bool simple_wallet::try_connect_to_daemon()
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password)
|
||||
bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password, bool create_auditable_wallet)
|
||||
{
|
||||
m_wallet_file = wallet_file;
|
||||
|
||||
|
|
@ -383,10 +411,10 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas
|
|||
m_wallet->set_do_rise_transfer(false);
|
||||
try
|
||||
{
|
||||
m_wallet->generate(epee::string_encoding::utf8_to_wstring(m_wallet_file), password);
|
||||
message_writer(epee::log_space::console_color_white, true) << "Generated new wallet: " << m_wallet->get_account().get_public_address_str();
|
||||
m_wallet->generate(epee::string_encoding::utf8_to_wstring(m_wallet_file), password, create_auditable_wallet);
|
||||
message_writer(epee::log_space::console_color_white, true) << "Generated new " << (create_auditable_wallet ? "AUDITABLE" : "") << " wallet: " << m_wallet->get_account().get_public_address_str();
|
||||
std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush;
|
||||
if(m_do_not_set_date)
|
||||
if (m_do_not_set_date)
|
||||
m_wallet->reset_creation_time(0);
|
||||
|
||||
if (m_print_brain_wallet)
|
||||
|
|
@ -407,16 +435,11 @@ bool simple_wallet::new_wallet(const string &wallet_file, const std::string& pas
|
|||
success_msg_writer() <<
|
||||
"**********************************************************************\n" <<
|
||||
"Your wallet has been generated.\n" <<
|
||||
"To start synchronizing with the daemon use \"refresh\" command.\n" <<
|
||||
"Use \"help\" command to see the list of available commands.\n" <<
|
||||
"Always use \"exit\" command when closing simplewallet to save\n" <<
|
||||
"current session's state. Otherwise, you will possibly need to synchronize \n" <<
|
||||
"your wallet again. Your wallet key is NOT under risk anyway.\n" <<
|
||||
"**********************************************************************";
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::restore_wallet(const std::string &wallet_file, const std::string &restore_seed, const std::string& password)
|
||||
bool simple_wallet::restore_wallet(const std::string &wallet_file, const std::string &seed_or_awo_blob, const std::string& password, bool auditable_watch_only)
|
||||
{
|
||||
m_wallet_file = wallet_file;
|
||||
|
||||
|
|
@ -425,15 +448,24 @@ bool simple_wallet::restore_wallet(const std::string &wallet_file, const std::st
|
|||
m_wallet->set_do_rise_transfer(false);
|
||||
try
|
||||
{
|
||||
m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, restore_seed);
|
||||
message_writer(epee::log_space::console_color_white, true) << "Wallet restored: " << m_wallet->get_account().get_public_address_str();
|
||||
std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush;
|
||||
if (auditable_watch_only)
|
||||
{
|
||||
m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_awo_blob, true);
|
||||
message_writer(epee::log_space::console_color_white, true) << "Auditable watch-only wallet restored: " << m_wallet->get_account().get_public_address_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal wallet
|
||||
m_wallet->restore(epee::string_encoding::utf8_to_wstring(wallet_file), password, seed_or_awo_blob, false);
|
||||
message_writer(epee::log_space::console_color_white, true) << "Wallet restored: " << m_wallet->get_account().get_public_address_str();
|
||||
std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().view_secret_key) << std::endl << std::flush;
|
||||
}
|
||||
if (m_do_not_set_date)
|
||||
m_wallet->reset_creation_time(0);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
fail_msg_writer() << "failed to restore wallet: " << e.what();
|
||||
fail_msg_writer() << "failed to restore wallet, check your " << (auditable_watch_only ? "awo blob!" : "seed phrase!") << ENDL << e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -462,7 +494,7 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa
|
|||
try
|
||||
{
|
||||
m_wallet->load(epee::string_encoding::utf8_to_wstring(m_wallet_file), password);
|
||||
message_writer(epee::log_space::console_color_white, true) << "Opened" << (m_wallet->is_watch_only() ? " watch-only" : "") << " wallet: " << m_wallet->get_account().get_public_address_str();
|
||||
message_writer(epee::log_space::console_color_white, true) << "Opened" << (m_wallet->is_auditable() ? " auditable" : "") << (m_wallet->is_watch_only() ? " watch-only" : "") << " wallet: " << m_wallet->get_account().get_public_address_str();
|
||||
|
||||
if (m_print_brain_wallet)
|
||||
std::cout << "Brain wallet: " << m_wallet->get_account().get_restore_braindata() << std::endl << std::flush;
|
||||
|
|
@ -592,22 +624,40 @@ void simple_wallet::on_new_block(uint64_t height, const currency::block& block)
|
|||
m_refresh_progress_reporter.update(height, false);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void simple_wallet::on_money_received(uint64_t height, const currency::transaction& tx, size_t out_index)
|
||||
std::string print_money_trailing_zeros_replaced_with_spaces(uint64_t amount)
|
||||
{
|
||||
message_writer(epee::log_space::console_color_green, false) <<
|
||||
"Height " << height <<
|
||||
", transaction " << get_transaction_hash(tx) <<
|
||||
", received " << print_money(tx.vout[out_index].amount);
|
||||
m_refresh_progress_reporter.update(height, true);
|
||||
std::string s = print_money(amount);
|
||||
size_t p = s.find_last_not_of('0');
|
||||
if (p != std::string::npos)
|
||||
{
|
||||
if (s[p] == '.')
|
||||
++p;
|
||||
size_t l = s.length() - p - 1;
|
||||
return s.replace(p + 1, l, l, ' ');
|
||||
}
|
||||
return s;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void simple_wallet::on_money_spent(uint64_t height, const currency::transaction& in_tx, size_t out_index, const currency::transaction& spend_tx)
|
||||
void simple_wallet::on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined)
|
||||
{
|
||||
message_writer(epee::log_space::console_color_magenta, false) <<
|
||||
"Height " << height <<
|
||||
", transaction " << get_transaction_hash(spend_tx) <<
|
||||
", spent " << print_money(in_tx.vout[out_index].amount);
|
||||
m_refresh_progress_reporter.update(height, true);
|
||||
epee::log_space::console_colors color = wti.is_income ? epee::log_space::console_color_green : epee::log_space::console_color_magenta;
|
||||
message_writer(color, false) <<
|
||||
"height " << wti.height <<
|
||||
", tx " << wti.tx_hash <<
|
||||
" " << std::right << std::setw(18) << print_money_trailing_zeros_replaced_with_spaces(wti.amount) << (wti.is_income ? " received," : " spent, ") <<
|
||||
" balance: " << print_money_brief(balance);
|
||||
m_refresh_progress_reporter.update(wti.height, true);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void simple_wallet::on_message(i_wallet2_callback::message_severity severity, const std::string& m)
|
||||
{
|
||||
epee::log_space::console_colors color = epee::log_space::console_color_white;
|
||||
if (severity == i_wallet2_callback::ms_red)
|
||||
color = epee::log_space::console_color_red;
|
||||
else if (severity == i_wallet2_callback::ms_yellow)
|
||||
color = epee::log_space::console_color_yellow;
|
||||
|
||||
message_writer(color, true, std::string()) << m;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::refresh(const std::vector<std::string>& args)
|
||||
|
|
@ -1322,7 +1372,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
|||
bool simple_wallet::show_seed(const std::vector<std::string> &args)
|
||||
{
|
||||
success_msg_writer() << "Here's your wallet's seed phrase. Write it down and keep in a safe place.";
|
||||
success_msg_writer(true) << "Anyone who knows the following 25 words can access your wallet:";
|
||||
success_msg_writer(true) << "Anyone who knows the following 26 words can access your wallet:";
|
||||
std::cout << m_wallet->get_account().get_restore_braindata() << std::endl << std::flush;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1452,6 +1502,19 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
|
|||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::awo_blob(const std::vector<std::string> &args_)
|
||||
{
|
||||
if (!m_wallet->is_auditable())
|
||||
{
|
||||
fail_msg_writer() << "this command is allowed for auditable wallets only";
|
||||
return true;
|
||||
}
|
||||
|
||||
success_msg_writer() << "Auditable watch-only blob for this wallet is:";
|
||||
std::cout << m_wallet->get_account().get_awo_blob() << ENDL;
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void simple_wallet::set_offline_mode(bool offline_mode)
|
||||
{
|
||||
if (offline_mode && !m_offline_mode)
|
||||
|
|
@ -1702,6 +1765,7 @@ int main(int argc, char* argv[])
|
|||
po::options_description desc_params("Wallet options");
|
||||
command_line::add_arg(desc_params, arg_wallet_file);
|
||||
command_line::add_arg(desc_params, arg_generate_new_wallet);
|
||||
command_line::add_arg(desc_params, arg_generate_new_auditable_wallet);
|
||||
command_line::add_arg(desc_params, arg_password);
|
||||
command_line::add_arg(desc_params, arg_daemon_address);
|
||||
command_line::add_arg(desc_params, arg_daemon_host);
|
||||
|
|
@ -1714,6 +1778,7 @@ int main(int argc, char* argv[])
|
|||
command_line::add_arg(desc_params, arg_do_pos_mining);
|
||||
command_line::add_arg(desc_params, arg_pos_mining_reward_address);
|
||||
command_line::add_arg(desc_params, arg_restore_wallet);
|
||||
command_line::add_arg(desc_params, arg_restore_awo_wallet);
|
||||
command_line::add_arg(desc_params, arg_offline_mode);
|
||||
command_line::add_arg(desc_params, command_line::arg_log_file);
|
||||
command_line::add_arg(desc_params, command_line::arg_log_level);
|
||||
|
|
@ -1848,7 +1913,7 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
LOG_PRINT_L0("Initializing wallet...");
|
||||
wal.init(daemon_address);
|
||||
if (command_line::get_arg(vm, arg_generate_new_wallet).size())
|
||||
if (command_line::get_arg(vm, arg_generate_new_wallet).size() || command_line::get_arg(vm, arg_generate_new_auditable_wallet).size())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
if (!offline_mode)
|
||||
|
|
@ -1903,7 +1968,7 @@ int main(int argc, char* argv[])
|
|||
sw->set_offline_mode(offline_mode);
|
||||
r = sw->init(vm);
|
||||
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet");
|
||||
if (command_line::get_arg(vm, arg_generate_new_wallet).size())
|
||||
if (command_line::get_arg(vm, arg_generate_new_wallet).size() || command_line::get_arg(vm, arg_generate_new_auditable_wallet).size())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ namespace currency
|
|||
|
||||
bool run_console_handler();
|
||||
|
||||
bool new_wallet(const std::string &wallet_file, const std::string& password);
|
||||
bool new_wallet(const std::string &wallet_file, const std::string& password, bool create_auditable_wallet);
|
||||
bool open_wallet(const std::string &wallet_file, const std::string& password);
|
||||
bool restore_wallet(const std::string &wallet_file, const std::string &restore_seed, const std::string& password);
|
||||
bool restore_wallet(const std::string &wallet_file, const std::string &seed_or_awo_blob, const std::string& password, bool auditable_watch_only);
|
||||
bool close_wallet();
|
||||
|
||||
bool help(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
|
|
@ -81,6 +81,7 @@ namespace currency
|
|||
bool enable_console_logger(const std::vector<std::string> &args);
|
||||
bool integrated_address(const std::vector<std::string> &args);
|
||||
bool get_tx_key(const std::vector<std::string> &args_);
|
||||
bool awo_blob(const std::vector<std::string> &args_);
|
||||
bool save_watch_only(const std::vector<std::string> &args);
|
||||
bool sign_transfer(const std::vector<std::string> &args);
|
||||
bool submit_transfer(const std::vector<std::string> &args);
|
||||
|
|
@ -93,9 +94,10 @@ namespace currency
|
|||
bool try_connect_to_daemon();
|
||||
|
||||
//----------------- i_wallet2_callback ---------------------
|
||||
virtual void on_new_block(uint64_t height, const currency::block& block);
|
||||
virtual void on_money_received(uint64_t height, const currency::transaction& tx, size_t out_index);
|
||||
virtual void on_money_spent(uint64_t height, const currency::transaction& in_tx, size_t out_index, const currency::transaction& spend_tx);
|
||||
virtual void on_new_block(uint64_t height, const currency::block& block) override;
|
||||
virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) override;
|
||||
virtual void on_message(i_wallet2_callback::message_severity severity, const std::string& m) override;
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
friend class refresh_progress_reporter_t;
|
||||
|
|
@ -153,6 +155,7 @@ namespace currency
|
|||
private:
|
||||
std::string m_wallet_file;
|
||||
std::string m_generate_new;
|
||||
std::string m_generate_new_aw;
|
||||
std::string m_import_path;
|
||||
|
||||
std::string m_daemon_address;
|
||||
|
|
@ -164,6 +167,7 @@ namespace currency
|
|||
bool m_do_pos_mining;
|
||||
bool m_offline_mode;
|
||||
std::string m_restore_wallet;
|
||||
std::string m_restore_awo_wallet;
|
||||
|
||||
epee::console_handlers_binder m_cmd_binder;
|
||||
|
||||
|
|
|
|||
|
|
@ -365,7 +365,7 @@ namespace plain_wallet
|
|||
|
||||
std::string full_path = get_wallets_folder() + path;
|
||||
epee::json_rpc::response<view::open_wallet_response, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
|
||||
std::string rsp = inst_ptr->gwm.restore_wallet(epee::string_encoding::convert_to_unicode(full_path), password, seed, ok_response.result);
|
||||
std::string rsp = inst_ptr->gwm.restore_wallet(epee::string_encoding::convert_to_unicode(full_path), password, seed, false, ok_response.result);
|
||||
if (rsp == API_RETURN_CODE_OK || rsp == API_RETURN_CODE_FILE_RESTORED)
|
||||
{
|
||||
if (rsp == API_RETURN_CODE_FILE_RESTORED)
|
||||
|
|
|
|||
|
|
@ -213,16 +213,20 @@ public:
|
|||
uint64_t balance;
|
||||
uint64_t mined_total;
|
||||
std::string address;
|
||||
std::string tracking_hey;
|
||||
std::string view_sec_key;
|
||||
std::string path;
|
||||
bool is_auditable;
|
||||
bool is_watch_only;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(unlocked_balance)
|
||||
KV_SERIALIZE(balance)
|
||||
KV_SERIALIZE(mined_total)
|
||||
KV_SERIALIZE(address)
|
||||
KV_SERIALIZE(tracking_hey)
|
||||
KV_SERIALIZE(view_sec_key)
|
||||
KV_SERIALIZE(path)
|
||||
KV_SERIALIZE(is_auditable);
|
||||
KV_SERIALIZE(is_watch_only);
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
@ -416,11 +420,13 @@ public:
|
|||
std::string pass;
|
||||
std::string path;
|
||||
std::string restore_key;
|
||||
bool auditable_watch_only;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(pass)
|
||||
KV_SERIALIZE(path)
|
||||
KV_SERIALIZE(restore_key)
|
||||
KV_SERIALIZE(auditable_watch_only)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -263,11 +263,60 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
{
|
||||
if (in.type() == typeid(currency::txin_to_key))
|
||||
{
|
||||
auto it = m_key_images.find(boost::get<currency::txin_to_key>(in).k_image);
|
||||
if (it != m_key_images.end())
|
||||
const currency::txin_to_key& intk = boost::get<currency::txin_to_key>(in);
|
||||
|
||||
// check if this input spends our output
|
||||
transfer_details* p_td = nullptr;
|
||||
uint64_t tid = UINT64_MAX;
|
||||
|
||||
if (is_auditable() && is_watch_only())
|
||||
{
|
||||
tx_money_spent_in_ins += boost::get<currency::txin_to_key>(in).amount;
|
||||
transfer_details& td = m_transfers[it->second];
|
||||
// auditable wallet
|
||||
// try to find a reference among own UTXOs
|
||||
std::vector<txout_v> abs_key_offsets = relative_output_offsets_to_absolute(intk.key_offsets); // potential speed-up: don't convert to abs offsets as we interested only in direct spends for auditable wallets. Now it's kind a bit paranoid.
|
||||
for(auto v : abs_key_offsets)
|
||||
{
|
||||
if (v.type() != typeid(uint64_t))
|
||||
continue;
|
||||
uint64_t gindex = boost::get<uint64_t>(v);
|
||||
auto it = m_amount_gindex_to_transfer_id.find(std::make_pair(intk.amount, gindex));
|
||||
if (it != m_amount_gindex_to_transfer_id.end())
|
||||
{
|
||||
tid = it->second;
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(tid < m_transfers.size(), "invalid tid: " << tid << ", ref from input with amount: " << intk.amount << ", gindex: " << gindex);
|
||||
auto& td = m_transfers[it->second];
|
||||
if (intk.key_offsets.size() != 1)
|
||||
{
|
||||
// own output was used in non-direct transaction
|
||||
// the core should not allow this to happen, the only way it may happen - mixing in own output that was sent without mix_attr == 1
|
||||
// log strange situation
|
||||
std::stringstream ss;
|
||||
ss << "own transfer tid=" << tid << " tx=" << td.tx_hash() << " mix_attr=" << td.mix_attr() << ", is referenced by a transaction with mixins, ref from input with amount: " << intk.amount << ", gindex: " << gindex;
|
||||
WLT_LOG_YELLOW(ss.str(), LOG_LEVEL_0);
|
||||
if (m_wcallback)
|
||||
m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str());
|
||||
continue;
|
||||
}
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!td.is_spent(), "transfer is spent, tid: " << tid << ", ref from input with amount: " << intk.amount << ", gindex: " << gindex);
|
||||
// own output is spent, handle it
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// wallet with spend secret key -- we can calculate own key images and then search by them
|
||||
auto it = m_key_images.find(intk.k_image);
|
||||
if (it != m_key_images.end())
|
||||
{
|
||||
tid = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
if (tid != UINT64_MAX)
|
||||
{
|
||||
tx_money_spent_in_ins += intk.amount;
|
||||
transfer_details& td = m_transfers[tid];
|
||||
uint32_t flags_before = td.m_flags;
|
||||
td.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT;
|
||||
td.m_spent_height = height;
|
||||
|
|
@ -275,10 +324,10 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
is_derived_from_coinbase = true;
|
||||
else
|
||||
is_derived_from_coinbase = false;
|
||||
WLT_LOG_L0("Spent key out, transfer #" << it->second << ", amount: " << print_money(m_transfers[it->second].amount()) << ", with tx: " << get_transaction_hash(tx) << ", at height " << height <<
|
||||
WLT_LOG_L0("Spent key out, transfer #" << tid << ", amount: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx) << ", at height " << height <<
|
||||
"; flags: " << flags_before << " -> " << td.m_flags);
|
||||
mtd.spent_indices.push_back(i);
|
||||
remove_transfer_from_expiration_list(it->second);
|
||||
remove_transfer_from_expiration_list(tid);
|
||||
}
|
||||
}
|
||||
else if (in.type() == typeid(currency::txin_multisig))
|
||||
|
|
@ -341,18 +390,21 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
crypto::key_image ki = currency::null_ki;
|
||||
if (m_watch_only)
|
||||
{
|
||||
// don't have spend secret key, so we unable to calculate key image for an output
|
||||
// look it up in special container instead
|
||||
auto it = m_pending_key_images.find(otk.key);
|
||||
if (it != m_pending_key_images.end())
|
||||
if (!is_auditable())
|
||||
{
|
||||
ki = it->second;
|
||||
WLT_LOG_L1("pending key image " << ki << " was found by out pub key " << otk.key);
|
||||
}
|
||||
else
|
||||
{
|
||||
ki = currency::null_ki;
|
||||
WLT_LOG_L1("can't find pending key image by out pub key: " << otk.key << ", key image temporarily set to null");
|
||||
// don't have spend secret key, so we unable to calculate key image for an output
|
||||
// look it up in special container instead
|
||||
auto it = m_pending_key_images.find(otk.key);
|
||||
if (it != m_pending_key_images.end())
|
||||
{
|
||||
ki = it->second;
|
||||
WLT_LOG_L1("pending key image " << ki << " was found by out pub key " << otk.key);
|
||||
}
|
||||
else
|
||||
{
|
||||
ki = currency::null_ki;
|
||||
WLT_LOG_L1("can't find pending key image by out pub key: " << otk.key << ", key image temporarily set to null");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -365,20 +417,37 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
|
||||
if (ki != currency::null_ki)
|
||||
{
|
||||
// make sure calculated key image for this own output has not been seen before
|
||||
auto it = m_key_images.find(ki);
|
||||
if (it != m_key_images.end())
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "m_key_images entry has wrong m_transfers index, it->second: " << it->second << ", m_transfers.size(): " << m_transfers.size());
|
||||
const transfer_details& local_td = m_transfers[it->second];
|
||||
WLT_LOG_YELLOW("tx " << get_transaction_hash(tx) << " @ block " << height << " has output #" << o << " with key image " << ki << " that has already been seen in output #" <<
|
||||
std::stringstream ss;
|
||||
ss << "tx " << get_transaction_hash(tx) << " @ block " << height << " has output #" << o << " with key image " << ki << " that has already been seen in output #" <<
|
||||
local_td.m_internal_output_index << " in tx " << get_transaction_hash(local_td.m_ptx_wallet_info->m_tx) << " @ block " << local_td.m_spent_height <<
|
||||
". This output can't ever be spent and will be skipped.", LOG_LEVEL_0);
|
||||
". This output can't ever be spent and will be skipped.";
|
||||
WLT_LOG_YELLOW(ss.str(), LOG_LEVEL_0);
|
||||
if (m_wcallback)
|
||||
m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str());
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(tx_money_got_in_outs >= tx.vout[o].amount, "tx_money_got_in_outs: " << tx_money_got_in_outs << ", tx.vout[o].amount:" << tx.vout[o].amount);
|
||||
tx_money_got_in_outs -= tx.vout[o].amount;
|
||||
continue; // skip the output
|
||||
}
|
||||
}
|
||||
|
||||
if (is_auditable() && otk.mix_attr != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "output #" << o << " from tx " << get_transaction_hash(tx) << " with amount " << print_money_brief(tx.vout[o].amount)
|
||||
<< " is targeted to this auditable wallet and has INCORRECT mix_attr = " << (uint64_t)otk.mix_attr << ". Output IGNORED.";
|
||||
WLT_LOG_RED(ss.str(), LOG_LEVEL_0);
|
||||
if (m_wcallback)
|
||||
m_wcallback->on_message(i_wallet2_callback::ms_red, ss.str());
|
||||
tx_money_got_in_outs -= tx.vout[o].amount;
|
||||
continue; // skip the output
|
||||
}
|
||||
|
||||
mtd.receive_indices.push_back(o);
|
||||
|
||||
m_transfers.push_back(boost::value_initialized<transfer_details>());
|
||||
|
|
@ -399,6 +468,11 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
if (td.m_key_image != currency::null_ki)
|
||||
m_key_images[td.m_key_image] = transfer_index;
|
||||
add_transfer_to_transfers_cache(tx.vout[o].amount, transfer_index);
|
||||
uint64_t amount = tx.vout[o].amount;
|
||||
|
||||
auto amount_gindex_pair = std::make_pair(amount, td.m_global_output_index);
|
||||
WLT_CHECK_AND_ASSERT_MES_NO_RET(m_amount_gindex_to_transfer_id.count(amount_gindex_pair) == 0, "update m_amount_gindex_to_transfer_id: amount " << amount << ", gindex " << td.m_global_output_index << " already exists");
|
||||
m_amount_gindex_to_transfer_id[amount_gindex_pair] = transfer_index;
|
||||
|
||||
if (max_out_unlock_time < get_tx_unlock_time(tx, o))
|
||||
max_out_unlock_time = get_tx_unlock_time(tx, o);
|
||||
|
|
@ -469,20 +543,25 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
void wallet2::prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_info& wti, const std::vector<currency::payload_items_v>& decrypted_att)
|
||||
{
|
||||
PROFILE_FUNC("wallet2::prepare_wti_decrypted_attachments");
|
||||
tx_payer tp = AUTO_VAL_INIT(tp);
|
||||
wti.show_sender = get_type_in_variant_container(decrypted_att, tp);
|
||||
|
||||
if (wti.is_income)
|
||||
{
|
||||
if(wti.show_sender)
|
||||
wti.remote_addresses.push_back(currency::get_account_address_as_str(tp.acc_addr));
|
||||
account_public_address sender_address = AUTO_VAL_INIT(sender_address);
|
||||
wti.show_sender = handle_2_alternative_types_in_variant_container<tx_payer, tx_payer_old>(decrypted_att, [&](const tx_payer& p) { sender_address = p.acc_addr; return false; /* <- continue? */ } );
|
||||
if (wti.show_sender)
|
||||
wti.remote_addresses.push_back(currency::get_account_address_as_str(sender_address));
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: actually recipients could be more then one, handle it in future
|
||||
tx_receiver tr = AUTO_VAL_INIT(tr);
|
||||
if (!wti.remote_addresses.size() && get_type_in_variant_container(decrypted_att, tr))
|
||||
wti.remote_addresses.push_back(currency::get_account_address_as_str(tr.acc_addr));
|
||||
if (wti.remote_addresses.empty())
|
||||
{
|
||||
handle_2_alternative_types_in_variant_container<tx_receiver, tx_receiver_old>(decrypted_att, [&](const tx_receiver& p) {
|
||||
std::string addr_str = currency::get_account_address_as_str(p.acc_addr);
|
||||
wti.remote_addresses.push_back(addr_str);
|
||||
LOG_PRINT_YELLOW("prepare_wti_decrypted_attachments, income=false, wti.amount = " << print_money_brief(wti.amount) << ", rem. addr = " << addr_str, LOG_LEVEL_0);
|
||||
return true; // continue iterating through the container
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
currency::tx_comment cm;
|
||||
|
|
@ -1163,7 +1242,6 @@ void wallet2::pull_blocks(size_t& blocks_added, std::atomic<bool>& stop)
|
|||
bool r = m_core_proxy->call_COMMAND_RPC_GET_BLOCKS_DIRECT(req, res);
|
||||
if (!r)
|
||||
throw error::no_connection_to_daemon(LOCATION_STR, "getblocks.bin");
|
||||
WLT_LOG_L0("COMMAND_RPC_GET_BLOCKS_DIRECT: " << epee::serialization::store_t_to_json(req));
|
||||
if (res.status == API_RETURN_CODE_GENESIS_MISMATCH)
|
||||
{
|
||||
WLT_LOG_MAGENTA("Reseting genesis block...", LOG_LEVEL_0);
|
||||
|
|
@ -1799,6 +1877,17 @@ uint64_t wallet2::detach_from_block_ids(uint64_t including_height)
|
|||
return blocks_detached;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::remove_transfer_from_amount_gindex_map(uint64_t tid)
|
||||
{
|
||||
for (auto it = m_amount_gindex_to_transfer_id.begin(); it != m_amount_gindex_to_transfer_id.end(); )
|
||||
{
|
||||
if (it->second == tid)
|
||||
it = m_amount_gindex_to_transfer_id.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::detach_blockchain(uint64_t including_height)
|
||||
{
|
||||
WLT_LOG_L0("Detaching blockchain on height " << including_height);
|
||||
|
|
@ -1817,6 +1906,7 @@ void wallet2::detach_blockchain(uint64_t including_height)
|
|||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it_ki != m_key_images.end(), "key image " << m_transfers[i].m_key_image << " not found");
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(m_transfers[i].m_ptx_wallet_info->m_block_height >= including_height, "transfer #" << i << " block height is less than " << including_height);
|
||||
m_key_images.erase(it_ki);
|
||||
remove_transfer_from_amount_gindex_map(i);
|
||||
++transfers_detached;
|
||||
}
|
||||
m_transfers.erase(it, m_transfers.end());
|
||||
|
|
@ -1902,6 +1992,7 @@ bool wallet2::reset_all()
|
|||
//m_blockchain.clear();
|
||||
m_chain.clear();
|
||||
m_transfers.clear();
|
||||
m_amount_gindex_to_transfer_id.clear();
|
||||
m_key_images.clear();
|
||||
// m_pending_key_images is not cleared intentionally
|
||||
m_unconfirmed_in_transfers.clear();
|
||||
|
|
@ -2035,20 +2126,27 @@ bool wallet2::prepare_file_names(const std::wstring& file_path)
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::load_keys(const std::string& buff, const std::string& password)
|
||||
void wallet2::load_keys(const std::string& buff, const std::string& password, uint64_t file_signature)
|
||||
{
|
||||
wallet2::keys_file_data keys_file_data;
|
||||
// std::string buf;
|
||||
// bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf);
|
||||
// CHECK_AND_THROW_WALLET_EX(!r, error::file_read_error, keys_file_name);
|
||||
bool r = ::serialization::parse_binary(buff, keys_file_data);
|
||||
bool r = false;
|
||||
wallet2::keys_file_data kf_data = AUTO_VAL_INIT(kf_data);
|
||||
if (file_signature == WALLET_FILE_SIGNATURE_OLD)
|
||||
{
|
||||
wallet2::keys_file_data_old kf_data_old;
|
||||
r = ::serialization::parse_binary(buff, kf_data_old);
|
||||
kf_data = wallet2::keys_file_data::from_old(kf_data_old);
|
||||
}
|
||||
else if (file_signature == WALLET_FILE_SIGNATURE_V2)
|
||||
{
|
||||
r = ::serialization::parse_binary(buff, kf_data);
|
||||
}
|
||||
THROW_IF_TRUE_WALLET_EX(!r, error::wallet_internal_error, "internal error: failed to deserialize");
|
||||
|
||||
crypto::chacha8_key key;
|
||||
crypto::generate_chacha8_key(password, key);
|
||||
std::string account_data;
|
||||
account_data.resize(keys_file_data.account_data.size());
|
||||
crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
|
||||
account_data.resize(kf_data.account_data.size());
|
||||
crypto::chacha8(kf_data.account_data.data(), kf_data.account_data.size(), key, kf_data.iv, &account_data[0]);
|
||||
|
||||
const currency::account_keys& keys = m_account.get_keys();
|
||||
r = epee::serialization::load_t_from_binary(m_account, account_data);
|
||||
|
|
@ -2072,7 +2170,7 @@ void wallet2::assign_account(const currency::account_base& acc)
|
|||
init_log_prefix();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::generate(const std::wstring& path, const std::string& pass)
|
||||
void wallet2::generate(const std::wstring& path, const std::string& pass, bool auditable_wallet)
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(validate_password(pass), "new wallet generation failed: password contains forbidden characters")
|
||||
clear();
|
||||
|
|
@ -2081,11 +2179,11 @@ void wallet2::generate(const std::wstring& path, const std::string& pass)
|
|||
check_for_free_space_and_throw_if_it_lacks(m_wallet_file);
|
||||
|
||||
m_password = pass;
|
||||
m_account.generate();
|
||||
m_account.generate(auditable_wallet);
|
||||
init_log_prefix();
|
||||
boost::system::error_code ignored_ec;
|
||||
THROW_IF_TRUE_WALLET_EX(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
if (m_watch_only)
|
||||
if (m_watch_only && !auditable_wallet)
|
||||
{
|
||||
bool stub;
|
||||
load_keys2ki(true, stub);
|
||||
|
|
@ -2093,14 +2191,27 @@ void wallet2::generate(const std::wstring& path, const std::string& pass)
|
|||
store();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::restore(const std::wstring& path, const std::string& pass, const std::string& restore_key)
|
||||
void wallet2::restore(const std::wstring& path, const std::string& pass, const std::string& seed_phrase_or_awo_blob, bool auditable_watch_only)
|
||||
{
|
||||
bool r = false;
|
||||
clear();
|
||||
prepare_file_names(path);
|
||||
m_password = pass;
|
||||
bool r = m_account.restore_keys_from_braindata(restore_key);
|
||||
init_log_prefix();
|
||||
THROW_IF_TRUE_WALLET_EX(!r, error::wallet_wrong_seed_error, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
|
||||
if (auditable_watch_only)
|
||||
{
|
||||
r = m_account.restore_from_awo_blob(seed_phrase_or_awo_blob);
|
||||
init_log_prefix();
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "Could not load auditable watch-only wallet from a given blob: invalid awo blob");
|
||||
m_watch_only = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = m_account.restore_from_braindata(seed_phrase_or_awo_blob);
|
||||
init_log_prefix();
|
||||
THROW_IF_FALSE_WALLET_EX(r, error::wallet_wrong_seed_error, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
}
|
||||
|
||||
boost::system::error_code ignored_ec;
|
||||
THROW_IF_TRUE_WALLET_EX(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
store();
|
||||
|
|
@ -2129,36 +2240,38 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password)
|
|||
THROW_IF_TRUE_WALLET_EX(e || !exists, error::file_not_found, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
boost::filesystem::ifstream data_file;
|
||||
data_file.open(m_wallet_file, std::ios_base::binary | std::ios_base::in);
|
||||
THROW_IF_TRUE_WALLET_EX(data_file.fail(), error::file_not_found, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
THROW_IF_TRUE_WALLET_EX(data_file.fail(), error::file_read_error, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
|
||||
wallet_file_binary_header wbh = AUTO_VAL_INIT(wbh);
|
||||
|
||||
data_file.read((char*)&wbh, sizeof(wbh));
|
||||
THROW_IF_TRUE_WALLET_EX(data_file.fail(), error::file_not_found, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
THROW_IF_TRUE_WALLET_EX(data_file.fail(), error::file_read_error, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
|
||||
THROW_IF_TRUE_WALLET_EX(wbh.m_signature != WALLET_FILE_SIGNATURE, error::file_not_found, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
THROW_IF_TRUE_WALLET_EX(wbh.m_signature != WALLET_FILE_SIGNATURE_OLD && wbh.m_signature != WALLET_FILE_SIGNATURE_V2, error::file_read_error, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
THROW_IF_TRUE_WALLET_EX(wbh.m_cb_body > WALLET_FILE_MAX_BODY_SIZE ||
|
||||
wbh.m_cb_keys > WALLET_FILE_MAX_KEYS_SIZE, error::file_not_found, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
wbh.m_cb_keys > WALLET_FILE_MAX_KEYS_SIZE, error::file_read_error, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
|
||||
|
||||
keys_buff.resize(wbh.m_cb_keys);
|
||||
data_file.read((char*)keys_buff.data(), wbh.m_cb_keys);
|
||||
|
||||
load_keys(keys_buff, password);
|
||||
load_keys(keys_buff, password, wbh.m_signature);
|
||||
|
||||
bool need_to_resync = !tools::portable_unserialize_obj_from_stream(*this, data_file);
|
||||
|
||||
if (m_watch_only)
|
||||
if (m_watch_only && !is_auditable())
|
||||
load_keys2ki(true, need_to_resync);
|
||||
|
||||
WLT_LOG_L0("Loaded wallet file" << (m_watch_only ? " (WATCH ONLY) " : " ") << string_encoding::convert_to_ansii(m_wallet_file) << " with public address: " << m_account.get_public_address_str());
|
||||
WLT_LOG_L0("(after loading: pending_key_images: " << m_pending_key_images.size() << ", pki file elements: " << m_pending_key_images_file_container.size() << ", tx_keys: " << m_tx_keys.size() << ")");
|
||||
|
||||
if (need_to_resync)
|
||||
{
|
||||
reset_history();
|
||||
WLT_LOG_L0("Unable to load history data from wallet file, wallet will be resynced!");
|
||||
}
|
||||
THROW_IF_TRUE_WALLET_EX(need_to_resync, error::wallet_load_notice_wallet_restored, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
|
||||
WLT_LOG_L0("Loaded wallet file" << (m_watch_only ? " (WATCH ONLY) " : " ") << string_encoding::convert_to_ansii(m_wallet_file) << " with public address: " << m_account.get_public_address_str());
|
||||
WLT_LOG_L0("(after loading: pending_key_images: " << m_pending_key_images.size() << ", pki file elements: " << m_pending_key_images_file_container.size() << ", tx_keys: " << m_tx_keys.size() << ")");
|
||||
THROW_IF_TRUE_WALLET_EX(need_to_resync, error::wallet_load_notice_wallet_restored, epee::string_encoding::convert_to_ansii(m_wallet_file));
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::store()
|
||||
|
|
@ -2186,7 +2299,7 @@ void wallet2::store(const std::wstring& path_to_save, const std::string& passwor
|
|||
|
||||
//store data
|
||||
wallet_file_binary_header wbh = AUTO_VAL_INIT(wbh);
|
||||
wbh.m_signature = WALLET_FILE_SIGNATURE;
|
||||
wbh.m_signature = WALLET_FILE_SIGNATURE_V2;
|
||||
wbh.m_cb_keys = keys_buff.size();
|
||||
//@#@ change it to proper
|
||||
wbh.m_cb_body = 1000;
|
||||
|
|
@ -2272,8 +2385,11 @@ void wallet2::store_watch_only(const std::wstring& path_to_save, const std::stri
|
|||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!boost::filesystem::exists(wo.m_pending_ki_file), "file " << epee::string_encoding::convert_to_ansii(wo.m_pending_ki_file) << " already exists");
|
||||
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(wo.m_pending_key_images.empty(), "pending key images is expected to be empty");
|
||||
bool stub = false;
|
||||
wo.load_keys2ki(true, stub); // to create outkey2ki file
|
||||
if (!is_auditable())
|
||||
{
|
||||
bool stub = false;
|
||||
wo.load_keys2ki(true, stub); // to create outkey2ki file
|
||||
}
|
||||
|
||||
// populate pending key images for spent outputs (this will help to resync watch-only wallet)
|
||||
for (size_t ti = 0; ti < wo.m_transfers.size(); ++ti)
|
||||
|
|
@ -3112,6 +3228,21 @@ void wallet2::update_offer_by_id(const crypto::hash& tx_id, uint64_t of_ind, con
|
|||
transfer(destinations, 0, 0, od.fee, extra, attachments, detail::ssi_digit, tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::push_alias_info_to_extra_according_to_hf_status(const currency::extra_alias_entry& ai, std::vector<currency::extra_v>& extra)
|
||||
{
|
||||
if (get_top_block_height() > m_core_runtime_config.hard_fork_02_starts_after_height)
|
||||
{
|
||||
// after HF2
|
||||
extra.push_back(ai);
|
||||
}
|
||||
else
|
||||
{
|
||||
// before HF2
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!ai.m_address.is_auditable(), "auditable addresses are not supported in aliases prior to HF2");
|
||||
extra.push_back(ai.to_old());
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::request_alias_registration(const currency::extra_alias_entry& ai, currency::transaction& res_tx, uint64_t fee, uint64_t reward)
|
||||
{
|
||||
if (!validate_alias_name(ai.m_alias))
|
||||
|
|
@ -3122,7 +3253,8 @@ void wallet2::request_alias_registration(const currency::extra_alias_entry& ai,
|
|||
std::vector<currency::tx_destination_entry> destinations;
|
||||
std::vector<currency::extra_v> extra;
|
||||
std::vector<currency::attachment_v> attachments;
|
||||
extra.push_back(ai);
|
||||
|
||||
push_alias_info_to_extra_according_to_hf_status(ai, extra);
|
||||
|
||||
currency::tx_destination_entry tx_dest_alias_reward;
|
||||
tx_dest_alias_reward.addr.resize(1);
|
||||
|
|
@ -3152,7 +3284,9 @@ void wallet2::request_alias_update(currency::extra_alias_entry& ai, currency::tr
|
|||
std::vector<currency::tx_destination_entry> destinations;
|
||||
std::vector<currency::extra_v> extra;
|
||||
std::vector<currency::attachment_v> attachments;
|
||||
extra.push_back(ai);
|
||||
|
||||
push_alias_info_to_extra_according_to_hf_status(ai, extra);
|
||||
|
||||
transfer(destinations, 0, 0, fee, extra, attachments, detail::ssi_digit, tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx, CURRENCY_TO_KEY_OUT_RELAXED, false);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -4465,6 +4599,8 @@ void wallet2::transfer(const construct_tx_param& ctp,
|
|||
bool send_to_network,
|
||||
std::string* p_signed_tx_blob_str)
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!is_auditable() || !is_watch_only(), "You can't initiate coins transfer using an auditable watch-only wallet."); // btw, watch-only wallets can call transfer() within cold-signing process
|
||||
|
||||
check_and_throw_if_self_directed_tx_with_payment_id_requested(ctp);
|
||||
|
||||
TIME_MEASURE_START(prepare_transaction_time);
|
||||
|
|
@ -4578,9 +4714,9 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
|
|||
set_payment_id_to_tx(ftp.attachments, payment_id);
|
||||
// put encrypted payer info into the extra
|
||||
ftp.crypt_address = destination_addr;
|
||||
currency::tx_payer txp = AUTO_VAL_INIT(txp);
|
||||
txp.acc_addr = m_account.get_public_address();
|
||||
ftp.extra.push_back(txp);
|
||||
|
||||
currency::create_and_add_tx_payer_to_container_from_address(ftp.extra, m_account.get_public_address(), get_top_block_height(), m_core_runtime_config);
|
||||
|
||||
ftp.flags = 0;
|
||||
// ftp.multisig_id -- not required
|
||||
// ftp.prepared_destinations -- will be filled by prepare_tx_destinations
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2020 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
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
#include "currency_core/account_boost_serialization.h"
|
||||
#include "currency_core/currency_format_utils.h"
|
||||
|
||||
#include "common/make_hashable.h"
|
||||
#include "wallet_public_structs_defs.h"
|
||||
#include "currency_core/currency_format_utils.h"
|
||||
#include "common/unordered_containers_boost_serialization.h"
|
||||
|
|
@ -94,6 +95,8 @@ namespace tools
|
|||
class i_wallet2_callback
|
||||
{
|
||||
public:
|
||||
enum message_severity { ms_red, ms_yellow, ms_normal };
|
||||
|
||||
virtual ~i_wallet2_callback() = default;
|
||||
|
||||
virtual void on_new_block(uint64_t /*height*/, const currency::block& /*block*/) {}
|
||||
|
|
@ -101,6 +104,7 @@ namespace tools
|
|||
virtual void on_pos_block_found(const currency::block& /*block*/) {}
|
||||
virtual void on_sync_progress(const uint64_t& /*percents*/) {}
|
||||
virtual void on_transfer_canceled(const wallet_public::wallet_transfer_info& wti) {}
|
||||
virtual void on_message(message_severity /*severity*/, const std::string& /*m*/) {}
|
||||
};
|
||||
|
||||
struct tx_dust_policy
|
||||
|
|
@ -380,6 +384,9 @@ namespace tools
|
|||
uint32_t m_flags;
|
||||
|
||||
uint64_t amount() const { return m_ptx_wallet_info->m_tx.vout[m_internal_output_index].amount; }
|
||||
const currency::tx_out& output() const { return m_ptx_wallet_info->m_tx.vout[m_internal_output_index]; }
|
||||
uint8_t mix_attr() const { return output().target.type() == typeid(currency::txout_to_key) ? boost::get<const currency::txout_to_key&>(output().target).mix_attr : UINT8_MAX; }
|
||||
crypto::hash tx_hash() const { return get_transaction_hash(m_ptx_wallet_info->m_tx); }
|
||||
bool is_spent() const { return m_flags & WALLET_TRANSFER_DETAIL_FLAG_SPENT; }
|
||||
bool is_spendable() const { return (m_flags & (WALLET_TRANSFER_DETAIL_FLAG_SPENT | WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION | WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION)) == 0; }
|
||||
bool is_reserved_for_escrow() const { return ( (m_flags & WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION) != 0 ); }
|
||||
|
|
@ -443,9 +450,10 @@ namespace tools
|
|||
typedef std::unordered_map<crypto::hash, transfer_details_base> multisig_transfer_container;
|
||||
typedef std::unordered_map<crypto::hash, tools::wallet_public::escrow_contract_details_basic> escrow_contracts_container;
|
||||
typedef std::map<uint64_t, std::set<size_t> > free_amounts_cache_type;
|
||||
typedef std::unordered_map<std::pair<uint64_t, uint64_t>, uint64_t> amount_gindex_to_transfer_id_container; // maps [amount; gindex] -> tid
|
||||
|
||||
|
||||
struct keys_file_data
|
||||
struct keys_file_data_old
|
||||
{
|
||||
crypto::chacha8_iv iv;
|
||||
std::string account_data;
|
||||
|
|
@ -455,9 +463,32 @@ namespace tools
|
|||
FIELD(account_data)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct keys_file_data
|
||||
{
|
||||
uint8_t version;
|
||||
crypto::chacha8_iv iv;
|
||||
std::string account_data;
|
||||
|
||||
static keys_file_data from_old(const keys_file_data_old& v)
|
||||
{
|
||||
keys_file_data result = AUTO_VAL_INIT(result);
|
||||
result.iv = v.iv;
|
||||
result.account_data = v.account_data;
|
||||
return result;
|
||||
}
|
||||
|
||||
DEFINE_SERIALIZATION_VERSION(1)
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VERSION_ENTRY(version)
|
||||
FIELD(iv)
|
||||
FIELD(account_data)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
void assign_account(const currency::account_base& acc);
|
||||
void generate(const std::wstring& path, const std::string& password);
|
||||
void restore(const std::wstring& path, const std::string& pass, const std::string& restore_key);
|
||||
void generate(const std::wstring& path, const std::string& password, bool auditable_wallet);
|
||||
void restore(const std::wstring& path, const std::string& pass, const std::string& seed_phrase_or_awo_blob, bool auditable_watch_only);
|
||||
void load(const std::wstring& path, const std::string& password);
|
||||
void store();
|
||||
void store(const std::wstring& path);
|
||||
|
|
@ -480,7 +511,7 @@ namespace tools
|
|||
|
||||
//i_wallet2_callback* callback() const { return m_wcallback; }
|
||||
//void callback(i_wallet2_callback* callback) { m_callback = callback; }
|
||||
void callback(std::shared_ptr<i_wallet2_callback> callback) { m_wcallback = callback; m_do_rise_transfer = true; }
|
||||
void callback(std::shared_ptr<i_wallet2_callback> callback) { m_wcallback = callback; m_do_rise_transfer = (callback != nullptr); }
|
||||
void set_do_rise_transfer(bool do_rise) { m_do_rise_transfer = do_rise; }
|
||||
|
||||
bool has_related_alias_entry_unconfirmed(const currency::transaction& tx);
|
||||
|
|
@ -631,6 +662,7 @@ namespace tools
|
|||
void enumerate_unconfirmed_transfers(callback_t cb) const;
|
||||
|
||||
bool is_watch_only() const { return m_watch_only; }
|
||||
bool is_auditable() const { return m_account.get_public_address().is_auditable(); }
|
||||
void sign_transfer(const std::string& tx_sources_blob, std::string& signed_tx_blob, currency::transaction& tx);
|
||||
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);
|
||||
|
|
@ -697,6 +729,9 @@ namespace tools
|
|||
a & m_minimum_height;
|
||||
}
|
||||
|
||||
// v151: m_amount_gindex_to_transfer_id added
|
||||
if (ver >= 151)
|
||||
a & m_amount_gindex_to_transfer_id;
|
||||
|
||||
a & m_transfers;
|
||||
a & m_multisig_transfers;
|
||||
|
|
@ -788,7 +823,7 @@ private:
|
|||
|
||||
void add_transfers_to_expiration_list(const std::vector<uint64_t>& selected_transfers, uint64_t expiration, uint64_t change_amount, const crypto::hash& related_tx_id);
|
||||
void remove_transfer_from_expiration_list(uint64_t transfer_index);
|
||||
void load_keys(const std::string& keys_file_name, const std::string& password);
|
||||
void load_keys(const std::string& keys_file_name, const std::string& password, uint64_t file_signature);
|
||||
void process_new_transaction(const currency::transaction& tx, uint64_t height, const currency::block& b);
|
||||
void detach_blockchain(uint64_t including_height);
|
||||
bool extract_offers_from_transfer_entry(size_t i, std::unordered_map<crypto::hash, bc_services::offer_details_ex>& offers_local);
|
||||
|
|
@ -910,6 +945,9 @@ private:
|
|||
uint64_t detach_from_block_ids(uint64_t height);
|
||||
uint64_t get_wallet_minimum_height();
|
||||
|
||||
void push_alias_info_to_extra_according_to_hf_status(const currency::extra_alias_entry& ai, std::vector<currency::extra_v>& extra);
|
||||
void remove_transfer_from_amount_gindex_map(uint64_t tid);
|
||||
|
||||
currency::account_base m_account;
|
||||
bool m_watch_only;
|
||||
std::string m_log_prefix; // part of pub address, prefix for logging functions
|
||||
|
|
@ -924,6 +962,7 @@ private:
|
|||
|
||||
transfer_container m_transfers;
|
||||
multisig_transfer_container m_multisig_transfers;
|
||||
amount_gindex_to_transfer_id_container m_amount_gindex_to_transfer_id;
|
||||
payment_container m_payments;
|
||||
std::unordered_map<crypto::key_image, size_t> m_key_images;
|
||||
std::unordered_map<crypto::public_key, crypto::key_image> m_pending_key_images; // (out_pk -> ki) pairs of change outputs to be added in watch-only wallet without spend sec key
|
||||
|
|
|
|||
|
|
@ -68,6 +68,12 @@ namespace tools
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
virtual const char* what() const noexcept
|
||||
{
|
||||
m_what = to_string();
|
||||
return m_what.c_str();
|
||||
}
|
||||
|
||||
protected:
|
||||
wallet_error_base(std::string&& loc, const std::string& message)
|
||||
: Base(message)
|
||||
|
|
@ -77,6 +83,7 @@ namespace tools
|
|||
|
||||
private:
|
||||
std::string m_loc;
|
||||
mutable std::string m_what;
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
const char* const failed_rpc_request_messages[] = {
|
||||
|
|
@ -113,8 +120,9 @@ namespace tools
|
|||
std::string m_status;
|
||||
};
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
typedef wallet_error_base<std::logic_error> wallet_logic_error;
|
||||
typedef wallet_error_base<std::runtime_error> wallet_runtime_error;
|
||||
typedef wallet_error_base<std::runtime_error> wallet_error;
|
||||
typedef wallet_error wallet_logic_error;
|
||||
typedef wallet_error wallet_runtime_error;
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
struct wallet_internal_error : public wallet_runtime_error
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,10 +15,12 @@ namespace tools
|
|||
{
|
||||
wi = AUTO_VAL_INIT_T(view::wallet_info);
|
||||
wi.address = w.get_account().get_public_address_str();
|
||||
wi.tracking_hey = epee::string_tools::pod_to_hex(w.get_account().get_keys().view_secret_key);
|
||||
wi.view_sec_key = epee::string_tools::pod_to_hex(w.get_account().get_keys().view_secret_key);
|
||||
uint64_t fake = 0;
|
||||
wi.balance = w.balance(wi.unlocked_balance, fake, fake, wi.mined_total);
|
||||
wi.path = epee::string_encoding::wstring_to_utf8(w.get_wallet_path());
|
||||
wi.is_auditable = w.is_auditable();
|
||||
wi.is_watch_only = w.is_watch_only();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -292,20 +292,15 @@ namespace tools
|
|||
|
||||
if (req.push_payer)
|
||||
{
|
||||
currency::tx_payer txp = AUTO_VAL_INIT(txp);
|
||||
txp.acc_addr = m_wallet.get_account().get_keys().account_address;
|
||||
extra.push_back(txp);
|
||||
currency::create_and_add_tx_payer_to_container_from_address(extra, m_wallet.get_account().get_keys().account_address, m_wallet.get_top_block_height(), m_wallet.get_core_runtime_config());
|
||||
}
|
||||
|
||||
if (!req.hide_receiver)
|
||||
{
|
||||
for (auto& d : dsts)
|
||||
{
|
||||
for (auto& a : d.addr)
|
||||
{
|
||||
currency::tx_receiver txr = AUTO_VAL_INIT(txr);
|
||||
txr.acc_addr = a;
|
||||
extra.push_back(txr);
|
||||
}
|
||||
currency::create_and_add_tx_receiver_to_container_from_address(extra, a, m_wallet.get_top_block_height(), m_wallet.get_core_runtime_config());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -805,7 +805,7 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st
|
|||
try
|
||||
{
|
||||
w->load(path, password);
|
||||
if (w->is_watch_only())
|
||||
if (w->is_watch_only() && !w->is_auditable())
|
||||
return API_RETURN_CODE_WALLET_WATCH_ONLY_NOT_SUPPORTED;
|
||||
w->get_recent_transfers_history(owr.recent_history.history, 0, txs_to_return, owr.recent_history.total_history_items);
|
||||
//w->get_unconfirmed_transfers(owr.recent_history.unconfirmed);
|
||||
|
|
@ -819,6 +819,10 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st
|
|||
{
|
||||
return API_RETURN_CODE_FILE_NOT_FOUND;
|
||||
}
|
||||
catch (const tools::error::file_read_error&)
|
||||
{
|
||||
return API_RETURN_CODE_INVALID_FILE;
|
||||
}
|
||||
catch (const tools::error::wallet_load_notice_wallet_restored& /**/)
|
||||
{
|
||||
return_code = API_RETURN_CODE_FILE_RESTORED;
|
||||
|
|
@ -892,7 +896,7 @@ std::string wallets_manager::generate_wallet(const std::wstring& path, const std
|
|||
|
||||
try
|
||||
{
|
||||
w->generate(path, password);
|
||||
w->generate(path, password, false);
|
||||
w->set_minimum_height(m_last_daemon_height);
|
||||
owr.seed = w->get_account().get_restore_braindata();
|
||||
}
|
||||
|
|
@ -939,7 +943,7 @@ std::string wallets_manager::is_pos_allowed()
|
|||
std::string wallets_manager::is_valid_brain_restore_data(const std::string& brain_text)
|
||||
{
|
||||
currency::account_base acc;
|
||||
if (acc.restore_keys_from_braindata(brain_text))
|
||||
if (acc.restore_from_braindata(brain_text))
|
||||
return API_RETURN_CODE_TRUE;
|
||||
else
|
||||
return API_RETURN_CODE_FALSE;
|
||||
|
|
@ -957,7 +961,7 @@ void wallets_manager::get_gui_options(view::gui_options& opt)
|
|||
{
|
||||
opt = m_ui_opt;
|
||||
}
|
||||
std::string wallets_manager::restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, view::open_wallet_response& owr)
|
||||
std::string wallets_manager::restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, bool auditable_watch_only, view::open_wallet_response& owr)
|
||||
{
|
||||
std::shared_ptr<tools::wallet2> w(new tools::wallet2());
|
||||
owr.wallet_id = m_wallet_id_counter++;
|
||||
|
|
@ -979,7 +983,7 @@ std::string wallets_manager::restore_wallet(const std::wstring& path, const std:
|
|||
currency::account_base acc;
|
||||
try
|
||||
{
|
||||
w->restore(path, password, restore_key);
|
||||
w->restore(path, password, restore_key, auditable_watch_only);
|
||||
owr.seed = w->get_account().get_restore_braindata();
|
||||
}
|
||||
catch (const tools::error::file_exists&)
|
||||
|
|
@ -1253,20 +1257,14 @@ std::string wallets_manager::transfer(size_t wallet_id, const view::transfer_par
|
|||
}
|
||||
if (tp.push_payer)
|
||||
{
|
||||
currency::tx_payer txp = AUTO_VAL_INIT(txp);
|
||||
txp.acc_addr = w->get()->get_account().get_keys().account_address;
|
||||
extra.push_back(txp);
|
||||
currency::create_and_add_tx_payer_to_container_from_address(extra, w->get()->get_account().get_keys().account_address, w->get()->get_top_block_height(), w->get()->get_core_runtime_config());
|
||||
}
|
||||
if (!tp.hide_receiver)
|
||||
{
|
||||
for (auto& d : dsts)
|
||||
{
|
||||
for (auto& a : d.addr)
|
||||
{
|
||||
currency::tx_receiver txr = AUTO_VAL_INIT(txr);
|
||||
txr.acc_addr = a;
|
||||
extra.push_back(txr);
|
||||
}
|
||||
currency::create_and_add_tx_receiver_to_container_from_address(extra, a, w->get()->get_top_block_height(), w->get()->get_core_runtime_config());
|
||||
}
|
||||
}
|
||||
w->get()->transfer(dsts, tp.mixin_count, unlock_time ? unlock_time + 1 : 0, fee, extra, attachments, res_tx);
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ public:
|
|||
bool send_stop_signal();
|
||||
std::string open_wallet(const std::wstring& path, const std::string& password, uint64_t txs_to_return, view::open_wallet_response& owr);
|
||||
std::string generate_wallet(const std::wstring& path, const std::string& password, view::open_wallet_response& owr);
|
||||
std::string restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, view::open_wallet_response& owr);
|
||||
std::string restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, bool auditable_watch_only, view::open_wallet_response& owr);
|
||||
std::string invoke(uint64_t wallet_id, std::string params);
|
||||
std::string get_wallet_status(uint64_t wallet_id);
|
||||
std::string run_wallet(uint64_t wallet_id);
|
||||
|
|
|
|||
|
|
@ -18,72 +18,20 @@ using namespace currency;
|
|||
#define FIFTH_NAME "fifth--01234567890"
|
||||
#define SIX_NAME "sixsix-double--01234567890"
|
||||
|
||||
std::string gen_random_alias(size_t len)
|
||||
{
|
||||
const char allowed_chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
char buffer[2048] = "";
|
||||
if (len >= sizeof buffer)
|
||||
return "";
|
||||
|
||||
crypto::generate_random_bytes(len, buffer);
|
||||
buffer[len] = 0;
|
||||
for(size_t i = 0; i < len; ++i)
|
||||
buffer[i] = allowed_chars[buffer[i] % (sizeof allowed_chars - 1)];
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool put_alias_via_tx_to_list(std::vector<test_event_entry>& events,
|
||||
std::list<currency::transaction>& tx_set,
|
||||
const block& head_block,
|
||||
const account_base& miner_acc,
|
||||
currency::extra_alias_entry ai2,
|
||||
test_generator& generator)
|
||||
{
|
||||
|
||||
std::vector<currency::extra_v> ex;
|
||||
ex.push_back(ai2);
|
||||
account_base reward_acc;
|
||||
account_keys& ak = const_cast<account_keys&>(reward_acc.get_keys());
|
||||
currency::get_aliases_reward_account(ak.account_address, ak.view_secret_key);
|
||||
|
||||
uint64_t fee_median = generator.get_last_n_blocks_fee_median(get_block_hash(head_block));
|
||||
uint64_t reward = currency::get_alias_coast_from_fee(ai2.m_alias, fee_median);
|
||||
|
||||
MAKE_TX_MIX_LIST_EXTRA_MIX_ATTR(events,
|
||||
tx_set,
|
||||
miner_acc,
|
||||
reward_acc,
|
||||
reward,
|
||||
0,
|
||||
head_block,
|
||||
CURRENCY_TO_KEY_OUT_RELAXED,
|
||||
ex,
|
||||
std::vector<currency::attachment_v>());
|
||||
|
||||
|
||||
uint64_t found_alias_reward = get_amount_for_zero_pubkeys(tx_set.back());
|
||||
if (found_alias_reward != reward)
|
||||
{
|
||||
LOCAL_ASSERT(false);
|
||||
CHECK_AND_ASSERT_MES(false, false, "wrong transaction constructed, first input value not match alias amount or account");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
std::list<currency::transaction>& tx_set,
|
||||
const block& head_block,
|
||||
const std::string& alias_name,
|
||||
const account_base& miner_acc,
|
||||
const account_base& alias_acc,
|
||||
test_generator& generator)
|
||||
{
|
||||
currency::extra_alias_entry ai2 = AUTO_VAL_INIT(ai2);
|
||||
ai2.m_alias = alias_name;
|
||||
ai2.m_address = alias_acc.get_keys().account_address;
|
||||
ai2.m_text_comment = "ssdss";
|
||||
return put_alias_via_tx_to_list(events, tx_set, head_block, miner_acc, ai2, generator);
|
||||
}
|
||||
bool put_alias_via_tx_to_list(std::vector<test_event_entry>& events,
|
||||
std::list<currency::transaction>& tx_set,
|
||||
const block& head_block,
|
||||
const std::string& alias_name,
|
||||
const account_base& miner_acc,
|
||||
const account_base& alias_acc,
|
||||
test_generator& generator)
|
||||
{
|
||||
currency::extra_alias_entry ai2 = AUTO_VAL_INIT(ai2);
|
||||
ai2.m_alias = alias_name;
|
||||
ai2.m_address = alias_acc.get_keys().account_address;
|
||||
ai2.m_text_comment = "ssdss";
|
||||
return put_alias_via_tx_to_list(events, tx_set, head_block, miner_acc, ai2, generator);
|
||||
}
|
||||
|
||||
bool put_next_block_with_alias_in_tx(std::vector<test_event_entry>& events,
|
||||
block& b,
|
||||
|
|
@ -92,13 +40,13 @@ bool put_next_block_with_alias_in_tx(std::vector<test_event_entry>& events,
|
|||
const currency::extra_alias_entry& ai,
|
||||
test_generator& generator)
|
||||
{
|
||||
std::list<currency::transaction> txs_0;
|
||||
if (!put_alias_via_tx_to_list(events, txs_0, head_block, miner_acc, ai, generator))
|
||||
return false;
|
||||
std::list<currency::transaction> txs_0;
|
||||
if (!put_alias_via_tx_to_list(events, txs_0, head_block, miner_acc, ai, generator))
|
||||
return false;
|
||||
|
||||
MAKE_NEXT_BLOCK_TX_LIST(events, blk, head_block, miner_acc, txs_0);
|
||||
b = blk;
|
||||
return true;
|
||||
MAKE_NEXT_BLOCK_TX_LIST(events, blk, head_block, miner_acc, txs_0);
|
||||
b = blk;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
#include "currency_core/currency_core.h"
|
||||
#include "wallet/wallet2.h"
|
||||
#include "test_core_time.h"
|
||||
#include "chaingen_helpers.h"
|
||||
|
||||
#define TESTS_DEFAULT_FEE ((uint64_t)TX_DEFAULT_FEE)
|
||||
#define MK_TEST_COINS(amount) (static_cast<uint64_t>(amount) * TX_DEFAULT_FEE)
|
||||
|
|
@ -1205,3 +1204,4 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
|
||||
// --- end of gentime wallet helpers -----------------------------------------------------------------------
|
||||
|
||||
#include "chaingen_helpers.h"
|
||||
|
|
|
|||
|
|
@ -228,3 +228,57 @@ inline bool resign_tx(const currency::account_keys& sender_keys, const std::vect
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline std::string gen_random_alias(size_t len)
|
||||
{
|
||||
const char allowed_chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
char buffer[2048] = "";
|
||||
if (len >= sizeof buffer)
|
||||
return "";
|
||||
|
||||
crypto::generate_random_bytes(len, buffer);
|
||||
buffer[len] = 0;
|
||||
for(size_t i = 0; i < len; ++i)
|
||||
buffer[i] = allowed_chars[buffer[i] % (sizeof allowed_chars - 1)];
|
||||
return buffer;
|
||||
}
|
||||
|
||||
template<typename alias_entry_t>
|
||||
inline bool put_alias_via_tx_to_list(std::vector<test_event_entry>& events,
|
||||
std::list<currency::transaction>& tx_set,
|
||||
const currency::block& head_block,
|
||||
const currency::account_base& miner_acc,
|
||||
const alias_entry_t& ae,
|
||||
test_generator& generator)
|
||||
{
|
||||
std::vector<currency::extra_v> ex;
|
||||
ex.push_back(ae);
|
||||
currency::account_base reward_acc;
|
||||
currency::account_keys& ak = const_cast<currency::account_keys&>(reward_acc.get_keys());
|
||||
currency::get_aliases_reward_account(ak.account_address, ak.view_secret_key);
|
||||
|
||||
uint64_t fee_median = generator.get_last_n_blocks_fee_median(get_block_hash(head_block));
|
||||
uint64_t reward = currency::get_alias_coast_from_fee(ae.m_alias, fee_median);
|
||||
|
||||
MAKE_TX_MIX_LIST_EXTRA_MIX_ATTR(events,
|
||||
tx_set,
|
||||
miner_acc,
|
||||
reward_acc,
|
||||
reward,
|
||||
0,
|
||||
head_block,
|
||||
CURRENCY_TO_KEY_OUT_RELAXED,
|
||||
ex,
|
||||
std::vector<currency::attachment_v>());
|
||||
|
||||
|
||||
uint64_t found_alias_reward = get_amount_for_zero_pubkeys(tx_set.back());
|
||||
if (found_alias_reward != reward)
|
||||
{
|
||||
LOCAL_ASSERT(false);
|
||||
CHECK_AND_ASSERT_MES(false, false, "wrong transaction constructed, first input value not match alias amount or account");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -987,7 +987,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(gen_uint_overflow_2);
|
||||
|
||||
|
||||
// Hardfok1 tests
|
||||
// Hardfok 1 tests
|
||||
GENERATE_AND_PLAY(before_hard_fork_1_cumulative_difficulty);
|
||||
GENERATE_AND_PLAY(inthe_middle_hard_fork_1_cumulative_difficulty);
|
||||
GENERATE_AND_PLAY(after_hard_fork_1_cumulative_difficulty);
|
||||
|
|
@ -998,10 +998,19 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(hard_fork_1_chain_switch_pow_only);
|
||||
GENERATE_AND_PLAY(hard_fork_1_checkpoint_basic_test);
|
||||
GENERATE_AND_PLAY(hard_fork_1_pos_locked_height_vs_time);
|
||||
//GENERATE_AND_PLAY(gen_block_reward); */
|
||||
|
||||
|
||||
// Hardfork 2 tests
|
||||
GENERATE_AND_PLAY(hard_fork_2_tx_payer_in_wallet);
|
||||
GENERATE_AND_PLAY(hard_fork_2_tx_receiver_in_wallet);
|
||||
GENERATE_AND_PLAY(hard_fork_2_tx_extra_alias_entry_in_wallet);
|
||||
GENERATE_AND_PLAY(hard_fork_2_auditable_addresses_basics);
|
||||
GENERATE_AND_PLAY(hard_fork_2_no_new_structures_before_hf);
|
||||
GENERATE_AND_PLAY(hard_fork_2_awo_wallets_basic_test<true>);
|
||||
GENERATE_AND_PLAY(hard_fork_2_awo_wallets_basic_test<false>);
|
||||
|
||||
|
||||
// GENERATE_AND_PLAY(gen_block_reward);
|
||||
// END OF TESTS */
|
||||
|
||||
size_t failed_postponed_tests_count = 0;
|
||||
uint64_t total_time = 0;
|
||||
|
|
|
|||
|
|
@ -37,3 +37,4 @@
|
|||
#include "hard_fork_1_consensus_test.h"
|
||||
#include "hard_fork_1_bad_pos_source.h"
|
||||
#include "hard_fork_1.h"
|
||||
#include "hard_fork_2.h"
|
||||
|
|
|
|||
|
|
@ -612,7 +612,7 @@ gen_no_attchments_in_coinbase::gen_no_attchments_in_coinbase()
|
|||
// NOTE: This test is made deterministic to be able to correctly set up checkpoint.
|
||||
random_state_test_restorer::reset_random(); // random generator's state was previously stored, will be restore on dtor (see also m_random_state_test_restorer)
|
||||
|
||||
bool r = m_miner_acc.restore_keys_from_braindata("battle harsh arrow gain best doubt nose raw protect salty apart tell distant final yeah stubborn true stop shoulder breathe throne problem everyone stranger only");
|
||||
bool r = m_miner_acc.restore_from_braindata("battle harsh arrow gain best doubt nose raw protect salty apart tell distant final yeah stubborn true stop shoulder breathe throne problem everyone stranger only");
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "gen_no_attchments_in_coinbase: Can't restore account from braindata");
|
||||
|
||||
REGISTER_CALLBACK_METHOD(gen_no_attchments_in_coinbase, c1);
|
||||
|
|
|
|||
1116
tests/core_tests/hard_fork_2.cpp
Normal file
1116
tests/core_tests/hard_fork_2.cpp
Normal file
File diff suppressed because it is too large
Load diff
68
tests/core_tests/hard_fork_2.h
Normal file
68
tests/core_tests/hard_fork_2.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) 2020 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 "chaingen.h"
|
||||
#include "wallet_tests_basic.h"
|
||||
|
||||
struct hard_fork_2_base_test : virtual public test_chain_unit_enchanced
|
||||
{
|
||||
hard_fork_2_base_test(size_t hardfork_02_height);
|
||||
hard_fork_2_base_test(size_t hardfork_01_height, size_t hardfork_02_height);
|
||||
bool configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
void set_hard_fork_heights_to_generator(test_generator& generator) const;
|
||||
|
||||
size_t m_hardfork_01_height;
|
||||
size_t m_hardfork_02_height;
|
||||
};
|
||||
|
||||
struct hard_fork_2_tx_payer_in_wallet : public wallet_test, public hard_fork_2_base_test
|
||||
{
|
||||
hard_fork_2_tx_payer_in_wallet();
|
||||
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 hard_fork_2_tx_receiver_in_wallet : public wallet_test, public hard_fork_2_base_test
|
||||
{
|
||||
hard_fork_2_tx_receiver_in_wallet();
|
||||
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);
|
||||
|
||||
mutable uint64_t m_alice_start_balance;
|
||||
};
|
||||
|
||||
struct hard_fork_2_tx_extra_alias_entry_in_wallet : public wallet_test, public hard_fork_2_base_test
|
||||
{
|
||||
hard_fork_2_tx_extra_alias_entry_in_wallet();
|
||||
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 hard_fork_2_auditable_addresses_basics : public wallet_test, public hard_fork_2_base_test
|
||||
{
|
||||
hard_fork_2_auditable_addresses_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 hard_fork_2_no_new_structures_before_hf : public wallet_test, public hard_fork_2_base_test
|
||||
{
|
||||
using hard_fork_2_base_test::check_block_verification_context; // this is necessary for correct work of do_check_block_verification_context, consider rafactoring
|
||||
|
||||
hard_fork_2_no_new_structures_before_hf();
|
||||
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);
|
||||
};
|
||||
|
||||
template<bool before_hf_2>
|
||||
struct hard_fork_2_awo_wallets_basic_test : public wallet_test, public hard_fork_2_base_test
|
||||
{
|
||||
//using hard_fork_2_base_test::check_block_verification_context; // this is necessary for correct work of do_check_block_verification_context, consider rafactoring
|
||||
|
||||
hard_fork_2_awo_wallets_basic_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);
|
||||
};
|
||||
|
|
@ -22,18 +22,6 @@ const std::string g_wallet_password = "dofatibmzibeziyekigo";
|
|||
const currency::account_base null_account = AUTO_VAL_INIT(null_account);
|
||||
|
||||
|
||||
struct wlt_lambda_on_transfer2_wrapper : public tools::i_wallet2_callback
|
||||
{
|
||||
typedef std::function<bool(const tools::wallet_public::wallet_transfer_info&, uint64_t, uint64_t, uint64_t)> Func;
|
||||
wlt_lambda_on_transfer2_wrapper(Func callback) : m_result(false), m_callback(callback) {}
|
||||
virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) override
|
||||
{
|
||||
m_result = m_callback(wti, balance, unlocked_balance, total_mined);
|
||||
}
|
||||
bool m_result;
|
||||
Func m_callback;
|
||||
};
|
||||
|
||||
POD_MAKE_COMPARABLE(currency, tx_out);
|
||||
|
||||
// Determines which output is real and actually spent in tx inputs, when there are fake outputs.
|
||||
|
|
@ -1434,7 +1422,7 @@ bool gen_wallet_decrypted_attachments::generate(std::vector<test_event_entry>& e
|
|||
CREATE_TEST_WALLET(alice_wlt, alice_acc, blk_0);
|
||||
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_0r, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
// these attachments will be use across all the transactions in this test
|
||||
// these attachments will be used across all the transactions in this test
|
||||
currency::tx_payer a_tx_payer = AUTO_VAL_INIT(a_tx_payer);
|
||||
a_tx_payer.acc_addr = miner_acc.get_keys().account_address;
|
||||
currency::tx_comment a_tx_comment = AUTO_VAL_INIT(a_tx_comment);
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ bool wallet_test::check_balance(currency::core& c, size_t ev_index, const std::v
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<tools::wallet2> wallet_test::init_playtime_test_wallet(const std::vector<test_event_entry>& events, currency::core& c, const account_base& acc) const
|
||||
{
|
||||
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");
|
||||
|
|
@ -84,6 +85,7 @@ std::shared_ptr<tools::wallet2> wallet_test::init_playtime_test_wallet(const std
|
|||
w->set_core_proxy(m_core_proxy);
|
||||
return w;
|
||||
}
|
||||
|
||||
std::shared_ptr<tools::wallet2> wallet_test::init_playtime_test_wallet(const std::vector<test_event_entry>& events, currency::core& c, size_t account_index) const
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(account_index < m_accounts.size(), "Invalid account index");
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#pragma once
|
||||
#include "chaingen.h"
|
||||
|
||||
struct wallet_test : public test_chain_unit_enchanced
|
||||
struct wallet_test : virtual public test_chain_unit_enchanced
|
||||
{
|
||||
enum { MINER_ACC_IDX = 0, ALICE_ACC_IDX = 1, BOB_ACC_IDX = 2, CAROL_ACC_IDX = 3, DAN_ACC_IDX = 4, TOTAL_ACCS_COUNT = 5 }; // to be used as index for m_accounts
|
||||
|
||||
|
|
@ -87,3 +87,15 @@ struct wallet_callback_balance_checker : public tools::i_wallet2_callback
|
|||
uint64_t m_unlocked_balance;
|
||||
uint64_t m_total_mined;
|
||||
};
|
||||
|
||||
struct wlt_lambda_on_transfer2_wrapper : public tools::i_wallet2_callback
|
||||
{
|
||||
typedef std::function<bool(const tools::wallet_public::wallet_transfer_info&, uint64_t, uint64_t, uint64_t)> Func;
|
||||
wlt_lambda_on_transfer2_wrapper(Func callback) : m_result(false), m_callback(callback) {}
|
||||
virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) override
|
||||
{
|
||||
m_result = m_callback(wti, balance, unlocked_balance, total_mined);
|
||||
}
|
||||
bool m_result;
|
||||
Func m_callback;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -439,7 +439,8 @@ namespace
|
|||
"\xf7\x24\xbc\x5c\x6c\xfb\xb9\xd9\x76\x02\xc3\x00\x42\x3a\x2f\x28"
|
||||
"\x64\x18\x74\x51\x3a\x03\x57\x78\xa0\xc1\x77\x8d\x83\x32\x01\xe9"
|
||||
"\x22\x09\x39\x68\x9e\xdf\x1a\xbd\x5b\xc1\xd0\x31\xf7\x3e\xcd\x6c"
|
||||
"\x99\x3a\xdd\x66\xd6\x80\x88\x70\x45\x6a\xfe\xb8\xe7\xee\xb6\x8d");
|
||||
"\x99\x3a\xdd\x66\xd6\x80\x88\x70\x45\x6a\xfe\xb8\xe7\xee\xb6\x8d"
|
||||
"\x00");
|
||||
std::string test_keys_addr_str = "ZxDqHy6WnyYY5yQcdApjMb8tVPik5BC3LFdaevfbGq7X1KY5vdsWmUi5UQgse2GBZFbMsb47TFqBmPpdFHDDwDxR2ZuZ6zX4W"; // correct str address depends on CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX value
|
||||
}
|
||||
|
||||
|
|
@ -499,7 +500,7 @@ TEST(get_account_address_from_str, fails_on_invalid_address_spend_key)
|
|||
TEST(get_account_address_from_str, fails_on_invalid_address_view_key)
|
||||
{
|
||||
std::string serialized_keys_copy = test_serialized_keys;
|
||||
serialized_keys_copy.back() = '\x01';
|
||||
serialized_keys_copy[serialized_keys_copy.size() - 2] = '\x01';
|
||||
std::string addr_str = base58::encode_addr(CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX, serialized_keys_copy);
|
||||
|
||||
currency::account_public_address addr;
|
||||
|
|
@ -551,3 +552,103 @@ TEST(integ_address, payment_id_sizes)
|
|||
ASSERT_NE(addr2, addr);
|
||||
ASSERT_NE(integrated_payment_id, payment_id);
|
||||
}
|
||||
|
||||
|
||||
struct addr_entry_t
|
||||
{
|
||||
std::string address;
|
||||
std::string view_pub_key;
|
||||
std::string spend_pub_key;
|
||||
std::string payment_id_hex;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
addr_entry_t addr_entries[] =
|
||||
{
|
||||
{
|
||||
// classic normal address
|
||||
"ZxD5aoLDPTdcaRx4uCpyW4XiLfEXejepAVz8cSY2fwHNEiJNu6NmpBBDLGTJzCsUvn3acCVDVDPMV8yQXdPooAp338Se7AxeH", // address
|
||||
"a3f208c8f9ba49bab28eed62b35b0f6be0a297bcd85c2faa1eb1820527bcf7e3", // view_pub_key
|
||||
"9f5e1fa93630d4b281b18bb67a3db79e9622fc703cc3ad4a453a82e0a36d51fa", // spend_pub_key
|
||||
"", // payment_id_hex
|
||||
0 // flags
|
||||
},
|
||||
{
|
||||
// classic integrated address
|
||||
"iZ2Zi6RmTWwcaRx4uCpyW4XiLfEXejepAVz8cSY2fwHNEiJNu6NmpBBDLGTJzCsUvn3acCVDVDPMV8yQXdPooAp3iTqEsjvJoco1aLSZXS6T", // address
|
||||
"a3f208c8f9ba49bab28eed62b35b0f6be0a297bcd85c2faa1eb1820527bcf7e3", // view_pub_key
|
||||
"9f5e1fa93630d4b281b18bb67a3db79e9622fc703cc3ad4a453a82e0a36d51fa", // spend_pub_key
|
||||
"87440d0b9acc42f1", // payment_id_hex
|
||||
0 // flags
|
||||
},
|
||||
{
|
||||
// new format normal address with custom flags
|
||||
"ZxD5aoLDPTdcaRx4uCpyW4XiLfEXejepAVz8cSY2fwHNEiJNu6NmpBBDLGTJzCsUvn3acCVDVDPMV8yQXdPooAp3APrDvRoL5C", // address
|
||||
"a3f208c8f9ba49bab28eed62b35b0f6be0a297bcd85c2faa1eb1820527bcf7e3", // view_pub_key
|
||||
"9f5e1fa93630d4b281b18bb67a3db79e9622fc703cc3ad4a453a82e0a36d51fa", // spend_pub_key
|
||||
"", // payment_id_hex
|
||||
0xfe // flags
|
||||
},
|
||||
{
|
||||
// new format integrated address with custom flags
|
||||
"iZ4mBxubNfqcaRx4uCpyW4XiLfEXejepAVz8cSY2fwHNEiJNu6NmpBBDLGTJzCsUvn3acCVDVDPMV8yQXdPooAp3iTrG7nU5rRCWmcozLaMoY95sAbo6", // address
|
||||
"a3f208c8f9ba49bab28eed62b35b0f6be0a297bcd85c2faa1eb1820527bcf7e3", // view_pub_key
|
||||
"9f5e1fa93630d4b281b18bb67a3db79e9622fc703cc3ad4a453a82e0a36d51fa", // spend_pub_key
|
||||
"3ba0527bcfb1fa93630d28eed6", // payment_id
|
||||
0xfe // flags
|
||||
},
|
||||
{
|
||||
// normal auditable address
|
||||
"aZxb9Et6FhP9AinRwcPqSqBKjckre7PgoZjK3q5YG2fUKHYWFZMWjB6YAEAdw4yDDUGEQ7CGEgbqhGRKeadGV1jLYcEJMEmqQFn", // address
|
||||
"a3f208c8f9ba49bab28eed62b35b0f6be0a297bcd85c2faa1eb1820527bcf7e3", // view_pub_key
|
||||
"9f5e1fa93630d4b281b18bb67a3db79e9622fc703cc3ad4a453a82e0a36d51fa", // spend_pub_key
|
||||
"", // payment_id
|
||||
ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE // flags
|
||||
},
|
||||
{
|
||||
// auditable integrated address
|
||||
"aiZXDondHWu9AinRwcPqSqBKjckre7PgoZjK3q5YG2fUKHYWFZMWjB6YAEAdw4yDDUGEQ7CGEgbqhGRKeadGV1jLYcEJM9xJH8EbjuRiMJgFmPRATsEV9", // address
|
||||
"a3f208c8f9ba49bab28eed62b35b0f6be0a297bcd85c2faa1eb1820527bcf7e3", // view_pub_key
|
||||
"9f5e1fa93630d4b281b18bb67a3db79e9622fc703cc3ad4a453a82e0a36d51fa", // spend_pub_key
|
||||
"3ba0527bcfb1fa93630d28eed6", // payment_id
|
||||
ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE // flags
|
||||
}
|
||||
};
|
||||
|
||||
void check_add_entry(const addr_entry_t& ae)
|
||||
{
|
||||
std::string payment_id, payment_id_hex;
|
||||
currency::account_public_address addr = AUTO_VAL_INIT(addr);
|
||||
|
||||
ASSERT_TRUE(currency::get_account_address_and_payment_id_from_str(addr, payment_id, ae.address));
|
||||
payment_id_hex = epee::string_tools::buff_to_hex_nodelimer(payment_id);
|
||||
|
||||
ASSERT_EQ(ae.flags, addr.flags);
|
||||
ASSERT_EQ(ae.payment_id_hex, payment_id_hex);
|
||||
ASSERT_EQ(ae.view_pub_key, epee::string_tools::pod_to_hex(addr.view_public_key));
|
||||
ASSERT_EQ(ae.spend_pub_key, epee::string_tools::pod_to_hex(addr.spend_public_key));
|
||||
}
|
||||
|
||||
TEST(auditable_addresses, basic)
|
||||
{
|
||||
/*
|
||||
currency::account_keys keys = AUTO_VAL_INIT(keys);
|
||||
epee::string_tools::parse_tpod_from_hex_string("248b019d145d485576ecb0367d92b5a12e8aa15084b59ef15014a7a22d1f3b0c", keys.spend_secret_key);
|
||||
dependent_key(keys.spend_secret_key, keys.view_secret_key);
|
||||
crypto::secret_key_to_public_key(keys.view_secret_key, keys.account_address.view_public_key);
|
||||
crypto::secret_key_to_public_key(keys.spend_secret_key, keys.account_address.spend_public_key);
|
||||
|
||||
keys.account_address.flags = 0xfe;
|
||||
|
||||
std::string payment_id;
|
||||
epee::string_tools::parse_hexstr_to_binbuff(std::string("3ba0527bcfb1fa93630d28eed6"), payment_id);
|
||||
|
||||
std::cout << currency::get_account_address_as_str(keys.account_address) << " " << epee::string_tools::pod_to_hex(keys.account_address.view_public_key) << " " << epee::string_tools::pod_to_hex(keys.account_address.spend_public_key) << ENDL;
|
||||
std::cout << currency::get_account_address_and_payment_id_as_str(keys.account_address, payment_id) << " " << epee::string_tools::pod_to_hex(keys.account_address.view_public_key) << " " << epee::string_tools::pod_to_hex(keys.account_address.spend_public_key) << ENDL;
|
||||
*/
|
||||
|
||||
|
||||
for (size_t i = 0; i < sizeof addr_entries / sizeof addr_entries[0]; ++i)
|
||||
check_add_entry(addr_entries[i]);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ TEST(brain_wallet, store_restore_test)
|
|||
{
|
||||
currency::account_base acc;
|
||||
acc.generate();
|
||||
auto restore_data = acc.get_restore_data();
|
||||
auto seed_phrase = acc.get_restore_braindata();
|
||||
|
||||
currency::account_base acc2;
|
||||
bool r = acc2.restore_keys(restore_data);
|
||||
bool r = acc2.restore_from_braindata(seed_phrase);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
if (memcmp(&acc2.get_keys(), &acc.get_keys(), sizeof(currency::account_keys)))
|
||||
|
|
@ -29,10 +29,10 @@ TEST(brain_wallet, store_restore_test)
|
|||
{
|
||||
currency::account_base acc;
|
||||
acc.generate();
|
||||
auto restore_data = acc.get_restore_braindata();
|
||||
auto seed_phrase = acc.get_restore_braindata();
|
||||
|
||||
currency::account_base acc2;
|
||||
bool r = acc2.restore_keys_from_braindata(restore_data);
|
||||
bool r = acc2.restore_from_braindata(seed_phrase);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
if (memcmp(&acc2.get_keys(), &acc.get_keys(), sizeof(currency::account_keys)))
|
||||
|
|
@ -42,3 +42,136 @@ TEST(brain_wallet, store_restore_test)
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
struct wallet_seed_entry
|
||||
{
|
||||
std::string seed_phrase;
|
||||
std::string spend_secret_key;
|
||||
std::string view_secret_key;
|
||||
uint64_t timestamp;
|
||||
bool auditable;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
wallet_seed_entry wallet_seed_entries[] =
|
||||
{
|
||||
{
|
||||
// legacy 24-word seed phrase -- invalid
|
||||
"dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew",
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
false
|
||||
},
|
||||
{
|
||||
// old-style 25-word seed phrase -- valid
|
||||
"dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew",
|
||||
"5e051454d7226b5734ebd64f754b57db4c655ecda00bd324f1b241d0b6381c0f",
|
||||
"7dde5590fdf430568c00556ac2accf09da6cde9a29a4bc7d1cb6fd267130f006",
|
||||
0,
|
||||
false,
|
||||
true
|
||||
},
|
||||
{
|
||||
// old-style 25-word seed phrase -- valid
|
||||
"conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation conversation",
|
||||
"71162f207499bc16260957c36a6586bb931d54be33ff56b94d565dfedbb3c70e",
|
||||
"8454372096986c457f4e7dceef2f39b6050c35d87b31d9c9eb8d37bf8f1f430f",
|
||||
0,
|
||||
false,
|
||||
true
|
||||
},
|
||||
{
|
||||
// old-style 25-word seed phrase -- invalid word
|
||||
"dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew dew!",
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
false
|
||||
},
|
||||
{
|
||||
// old-style 25-word seed phrase -- invalid word
|
||||
"six six six six six six six six six sex six six six six six six six six six six six six six six six",
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
false
|
||||
},
|
||||
{
|
||||
// new-style 26-word seed phrase -- invalid word
|
||||
"six six six six six six six six six six six six six six six six six six six six six six six six six sex",
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
false
|
||||
},
|
||||
{
|
||||
// new-style 26-word seed phrase -- invalid checksum
|
||||
"six six six six six six six six six six six six six six six six six six six six six six six six six six",
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
false
|
||||
},
|
||||
{
|
||||
// new-style 26-word seed phrase - valid
|
||||
"six six six six six six six six six six six six six six six six six six six six six six six six six frown",
|
||||
"F54F61E3B974AD86171AE4944205C7BD0395BD7845899CDA8B1FBC5C947BB402",
|
||||
"A18715058BBD914959C3A735B2022E9AE1D04452BC1FAD9E63C53668B7F57907",
|
||||
1922832000,
|
||||
false,
|
||||
true
|
||||
},
|
||||
{
|
||||
// new-style 26-word seed phrase auditable - valid
|
||||
"six six six six six six six six six six six six six six six six six six six six six six six six six grace",
|
||||
"F54F61E3B974AD86171AE4944205C7BD0395BD7845899CDA8B1FBC5C947BB402",
|
||||
"A18715058BBD914959C3A735B2022E9AE1D04452BC1FAD9E63C53668B7F57907",
|
||||
1922832000,
|
||||
true,
|
||||
true
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
TEST(wallet_seed, basic_test)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof wallet_seed_entries / sizeof wallet_seed_entries[0]; ++i)
|
||||
{
|
||||
const wallet_seed_entry& wse = wallet_seed_entries[i];
|
||||
currency::account_base acc;
|
||||
bool r = false;
|
||||
try
|
||||
{
|
||||
r = acc.restore_from_braindata(wse.seed_phrase);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
r = false;
|
||||
}
|
||||
ASSERT_EQ(r, wse.valid);
|
||||
|
||||
if (r)
|
||||
{
|
||||
if (wse.timestamp)
|
||||
ASSERT_EQ(wse.timestamp, acc.get_createtime());
|
||||
|
||||
ASSERT_EQ(wse.auditable, acc.get_public_address().is_auditable());
|
||||
|
||||
// check keys
|
||||
crypto::secret_key v, s;
|
||||
ASSERT_TRUE(epee::string_tools::parse_tpod_from_hex_string(wse.spend_secret_key, s));
|
||||
ASSERT_EQ(s, acc.get_keys().spend_secret_key);
|
||||
|
||||
ASSERT_TRUE(epee::string_tools::parse_tpod_from_hex_string(wse.view_secret_key, v));
|
||||
ASSERT_EQ(v, acc.get_keys().view_secret_key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -903,7 +903,7 @@ namespace lmdb_test
|
|||
|
||||
static const uint64_t buffer_size = 64 * 1024; // 64 KB
|
||||
static const uint64_t db_total_size = static_cast<uint64_t>(2.1 * 1024 * 1024 * 1024); // 2.1 GB -- a bit more than 2GB to test 2GB boundary
|
||||
static const std::string db_file_path = std::string("2gb_") + typeid(db_backend_t).name() + "_test";
|
||||
static const std::string db_file_path = boost::algorithm::replace_all_copy(boost::algorithm::replace_all_copy(std::string("2gb_") + typeid(db_backend_t).name() + "_test", ":", "_"), " ", "_");
|
||||
|
||||
std::shared_ptr<db_backend_t> lmdb_ptr = std::make_shared<db_backend_t>();
|
||||
db::basic_db_accessor bdba(lmdb_ptr, rw_lock);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue