Initialize tx key from previous blocks

pull/238/head
SChernykh 2023-01-09 15:55:52 +01:00
parent 1bd04c2840
commit ae6747c82d
5 changed files with 73 additions and 23 deletions

View File

@ -268,19 +268,10 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, Wallet
const int sidechain_version = m_poolBlockTemplate->get_sidechain_version(); const int sidechain_version = m_poolBlockTemplate->get_sidechain_version();
if (sidechain_version > 1) { if (sidechain_version <= 1) {
static_assert(decltype(m_rng)::word_size == 64, "m_rng must be 64-bit"); m_poolBlockTemplate->m_txkeySecSeed = miner_wallet->spend_public_key();
uint64_t* p = reinterpret_cast<uint64_t*>(m_poolBlockTemplate->m_txkeySecSeed.h);
for (size_t i = 0; i < HASH_SIZE / sizeof(uint64_t); ++i) {
p[i] = m_rng();
}
get_tx_keys(m_poolBlockTemplate->m_txkeyPub, m_poolBlockTemplate->m_txkeySec, m_poolBlockTemplate->m_txkeySecSeed, data.prev_id); get_tx_keys(m_poolBlockTemplate->m_txkeyPub, m_poolBlockTemplate->m_txkeySec, m_poolBlockTemplate->m_txkeySecSeed, data.prev_id);
} }
else {
get_tx_keys(m_poolBlockTemplate->m_txkeyPub, m_poolBlockTemplate->m_txkeySec, miner_wallet->spend_public_key(), data.prev_id);
}
m_poolBlockTemplate->m_minerWallet = *miner_wallet; m_poolBlockTemplate->m_minerWallet = *miner_wallet;

View File

@ -122,13 +122,13 @@ PoolBlock::~PoolBlock()
uv_mutex_destroy(&m_lock); uv_mutex_destroy(&m_lock);
} }
std::vector<uint8_t> PoolBlock::serialize_mainchain_data(size_t* header_size, size_t* miner_tx_size, int* outputs_offset, int* outputs_blob_size) const std::vector<uint8_t> PoolBlock::serialize_mainchain_data(size_t* header_size, size_t* miner_tx_size, int* outputs_offset, int* outputs_blob_size, const uint32_t* nonce, const uint32_t* extra_nonce) const
{ {
MutexLock lock(m_lock); MutexLock lock(m_lock);
return serialize_mainchain_data_nolock(header_size, miner_tx_size, outputs_offset, outputs_blob_size); return serialize_mainchain_data_nolock(header_size, miner_tx_size, outputs_offset, outputs_blob_size, nonce, extra_nonce);
} }
std::vector<uint8_t> PoolBlock::serialize_mainchain_data_nolock(size_t* header_size, size_t* miner_tx_size, int* outputs_offset, int* outputs_blob_size) const std::vector<uint8_t> PoolBlock::serialize_mainchain_data_nolock(size_t* header_size, size_t* miner_tx_size, int* outputs_offset, int* outputs_blob_size, const uint32_t* nonce, const uint32_t* extra_nonce) const
{ {
std::vector<uint8_t> data; std::vector<uint8_t> data;
data.reserve(128 + m_outputs.size() * 39 + m_transactions.size() * HASH_SIZE); data.reserve(128 + m_outputs.size() * 39 + m_transactions.size() * HASH_SIZE);
@ -138,7 +138,11 @@ std::vector<uint8_t> PoolBlock::serialize_mainchain_data_nolock(size_t* header_s
data.push_back(m_minorVersion); data.push_back(m_minorVersion);
writeVarint(m_timestamp, data); writeVarint(m_timestamp, data);
data.insert(data.end(), m_prevId.h, m_prevId.h + HASH_SIZE); data.insert(data.end(), m_prevId.h, m_prevId.h + HASH_SIZE);
data.insert(data.end(), reinterpret_cast<const uint8_t*>(&m_nonce), reinterpret_cast<const uint8_t*>(&m_nonce) + NONCE_SIZE);
if (!nonce) {
nonce = &m_nonce;
}
data.insert(data.end(), reinterpret_cast<const uint8_t*>(nonce), reinterpret_cast<const uint8_t*>(nonce) + NONCE_SIZE);
const size_t header_size0 = data.size(); const size_t header_size0 = data.size();
if (header_size) { if (header_size) {
@ -191,7 +195,10 @@ std::vector<uint8_t> PoolBlock::serialize_mainchain_data_nolock(size_t* header_s
*(p++) = TX_EXTRA_NONCE; *(p++) = TX_EXTRA_NONCE;
*(p++) = static_cast<uint8_t>(extra_nonce_size); *(p++) = static_cast<uint8_t>(extra_nonce_size);
memcpy(p, &m_extraNonce, EXTRA_NONCE_SIZE); if (!extra_nonce) {
extra_nonce = &m_extraNonce;
}
memcpy(p, extra_nonce, EXTRA_NONCE_SIZE);
p += EXTRA_NONCE_SIZE; p += EXTRA_NONCE_SIZE;
if (extra_nonce_size > EXTRA_NONCE_SIZE) { if (extra_nonce_size > EXTRA_NONCE_SIZE) {
memset(p, 0, extra_nonce_size - EXTRA_NONCE_SIZE); memset(p, 0, extra_nonce_size - EXTRA_NONCE_SIZE);
@ -232,7 +239,7 @@ std::vector<uint8_t> PoolBlock::serialize_sidechain_data() const
MutexLock lock(m_lock); MutexLock lock(m_lock);
data.reserve((m_uncles.size() + 4) * HASH_SIZE + 20); data.reserve((m_uncles.size() + 4) * HASH_SIZE + 36);
const hash& spend = m_minerWallet.spend_public_key(); const hash& spend = m_minerWallet.spend_public_key();
const hash& view = m_minerWallet.view_public_key(); const hash& view = m_minerWallet.view_public_key();
@ -317,7 +324,7 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const
MutexLock lock(m_lock); MutexLock lock(m_lock);
size_t header_size, miner_tx_size; size_t header_size, miner_tx_size;
const std::vector<uint8_t> mainchain_data = serialize_mainchain_data_nolock(&header_size, &miner_tx_size, nullptr, nullptr); const std::vector<uint8_t> mainchain_data = serialize_mainchain_data_nolock(&header_size, &miner_tx_size, nullptr, nullptr, nullptr, nullptr);
if (!header_size || !miner_tx_size || (mainchain_data.size() < header_size + miner_tx_size)) { if (!header_size || !miner_tx_size || (mainchain_data.size() < header_size + miner_tx_size)) {
LOGERR(1, "tried to calculate PoW of uninitialized block"); LOGERR(1, "tried to calculate PoW of uninitialized block");
@ -405,4 +412,28 @@ uint64_t PoolBlock::get_payout(const Wallet& w) const
return 0; return 0;
} }
hash PoolBlock::calculate_tx_key_seed() const
{
const char domain[] = "tx_key_seed";
const uint32_t zero = 0;
const std::vector<uint8_t> mainchain_data = serialize_mainchain_data(nullptr, nullptr, nullptr, nullptr, &zero, &zero);
const std::vector<uint8_t> sidechain_data = serialize_sidechain_data();
hash result;
keccak_custom([&domain, &mainchain_data, &sidechain_data](int offset) -> uint8_t {
size_t k = offset;
if (k < sizeof(domain)) return domain[k];
k -= sizeof(domain);
if (k < mainchain_data.size()) return mainchain_data[k];
k -= mainchain_data.size();
return sidechain_data[k];
}, static_cast<int>(sizeof(domain) + mainchain_data.size() + sidechain_data.size()), result.h, HASH_SIZE);
return result;
}
} // namespace p2pool } // namespace p2pool

View File

@ -137,8 +137,8 @@ struct PoolBlock
uint64_t m_localTimestamp; uint64_t m_localTimestamp;
std::vector<uint8_t> serialize_mainchain_data(size_t* header_size = nullptr, size_t* miner_tx_size = nullptr, int* outputs_offset = nullptr, int* outputs_blob_size = nullptr) const; std::vector<uint8_t> serialize_mainchain_data(size_t* header_size = nullptr, size_t* miner_tx_size = nullptr, int* outputs_offset = nullptr, int* outputs_blob_size = nullptr, const uint32_t* nonce = nullptr, const uint32_t* extra_nonce = nullptr) const;
std::vector<uint8_t> serialize_mainchain_data_nolock(size_t* header_size, size_t* miner_tx_size, int* outputs_offset, int* outputs_blob_size) const; std::vector<uint8_t> serialize_mainchain_data_nolock(size_t* header_size, size_t* miner_tx_size, int* outputs_offset, int* outputs_blob_size, const uint32_t* nonce, const uint32_t* extra_nonce) const;
std::vector<uint8_t> serialize_sidechain_data() const; std::vector<uint8_t> serialize_sidechain_data() const;
int deserialize(const uint8_t* data, size_t size, const SideChain& sidechain, uv_loop_t* loop, bool compact); int deserialize(const uint8_t* data, size_t size, const SideChain& sidechain, uv_loop_t* loop, bool compact);
@ -171,6 +171,8 @@ struct PoolBlock
memcpy(p + HASH_SIZE + NONCE_SIZE, &m_extraNonce, EXTRA_NONCE_SIZE); memcpy(p + HASH_SIZE + NONCE_SIZE, &m_extraNonce, EXTRA_NONCE_SIZE);
return key; return key;
} }
hash calculate_tx_key_seed() const;
}; };
} // namespace p2pool } // namespace p2pool

View File

@ -203,6 +203,7 @@ SideChain::~SideChain()
void SideChain::fill_sidechain_data(PoolBlock& block, std::vector<MinerShare>& shares) const void SideChain::fill_sidechain_data(PoolBlock& block, std::vector<MinerShare>& shares) const
{ {
const int sidechain_version = block.get_sidechain_version();
block.m_uncles.clear(); block.m_uncles.clear();
ReadLock lock(m_sidechainLock); ReadLock lock(m_sidechainLock);
@ -215,10 +216,20 @@ void SideChain::fill_sidechain_data(PoolBlock& block, std::vector<MinerShare>& s
block.m_difficulty = m_minDifficulty; block.m_difficulty = m_minDifficulty;
block.m_cumulativeDifficulty = m_minDifficulty; block.m_cumulativeDifficulty = m_minDifficulty;
if (sidechain_version > 1) {
block.m_txkeySecSeed = {};
get_tx_keys(block.m_txkeyPub, block.m_txkeySec, block.m_txkeySecSeed, block.m_prevId);
}
get_shares(&block, shares); get_shares(&block, shares);
return; return;
} }
if (sidechain_version > 1) {
block.m_txkeySecSeed = (block.m_prevId == tip->m_prevId) ? tip->m_txkeySecSeed : tip->calculate_tx_key_seed();
get_tx_keys(block.m_txkeyPub, block.m_txkeySec, block.m_txkeySecSeed, block.m_prevId);
}
block.m_parent = tip->m_sidechainId; block.m_parent = tip->m_sidechainId;
block.m_sidechainHeight = tip->m_sidechainHeight + 1; block.m_sidechainHeight = tip->m_sidechainHeight + 1;
@ -1331,12 +1342,15 @@ void SideChain::verify_loop(PoolBlock* block)
void SideChain::verify(PoolBlock* block) void SideChain::verify(PoolBlock* block)
{ {
const int sidechain_version = block->get_sidechain_version();
// Genesis block // Genesis block
if (block->m_sidechainHeight == 0) { if (block->m_sidechainHeight == 0) {
if (!block->m_parent.empty() || if (!block->m_parent.empty() ||
!block->m_uncles.empty() || !block->m_uncles.empty() ||
(block->m_difficulty != m_minDifficulty) || (block->m_difficulty != m_minDifficulty) ||
(block->m_cumulativeDifficulty != m_minDifficulty)) (block->m_cumulativeDifficulty != m_minDifficulty) ||
((sidechain_version > 1) && !block->m_txkeySecSeed.empty()))
{ {
block->m_invalid = true; block->m_invalid = true;
} }
@ -1382,12 +1396,24 @@ void SideChain::verify(PoolBlock* block)
return; return;
} }
if (sidechain_version > 1) {
// Check m_txkeySecSeed
const hash h = (block->m_prevId == parent->m_prevId) ? parent->m_txkeySecSeed : parent->calculate_tx_key_seed();
if (block->m_txkeySecSeed != h) {
LOGWARN(3, "block " << block->m_sidechainId << " has invalid tx key seed: expected " << h << ", got " << block->m_txkeySecSeed);
block->m_verified = true;
block->m_invalid = true;
return;
}
}
const uint64_t expectedHeight = parent->m_sidechainHeight + 1; const uint64_t expectedHeight = parent->m_sidechainHeight + 1;
if (block->m_sidechainHeight != expectedHeight) { if (block->m_sidechainHeight != expectedHeight) {
LOGWARN(3, "block at height = " << block->m_sidechainHeight << LOGWARN(3, "block at height = " << block->m_sidechainHeight <<
", id = " << block->m_sidechainId << ", id = " << block->m_sidechainId <<
", mainchain height = " << block->m_txinGenHeight << ", mainchain height = " << block->m_txinGenHeight <<
" has wrong height: expected " << expectedHeight); " has wrong height: expected " << expectedHeight);
block->m_verified = true;
block->m_invalid = true; block->m_invalid = true;
return; return;
} }

View File

@ -60,7 +60,7 @@ TEST(block_template, update)
tpl.update(data, mempool, &wallet); tpl.update(data, mempool, &wallet);
const PoolBlock* b = tpl.pool_block_template(); const PoolBlock* b = tpl.pool_block_template();
ASSERT_EQ(b->m_sidechainId, H("e6fa454c10374439dcc9eee3198f6ba17a7a3764510569c3b963b31510b74780")); ASSERT_EQ(b->m_sidechainId, H("3085dc0425d94fb2752e21e5d5a4fbad42105a189f9678cadabb69cf55a321ee"));
std::vector<uint8_t> blobs; std::vector<uint8_t> blobs;
uint64_t height; uint64_t height;
@ -79,7 +79,7 @@ TEST(block_template, update)
hash blobs_hash; hash blobs_hash;
keccak(blobs.data(), static_cast<int>(blobs.size()), blobs_hash.h); keccak(blobs.data(), static_cast<int>(blobs.size()), blobs_hash.h);
ASSERT_EQ(blobs_hash, H("fd0079d39d1739ded6e710192228276cbaa55eaabde7a26c38f8986709a030e4")); ASSERT_EQ(blobs_hash, H("c1211e083d27ddb81eddb125af4f10b6df16efd418cf684f6d0e8e49a5ffaf3f"));
// Test 2: mempool with high fee and low fee transactions, it must choose high fee transactions // Test 2: mempool with high fee and low fee transactions, it must choose high fee transactions
for (uint64_t i = 0; i < 512; ++i) { for (uint64_t i = 0; i < 512; ++i) {