Initialize tx key from previous blocks

This commit is contained in:
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();
if (sidechain_version > 1) {
static_assert(decltype(m_rng)::word_size == 64, "m_rng must be 64-bit");
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();
}
if (sidechain_version <= 1) {
m_poolBlockTemplate->m_txkeySecSeed = miner_wallet->spend_public_key();
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;

View file

@ -122,13 +122,13 @@ PoolBlock::~PoolBlock()
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);
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;
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);
writeVarint(m_timestamp, data);
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();
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++) = 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;
if (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);
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& 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);
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)) {
LOGERR(1, "tried to calculate PoW of uninitialized block");
@ -405,4 +412,28 @@ uint64_t PoolBlock::get_payout(const Wallet& w) const
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

View file

@ -137,8 +137,8 @@ struct PoolBlock
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_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(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 uint32_t* nonce, const uint32_t* extra_nonce) 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);
@ -171,6 +171,8 @@ struct PoolBlock
memcpy(p + HASH_SIZE + NONCE_SIZE, &m_extraNonce, EXTRA_NONCE_SIZE);
return key;
}
hash calculate_tx_key_seed() const;
};
} // namespace p2pool

View file

@ -203,6 +203,7 @@ SideChain::~SideChain()
void SideChain::fill_sidechain_data(PoolBlock& block, std::vector<MinerShare>& shares) const
{
const int sidechain_version = block.get_sidechain_version();
block.m_uncles.clear();
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_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);
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_sidechainHeight = tip->m_sidechainHeight + 1;
@ -1331,12 +1342,15 @@ void SideChain::verify_loop(PoolBlock* block)
void SideChain::verify(PoolBlock* block)
{
const int sidechain_version = block->get_sidechain_version();
// Genesis block
if (block->m_sidechainHeight == 0) {
if (!block->m_parent.empty() ||
!block->m_uncles.empty() ||
(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;
}
@ -1382,12 +1396,24 @@ void SideChain::verify(PoolBlock* block)
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;
if (block->m_sidechainHeight != expectedHeight) {
LOGWARN(3, "block at height = " << block->m_sidechainHeight <<
", id = " << block->m_sidechainId <<
", mainchain height = " << block->m_txinGenHeight <<
" has wrong height: expected " << expectedHeight);
block->m_verified = true;
block->m_invalid = true;
return;
}

View file

@ -60,7 +60,7 @@ TEST(block_template, update)
tpl.update(data, mempool, &wallet);
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;
uint64_t height;
@ -79,7 +79,7 @@ TEST(block_template, update)
hash blobs_hash;
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
for (uint64_t i = 0; i < 512; ++i) {