diff --git a/src/block_template.cpp b/src/block_template.cpp index 34b7138..783e774 100644 --- a/src/block_template.cpp +++ b/src/block_template.cpp @@ -596,6 +596,32 @@ void BlockTemplate::update(const MinerData& data, const Mempool& mempool, const m_minerTxOffsetInTemplate = m_blockHeader.size(); m_minerTxSize = m_minerTx.size(); m_blockTemplateBlob.insert(m_blockTemplateBlob.end(), m_minerTx.begin(), m_minerTx.end()); + + // Add protocol_tx for Salvium Carrot v1+ + if (data.major_version >= 10) { + writeVarint(4, m_blockTemplateBlob); // version = TRANSACTION_VERSION_CARROT + writeVarint(60, m_blockTemplateBlob); // unlock_time = 60 + + // vin (1 txin_gen) + writeVarint(1, m_blockTemplateBlob); // vin.size() = 1 + m_blockTemplateBlob.push_back(TXIN_GEN); + writeVarint(data.height, m_blockTemplateBlob); + + // vout (empty) + writeVarint(0, m_blockTemplateBlob); // vout.size() = 0 + + // extra (2 bytes: 0x02 0x00) + writeVarint(2, m_blockTemplateBlob); // extra.size() = 2 + m_blockTemplateBlob.push_back(0x02); + m_blockTemplateBlob.push_back(0x00); + + // type = PROTOCOL + writeVarint(2, m_blockTemplateBlob); // transaction_type::PROTOCOL = 2 + + // rct_signatures (null) + m_blockTemplateBlob.push_back(0); // RCTTypeNull + } + writeVarint(m_numTransactionHashes, m_blockTemplateBlob); // Miner tx hash is skipped here because it's not a part of block template diff --git a/src/pool_block.cpp b/src/pool_block.cpp index b12ee10..9789922 100644 --- a/src/pool_block.cpp +++ b/src/pool_block.cpp @@ -228,31 +228,6 @@ std::vector PoolBlock::serialize_mainchain_data(size_t* header_size, si *miner_tx_size = data.size() - header_size0; } - // Protocol tx (required for Salvium) - if (m_majorVersion >= 10) { - data.push_back(4); // version = TRANSACTION_VERSION_CARROT - writeVarint(60, data); // unlock_time = 60 - - // vin (1 txin_gen) - data.push_back(1); // vin.size() = 1 - data.push_back(TXIN_GEN); - writeVarint(m_txinGenHeight, data); - - // vout (empty) - data.push_back(0); // vout.size() = 0 - - // extra (2 bytes: 0x02 0x00) - data.push_back(2); // extra.size() = 2 - data.push_back(0x02); - data.push_back(0x00); - - // type = PROTOCOL - writeVarint(2, data); // transaction_type::PROTOCOL = 2 - - // rct_signatures (null) - data.push_back(0); // RCTTypeNull - } - writeVarint(m_transactions.size() - 1, data); #ifdef WITH_INDEXED_HASHES diff --git a/src/pool_block_parser.inl b/src/pool_block_parser.inl index 2c2c4e5..343d46c 100644 --- a/src/pool_block_parser.inl +++ b/src/pool_block_parser.inl @@ -219,9 +219,74 @@ int PoolBlock::deserialize(const uint8_t* data, size_t size, const SideChain& si if (static_cast(data - tx_extra_begin) != tx_extra_size) return __LINE__; EXPECT_BYTE(0); - - uint64_t num_transactions; - READ_VARINT(num_transactions); + + // Protocol TX (Salvium Carrot v1+) - parse if present + if (m_majorVersion >= 10) { + // Save position in case we need to backtrack + const uint8_t* saved_pos = data; + + uint64_t next_val; + const uint8_t* peek = readVarint(data, data_end, next_val); + + // Check if this looks like protocol_tx (version 4) or num_transactions + // num_transactions is typically 0-100, protocol version is 4 + if (peek && next_val == 4) { + // Likely protocol_tx, try to parse it + data = peek; // Consume the version varint + + uint64_t protocol_unlock_time; + data = readVarint(data, data_end, protocol_unlock_time); + if (!data) { data = saved_pos; goto skip_protocol_tx; } + + uint64_t protocol_vin_size; + data = readVarint(data, data_end, protocol_vin_size); + if (!data || protocol_vin_size != 1) { data = saved_pos; goto skip_protocol_tx; } + + uint8_t txin_type; + READ_BYTE(txin_type); + if (txin_type != TXIN_GEN) { data = saved_pos; goto skip_protocol_tx; } + + uint64_t protocol_height; + data = readVarint(data, data_end, protocol_height); + if (!data) { data = saved_pos; goto skip_protocol_tx; } + + uint64_t protocol_vout_size; + data = readVarint(data, data_end, protocol_vout_size); + if (!data) { data = saved_pos; goto skip_protocol_tx; } + + // Skip vout if any + for (uint64_t i = 0; i < protocol_vout_size; ++i) { + uint64_t amount; + data = readVarint(data, data_end, amount); + if (!data) { data = saved_pos; goto skip_protocol_tx; } + uint8_t type; + READ_BYTE(type); + // Skip output data based on type + if (!read_buf(nullptr, 32)) { data = saved_pos; goto skip_protocol_tx; } + } + + uint64_t protocol_extra_size; + data = readVarint(data, data_end, protocol_extra_size); + if (!data) { data = saved_pos; goto skip_protocol_tx; } + + for (uint64_t i = 0; i < protocol_extra_size; ++i) { + uint8_t tmp; + READ_BYTE(tmp); + } + + uint64_t protocol_type; + data = readVarint(data, data_end, protocol_type); + if (!data) { data = saved_pos; goto skip_protocol_tx; } + + uint8_t rct; + READ_BYTE(rct); + if (rct != 0) { data = saved_pos; goto skip_protocol_tx; } + } + } + +skip_protocol_tx: + uint64_t num_transactions; + READ_VARINT(num_transactions); const int transactions_offset = static_cast(data - data_begin);