Show wallet address in error messages and status

This commit is contained in:
SChernykh 2022-11-03 11:38:43 +01:00
parent 732190bb11
commit 45660e3d96
9 changed files with 147 additions and 64 deletions

View file

@ -128,7 +128,7 @@ FORCEINLINE uint64_t udiv128(uint64_t hi, uint64_t lo, uint64_t divisor, uint64_
}
#endif
template<typename T> FORCEINLINE T round_up(T a, size_t granularity) { return static_cast<T>(((a + (granularity - static_cast<size_t>(1))) / granularity) * granularity); }
template<typename T> constexpr FORCEINLINE T round_up(T a, size_t granularity) { return static_cast<T>(((a + (granularity - static_cast<size_t>(1))) / granularity) * granularity); }
struct hash
{

View file

@ -17,6 +17,7 @@
#include "common.h"
#include "uv_util.h"
#include "wallet.h"
#include <ctime>
#include <fstream>
#include <thread>
@ -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<raw_ip>::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<Wallet>::put(const Wallet& w, Stream* wrapper)
{
char buf[Wallet::ADDRESS_LENGTH];
w.encode(buf);
wrapper->writeBuf(buf, Wallet::ADDRESS_LENGTH);
}
} // namespace log
} // namespace p2pool

View file

@ -19,6 +19,8 @@
namespace p2pool {
class Wallet;
namespace log {
extern int GLOBAL_LOG_LEVEL;
@ -451,12 +453,8 @@ struct log::Stream::Entry<PadRight<T>>
}
};
void put_rawip(const raw_ip& value, Stream* wrapper);
template<> struct log::Stream::Entry<raw_ip>
{
static FORCEINLINE void put(const raw_ip& value, Stream* wrapper) { put_rawip(value, wrapper); }
};
template<> struct log::Stream::Entry<raw_ip> { static NOINLINE void put(const raw_ip& value, Stream* wrapper); };
template<> struct log::Stream::Entry<Wallet> { static NOINLINE void put(const Wallet& w, Stream* wrapper); };
namespace {
template<log::Severity severity> void apply_severity(log::Stream&);

View file

@ -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<char*>(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;

View file

@ -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;
}
}

View file

@ -465,7 +465,7 @@ void SideChain::unsee_block(const PoolBlock& block)
bool SideChain::add_external_block(PoolBlock& block, std::vector<hash>& 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<hash>& 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<hash>& 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<hash>& 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<hash>& 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 <<

View file

@ -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<int, 9> 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<uint8_t>(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
{
uint8_t data[1 + HASH_SIZE * 2 + sizeof(m_checksum)];
data[0] = static_cast<uint8_t>(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));
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(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;
if (!generate_key_derivation(m_viewPublicKey, txkey_sec, output_index, derivation, view_tag)) {
return false;
}
if (!derive_public_key(derivation, output_index, m_spendPublicKey, eph_public_key)) {
return false;
}
return true;
}
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
{
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 (expected_view_tag && (view_tag != *expected_view_tag)) {
return false;
}

View file

@ -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);
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 uint8_t* expected_view_tag = nullptr) const;
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; }
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;
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 uint32_t checksum() const { return m_checksum; }
FORCEINLINE NetworkType type() const { return m_type; }
private:
uint64_t m_prefix;

View file

@ -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"
);
}