Check network type at startup

- Make network type part of consensus ID to avoid mixing p2pool nodes from mainnet and testnet/stagenet
- Check that wallet address matches the network type of monerod
pull/5/head
SChernykh 3 years ago
parent afca83d6c2
commit 27c2aab145

@ -251,6 +251,13 @@ struct ChainMain
hash id;
};
enum class NetworkType {
Invalid,
Mainnet,
Testnet,
Stagenet,
};
} // namespace p2pool
#include "util.h"

@ -54,6 +54,7 @@ JSON_VALUE_PARSER(String, const char*)
JSON_VALUE_PARSER(String, std::string)
JSON_VALUE_PARSER(Uint, uint8_t)
JSON_VALUE_PARSER(Uint64, uint64_t)
JSON_VALUE_PARSER(Bool, bool)
#undef JSON_VALUE_PARSER

@ -359,6 +359,19 @@ template<> struct log::Stream::Entry<XMRAmount>
}
};
template<> struct log::Stream::Entry<NetworkType>
{
static NOINLINE void put(const NetworkType& value, Stream* wrapper)
{
switch (value) {
case NetworkType::Invalid: *wrapper << "invalid"; break;
case NetworkType::Mainnet: *wrapper << "mainnet"; break;
case NetworkType::Testnet: *wrapper << "testnet"; break;
case NetworkType::Stagenet: *wrapper << "stagenet"; break;
}
}
};
namespace {
template<log::Severity severity> void apply_severity(log::Stream&);

@ -51,12 +51,12 @@ p2pool::p2pool(int argc, char* argv[])
panic();
}
const Wallet::Type type = m_params->m_wallet.type();
const NetworkType type = m_params->m_wallet.type();
if (type == Wallet::Type::Testnet) {
if (type == NetworkType::Testnet) {
LOGWARN(1, "Mining to a testnet wallet address");
}
else if (type == Wallet::Type::Stagenet) {
else if (type == NetworkType::Stagenet) {
LOGWARN(1, "Mining to a stagenet wallet address");
}
@ -86,7 +86,7 @@ p2pool::p2pool(int argc, char* argv[])
MinerData d;
m_sideChain = new SideChain(this);
m_sideChain = new SideChain(this, type);
m_hasher = new RandomX_Hasher(this);
m_blockTemplate = new BlockTemplate(this);
m_mempool = new Mempool();
@ -530,6 +530,63 @@ void p2pool::stratum_on_block()
#endif
}
void p2pool::get_info()
{
JSONRPCRequest::call(m_params->m_host, m_params->m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_info\"}",
[this](const char* data, size_t size)
{
parse_get_info_rpc(data, size);
});
}
void p2pool::parse_get_info_rpc(const char* data, size_t size)
{
rapidjson::Document doc;
doc.Parse(data, size);
if (!doc.IsObject() || !doc.HasMember("result")) {
LOGWARN(1, "get_info RPC response is invalid (\"result\" not found), trying again in 1 second");
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
get_info();
return;
}
const auto& result = doc["result"];
struct {
bool busy_syncing, mainnet, testnet, stagenet;
} info;
if (!PARSE(result, info, busy_syncing) || !PARSE(result, info, mainnet) || !PARSE(result, info, testnet) || !PARSE(result, info, stagenet)) {
LOGWARN(1, "get_info RPC response is invalid, trying again in 1 second");
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
get_info();
return;
}
if (info.busy_syncing) {
LOGINFO(1, "monerod is busy syncing, trying again in 1 second");
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
get_info();
return;
}
NetworkType monero_network = NetworkType::Invalid;
if (info.mainnet) monero_network = NetworkType::Mainnet;
if (info.testnet) monero_network = NetworkType::Testnet;
if (info.stagenet) monero_network = NetworkType::Stagenet;
const NetworkType sidechain_network = m_sideChain->network_type();
if (monero_network != sidechain_network) {
LOGERR(1, "monerod is on " << monero_network << ", but you're mining to a " << sidechain_network << " sidechain");
panic();
}
get_miner_data();
}
void p2pool::get_miner_data()
{
JSONRPCRequest::call(m_params->m_host, m_params->m_rpcPort, "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_miner_data\"}",
@ -761,7 +818,7 @@ int p2pool::run()
{
ZMQReader z(m_params->m_host, m_params->m_rpcPort, m_params->m_zmqPort, this);
get_miner_data();
get_info();
const int rc = uv_run(uv_default_loop_checked(), UV_RUN_DEFAULT);
LOGINFO(1, "uv_run exited, result = " << rc);
}

@ -102,6 +102,9 @@ private:
void stratum_on_block();
void get_info();
void parse_get_info_rpc(const char* data, size_t size);
void get_miner_data();
void parse_get_miner_data_rpc(const char* data, size_t size);

@ -51,8 +51,9 @@ static_assert(1 <= UNCLE_BLOCK_DEPTH && UNCLE_BLOCK_DEPTH <= 10, "Invalid UNCLE_
namespace p2pool {
SideChain::SideChain(p2pool* pool)
SideChain::SideChain(p2pool* pool, NetworkType type)
: m_pool(pool)
, m_networkType(type)
, m_chainTip(nullptr)
, m_poolName("default")
, m_targetBlockTime(1)
@ -61,6 +62,8 @@ SideChain::SideChain(p2pool* pool)
, m_unclePenalty(20)
, m_curDifficulty(m_minDifficulty)
{
LOGINFO(1, log::LightCyan() << "network type = " << m_networkType);
if (!load_config(m_pool->params().m_config)) {
panic();
}
@ -90,12 +93,13 @@ SideChain::SideChain(p2pool* pool)
char consensus_str[log::Stream::BUF_SIZE + 1];
log::Stream s(consensus_str);
s << m_poolName << '\0'
<< m_poolPassword << '\0'
<< m_targetBlockTime << '\0'
<< m_minDifficulty << '\0'
<< m_chainWindowSize << '\0'
<< m_unclePenalty << '\0';
s << m_networkType << '\0'
<< m_poolName << '\0'
<< m_poolPassword << '\0'
<< m_targetBlockTime << '\0'
<< m_minDifficulty << '\0'
<< m_chainWindowSize << '\0'
<< m_unclePenalty << '\0';
randomx_init_cache(cache, consensus_str, s.m_pos);
}

@ -41,7 +41,7 @@ struct MinerShare
class SideChain
{
public:
explicit SideChain(p2pool* pool);
SideChain(p2pool* pool, NetworkType type);
~SideChain();
void fill_sidechain_data(PoolBlock& block, Wallet* w, const hash& txkeySec, std::vector<MinerShare>& shares);
@ -62,11 +62,13 @@ public:
// Consensus ID can therefore be used as a password to create private P2Pools
const std::vector<uint8_t>& consensus_id() const { return m_consensusId; }
uint64_t chain_window_size() const { return m_chainWindowSize; }
NetworkType network_type() const { return m_networkType; }
static bool split_reward(uint64_t reward, const std::vector<MinerShare>& shares, std::vector<uint64_t>& rewards);
private:
p2pool* m_pool;
NetworkType m_networkType;
private:
bool get_shares(PoolBlock* tip, std::vector<MinerShare>& shares) const;

@ -123,7 +123,7 @@ Wallet& Wallet::operator=(const Wallet& w)
bool Wallet::decode(const char* address)
{
m_type = Type::Invalid;
m_type = NetworkType::Invalid;
if (!address || (strlen(address) != ADDRESS_LENGTH)) {
return false;
@ -167,11 +167,11 @@ bool Wallet::decode(const char* address)
m_prefix = data[0];
if (m_prefix == valid_prefixes[0]) m_type = Type::Mainnet;
if (m_prefix == valid_prefixes[1]) m_type = Type::Testnet;
if (m_prefix == valid_prefixes[2]) m_type = Type::Stagenet;
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;
if (m_type == Type::Invalid) {
if (m_type == NetworkType::Invalid) {
return false;
}
@ -183,7 +183,7 @@ bool Wallet::decode(const char* address)
keccak(data, sizeof(data) - sizeof(m_checksum), md);
if (memcmp(&m_checksum, md, sizeof(m_checksum)) != 0) {
m_type = Type::Invalid;
m_type = NetworkType::Invalid;
}
return valid();
@ -198,7 +198,7 @@ void Wallet::assign(const hash& spend_pub_key, const hash& view_pub_key)
m_viewPublicKey = view_pub_key;
m_checksum = 0;
m_type = Type::Mainnet;
m_type = NetworkType::Mainnet;
m_txkeySec = {};
m_outputIndex = std::numeric_limits<size_t>::max();

@ -24,21 +24,14 @@ namespace p2pool {
class Wallet
{
public:
enum class Type {
Invalid,
Mainnet,
Testnet,
Stagenet,
};
explicit Wallet(const char* address);
~Wallet();
Wallet(const Wallet& w);
Wallet& operator=(const Wallet& w);
FORCEINLINE bool valid() const { return m_type != Type::Invalid; }
FORCEINLINE Type type() const { return m_type; }
FORCEINLINE bool valid() const { return m_type != NetworkType::Invalid; }
FORCEINLINE NetworkType type() const { return m_type; }
bool decode(const char* address);
void assign(const hash& spend_pub_key, const hash& view_pub_key);
@ -56,7 +49,7 @@ private:
hash m_spendPublicKey;
hash m_viewPublicKey;
uint32_t m_checksum;
Type m_type;
NetworkType m_type;
mutable uv_mutex_t m_lock;
hash m_txkeySec;

Loading…
Cancel
Save