From 45660e3d9612428eb7855f64f103b52088a214ed Mon Sep 17 00:00:00 2001 From: SChernykh Date: Thu, 3 Nov 2022 11:38:43 +0100 Subject: [PATCH] Show wallet address in error messages and status --- src/common.h | 2 +- src/log.cpp | 10 ++++- src/log.h | 10 ++--- src/p2p_server.cpp | 6 +-- src/pool_block.cpp | 4 +- src/side_chain.cpp | 21 +++++++---- src/wallet.cpp | 75 +++++++++++++++++++++++++------------- src/wallet.h | 29 +++++++++++---- tests/src/wallet_tests.cpp | 52 ++++++++++++++++++++------ 9 files changed, 146 insertions(+), 63 deletions(-) diff --git a/src/common.h b/src/common.h index aaf0bc3..e401ab1 100644 --- a/src/common.h +++ b/src/common.h @@ -128,7 +128,7 @@ FORCEINLINE uint64_t udiv128(uint64_t hi, uint64_t lo, uint64_t divisor, uint64_ } #endif -template FORCEINLINE T round_up(T a, size_t granularity) { return static_cast(((a + (granularity - static_cast(1))) / granularity) * granularity); } +template constexpr FORCEINLINE T round_up(T a, size_t granularity) { return static_cast(((a + (granularity - static_cast(1))) / granularity) * granularity); } struct hash { diff --git a/src/log.cpp b/src/log.cpp index 7ca51f9..c381e7b 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -17,6 +17,7 @@ #include "common.h" #include "uv_util.h" +#include "wallet.h" #include #include #include @@ -336,7 +337,7 @@ NOINLINE void Stream::writeCurrentTime() m_numberWidth = 1; } -NOINLINE void put_rawip(const raw_ip& value, Stream* wrapper) +NOINLINE void Stream::Entry::put(const raw_ip& value, Stream* wrapper) { const char* addr_str; char addr_str_buf[64]; @@ -359,6 +360,13 @@ NOINLINE void put_rawip(const raw_ip& value, Stream* wrapper) } } +NOINLINE void Stream::Entry::put(const Wallet& w, Stream* wrapper) +{ + char buf[Wallet::ADDRESS_LENGTH]; + w.encode(buf); + wrapper->writeBuf(buf, Wallet::ADDRESS_LENGTH); +} + } // namespace log } // namespace p2pool diff --git a/src/log.h b/src/log.h index f901529..8f5d7df 100644 --- a/src/log.h +++ b/src/log.h @@ -19,6 +19,8 @@ namespace p2pool { +class Wallet; + namespace log { extern int GLOBAL_LOG_LEVEL; @@ -451,12 +453,8 @@ struct log::Stream::Entry> } }; -void put_rawip(const raw_ip& value, Stream* wrapper); - -template<> struct log::Stream::Entry -{ - static FORCEINLINE void put(const raw_ip& value, Stream* wrapper) { put_rawip(value, wrapper); } -}; +template<> struct log::Stream::Entry { static NOINLINE void put(const raw_ip& value, Stream* wrapper); }; +template<> struct log::Stream::Entry { static NOINLINE void put(const Wallet& w, Stream* wrapper); }; namespace { template void apply_severity(log::Stream&); diff --git a/src/p2p_server.cpp b/src/p2p_server.cpp index 72a0f3d..f5324b2 100644 --- a/src/p2p_server.cpp +++ b/src/p2p_server.cpp @@ -2067,15 +2067,15 @@ bool P2PServer::P2PClient::handle_incoming_block_async(const PoolBlock* block, u // Limit system clock difference between connected peers if (max_time_delta) { - static uint32_t total_checks = 0; - static uint32_t failed_checks = 0; + static uint64_t total_checks = 0; + static uint64_t failed_checks = 0; ++total_checks; const uint64_t t = time(nullptr); if ((block->m_timestamp + max_time_delta < t) || (block->m_timestamp > t + max_time_delta)) { LOGWARN(4, "peer " << static_cast(m_addrString) - << " sent a block with an invalid timestamp " << block->m_timestamp + << " sent a block (mined by " << block->m_minerWallet << ") with an invalid timestamp " << block->m_timestamp << " (your local timestamp is " << t << ")"); ++failed_checks; diff --git a/src/pool_block.cpp b/src/pool_block.cpp index 6e2e5f2..003b528 100644 --- a/src/pool_block.cpp +++ b/src/pool_block.cpp @@ -363,7 +363,9 @@ uint64_t PoolBlock::get_payout(const Wallet& w) const hash eph_public_key; if (tx_type == TXOUT_TO_TAGGED_KEY) { - if (w.get_eph_public_key_with_view_tag(m_txkeySec, i, eph_public_key, out.m_viewTag) && (eph_public_key == out.m_ephPublicKey)) { + uint8_t view_tag; + const uint8_t expected_view_tag = out.m_viewTag; + if (w.get_eph_public_key(m_txkeySec, i, eph_public_key, view_tag, &expected_view_tag) && (eph_public_key == out.m_ephPublicKey)) { return out.m_reward; } } diff --git a/src/side_chain.cpp b/src/side_chain.cpp index 8f4bc6e..3d57caf 100644 --- a/src/side_chain.cpp +++ b/src/side_chain.cpp @@ -465,7 +465,7 @@ void SideChain::unsee_block(const PoolBlock& block) bool SideChain::add_external_block(PoolBlock& block, std::vector& missing_blocks) { if (block.m_difficulty < m_minDifficulty) { - LOGWARN(3, "add_external_block: block has invalid difficulty " << block.m_difficulty << ", expected >= " << m_minDifficulty); + LOGWARN(3, "add_external_block: block mined by " << block.m_minerWallet << " has invalid difficulty " << block.m_difficulty << ", expected >= " << m_minDifficulty); return false; } @@ -498,7 +498,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector& missing_ LOGINFO(4, "add_external_block: height = " << block.m_sidechainHeight << ", id = " << block.m_sidechainId << ", mainchain height = " << block.m_txinGenHeight); if (too_low_diff) { - LOGWARN(4, "add_external_block: block has too low difficulty " << block.m_difficulty << ", expected >= ~" << expected_diff << ". Ignoring it."); + LOGWARN(4, "add_external_block: block mined by " << block.m_minerWallet << " has too low difficulty " << block.m_difficulty << ", expected >= ~" << expected_diff << ". Ignoring it."); return true; } @@ -506,7 +506,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector& missing_ ChainMain data; if (m_pool->chainmain_get_by_hash(block.m_prevId, data)) { if (data.height + 1 != block.m_txinGenHeight) { - LOGWARN(3, "add_external_block: wrong mainchain height " << block.m_txinGenHeight << ", expected " << data.height + 1); + LOGWARN(3, "add_external_block mined by " << block.m_minerWallet << ": wrong mainchain height " << block.m_txinGenHeight << ", expected " << data.height + 1); return false; } } @@ -516,7 +516,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector& missing_ hash seed; if (!m_pool->get_seed(block.m_txinGenHeight, seed)) { - LOGWARN(3, "add_external_block: couldn't get seed hash for mainchain height " << block.m_txinGenHeight); + LOGWARN(3, "add_external_block mined by " << block.m_minerWallet << ": couldn't get seed hash for mainchain height " << block.m_txinGenHeight); unsee_block(block); return false; } @@ -546,7 +546,7 @@ bool SideChain::add_external_block(PoolBlock& block, std::vector& missing_ } if (!block.m_difficulty.check_pow(pow_hash)) { - LOGWARN(3, "add_external_block: not enough PoW for height = " << block.m_sidechainHeight << ", mainchain height " << block.m_txinGenHeight); + LOGWARN(3, "add_external_block mined by " << block.m_minerWallet << ": not enough PoW for height = " << block.m_sidechainHeight << ", mainchain height " << block.m_txinGenHeight); return false; } @@ -937,7 +937,9 @@ void SideChain::print_status(bool obtain_sidechain_lock) const const PoolBlock::TxOutput& out = tip->m_outputs[i]; if (!your_reward) { if (tx_type == TXOUT_TO_TAGGED_KEY) { - if (w.get_eph_public_key_with_view_tag(tip->m_txkeySec, i, eph_public_key, out.m_viewTag) && (out.m_ephPublicKey == eph_public_key)) { + uint8_t view_tag; + const uint8_t expected_view_tag = out.m_viewTag; + if (w.get_eph_public_key(tip->m_txkeySec, i, eph_public_key, view_tag, &expected_view_tag) && (out.m_ephPublicKey == eph_public_key)) { your_reward = out.m_reward; } } @@ -988,6 +990,7 @@ void SideChain::print_status(bool obtain_sidechain_lock) const "\nSide chain hashrate = " << log::Hashrate(pool_hashrate) << (hashrate_est ? "\nYour hashrate (pool-side) = " : "") << (hashrate_est ? log::Hashrate(hashrate_est) : log::Hashrate()) << "\nPPLNS window = " << total_blocks_in_window << " blocks (+" << total_uncles_in_window << " uncles, " << total_orphans << " orphans)" << + "\nYour wallet address = " << m_pool->params().m_wallet << "\nYour shares = " << our_blocks_in_window_total << " blocks (+" << our_uncles_in_window_total << " uncles, " << our_orphans << " orphans)" << our_blocks_in_window_chart << our_uncles_in_window_chart << "\nBlock reward share = " << block_share << "% (" << log::XMRAmount(your_reward) << ')' @@ -1009,7 +1012,9 @@ double SideChain::get_reward_share(const Wallet& w) const const PoolBlock::TxOutput& out = tip->m_outputs[i]; if (!reward) { if (tx_type == TXOUT_TO_TAGGED_KEY) { - if (w.get_eph_public_key_with_view_tag(tip->m_txkeySec, i, eph_public_key, out.m_viewTag) && (out.m_ephPublicKey == eph_public_key)) { + uint8_t view_tag; + const uint8_t expected_view_tag = out.m_viewTag; + if (w.get_eph_public_key(tip->m_txkeySec, i, eph_public_key, view_tag, &expected_view_tag) && (out.m_ephPublicKey == eph_public_key)) { reward = out.m_reward; } } @@ -1241,7 +1246,7 @@ void SideChain::verify_loop(PoolBlock* block) if (block->m_invalid) { LOGWARN(3, "block at height = " << block->m_sidechainHeight << ", id = " << block->m_sidechainId << - ", mainchain height = " << block->m_txinGenHeight << " is invalid"); + ", mainchain height = " << block->m_txinGenHeight << ", mined by " << block->m_minerWallet << " is invalid"); } else { LOGINFO(3, "verified block at height = " << block->m_sidechainHeight << diff --git a/src/wallet.cpp b/src/wallet.cpp index 874cd76..7d32c42 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -29,16 +29,14 @@ extern "C" { namespace { -// public keys: 64 bytes -> 88 characters in base58 -// prefix (1 byte) + checksum (4 bytes) -> 7 characters in base58 -// 95 characters in total -constexpr int ADDRESS_LENGTH = 95; - // Allow only regular addresses (no integrated addresses, no subaddresses) // Values taken from cryptonote_config.h (CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX) constexpr uint64_t valid_prefixes[] = { 18, 53, 24 }; constexpr std::array block_sizes{ 0, 2, 3, 5, 6, 7, 9, 10, 11 }; +constexpr int num_full_blocks = p2pool::Wallet::ADDRESS_LENGTH / block_sizes.back(); +constexpr int last_block_size = p2pool::Wallet::ADDRESS_LENGTH % block_sizes.back(); + constexpr int block_sizes_lookup[11] = { 0, -1, 1, 2, -1, 3, 4, 5, -1, 6, 7 }; constexpr char alphabet[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; @@ -112,8 +110,6 @@ bool Wallet::decode(const char* address) return false; } - constexpr int num_full_blocks = ADDRESS_LENGTH / block_sizes.back(); - constexpr int last_block_size = ADDRESS_LENGTH % block_sizes.back(); constexpr int last_block_size_index = block_sizes_lookup[last_block_size]; static_assert(last_block_size_index >= 0, "Check ADDRESS_LENGTH"); @@ -150,11 +146,13 @@ bool Wallet::decode(const char* address) m_prefix = data[0]; - if (m_prefix == valid_prefixes[0]) m_type = NetworkType::Mainnet; - if (m_prefix == valid_prefixes[1]) m_type = NetworkType::Testnet; - if (m_prefix == valid_prefixes[2]) m_type = NetworkType::Stagenet; + switch (m_prefix) + { + case valid_prefixes[0]: m_type = NetworkType::Mainnet; break; + case valid_prefixes[1]: m_type = NetworkType::Testnet; break; + case valid_prefixes[2]: m_type = NetworkType::Stagenet; break; - if (m_type == NetworkType::Invalid) { + default: return false; } @@ -184,35 +182,62 @@ bool Wallet::assign(const hash& spend_pub_key, const hash& view_pub_key, Network return false; } - m_prefix = 0; + switch (type) + { + case NetworkType::Mainnet: m_prefix = valid_prefixes[0]; break; + case NetworkType::Testnet: m_prefix = valid_prefixes[1]; break; + case NetworkType::Stagenet: m_prefix = valid_prefixes[2]; break; + default: m_prefix = 0; break; + } + m_spendPublicKey = spend_pub_key; m_viewPublicKey = view_pub_key; - m_checksum = 0; + + uint8_t data[1 + HASH_SIZE * 2]; + data[0] = static_cast(m_prefix); + memcpy(data + 1, spend_pub_key.h, HASH_SIZE); + memcpy(data + 1 + HASH_SIZE, view_pub_key.h, HASH_SIZE); + + uint8_t md[200]; + keccak(data, sizeof(data), md); + + memcpy(&m_checksum, md, sizeof(m_checksum)); m_type = type; return true; } -bool Wallet::get_eph_public_key(const hash& txkey_sec, size_t output_index, hash& eph_public_key, uint8_t& view_tag) const +void Wallet::encode(char (&buf)[ADDRESS_LENGTH]) const { - hash derivation; - if (!generate_key_derivation(m_viewPublicKey, txkey_sec, output_index, derivation, view_tag)) { - return false; - } + uint8_t data[1 + HASH_SIZE * 2 + sizeof(m_checksum)]; - if (!derive_public_key(derivation, output_index, m_spendPublicKey, eph_public_key)) { - return false; - } + data[0] = static_cast(m_prefix); + memcpy(data + 1, m_spendPublicKey.h, HASH_SIZE); + memcpy(data + 1 + HASH_SIZE, m_viewPublicKey.h, HASH_SIZE); + memcpy(data + 1 + HASH_SIZE * 2, &m_checksum, sizeof(m_checksum)); - return true; + for (int i = 0; i <= num_full_blocks; ++i) { + uint64_t n = 0; + for (int j = 0; (j < 8) && (i * sizeof(uint64_t) + j < sizeof(data)); ++j) { + n = (n << 8) | data[i * sizeof(uint64_t) + j]; + } + for (int j = (((i < num_full_blocks) ? block_sizes.back() : last_block_size)) - 1; j >= 0; --j) { + const int digit = n % alphabet_size; + n /= alphabet_size; + buf[i * block_sizes.back() + j] = alphabet[digit]; + } + } } -bool Wallet::get_eph_public_key_with_view_tag(const hash& txkey_sec, size_t output_index, hash& eph_public_key, uint8_t expected_view_tag) const +bool Wallet::get_eph_public_key(const hash& txkey_sec, size_t output_index, hash& eph_public_key, uint8_t& view_tag, const uint8_t* expected_view_tag) const { hash derivation; - uint8_t view_tag; - if (!generate_key_derivation(m_viewPublicKey, txkey_sec, output_index, derivation, view_tag) || (view_tag != expected_view_tag)) { + if (!generate_key_derivation(m_viewPublicKey, txkey_sec, output_index, derivation, view_tag)) { + return false; + } + + if (expected_view_tag && (view_tag != *expected_view_tag)) { return false; } diff --git a/src/wallet.h b/src/wallet.h index 2df8785..26d7171 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -24,25 +24,40 @@ namespace p2pool { class Wallet { public: + // public keys: 64 bytes -> 88 characters in base58 + // prefix (1 byte) + checksum (4 bytes) -> 7 characters in base58 + // 95 characters in total + static constexpr int ADDRESS_LENGTH = 95; + explicit Wallet(const char* address); Wallet(const Wallet& w); Wallet& operator=(const Wallet& w); FORCEINLINE bool valid() const { return m_type != NetworkType::Invalid; } - FORCEINLINE NetworkType type() const { return m_type; } bool decode(const char* address); bool assign(const hash& spend_pub_key, const hash& view_pub_key, NetworkType type); - FORCEINLINE const hash& spend_public_key() const { return m_spendPublicKey; } - FORCEINLINE const hash& view_public_key() const { return m_viewPublicKey; } + void encode(char (&buf)[ADDRESS_LENGTH]) const; + + FORCEINLINE std::string encode() const + { + char buf[ADDRESS_LENGTH]; + encode(buf); + return std::string(buf, buf + ADDRESS_LENGTH); + } - bool get_eph_public_key(const hash& txkey_sec, size_t output_index, hash& eph_public_key, uint8_t& view_tag) const; - bool get_eph_public_key_with_view_tag(const hash& txkey_sec, size_t output_index, hash& eph_public_key, uint8_t expected_view_tag) const; + bool get_eph_public_key(const hash& txkey_sec, size_t output_index, hash& eph_public_key, uint8_t& view_tag, const uint8_t* expected_view_tag = nullptr) const; - FORCEINLINE bool operator<(const Wallet& w) const { return m_spendPublicKey < w.m_spendPublicKey; } - FORCEINLINE bool operator==(const Wallet& w) const { return m_spendPublicKey == w.m_spendPublicKey; } + FORCEINLINE bool operator<(const Wallet& w) const { return (m_spendPublicKey < w.m_spendPublicKey) || ((m_spendPublicKey == w.m_spendPublicKey) && (m_viewPublicKey < w.m_viewPublicKey)); } + FORCEINLINE bool operator==(const Wallet& w) const { return (m_spendPublicKey == w.m_spendPublicKey) && (m_viewPublicKey == w.m_viewPublicKey); } + + FORCEINLINE uint64_t prefix() const { return m_prefix; } + FORCEINLINE const hash& spend_public_key() const { return m_spendPublicKey; } + FORCEINLINE const hash& view_public_key() const { return m_viewPublicKey; } + FORCEINLINE uint32_t checksum() const { return m_checksum; } + FORCEINLINE NetworkType type() const { return m_type; } private: uint64_t m_prefix; diff --git a/tests/src/wallet_tests.cpp b/tests/src/wallet_tests.cpp index 5f93434..98c1876 100644 --- a/tests/src/wallet_tests.cpp +++ b/tests/src/wallet_tests.cpp @@ -21,7 +21,7 @@ namespace p2pool { -TEST(wallet, decode) +TEST(wallet, input_output) { // No data { @@ -59,10 +59,12 @@ TEST(wallet, decode) ASSERT_EQ(w.valid(), false); } - auto check = [](NetworkType t, const char* address, const char* spendkey, const char* viewkey) + auto check = [](NetworkType t, uint64_t prefix, const char* address, const char* spendkey, const char* viewkey) { + // Test Wallet::decode() Wallet w(address); ASSERT_EQ(w.type(), t); + ASSERT_EQ(w.prefix(), prefix); char buf[log::Stream::BUF_SIZE + 1]; log::Stream s(buf); @@ -73,53 +75,81 @@ TEST(wallet, decode) s.m_pos = 0; s << w.view_public_key(); ASSERT_EQ(memcmp(buf, viewkey, HASH_SIZE * 2), 0); + + // Test Wallet::assign() + Wallet w2(nullptr); + w2.assign(w.spend_public_key(), w.view_public_key(), w.type()); + + ASSERT_EQ(w2.prefix(), w.prefix()); + ASSERT_EQ(w2.spend_public_key(), w.spend_public_key()); + ASSERT_EQ(w2.view_public_key(), w.view_public_key()); + ASSERT_EQ(w2.checksum(), w.checksum()); + ASSERT_EQ(w2.type(), w.type()); + + // Test Wallet::encode() + const std::string s0 = address; + const std::string s1 = w.encode(); + const std::string s2 = w2.encode(); + ASSERT_EQ(s1, s0); + ASSERT_EQ(s2, s0); + + // Test Wallet::encode(buf) + s.m_pos = 0; + memset(buf, 0, sizeof(buf)); + s << w; + ASSERT_EQ(memcmp(buf, address, Wallet::ADDRESS_LENGTH), 0); + + s.m_pos = 0; + memset(buf, 0, sizeof(buf)); + s << w2; + ASSERT_EQ(memcmp(buf, address, Wallet::ADDRESS_LENGTH), 0); }; // Correct mainnet addresses check( - NetworkType::Mainnet, "49ccoSmrBTPJd5yf8VYCULh4J5rHQaXP1TeC8Cnqhd5H9Y2cMwkJ9w42euLmMghKtCiQcgZEiGYW1K6Ae4biZ7w1HLSexS6", + NetworkType::Mainnet, 18, "49ccoSmrBTPJd5yf8VYCULh4J5rHQaXP1TeC8Cnqhd5H9Y2cMwkJ9w42euLmMghKtCiQcgZEiGYW1K6Ae4biZ7w1HLSexS6", "d2e232e441546a695b27187692d035ef7be5c54692700c9f470dcd706753a833", "06f68970da46f709e2b4d0ffabd0d1f78ea6717786b5766c25c259111f212490" ); check( - NetworkType::Mainnet, "45JHuqGBSqUXUyZx95H4C2J5aEL4zFjM3jpTmMTESPXPa3jmtSQWYezHX7r4A2xPQNBGsQupJqmPhRZb2QgBcEWRDQ9ywwR", + NetworkType::Mainnet, 18, "45JHuqGBSqUXUyZx95H4C2J5aEL4zFjM3jpTmMTESPXPa3jmtSQWYezHX7r4A2xPQNBGsQupJqmPhRZb2QgBcEWRDQ9ywwR", "60fe176eaf3cffb63df130bc25036b661b947900941052fffe6ff4b51fc4f2c5", "9387910b0a2e4f62c32621b77ddbeb3d6c0054e5ed9bc492d87bab1a1eef366d" ); check( - NetworkType::Mainnet, "43S5vhReDY4fJs99DBZtFS8JoJVNG17iaAVAARvRT8xzSYZqnJfXfTACLrZUzoBHQKhiJZCWCpqB4Kf3c64CEagdSRXd5D7", + NetworkType::Mainnet, 18, "43S5vhReDY4fJs99DBZtFS8JoJVNG17iaAVAARvRT8xzSYZqnJfXfTACLrZUzoBHQKhiJZCWCpqB4Kf3c64CEagdSRXd5D7", "2fc2f902659541e50753853ddb96912baf55f26bebe7d338b5c2239c437ddb98", "b814951166253543cfb0e1b8bdea58f366de824fddb8ef6f895fcf631873f6e1" ); // Correct testnet addresses check( - NetworkType::Testnet, "9x6aEN1yd2WhPMPw89LV5LLK1ZFe6N8xiAm18Ay4q1U4LKMde7MpDdPRN6GiiGCJMVTHuptGGmfj2Qfp2vcKSRSG79HJrQn", + NetworkType::Testnet, 53, "9x6aEN1yd2WhPMPw89LV5LLK1ZFe6N8xiAm18Ay4q1U4LKMde7MpDdPRN6GiiGCJMVTHuptGGmfj2Qfp2vcKSRSG79HJrQn", "821623ac165f07f172c86980254a43737332fd89ca36d33a57dc02d8026d9173", "7c55413e672f8691a9211eac6003109d2fdf224ba72c4d8d82353427a02bc136" ); check( - NetworkType::Testnet, "9zsJP6KFF6ZGern5UkR7gyRXHFRTba6jG8JKnfzDySeqEdwPZaD8MNYGkjyADdVpWs7rXgyeu712JdxhX2k7d9SNB4TdRdS", + NetworkType::Testnet, 53, "9zsJP6KFF6ZGern5UkR7gyRXHFRTba6jG8JKnfzDySeqEdwPZaD8MNYGkjyADdVpWs7rXgyeu712JdxhX2k7d9SNB4TdRdS", "cb366a3b44f6aa5d94e03db06325b6929b9e75dbf19dcf2ba2d14eb2efa53651", "8789afa33dca295e301baef826cec028fa22b831822c1bdcf8a847a43a3bff59" ); check( - NetworkType::Testnet, "A1SqL5oPjh8Km1At7mao7U1fNjWkzeSwvQ39GimMqvhBF3FUoJhx1zxL2i6XbHzzAXDhKetiwSmYQeVwG6sUgwJuEqPyjWq", + NetworkType::Testnet, 53, "A1SqL5oPjh8Km1At7mao7U1fNjWkzeSwvQ39GimMqvhBF3FUoJhx1zxL2i6XbHzzAXDhKetiwSmYQeVwG6sUgwJuEqPyjWq", "da78298fb6eb8f702698bec873bad703f4a51e1377a66d89ba977ca7f43b8e53", "eeb348f70afad971c50aa062f1d1544be64ef9cdc12475e030f2d295305e6e7a" ); // Correct stagenet addresses check( - NetworkType::Stagenet, "55AJ4jJBhV6JsoqrEsAazTLrJjg9SA1SFReLUoXDudrsA9tdL9i2VkJefEbx3zrFRt6swuibPVySPGNzsNvyshrRNZbSDnD", + NetworkType::Stagenet, 24, "55AJ4jJBhV6JsoqrEsAazTLrJjg9SA1SFReLUoXDudrsA9tdL9i2VkJefEbx3zrFRt6swuibPVySPGNzsNvyshrRNZbSDnD", "57e0c2fef80a1d6adfa3189134009076ad0ddc4c4668709355cea98524e9fc36", "b94fafe59d5037e126557665f76cd3232504ebd82500e05bf25801d853d182bf" ); check( - NetworkType::Stagenet, "5BQqg4HTWuN3j4NzBHTK31eTaygRXYxWRQW9dTD7qMuJSiVtskraSErXQ24FUBeifiV6NaQPmxLS559vbUT4xYUoF2fiGvH", + NetworkType::Stagenet, 24, "5BQqg4HTWuN3j4NzBHTK31eTaygRXYxWRQW9dTD7qMuJSiVtskraSErXQ24FUBeifiV6NaQPmxLS559vbUT4xYUoF2fiGvH", "fcd35a53cef9a1104ae556f01cee0cdff2f18f2f2f6bde8c833d5bd980fe8999", "be2b1142a046bfb5bb21e1f2a49bd1a7f46e1c18b009b218d5962f663938707c" ); check( - NetworkType::Stagenet, "53CFYfjzcouW95hQ7AHvqS3GZ2UAAaRLKc1ymmhHATQTZxhtakpYcfjiRVzrRdxVZ5F8p61KSpPEmFu9DVRULRDkK4v1TCU", + NetworkType::Stagenet, 24, "53CFYfjzcouW95hQ7AHvqS3GZ2UAAaRLKc1ymmhHATQTZxhtakpYcfjiRVzrRdxVZ5F8p61KSpPEmFu9DVRULRDkK4v1TCU", "23fdd143264794ae367083791bb8fd0d8f719b27b7b858d15a2b67d6eddd60c5", "0ebafc1284ab1af7a5ff4ade682bcc54817a319a00eede591344855c420beba0" ); }