View tags support
See http://github.com/monero-project/monero/pull/8061
This commit is contained in:
+11
-3
@@ -689,6 +689,8 @@ int BlockTemplate::create_miner_tx(const MinerData& data, const std::vector<Mine
|
||||
m_poolBlockTemplate->m_outputs.clear();
|
||||
m_poolBlockTemplate->m_outputs.reserve(num_outputs);
|
||||
|
||||
const uint8_t tx_type = m_poolBlockTemplate->get_tx_type();
|
||||
|
||||
uint64_t reward_amounts_weight = 0;
|
||||
for (size_t i = 0; i < num_outputs; ++i) {
|
||||
writeVarint(m_rewards[i], [this, &reward_amounts_weight](uint8_t b)
|
||||
@@ -696,18 +698,24 @@ int BlockTemplate::create_miner_tx(const MinerData& data, const std::vector<Mine
|
||||
m_minerTx.push_back(b);
|
||||
++reward_amounts_weight;
|
||||
});
|
||||
m_minerTx.push_back(TXOUT_TO_KEY);
|
||||
m_minerTx.push_back(tx_type);
|
||||
|
||||
uint8_t view_tag = 0;
|
||||
|
||||
if (dry_run) {
|
||||
m_minerTx.insert(m_minerTx.end(), HASH_SIZE, 0);
|
||||
}
|
||||
else {
|
||||
hash eph_public_key;
|
||||
if (!shares[i].m_wallet->get_eph_public_key(m_txkeySec, i, eph_public_key)) {
|
||||
if (!shares[i].m_wallet->get_eph_public_key(m_txkeySec, i, eph_public_key, view_tag)) {
|
||||
LOGERR(1, "get_eph_public_key failed at index " << i);
|
||||
}
|
||||
m_minerTx.insert(m_minerTx.end(), eph_public_key.h, eph_public_key.h + HASH_SIZE);
|
||||
m_poolBlockTemplate->m_outputs.emplace_back(m_rewards[i], eph_public_key);
|
||||
m_poolBlockTemplate->m_outputs.emplace_back(m_rewards[i], eph_public_key, tx_type, view_tag);
|
||||
}
|
||||
|
||||
if (tx_type == TXOUT_TO_TAGGED_KEY) {
|
||||
m_minerTx.emplace_back(view_tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -81,7 +81,8 @@
|
||||
namespace p2pool {
|
||||
|
||||
constexpr size_t HASH_SIZE = 32;
|
||||
constexpr uint8_t HARDFORK_SUPPORTED_VERSION = 14;
|
||||
constexpr uint8_t HARDFORK_VIEW_TAGS_VERSION = 15;
|
||||
constexpr uint8_t HARDFORK_SUPPORTED_VERSION = 16;
|
||||
constexpr uint8_t MINER_REWARD_UNLOCK_TIME = 60;
|
||||
constexpr uint8_t NONCE_SIZE = 4;
|
||||
constexpr uint8_t EXTRA_NONCE_SIZE = 4;
|
||||
@@ -89,6 +90,7 @@ constexpr uint8_t EXTRA_NONCE_MAX_SIZE = EXTRA_NONCE_SIZE + 10;
|
||||
constexpr uint8_t TX_VERSION = 2;
|
||||
constexpr uint8_t TXIN_GEN = 0xFF;
|
||||
constexpr uint8_t TXOUT_TO_KEY = 2;
|
||||
constexpr uint8_t TXOUT_TO_TAGGED_KEY = 3;
|
||||
constexpr uint8_t TX_EXTRA_TAG_PUBKEY = 1;
|
||||
constexpr uint8_t TX_EXTRA_NONCE = 2;
|
||||
constexpr uint8_t TX_EXTRA_MERGE_MINING_TAG = 3;
|
||||
|
||||
+33
-7
@@ -144,17 +144,19 @@ public:
|
||||
uv_mutex_destroy(&m);
|
||||
}
|
||||
|
||||
bool get_derivation(const hash& key1, const hash& key2, hash& derivation)
|
||||
bool get_derivation(const hash& key1, const hash& key2, size_t output_index, hash& derivation, uint8_t& view_tag)
|
||||
{
|
||||
std::array<uint8_t, HASH_SIZE * 2> index;
|
||||
std::array<uint8_t, HASH_SIZE * 2 + sizeof(size_t)> index;
|
||||
memcpy(index.data(), key1.h, HASH_SIZE);
|
||||
memcpy(index.data() + HASH_SIZE, key2.h, HASH_SIZE);
|
||||
memcpy(index.data() + HASH_SIZE * 2, &output_index, sizeof(size_t));
|
||||
|
||||
{
|
||||
MutexLock lock(m);
|
||||
auto it = derivations.find(index);
|
||||
if (it != derivations.end()) {
|
||||
derivation = it->second;
|
||||
derivation = it->second.derivation;
|
||||
view_tag = it->second.view_tag;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -172,9 +174,11 @@ public:
|
||||
ge_p1p1_to_p2(&point2, &point3);
|
||||
ge_tobytes(reinterpret_cast<uint8_t*>(&derivation), &point2);
|
||||
|
||||
derive_view_tag(derivation, output_index, view_tag);
|
||||
|
||||
{
|
||||
MutexLock lock(m);
|
||||
derivations.emplace(index, derivation);
|
||||
derivations.emplace(index, DerivationEntry{ derivation, view_tag } );
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -231,16 +235,22 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
struct DerivationEntry
|
||||
{
|
||||
hash derivation;
|
||||
uint8_t view_tag;
|
||||
};
|
||||
|
||||
uv_mutex_t m;
|
||||
unordered_map<std::array<uint8_t, HASH_SIZE * 2>, hash> derivations;
|
||||
unordered_map<std::array<uint8_t, HASH_SIZE * 2 + sizeof(size_t)>, DerivationEntry> derivations;
|
||||
unordered_map<std::array<uint8_t, HASH_SIZE * 2 + sizeof(size_t)>, hash> public_keys;
|
||||
};
|
||||
|
||||
static Cache* cache = nullptr;
|
||||
|
||||
bool generate_key_derivation(const hash& key1, const hash& key2, hash& derivation)
|
||||
bool generate_key_derivation(const hash& key1, const hash& key2, size_t output_index, hash& derivation, uint8_t& view_tag)
|
||||
{
|
||||
return cache->get_derivation(key1, key2, derivation);
|
||||
return cache->get_derivation(key1, key2, output_index, derivation, view_tag);
|
||||
}
|
||||
|
||||
bool derive_public_key(const hash& derivation, size_t output_index, const hash& base, hash& derived_key)
|
||||
@@ -248,6 +258,22 @@ bool derive_public_key(const hash& derivation, size_t output_index, const hash&
|
||||
return cache->get_public_key(derivation, output_index, base, derived_key);
|
||||
}
|
||||
|
||||
void derive_view_tag(const hash& derivation, size_t output_index, uint8_t& view_tag)
|
||||
{
|
||||
constexpr uint8_t salt[] = "view_tag";
|
||||
constexpr size_t SALT_SIZE = sizeof(salt) - 1;
|
||||
|
||||
uint8_t buf[64];
|
||||
memcpy(buf, salt, SALT_SIZE);
|
||||
memcpy(buf + SALT_SIZE, derivation.h, HASH_SIZE);
|
||||
uint8_t* p = buf + SALT_SIZE + HASH_SIZE;
|
||||
writeVarint(output_index, [&p](uint8_t b) { *(p++) = b; });
|
||||
|
||||
hash view_tag_full;
|
||||
keccak(buf, static_cast<int>(p - buf), view_tag_full.h, HASH_SIZE);
|
||||
view_tag = view_tag_full.h[0];
|
||||
}
|
||||
|
||||
void init_crypto_cache()
|
||||
{
|
||||
if (!cache) {
|
||||
|
||||
+2
-1
@@ -21,8 +21,9 @@ namespace p2pool {
|
||||
|
||||
void generate_keys(hash& pub, hash& sec);
|
||||
bool check_keys(const hash& pub, const hash& sec);
|
||||
bool generate_key_derivation(const hash& key1, const hash& key2, hash& derivation);
|
||||
bool generate_key_derivation(const hash& key1, const hash& key2, size_t output_index, hash& derivation, uint8_t& view_tag);
|
||||
bool derive_public_key(const hash& derivation, size_t output_index, const hash& base, hash& derived_key);
|
||||
void derive_view_tag(const hash& derivation, size_t output_index, uint8_t& view_tag);
|
||||
|
||||
void init_crypto_cache();
|
||||
void destroy_crypto_cache();
|
||||
|
||||
+10
-7
@@ -72,7 +72,8 @@ p2pool::p2pool(int argc, char* argv[])
|
||||
hash pub, sec, eph_public_key;
|
||||
generate_keys(pub, sec);
|
||||
|
||||
if (!m_params->m_wallet.get_eph_public_key(sec, 0, eph_public_key)) {
|
||||
uint8_t view_tag;
|
||||
if (!m_params->m_wallet.get_eph_public_key(sec, 0, eph_public_key, view_tag)) {
|
||||
LOGERR(1, "Invalid wallet address: get_eph_public_key failed");
|
||||
panic();
|
||||
}
|
||||
@@ -603,13 +604,15 @@ void p2pool::download_block_headers(uint64_t current_height)
|
||||
});
|
||||
}
|
||||
|
||||
const uint64_t start_height = (current_height > BLOCK_HEADERS_REQUIRED) ? (current_height - BLOCK_HEADERS_REQUIRED) : 0;
|
||||
|
||||
s.m_pos = 0;
|
||||
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_headers_range\",\"params\":{\"start_height\":" << current_height - BLOCK_HEADERS_REQUIRED << ",\"end_height\":" << current_height - 1 << "}}\0";
|
||||
s << "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"get_block_headers_range\",\"params\":{\"start_height\":" << start_height << ",\"end_height\":" << current_height - 1 << "}}\0";
|
||||
|
||||
JSONRPCRequest::call(m_params->m_host.c_str(), m_params->m_rpcPort, buf,
|
||||
[this, current_height](const char* data, size_t size)
|
||||
[this, start_height, current_height](const char* data, size_t size)
|
||||
{
|
||||
if (parse_block_headers_range(data, size) == BLOCK_HEADERS_REQUIRED) {
|
||||
if (parse_block_headers_range(data, size) == current_height - start_height) {
|
||||
update_median_timestamp();
|
||||
if (m_serversStarted.exchange(1) == 0) {
|
||||
m_ZMQReader = new ZMQReader(m_params->m_host.c_str(), m_params->m_zmqPort, this);
|
||||
@@ -624,14 +627,14 @@ void p2pool::download_block_headers(uint64_t current_height)
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOGERR(1, "fatal error: couldn't download block headers for heights " << current_height - BLOCK_HEADERS_REQUIRED << " - " << current_height - 1);
|
||||
LOGERR(1, "fatal error: couldn't download block headers for heights " << start_height << " - " << current_height - 1);
|
||||
panic();
|
||||
}
|
||||
},
|
||||
[current_height](const char* data, size_t size)
|
||||
[start_height, current_height](const char* data, size_t size)
|
||||
{
|
||||
if (size > 0) {
|
||||
LOGERR(1, "fatal error: couldn't download block headers for heights " << current_height - BLOCK_HEADERS_REQUIRED << " - " << current_height - 1 << ", error " << log::const_buf(data, size));
|
||||
LOGERR(1, "fatal error: couldn't download block headers for heights " << start_height << " - " << current_height - 1 << ", error " << log::const_buf(data, size));
|
||||
panic();
|
||||
}
|
||||
});
|
||||
|
||||
+17
-3
@@ -157,8 +157,12 @@ void PoolBlock::serialize_mainchain_data(uint32_t nonce, uint32_t extra_nonce, c
|
||||
|
||||
for (TxOutput& output : m_outputs) {
|
||||
writeVarint(output.m_reward, m_mainChainData);
|
||||
m_mainChainData.push_back(TXOUT_TO_KEY);
|
||||
m_mainChainData.push_back(output.m_txType);
|
||||
m_mainChainData.insert(m_mainChainData.end(), output.m_ephPublicKey.h, output.m_ephPublicKey.h + HASH_SIZE);
|
||||
|
||||
if (output.m_txType == TXOUT_TO_TAGGED_KEY) {
|
||||
m_mainChainData.push_back(output.m_viewTag);
|
||||
}
|
||||
}
|
||||
|
||||
m_mainChainOutputsBlobSize = static_cast<int>(m_mainChainData.size()) - m_mainChainOutputsOffset;
|
||||
@@ -301,9 +305,19 @@ bool PoolBlock::get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const
|
||||
uint64_t PoolBlock::get_payout(const Wallet& w) const
|
||||
{
|
||||
for (size_t i = 0, n = m_outputs.size(); i < n; ++i) {
|
||||
const TxOutput& out = m_outputs[i];
|
||||
hash eph_public_key;
|
||||
if ((w.get_eph_public_key(m_txkeySec, i, eph_public_key)) && (eph_public_key == m_outputs[i].m_ephPublicKey)) {
|
||||
return m_outputs[i].m_reward;
|
||||
|
||||
if (out.m_txType == 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)) {
|
||||
return out.m_reward;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint8_t view_tag;
|
||||
if (w.get_eph_public_key(m_txkeySec, i, eph_public_key, view_tag) && (eph_public_key == out.m_ephPublicKey)) {
|
||||
return out.m_reward;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-2
@@ -81,11 +81,13 @@ struct PoolBlock
|
||||
|
||||
struct TxOutput
|
||||
{
|
||||
FORCEINLINE TxOutput() : m_reward(0), m_ephPublicKey() {}
|
||||
FORCEINLINE TxOutput(uint64_t r, const hash& k) : m_reward(r), m_ephPublicKey(k) {}
|
||||
FORCEINLINE TxOutput() : m_reward(0), m_ephPublicKey(), m_txType(0), m_viewTag(0) {}
|
||||
FORCEINLINE TxOutput(uint64_t r, const hash& k, uint8_t tx_type, uint8_t view_tag) : m_reward(r), m_ephPublicKey(k), m_txType(tx_type), m_viewTag(view_tag) {}
|
||||
|
||||
uint64_t m_reward;
|
||||
hash m_ephPublicKey;
|
||||
uint8_t m_txType;
|
||||
uint8_t m_viewTag;
|
||||
};
|
||||
|
||||
std::vector<TxOutput> m_outputs;
|
||||
@@ -139,6 +141,10 @@ struct PoolBlock
|
||||
bool get_pow_hash(RandomX_Hasher_Base* hasher, uint64_t height, const hash& seed_hash, hash& pow_hash);
|
||||
|
||||
uint64_t get_payout(const Wallet& w) const;
|
||||
|
||||
// Both tx types are allowed by Monero consensus during v15 because it needs to process pre-fork mempool transactions,
|
||||
// but P2Pool can switch to using only TXOUT_TO_TAGGED_KEY for miner payouts starting from v15
|
||||
FORCEINLINE uint8_t get_tx_type() const { return (m_majorVersion < HARDFORK_VIEW_TAGS_VERSION) ? TXOUT_TO_KEY : TXOUT_TO_TAGGED_KEY; }
|
||||
};
|
||||
|
||||
} // namespace p2pool
|
||||
|
||||
@@ -99,7 +99,7 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, SideChain& sidechai
|
||||
if (num_outputs > 0) {
|
||||
// Outputs are in the buffer, just read them
|
||||
// Each output is at least 34 bytes, exit early if there's not enough data left
|
||||
// 1 byte for reward, 1 byte for TXOUT_TO_KEY, 32 bytes for eph_pub_key
|
||||
// 1 byte for reward, 1 byte for tx_type, 32 bytes for eph_pub_key
|
||||
constexpr uint64_t MIN_OUTPUT_SIZE = 34;
|
||||
|
||||
if (num_outputs > std::numeric_limits<uint64_t>::max() / MIN_OUTPUT_SIZE) return __LINE__;
|
||||
@@ -108,15 +108,23 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, SideChain& sidechai
|
||||
m_outputs.clear();
|
||||
m_outputs.reserve(num_outputs);
|
||||
|
||||
const uint8_t expected_tx_type = get_tx_type();
|
||||
|
||||
for (uint64_t i = 0; i < num_outputs; ++i) {
|
||||
TxOutput t;
|
||||
|
||||
READ_VARINT(t.m_reward);
|
||||
total_reward += t.m_reward;
|
||||
|
||||
EXPECT_BYTE(TXOUT_TO_KEY);
|
||||
EXPECT_BYTE(expected_tx_type);
|
||||
t.m_txType = expected_tx_type;
|
||||
|
||||
READ_BUF(t.m_ephPublicKey.h, HASH_SIZE);
|
||||
|
||||
if (expected_tx_type == TXOUT_TO_TAGGED_KEY) {
|
||||
READ_BYTE(t.m_viewTag);
|
||||
}
|
||||
|
||||
m_outputs.emplace_back(std::move(t));
|
||||
}
|
||||
|
||||
|
||||
+48
-15
@@ -613,13 +613,17 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v
|
||||
PoolBlock* b = it->second;
|
||||
const size_t n = b->m_outputs.size();
|
||||
|
||||
blob.reserve(n * 38 + 64);
|
||||
blob.reserve(n * 39 + 64);
|
||||
writeVarint(n, blob);
|
||||
|
||||
for (const PoolBlock::TxOutput& output : b->m_outputs) {
|
||||
writeVarint(output.m_reward, blob);
|
||||
blob.emplace_back(TXOUT_TO_KEY);
|
||||
blob.emplace_back(output.m_txType);
|
||||
blob.insert(blob.end(), output.m_ephPublicKey.h, output.m_ephPublicKey.h + HASH_SIZE);
|
||||
|
||||
if (output.m_txType == TXOUT_TO_TAGGED_KEY) {
|
||||
blob.emplace_back(output.m_viewTag);
|
||||
}
|
||||
}
|
||||
|
||||
block->m_outputs = b->m_outputs;
|
||||
@@ -632,25 +636,32 @@ bool SideChain::get_outputs_blob(PoolBlock* block, uint64_t total_reward, std::v
|
||||
|
||||
const size_t n = m_tmpShares.size();
|
||||
|
||||
blob.reserve(n * 38 + 64);
|
||||
blob.reserve(n * 39 + 64);
|
||||
|
||||
writeVarint(n, blob);
|
||||
|
||||
block->m_outputs.clear();
|
||||
block->m_outputs.reserve(n);
|
||||
|
||||
const uint8_t tx_type = block->get_tx_type();
|
||||
|
||||
hash eph_public_key;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
writeVarint(m_tmpRewards[i], blob);
|
||||
|
||||
blob.emplace_back(TXOUT_TO_KEY);
|
||||
blob.emplace_back(tx_type);
|
||||
|
||||
if (!m_tmpShares[i].m_wallet->get_eph_public_key(block->m_txkeySec, i, eph_public_key)) {
|
||||
uint8_t view_tag;
|
||||
if (!m_tmpShares[i].m_wallet->get_eph_public_key(block->m_txkeySec, i, eph_public_key, view_tag)) {
|
||||
LOGWARN(6, "get_eph_public_key failed at index " << i);
|
||||
}
|
||||
blob.insert(blob.end(), eph_public_key.h, eph_public_key.h + HASH_SIZE);
|
||||
|
||||
block->m_outputs.emplace_back(m_tmpRewards[i], eph_public_key);
|
||||
if (tx_type == TXOUT_TO_TAGGED_KEY) {
|
||||
blob.emplace_back(view_tag);
|
||||
}
|
||||
|
||||
block->m_outputs.emplace_back(m_tmpRewards[i], eph_public_key, tx_type, view_tag);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -737,14 +748,24 @@ void SideChain::print_status()
|
||||
}
|
||||
|
||||
Wallet w = m_pool->params().m_wallet;
|
||||
const std::vector<PoolBlock::TxOutput>& outs = tip->m_outputs;
|
||||
|
||||
hash eph_public_key;
|
||||
for (size_t i = 0, n = outs.size(); i < n; ++i) {
|
||||
if (w.get_eph_public_key(tip->m_txkeySec, i, eph_public_key) && (outs[i].m_ephPublicKey == eph_public_key)) {
|
||||
your_reward = outs[i].m_reward;
|
||||
for (size_t i = 0, n = tip->m_outputs.size(); i < n; ++i) {
|
||||
const PoolBlock::TxOutput& out = tip->m_outputs[i];
|
||||
if (!your_reward) {
|
||||
if (out.m_txType == 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)) {
|
||||
your_reward = out.m_reward;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint8_t view_tag;
|
||||
if (w.get_eph_public_key(tip->m_txkeySec, i, eph_public_key, view_tag) && (out.m_ephPublicKey == eph_public_key)) {
|
||||
your_reward = out.m_reward;
|
||||
}
|
||||
}
|
||||
}
|
||||
total_reward += outs[i].m_reward;
|
||||
total_reward += out.m_reward;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1320,17 +1341,20 @@ void SideChain::verify(PoolBlock* block)
|
||||
}
|
||||
|
||||
for (size_t i = 0, n = rewards.size(); i < n; ++i) {
|
||||
if (rewards[i] != block->m_outputs[i].m_reward) {
|
||||
const PoolBlock::TxOutput& out = block->m_outputs[i];
|
||||
|
||||
if (rewards[i] != out.m_reward) {
|
||||
LOGWARN(3, "block at height = " << block->m_sidechainHeight <<
|
||||
", id = " << block->m_sidechainId <<
|
||||
", mainchain height = " << block->m_txinGenHeight <<
|
||||
" has invalid reward at index " << i << ": got " << block->m_outputs[i].m_reward << ", expected " << rewards[i]);
|
||||
" has invalid reward at index " << i << ": got " << out.m_reward << ", expected " << rewards[i]);
|
||||
block->m_invalid = true;
|
||||
return;
|
||||
}
|
||||
|
||||
hash eph_public_key;
|
||||
if (!shares[i].m_wallet->get_eph_public_key(block->m_txkeySec, i, eph_public_key)) {
|
||||
uint8_t view_tag;
|
||||
if (!shares[i].m_wallet->get_eph_public_key(block->m_txkeySec, i, eph_public_key, view_tag)) {
|
||||
LOGWARN(3, "block at height = " << block->m_sidechainHeight <<
|
||||
", id = " << block->m_sidechainId <<
|
||||
", mainchain height = " << block->m_txinGenHeight <<
|
||||
@@ -1339,7 +1363,16 @@ void SideChain::verify(PoolBlock* block)
|
||||
return;
|
||||
}
|
||||
|
||||
if (eph_public_key != block->m_outputs[i].m_ephPublicKey) {
|
||||
if ((out.m_txType == TXOUT_TO_TAGGED_KEY) && (out.m_viewTag != view_tag)) {
|
||||
LOGWARN(3, "block at height = " << block->m_sidechainHeight <<
|
||||
", id = " << block->m_sidechainId <<
|
||||
", mainchain height = " << block->m_txinGenHeight <<
|
||||
" has an incorrect view tag at index " << i);
|
||||
block->m_invalid = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (eph_public_key != out.m_ephPublicKey) {
|
||||
LOGWARN(3, "block at height = " << block->m_sidechainHeight <<
|
||||
", id = " << block->m_sidechainId <<
|
||||
", mainchain height = " << block->m_txinGenHeight <<
|
||||
|
||||
+17
-2
@@ -195,10 +195,25 @@ bool Wallet::assign(const hash& spend_pub_key, const hash& view_pub_key, Network
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Wallet::get_eph_public_key(const hash& txkey_sec, size_t output_index, hash& eph_public_key) const
|
||||
bool Wallet::get_eph_public_key(const hash& txkey_sec, size_t output_index, hash& eph_public_key, uint8_t& view_tag) const
|
||||
{
|
||||
hash derivation;
|
||||
if (!generate_key_derivation(m_viewPublicKey, txkey_sec, 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)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -38,7 +38,8 @@ public:
|
||||
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) const;
|
||||
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; }
|
||||
|
||||
Reference in New Issue
Block a user