dncurrency/nano/core_test/numbers.cpp
2025-01-21 17:20:06 +01:00

865 lines
No EOL
28 KiB
C++

#include <nano/lib/numbers.hpp>
#include <nano/lib/numbers_templ.hpp>
#include <nano/secure/common.hpp>
#include <gtest/gtest.h>
#include <boost/container_hash/hash.hpp>
#include <thread>
#include <unordered_set>
TEST (numbers, identity)
{
ASSERT_EQ (1, nano::uint128_union (1).number ().convert_to<uint8_t> ());
ASSERT_EQ (1, nano::uint256_union (1).number ().convert_to<uint8_t> ());
ASSERT_EQ (1, nano::uint512_union (1).number ().convert_to<uint8_t> ());
}
namespace
{
template <typename Type>
void check_operator_less_than (Type lhs, Type rhs)
{
ASSERT_TRUE (lhs < rhs);
ASSERT_FALSE (rhs < lhs);
ASSERT_FALSE (lhs < lhs);
ASSERT_FALSE (rhs < rhs);
}
template <typename Type>
void test_operator_less_than ()
{
using underlying_t = typename Type::underlying_type;
// Small
check_operator_less_than (Type{ 123 }, Type{ 124 });
check_operator_less_than (Type{ 124 }, Type{ 125 });
// Medium
check_operator_less_than (Type{ std::numeric_limits<uint16_t>::max () - 1 }, Type{ std::numeric_limits<uint16_t>::max () + 1 });
check_operator_less_than (Type{ std::numeric_limits<uint32_t>::max () - 12345678 }, Type{ std::numeric_limits<uint32_t>::max () - 123456 });
// Large
check_operator_less_than (Type{ std::numeric_limits<uint64_t>::max () - 555555555555 }, Type{ std::numeric_limits<uint64_t>::max () - 1 });
// Boundary values
check_operator_less_than (Type{ std::numeric_limits<underlying_t>::min () }, Type{ std::numeric_limits<underlying_t>::max () });
}
template <typename Type>
void check_operator_greater_than (Type lhs, Type rhs)
{
ASSERT_TRUE (lhs > rhs);
ASSERT_FALSE (rhs > lhs);
ASSERT_FALSE (lhs > lhs);
ASSERT_FALSE (rhs > rhs);
}
template <typename Type>
void test_operator_greater_than ()
{
using underlying_t = typename Type::underlying_type;
// Small
check_operator_greater_than (Type{ 124 }, Type{ 123 });
check_operator_greater_than (Type{ 125 }, Type{ 124 });
// Medium
check_operator_greater_than (Type{ std::numeric_limits<uint16_t>::max () + 1 }, Type{ std::numeric_limits<uint16_t>::max () - 1 });
check_operator_greater_than (Type{ std::numeric_limits<uint32_t>::max () - 123456 }, Type{ std::numeric_limits<uint32_t>::max () - 12345678 });
// Large
check_operator_greater_than (Type{ std::numeric_limits<uint64_t>::max () - 1 }, Type{ std::numeric_limits<uint64_t>::max () - 555555555555 });
// Boundary values
check_operator_greater_than (Type{ std::numeric_limits<underlying_t>::max () }, Type{ std::numeric_limits<underlying_t>::min () });
}
template <typename Type>
void test_comparison ()
{
test_operator_less_than<Type> ();
test_operator_greater_than<Type> ();
}
}
TEST (numbers, comparison)
{
test_comparison<nano::uint128_union> ();
test_comparison<nano::uint256_union> ();
test_comparison<nano::uint512_union> ();
test_comparison<nano::block_hash> ();
test_comparison<nano::public_key> ();
test_comparison<nano::hash_or_account> ();
test_comparison<nano::link> ();
test_comparison<nano::root> ();
test_comparison<nano::raw_key> ();
test_comparison<nano::wallet_id> ();
test_comparison<nano::qualified_root> ();
}
namespace
{
template <typename Type, template <typename> class Hash>
void test_hashing ()
{
Hash<Type> hash;
using underlying_t = typename Type::underlying_type;
// Basic equality tests
ASSERT_EQ (hash (Type{}), hash (Type{}));
ASSERT_EQ (hash (Type{ 123 }), hash (Type{ 123 }));
// Basic inequality tests
ASSERT_NE (hash (Type{ 123 }), hash (Type{ 124 }));
ASSERT_NE (hash (Type{ 0 }), hash (Type{ 1 }));
// Boundary value tests
constexpr auto min_val = std::numeric_limits<underlying_t>::min ();
constexpr auto max_val = std::numeric_limits<underlying_t>::max ();
// Min/Max tests
ASSERT_EQ (hash (Type{ min_val }), hash (Type{ min_val }));
ASSERT_EQ (hash (Type{ max_val }), hash (Type{ max_val }));
ASSERT_NE (hash (Type{ min_val }), hash (Type{ max_val }));
// Near boundary tests
ASSERT_NE (hash (Type{ min_val }), hash (Type{ min_val + 1 }));
ASSERT_NE (hash (Type{ max_val }), hash (Type{ max_val - 1 }));
ASSERT_NE (hash (Type{ min_val + 1 }), hash (Type{ max_val }));
ASSERT_NE (hash (Type{ max_val - 1 }), hash (Type{ min_val }));
// Common value tests
std::vector<underlying_t> common_values = {
0, // Zero
1, // One
42, // Common test value
0xFF, // Byte boundary
0xFFFF, // Word boundary
min_val, // Minimum
max_val, // Maximum
max_val / 2, // Middle value
min_val + (max_val / 2) // Offset middle
};
// Test all common values against each other
for (size_t i = 0; i < common_values.size (); ++i)
{
for (size_t j = i + 1; j < common_values.size (); ++j)
{
if (common_values[i] != common_values[j])
{
ASSERT_NE (hash (Type{ common_values[i] }), hash (Type{ common_values[j] }));
}
else
{
ASSERT_EQ (hash (Type{ common_values[i] }), hash (Type{ common_values[j] }));
}
}
}
}
}
TEST (numbers, hashing)
{
// Using std::hash
test_hashing<nano::uint128_union, std::hash> ();
test_hashing<nano::uint256_union, std::hash> ();
test_hashing<nano::uint512_union, std::hash> ();
test_hashing<nano::block_hash, std::hash> ();
test_hashing<nano::public_key, std::hash> ();
test_hashing<nano::hash_or_account, std::hash> ();
test_hashing<nano::link, std::hash> ();
test_hashing<nano::root, std::hash> ();
test_hashing<nano::raw_key, std::hash> ();
test_hashing<nano::wallet_id, std::hash> ();
test_hashing<nano::qualified_root, std::hash> ();
// Using boost::hash
test_hashing<nano::uint128_union, boost::hash> ();
test_hashing<nano::uint256_union, boost::hash> ();
test_hashing<nano::uint512_union, boost::hash> ();
test_hashing<nano::block_hash, boost::hash> ();
test_hashing<nano::public_key, boost::hash> ();
test_hashing<nano::hash_or_account, boost::hash> ();
test_hashing<nano::link, boost::hash> ();
test_hashing<nano::root, boost::hash> ();
test_hashing<nano::raw_key, boost::hash> ();
test_hashing<nano::wallet_id, boost::hash> ();
test_hashing<nano::qualified_root, boost::hash> ();
}
TEST (uint128_union, decode_dec)
{
nano::uint128_union value;
std::string text ("16");
ASSERT_FALSE (value.decode_dec (text));
ASSERT_EQ (16, value.bytes[15]);
}
TEST (uint128_union, decode_dec_negative)
{
nano::uint128_union value;
std::string text ("-1");
auto error (value.decode_dec (text));
ASSERT_TRUE (error);
}
TEST (uint128_union, decode_dec_zero)
{
nano::uint128_union value;
std::string text ("0");
ASSERT_FALSE (value.decode_dec (text));
ASSERT_TRUE (value.is_zero ());
}
TEST (uint128_union, decode_dec_leading_zero)
{
nano::uint128_union value;
std::string text ("010");
auto error (value.decode_dec (text));
ASSERT_TRUE (error);
}
TEST (uint128_union, decode_dec_overflow)
{
nano::uint128_union value;
std::string text ("340282366920938463463374607431768211456");
auto error (value.decode_dec (text));
ASSERT_TRUE (error);
}
struct test_punct : std::moneypunct<char>
{
pattern do_pos_format () const
{
return { { value, none, none, none } };
}
int do_frac_digits () const
{
return 0;
}
char_type do_decimal_point () const
{
return '+';
}
char_type do_thousands_sep () const
{
return '-';
}
string_type do_grouping () const
{
return "\3\4";
}
};
TEST (uint128_union, balance_format)
{
ASSERT_EQ ("0", nano::amount (nano::uint128_t ("0")).format_balance (nano::nano_ratio, 0, false));
ASSERT_EQ ("0", nano::amount (nano::uint128_t ("0")).format_balance (nano::nano_ratio, 2, true));
ASSERT_EQ ("340,282,366", nano::amount (nano::uint128_t ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")).format_balance (nano::nano_ratio, 0, true));
ASSERT_EQ ("340,282,366.920938463463374607431768211455", nano::amount (nano::uint128_t ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")).format_balance (nano::nano_ratio, 64, true));
ASSERT_EQ ("340,282,366,920,938,463,463,374,607,431,768,211,455", nano::amount (nano::uint128_t ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")).format_balance (1, 4, true));
ASSERT_EQ ("340,282,366", nano::amount (nano::uint128_t ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE")).format_balance (nano::nano_ratio, 0, true));
ASSERT_EQ ("340,282,366.920938463463374607431768211454", nano::amount (nano::uint128_t ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE")).format_balance (nano::nano_ratio, 64, true));
ASSERT_EQ ("340282366920938463463374607431768211454", nano::amount (nano::uint128_t ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE")).format_balance (1, 4, false));
ASSERT_EQ ("170,141,183", nano::amount (nano::uint128_t ("0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE")).format_balance (nano::nano_ratio, 0, true));
ASSERT_EQ ("170,141,183.460469231731687303715884105726", nano::amount (nano::uint128_t ("0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE")).format_balance (nano::nano_ratio, 64, true));
ASSERT_EQ ("170141183460469231731687303715884105726", nano::amount (nano::uint128_t ("0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE")).format_balance (1, 4, false));
ASSERT_EQ ("1", nano::amount (nano::uint128_t ("1000000000000000000000000000000")).format_balance (nano::nano_ratio, 2, true));
ASSERT_EQ ("1.2", nano::amount (nano::uint128_t ("1200000000000000000000000000000")).format_balance (nano::nano_ratio, 2, true));
ASSERT_EQ ("1.23", nano::amount (nano::uint128_t ("1230000000000000000000000000000")).format_balance (nano::nano_ratio, 2, true));
ASSERT_EQ ("1.2", nano::amount (nano::uint128_t ("1230000000000000000000000000000")).format_balance (nano::nano_ratio, 1, true));
ASSERT_EQ ("1", nano::amount (nano::uint128_t ("1230000000000000000000000000000")).format_balance (nano::nano_ratio, 0, true));
ASSERT_EQ ("123456789", nano::amount (nano::nano_ratio * 123456789).format_balance (nano::nano_ratio, 2, false));
ASSERT_EQ ("123,456,789", nano::amount (nano::nano_ratio * 123456789).format_balance (nano::nano_ratio, 2, true));
}
TEST (uint128_union, decode_decimal)
{
nano::amount amount;
ASSERT_FALSE (amount.decode_dec ("340282366920938463463374607431768211455", nano::raw_ratio));
ASSERT_EQ (std::numeric_limits<nano::uint128_t>::max (), amount.number ());
ASSERT_TRUE (amount.decode_dec ("340282366920938463463374607431768211456", nano::raw_ratio));
ASSERT_TRUE (amount.decode_dec ("340282366920938463463374607431768211455.1", nano::raw_ratio));
ASSERT_TRUE (amount.decode_dec ("0.1", nano::raw_ratio));
ASSERT_FALSE (amount.decode_dec ("1", nano::raw_ratio));
ASSERT_EQ (1, amount.number ());
ASSERT_FALSE (amount.decode_dec ("340282366.920938463463374607431768211454", nano::nano_ratio));
ASSERT_EQ (std::numeric_limits<nano::uint128_t>::max () - 1, amount.number ());
ASSERT_TRUE (amount.decode_dec ("340282366.920938463463374607431768211456", nano::nano_ratio));
ASSERT_TRUE (amount.decode_dec ("340282367", nano::nano_ratio));
ASSERT_FALSE (amount.decode_dec ("0.000000000000000000000001", nano::nano_ratio));
ASSERT_EQ (1000000, amount.number ());
ASSERT_FALSE (amount.decode_dec ("0.000000000000000000000000000001", nano::nano_ratio));
ASSERT_EQ (1, amount.number ());
ASSERT_TRUE (amount.decode_dec ("0.0000000000000000000000000000001", nano::nano_ratio));
ASSERT_TRUE (amount.decode_dec (".1", nano::nano_ratio));
ASSERT_TRUE (amount.decode_dec ("0.", nano::nano_ratio));
ASSERT_FALSE (amount.decode_dec ("9.999999999999999999999999999999", nano::nano_ratio));
ASSERT_EQ (nano::uint128_t ("9999999999999999999999999999999"), amount.number ());
ASSERT_FALSE (amount.decode_dec ("170141183.460469231731687303715884105727", nano::nano_ratio));
ASSERT_EQ (nano::uint128_t ("170141183460469231731687303715884105727"), amount.number ());
ASSERT_FALSE (amount.decode_dec ("1230", nano::Knano_ratio));
ASSERT_EQ (1230 * nano::Knano_ratio, amount.number ());
}
TEST (uint256_union, key_encryption)
{
nano::keypair key1;
nano::raw_key secret_key;
secret_key.clear ();
nano::uint256_union encrypted;
encrypted.encrypt (key1.prv, secret_key, key1.pub.owords[0]);
nano::raw_key key4;
key4.decrypt (encrypted, secret_key, key1.pub.owords[0]);
ASSERT_EQ (key1.prv, key4);
auto pub (nano::pub_key (key4));
ASSERT_EQ (key1.pub, pub);
}
TEST (uint256_union, encryption)
{
nano::raw_key key;
key.clear ();
nano::raw_key number1;
number1 = 1;
nano::uint256_union encrypted1;
encrypted1.encrypt (number1, key, key.owords[0]);
nano::uint256_union encrypted2;
encrypted2.encrypt (number1, key, key.owords[0]);
ASSERT_EQ (encrypted1, encrypted2);
nano::raw_key number2;
number2.decrypt (encrypted1, key, key.owords[0]);
ASSERT_EQ (number1, number2);
}
TEST (uint256_union, decode_empty)
{
std::string text;
nano::uint256_union val;
ASSERT_TRUE (val.decode_hex (text));
}
TEST (uint256_union, parse_zero)
{
nano::uint256_union input (nano::uint256_t (0));
std::string text = input.to_string ();
nano::uint256_union output;
auto error (output.decode_hex (text));
ASSERT_FALSE (error);
ASSERT_EQ (input, output);
ASSERT_TRUE (output.number ().is_zero ());
}
TEST (uint256_union, parse_zero_short)
{
std::string text ("0");
nano::uint256_union output;
auto error (output.decode_hex (text));
ASSERT_FALSE (error);
ASSERT_TRUE (output.number ().is_zero ());
}
TEST (uint256_union, parse_one)
{
nano::uint256_union input (nano::uint256_t (1));
std::string text = input.to_string ();
nano::uint256_union output;
auto error (output.decode_hex (text));
ASSERT_FALSE (error);
ASSERT_EQ (input, output);
ASSERT_EQ (1, output.number ());
}
TEST (uint256_union, parse_error_symbol)
{
nano::uint256_union input (nano::uint256_t (1000));
std::string text = input.to_string ();
text[5] = '!';
nano::uint256_union output;
auto error (output.decode_hex (text));
ASSERT_TRUE (error);
}
TEST (uint256_union, max_hex)
{
nano::uint256_union input (std::numeric_limits<nano::uint256_t>::max ());
std::string text = input.to_string ();
nano::uint256_union output;
auto error (output.decode_hex (text));
ASSERT_FALSE (error);
ASSERT_EQ (input, output);
ASSERT_EQ (nano::uint256_t ("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), output.number ());
}
TEST (uint256_union, decode_dec)
{
nano::uint256_union value;
std::string text ("16");
ASSERT_FALSE (value.decode_dec (text));
ASSERT_EQ (16, value.bytes[31]);
}
TEST (uint256_union, max_dec)
{
nano::uint256_union input (std::numeric_limits<nano::uint256_t>::max ());
std::string text = input.to_string_dec ();
nano::uint256_union output;
auto error (output.decode_dec (text));
ASSERT_FALSE (error);
ASSERT_EQ (input, output);
ASSERT_EQ (nano::uint256_t ("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), output.number ());
}
TEST (uint256_union, decode_dec_negative)
{
nano::uint256_union value;
std::string text ("-1");
auto error (value.decode_dec (text));
ASSERT_TRUE (error);
}
TEST (uint256_union, decode_dec_zero)
{
nano::uint256_union value;
std::string text ("0");
ASSERT_FALSE (value.decode_dec (text));
ASSERT_TRUE (value.is_zero ());
}
TEST (uint256_union, decode_dec_leading_zero)
{
nano::uint256_union value;
std::string text ("010");
auto error (value.decode_dec (text));
ASSERT_TRUE (error);
}
TEST (uint256_union, parse_error_overflow)
{
nano::uint256_union input (std::numeric_limits<nano::uint256_t>::max ());
std::string text = input.to_string ();
text.push_back (0);
nano::uint256_union output;
auto error (output.decode_hex (text));
ASSERT_TRUE (error);
}
TEST (uint256_union, big_endian_union_constructor)
{
nano::uint256_t value1 (1);
nano::uint256_union bytes1 (value1);
ASSERT_EQ (1, bytes1.bytes[31]);
nano::uint512_t value2 (1);
nano::uint512_union bytes2 (value2);
ASSERT_EQ (1, bytes2.bytes[63]);
}
TEST (uint256_union, big_endian_union_function)
{
nano::uint256_union bytes1 ("FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210");
ASSERT_EQ (0xfe, bytes1.bytes[0x00]);
ASSERT_EQ (0xdc, bytes1.bytes[0x01]);
ASSERT_EQ (0xba, bytes1.bytes[0x02]);
ASSERT_EQ (0x98, bytes1.bytes[0x03]);
ASSERT_EQ (0x76, bytes1.bytes[0x04]);
ASSERT_EQ (0x54, bytes1.bytes[0x05]);
ASSERT_EQ (0x32, bytes1.bytes[0x06]);
ASSERT_EQ (0x10, bytes1.bytes[0x07]);
ASSERT_EQ (0xfe, bytes1.bytes[0x08]);
ASSERT_EQ (0xdc, bytes1.bytes[0x09]);
ASSERT_EQ (0xba, bytes1.bytes[0x0a]);
ASSERT_EQ (0x98, bytes1.bytes[0x0b]);
ASSERT_EQ (0x76, bytes1.bytes[0x0c]);
ASSERT_EQ (0x54, bytes1.bytes[0x0d]);
ASSERT_EQ (0x32, bytes1.bytes[0x0e]);
ASSERT_EQ (0x10, bytes1.bytes[0x0f]);
ASSERT_EQ (0xfe, bytes1.bytes[0x10]);
ASSERT_EQ (0xdc, bytes1.bytes[0x11]);
ASSERT_EQ (0xba, bytes1.bytes[0x12]);
ASSERT_EQ (0x98, bytes1.bytes[0x13]);
ASSERT_EQ (0x76, bytes1.bytes[0x14]);
ASSERT_EQ (0x54, bytes1.bytes[0x15]);
ASSERT_EQ (0x32, bytes1.bytes[0x16]);
ASSERT_EQ (0x10, bytes1.bytes[0x17]);
ASSERT_EQ (0xfe, bytes1.bytes[0x18]);
ASSERT_EQ (0xdc, bytes1.bytes[0x19]);
ASSERT_EQ (0xba, bytes1.bytes[0x1a]);
ASSERT_EQ (0x98, bytes1.bytes[0x1b]);
ASSERT_EQ (0x76, bytes1.bytes[0x1c]);
ASSERT_EQ (0x54, bytes1.bytes[0x1d]);
ASSERT_EQ (0x32, bytes1.bytes[0x1e]);
ASSERT_EQ (0x10, bytes1.bytes[0x1f]);
ASSERT_EQ ("FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210", bytes1.to_string ());
ASSERT_EQ (nano::uint256_t ("0xFEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210"), bytes1.number ());
nano::uint512_union bytes2;
bytes2.clear ();
bytes2.bytes[63] = 1;
ASSERT_EQ (nano::uint512_t (1), bytes2.number ());
}
TEST (uint256_union, decode_nano_variant)
{
nano::account key;
ASSERT_FALSE (key.decode_account ("xrb_1111111111111111111111111111111111111111111111111111hifc8npp"));
ASSERT_FALSE (key.decode_account ("nano_1111111111111111111111111111111111111111111111111111hifc8npp"));
}
/**
* It used to be the case that when the address was wrong only in the checksum part
* then the decode_account would return error and it would also write the address with
* fixed checksum into 'key', which is not desirable.
*/
TEST (uint256_union, key_is_not_updated_on_checksum_error)
{
nano::account key;
ASSERT_EQ (key, 0);
bool result = key.decode_account ("nano_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpiij4txtd1");
ASSERT_EQ (key, 0);
ASSERT_TRUE (result);
}
TEST (uint256_union, account_transcode)
{
nano::account value;
auto text (nano::dev::genesis_key.pub.to_account ());
ASSERT_FALSE (value.decode_account (text));
ASSERT_EQ (nano::dev::genesis_key.pub, value);
/*
* Handle different offsets for the underscore separator
* for "xrb_" prefixed and "nano_" prefixed accounts
*/
unsigned offset = (text.front () == 'x') ? 3 : 4;
ASSERT_EQ ('_', text[offset]);
text[offset] = '-';
nano::account value2;
ASSERT_FALSE (value2.decode_account (text));
ASSERT_EQ (value, value2);
}
TEST (uint256_union, account_encode_lex)
{
nano::account min ("0000000000000000000000000000000000000000000000000000000000000000");
nano::account max ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
auto min_text (min.to_account ());
auto max_text (max.to_account ());
/*
* Handle different lengths for "xrb_" prefixed and "nano_" prefixed accounts
*/
unsigned length = (min_text.front () == 'x') ? 64 : 65;
ASSERT_EQ (length, min_text.size ());
ASSERT_EQ (length, max_text.size ());
auto previous (min_text);
for (auto i (1); i != 1000; ++i)
{
nano::account number (min.number () + i);
auto text (number.to_account ());
nano::account output;
output.decode_account (text);
ASSERT_EQ (number, output);
ASSERT_GT (text, previous);
previous = text;
}
for (auto i (1); i != 1000; ++i)
{
nano::keypair key;
auto text (key.pub.to_account ());
nano::account output;
output.decode_account (text);
ASSERT_EQ (key.pub, output);
}
}
TEST (uint256_union, bounds)
{
nano::account key;
std::string bad1 (64, '\x000');
bad1[0] = 'x';
bad1[1] = 'r';
bad1[2] = 'b';
bad1[3] = '-';
ASSERT_TRUE (key.decode_account (bad1));
std::string bad2 (64, '\x0ff');
bad2[0] = 'x';
bad2[1] = 'r';
bad2[2] = 'b';
bad2[3] = '-';
ASSERT_TRUE (key.decode_account (bad2));
}
TEST (uint64_t, parse)
{
uint64_t value0 (1);
ASSERT_FALSE (nano::from_string_hex ("0", value0));
ASSERT_EQ (0, value0);
uint64_t value1 (1);
ASSERT_FALSE (nano::from_string_hex ("ffffffffffffffff", value1));
ASSERT_EQ (0xffffffffffffffffULL, value1);
uint64_t value2 (1);
ASSERT_TRUE (nano::from_string_hex ("g", value2));
uint64_t value3 (1);
ASSERT_TRUE (nano::from_string_hex ("ffffffffffffffff0", value3));
uint64_t value4 (1);
ASSERT_TRUE (nano::from_string_hex ("", value4));
}
TEST (uint256_union, hash)
{
ASSERT_EQ (4, nano::uint256_union{}.qwords.size ());
std::hash<nano::uint256_union> h{};
for (size_t i (0), n (nano::uint256_union{}.bytes.size ()); i < n; ++i)
{
nano::uint256_union x1{ 0 };
nano::uint256_union x2{ 0 };
x2.bytes[i] = 1;
ASSERT_NE (h (x1), h (x2));
}
}
TEST (uint512_union, hash)
{
ASSERT_EQ (2, nano::uint512_union{}.uint256s.size ());
std::hash<nano::uint512_union> h{};
for (size_t i (0), n (nano::uint512_union{}.bytes.size ()); i < n; ++i)
{
nano::uint512_union x1{ 0 };
nano::uint512_union x2{ 0 };
x2.bytes[i] = 1;
ASSERT_NE (h (x1), h (x2));
}
for (auto part (0); part < nano::uint512_union{}.uint256s.size (); ++part)
{
for (size_t i (0), n (nano::uint512_union{}.uint256s[part].bytes.size ()); i < n; ++i)
{
nano::uint512_union x1{ 0 };
nano::uint512_union x2{ 0 };
x2.uint256s[part].bytes[i] = 1;
ASSERT_NE (h (x1), h (x2));
}
}
}
TEST (uint512_union, parse_zero)
{
nano::uint512_union input (nano::uint512_t (0));
std::string text = input.to_string ();
nano::uint512_union output;
auto error (output.decode_hex (text));
ASSERT_FALSE (error);
ASSERT_EQ (input, output);
ASSERT_TRUE (output.number ().is_zero ());
}
TEST (uint512_union, parse_zero_short)
{
std::string text ("0");
nano::uint512_union output;
auto error (output.decode_hex (text));
ASSERT_FALSE (error);
ASSERT_TRUE (output.number ().is_zero ());
}
TEST (uint512_union, parse_one)
{
nano::uint512_union input (nano::uint512_t (1));
std::string text = input.to_string ();
nano::uint512_union output;
auto error (output.decode_hex (text));
ASSERT_FALSE (error);
ASSERT_EQ (input, output);
ASSERT_EQ (1, output.number ());
}
TEST (uint512_union, parse_error_symbol)
{
nano::uint512_union input (nano::uint512_t (1000));
std::string text = input.to_string ();
text[5] = '!';
nano::uint512_union output;
auto error (output.decode_hex (text));
ASSERT_TRUE (error);
}
TEST (uint512_union, max)
{
nano::uint512_union input (std::numeric_limits<nano::uint512_t>::max ());
std::string text = input.to_string ();
nano::uint512_union output;
auto error (output.decode_hex (text));
ASSERT_FALSE (error);
ASSERT_EQ (input, output);
ASSERT_EQ (nano::uint512_t ("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), output.number ());
}
TEST (uint512_union, parse_error_overflow)
{
nano::uint512_union input (std::numeric_limits<nano::uint512_t>::max ());
std::string text = input.to_string ();
text.push_back (0);
nano::uint512_union output;
auto error (output.decode_hex (text));
ASSERT_TRUE (error);
}
TEST (sat_math, add_sat)
{
// Test uint128_t
{
nano::uint128_t max = std::numeric_limits<nano::uint128_t>::max ();
nano::uint128_t one = 1;
nano::uint128_t large_val = max - 100;
// Normal addition
ASSERT_EQ (nano::add_sat (one, one), nano::uint128_t (2));
// Saturation at max
ASSERT_EQ (nano::add_sat (max, one), max);
ASSERT_EQ (nano::add_sat (large_val, nano::uint128_t (200)), max);
ASSERT_EQ (nano::add_sat (max, max), max);
}
// Test uint256_t
{
nano::uint256_t max = std::numeric_limits<nano::uint256_t>::max ();
nano::uint256_t one = 1;
nano::uint256_t large_val = max - 100;
// Normal addition
ASSERT_EQ (nano::add_sat (one, one), nano::uint256_t (2));
// Saturation at max
ASSERT_EQ (nano::add_sat (max, one), max);
ASSERT_EQ (nano::add_sat (large_val, nano::uint256_t (200)), max);
ASSERT_EQ (nano::add_sat (max, max), max);
}
// Test uint512_t
{
nano::uint512_t max = std::numeric_limits<nano::uint512_t>::max ();
nano::uint512_t one = 1;
nano::uint512_t large_val = max - 100;
// Normal addition
ASSERT_EQ (nano::add_sat (one, one), nano::uint512_t (2));
// Saturation at max
ASSERT_EQ (nano::add_sat (max, one), max);
ASSERT_EQ (nano::add_sat (large_val, nano::uint512_t (200)), max);
ASSERT_EQ (nano::add_sat (max, max), max);
}
}
TEST (sat_math, sub_sat)
{
// Test uint128_t
{
nano::uint128_t max = std::numeric_limits<nano::uint128_t>::max ();
nano::uint128_t min = std::numeric_limits<nano::uint128_t>::min ();
nano::uint128_t one = 1;
nano::uint128_t hundred (100);
// Normal subtraction
ASSERT_EQ (nano::sub_sat (hundred, one), nano::uint128_t (99));
// Saturation at min
ASSERT_EQ (nano::sub_sat (min, one), min);
ASSERT_EQ (nano::sub_sat (hundred, nano::uint128_t (200)), min);
ASSERT_EQ (nano::sub_sat (min, max), min);
}
// Test uint256_t
{
nano::uint256_t max = std::numeric_limits<nano::uint256_t>::max ();
nano::uint256_t min = std::numeric_limits<nano::uint256_t>::min ();
nano::uint256_t one = 1;
nano::uint256_t hundred (100);
// Normal subtraction
ASSERT_EQ (nano::sub_sat (hundred, one), nano::uint256_t (99));
// Saturation at min
ASSERT_EQ (nano::sub_sat (min, one), min);
ASSERT_EQ (nano::sub_sat (hundred, nano::uint256_t (200)), min);
ASSERT_EQ (nano::sub_sat (min, max), min);
}
// Test uint512_t
{
nano::uint512_t max = std::numeric_limits<nano::uint512_t>::max ();
nano::uint512_t min = std::numeric_limits<nano::uint512_t>::min ();
nano::uint512_t one = 1;
nano::uint512_t hundred (100);
// Normal subtraction
ASSERT_EQ (nano::sub_sat (hundred, one), nano::uint512_t (99));
// Saturation at min
ASSERT_EQ (nano::sub_sat (min, one), min);
ASSERT_EQ (nano::sub_sat (hundred, nano::uint512_t (200)), min);
ASSERT_EQ (nano::sub_sat (min, max), min);
}
}
TEST (account, encode_zero)
{
nano::account number0{};
std::stringstream stream;
number0.encode_account (stream);
auto str0 = stream.str ();
/*
* Handle different lengths for "xrb_" prefixed and "nano_" prefixed accounts
*/
ASSERT_EQ ((str0.front () == 'x') ? 64 : 65, str0.size ());
ASSERT_EQ (65, str0.size ());
nano::account number1;
ASSERT_FALSE (number1.decode_account (str0));
ASSERT_EQ (number0, number1);
}
TEST (account, encode_all)
{
nano::account number0;
number0.decode_hex ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
std::stringstream stream;
number0.encode_account (stream);
auto str0 = stream.str ();
/*
* Handle different lengths for "xrb_" prefixed and "nano_" prefixed accounts
*/
ASSERT_EQ ((str0.front () == 'x') ? 64 : 65, str0.size ());
nano::account number1;
ASSERT_FALSE (number1.decode_account (str0));
ASSERT_EQ (number0, number1);
}
TEST (account, encode_fail)
{
nano::account number0{};
std::stringstream stream;
number0.encode_account (stream);
auto str0 = stream.str ();
str0[16] ^= 1;
nano::account number1;
ASSERT_TRUE (number1.decode_account (str0));
}
TEST (account, known_addresses)
{
nano::account account1{ "0000000000000000000000000000000000000000000000000000000000000000" };
ASSERT_EQ (account1.to_account (), "nano_1111111111111111111111111111111111111111111111111111hifc8npp");
nano::account account2{ "B0311EA55708D6A53C75CDBF88300259C6D018522FE3D4D0A242E431F9E8B6D0" };
ASSERT_EQ (account2.to_account (), "nano_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpiij4txtdo");
nano::account account3{ "45C6FF9D1706D61F0821327752671BDA9F9ED2DA40326B01935AB566FB9E08ED" };
ASSERT_EQ (account3.to_account (), "nano_1jg8zygjg3pp5w644emqcbmjqpnzmubfni3kfe1s8pooeuxsw49fdq1mco9j");
nano::account account4{ "E89208DD038FBB269987689621D52292AE9C35941A7484756ECCED92A65093BA" };
ASSERT_EQ (account4.to_account (), "nano_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3");
nano::account account5{ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" };
ASSERT_EQ (account5.to_account (), "nano_3zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzc3yoon41");
}