fixed for Salvium Carrot/Token support
This commit is contained in:
@@ -24,6 +24,18 @@
|
||||
#include "base/tools/cryptonote/BlobReader.h"
|
||||
#include "base/tools/Cvt.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr uint8_t kSalviumProtocolHF = 2;
|
||||
constexpr uint8_t kSalviumProtocolTxVersionLegacy = 2;
|
||||
constexpr uint8_t kSalviumProtocolTxVersionCarrot = 4;
|
||||
constexpr uint8_t kSalviumProtocolTxVersionTokens = 5;
|
||||
constexpr uint8_t kSalviumCarrotHF = 10;
|
||||
constexpr uint8_t kSalviumTokensHF = 11;
|
||||
constexpr uint8_t kTxOutToKey = 2;
|
||||
constexpr uint8_t kTxOutToTaggedKey = 3;
|
||||
constexpr uint8_t kTxOutToCarrotV1 = 4;
|
||||
}
|
||||
|
||||
void xmrig::BlockTemplate::calculateMinerTxHash(const uint8_t *prefix_begin, const uint8_t *prefix_end, uint8_t *hash)
|
||||
{
|
||||
@@ -67,7 +79,7 @@ void xmrig::BlockTemplate::calculateMerkleTreeHash()
|
||||
{
|
||||
m_minerTxMerkleTreeBranch.clear();
|
||||
|
||||
const uint64_t count = m_numHashes + ((m_coin == Coin::SALVIUM) ? 2 : 1);
|
||||
const uint64_t count = m_numHashes + baseTransactionCount();
|
||||
const uint8_t *h = m_hashes.data();
|
||||
|
||||
if (count == 1) {
|
||||
@@ -169,7 +181,7 @@ void xmrig::BlockTemplate::generateHashingBlob(Buffer &out) const
|
||||
out.assign(m_blob.begin(), m_blob.begin() + offset(MINER_TX_PREFIX_OFFSET));
|
||||
out.insert(out.end(), m_rootHash, m_rootHash + kHashSize);
|
||||
|
||||
uint64_t k = m_numHashes + ((m_coin == Coin::SALVIUM) ? 2 : 1);
|
||||
uint64_t k = m_numHashes + baseTransactionCount();
|
||||
while (k >= 0x80) {
|
||||
out.emplace_back((static_cast<uint8_t>(k) & 0x7F) | 0x80);
|
||||
k >>= 7;
|
||||
@@ -181,6 +193,7 @@ void xmrig::BlockTemplate::generateHashingBlob(Buffer &out) const
|
||||
bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
{
|
||||
BlobReader<true> ar(m_blob.data(), m_blob.size());
|
||||
m_hasProtocolTx = false;
|
||||
|
||||
// Block header
|
||||
ar(m_version.first);
|
||||
@@ -191,6 +204,10 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
setOffset(NONCE_OFFSET, ar.index());
|
||||
ar.skip(kNonceSize);
|
||||
|
||||
if (m_coin == Coin::SALVIUM && m_version.first >= kSalviumProtocolHF) {
|
||||
m_hasProtocolTx = true;
|
||||
}
|
||||
|
||||
// Wownero block template has miner signature starting from version 18
|
||||
if (m_coin == Coin::WOWNERO && majorVersion() >= 18) {
|
||||
ar(m_minerSignature, kSignatureSize);
|
||||
@@ -234,6 +251,11 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_coin == Coin::SALVIUM) {
|
||||
if (m_numOutputs < 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_numOutputs != 1) {
|
||||
return false;
|
||||
}
|
||||
@@ -241,8 +263,12 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
ar(m_amount);
|
||||
ar(m_outputType);
|
||||
|
||||
// output type must be txout_to_key (2) or txout_to_tagged_key (3)
|
||||
if ((m_outputType != 2) && (m_outputType != 3)) {
|
||||
if (m_coin == Coin::SALVIUM) {
|
||||
if ((m_outputType != kTxOutToKey) && (m_outputType != kTxOutToTaggedKey) && (m_outputType != kTxOutToCarrotV1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ((m_outputType != kTxOutToKey) && (m_outputType != kTxOutToTaggedKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -251,19 +277,11 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
ar(m_ephPublicKey, kKeySize);
|
||||
|
||||
if (m_coin == Coin::SALVIUM) {
|
||||
|
||||
uint8_t asset_type_len;
|
||||
ar(asset_type_len);
|
||||
ar.skip(asset_type_len);
|
||||
|
||||
uint64_t output_unlock_time;
|
||||
ar(output_unlock_time);
|
||||
|
||||
if (m_outputType == 3) {
|
||||
ar(m_viewTag);
|
||||
}
|
||||
|
||||
} else if (m_coin == Coin::ZEPHYR) {
|
||||
if (!parseSalviumOutput(ar, m_outputType, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_coin == Coin::ZEPHYR) {
|
||||
if (m_outputType != 2) {
|
||||
return false;
|
||||
}
|
||||
@@ -297,6 +315,27 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
ar(m_viewTag);
|
||||
}
|
||||
|
||||
if (m_coin == Coin::SALVIUM && m_numOutputs > 1) {
|
||||
for (uint64_t k = 1; k < m_numOutputs; ++k) {
|
||||
uint64_t amount2;
|
||||
ar(amount2);
|
||||
|
||||
uint8_t output_type2;
|
||||
ar(output_type2);
|
||||
|
||||
if ((output_type2 != kTxOutToKey) && (output_type2 != kTxOutToTaggedKey) && (output_type2 != kTxOutToCarrotV1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Span key2;
|
||||
ar(key2, kKeySize);
|
||||
|
||||
if (!parseSalviumOutput(ar, output_type2, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_coin == Coin::TOWNFORGE) {
|
||||
ar(m_unlockTime);
|
||||
}
|
||||
@@ -306,6 +345,7 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
setOffset(TX_EXTRA_OFFSET, ar.index());
|
||||
|
||||
BlobReader<true> ar_extra(blob(TX_EXTRA_OFFSET), m_extraSize);
|
||||
const uint8_t *extra_ptr = blob(TX_EXTRA_OFFSET);
|
||||
ar.skip(m_extraSize);
|
||||
|
||||
bool pubkey_offset_first = true;
|
||||
@@ -317,6 +357,12 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
ar_extra(extra_tag);
|
||||
|
||||
switch (extra_tag) {
|
||||
case 0x00: // TX_EXTRA_TAG_PADDING
|
||||
while (ar_extra.index() < m_extraSize && extra_ptr[ar_extra.index()] == 0) {
|
||||
ar_extra.skip(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x01: // TX_EXTRA_TAG_PUBKEY
|
||||
if (pubkey_offset_first) {
|
||||
pubkey_offset_first = false;
|
||||
@@ -326,19 +372,36 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
break;
|
||||
|
||||
case 0x02: // TX_EXTRA_NONCE
|
||||
ar_extra(size);
|
||||
if (!ar_extra(size)) {
|
||||
return false;
|
||||
}
|
||||
setOffset(TX_EXTRA_NONCE_OFFSET, offset(TX_EXTRA_OFFSET) + ar_extra.index());
|
||||
ar_extra(m_txExtraNonce, size);
|
||||
break;
|
||||
|
||||
case 0x03: // TX_EXTRA_MERGE_MINING_TAG
|
||||
ar_extra(size);
|
||||
if (!ar_extra(size)) {
|
||||
return false;
|
||||
}
|
||||
setOffset(TX_EXTRA_MERGE_MINING_TAG_OFFSET, offset(TX_EXTRA_OFFSET) + ar_extra.index());
|
||||
ar_extra(m_txMergeMiningTag, size);
|
||||
break;
|
||||
|
||||
case 0x04: // TX_EXTRA_TAG_ADDITIONAL_PUBKEYS
|
||||
if (!ar_extra(size)) {
|
||||
return false;
|
||||
}
|
||||
ar_extra.skip(kKeySize * size);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false; // TODO(SChernykh): handle other tags
|
||||
if (!ar_extra(size)) {
|
||||
return false;
|
||||
}
|
||||
if (size > ar_extra.remaining()) {
|
||||
return false;
|
||||
}
|
||||
ar_extra.skip(static_cast<size_t>(size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,7 +449,7 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_coin == Coin::SALVIUM) {
|
||||
if (m_hasProtocolTx) {
|
||||
|
||||
// Protocol transaction begin
|
||||
// Prefix begin
|
||||
@@ -395,7 +458,10 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
// Parse/skip the protocol_tx
|
||||
uint64_t protocol_tx_version, protocol_tx_unlock_time, protocol_tx_num_inputs;
|
||||
ar(protocol_tx_version);
|
||||
if (protocol_tx_version != 2) {
|
||||
const uint8_t expected_protocol_version =
|
||||
(majorVersion() >= kSalviumTokensHF) ? kSalviumProtocolTxVersionTokens :
|
||||
(majorVersion() >= kSalviumCarrotHF) ? kSalviumProtocolTxVersionCarrot : kSalviumProtocolTxVersionLegacy;
|
||||
if (protocol_tx_version != expected_protocol_version) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -434,24 +500,16 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
uint8_t out_type;
|
||||
ar(out_type);
|
||||
|
||||
// output type must be txout_to_key (2) or txout_to_tagged_key (3)
|
||||
if ((out_type != 2) && (out_type != 3)) {
|
||||
// output type must be txout_to_key (2), txout_to_tagged_key (3) or txout_to_carrot_v1 (4)
|
||||
if ((out_type != kTxOutToKey) && (out_type != kTxOutToTaggedKey) && (out_type != kTxOutToCarrotV1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Span out_pubkey;
|
||||
ar(out_pubkey, kKeySize);
|
||||
|
||||
uint64_t out_at_len;
|
||||
ar(out_at_len);
|
||||
ar.skip(out_at_len);
|
||||
|
||||
uint64_t out_unlock;
|
||||
ar(out_unlock);
|
||||
|
||||
if (out_type == 3) {
|
||||
uint8_t out_vt;
|
||||
ar(out_vt);
|
||||
if (!parseSalviumOutput(ar, out_type, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,32 +548,70 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
ar(m_numHashes);
|
||||
|
||||
if (hashes) {
|
||||
if (m_coin == Coin::SALVIUM) {
|
||||
const uint64_t base_count = baseTransactionCount();
|
||||
m_hashes.resize((m_numHashes + base_count) * kHashSize);
|
||||
|
||||
m_hashes.resize((m_numHashes + 2) * kHashSize);
|
||||
// Miner TX
|
||||
calculateMinerTxHash(blob(MINER_TX_PREFIX_OFFSET), blob(MINER_TX_PREFIX_END_OFFSET), m_hashes.data());
|
||||
// Protocol TX
|
||||
calculateMinerTxHash(blob(PROTOCOL_TX_PREFIX_OFFSET), blob(PROTOCOL_TX_PREFIX_END_OFFSET), m_hashes.data() + kHashSize);
|
||||
// Miner TX hash always goes first
|
||||
calculateMinerTxHash(blob(MINER_TX_PREFIX_OFFSET), blob(MINER_TX_PREFIX_END_OFFSET), m_hashes.data());
|
||||
|
||||
for (uint64_t i = 0; i < m_numHashes; ++i) {
|
||||
Span h;
|
||||
ar(h, kHashSize);
|
||||
memcpy(m_hashes.data() + (i+2) * kHashSize, h.data(), kHashSize);
|
||||
}
|
||||
} else {
|
||||
|
||||
m_hashes.resize((m_numHashes + 1) * kHashSize);
|
||||
calculateMinerTxHash(blob(MINER_TX_PREFIX_OFFSET), blob(MINER_TX_PREFIX_END_OFFSET), m_hashes.data());
|
||||
uint64_t offset = 1;
|
||||
|
||||
for (uint64_t i = 1; i <= m_numHashes; ++i) {
|
||||
Span h;
|
||||
ar(h, kHashSize);
|
||||
memcpy(m_hashes.data() + i * kHashSize, h.data(), kHashSize);
|
||||
}
|
||||
if (m_hasProtocolTx) {
|
||||
calculateMinerTxHash(blob(PROTOCOL_TX_PREFIX_OFFSET), blob(PROTOCOL_TX_PREFIX_END_OFFSET), m_hashes.data() + offset * kHashSize);
|
||||
++offset;
|
||||
}
|
||||
|
||||
for (uint64_t i = 0; i < m_numHashes; ++i) {
|
||||
Span h;
|
||||
ar(h, kHashSize);
|
||||
memcpy(m_hashes.data() + (offset + i) * kHashSize, h.data(), kHashSize);
|
||||
}
|
||||
|
||||
calculateMerkleTreeHash();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool xmrig::BlockTemplate::parseSalviumOutput(BlobReader<true> &ar, uint8_t outputType, bool storeExtraData)
|
||||
{
|
||||
uint64_t asset_type_len = 0;
|
||||
ar(asset_type_len);
|
||||
|
||||
if (asset_type_len > ar.remaining()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (asset_type_len > 0 && !ar.skip(static_cast<size_t>(asset_type_len))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outputType == kTxOutToKey || outputType == kTxOutToTaggedKey) {
|
||||
uint64_t unlock_time = 0;
|
||||
ar(unlock_time);
|
||||
}
|
||||
|
||||
if (outputType == kTxOutToTaggedKey) {
|
||||
uint8_t view_tag = 0;
|
||||
ar(view_tag);
|
||||
|
||||
if (storeExtraData) {
|
||||
m_viewTag = view_tag;
|
||||
}
|
||||
}
|
||||
else if (outputType == kTxOutToCarrotV1) {
|
||||
uint8_t carrot_view_tag[kCarrotViewTagSize];
|
||||
uint8_t carrot_anchor[kCarrotAnchorSize];
|
||||
|
||||
ar(carrot_view_tag);
|
||||
ar(carrot_anchor);
|
||||
|
||||
if (storeExtraData) {
|
||||
memcpy(m_carrotViewTag, carrot_view_tag, kCarrotViewTagSize);
|
||||
memcpy(m_carrotEncryptedJanusAnchor, carrot_anchor, kCarrotAnchorSize);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user