From 8c6c331544a2c4d4ef02a0ce56118a7ec1ed659f Mon Sep 17 00:00:00 2001 From: CliffordST Date: Thu, 3 Jul 2014 14:31:22 +0400 Subject: [PATCH] Major update! Added support for FantomCoin blocks --- src/crypto/hash-ops.h | 3 + src/crypto/hash.h | 10 ++ src/crypto/tree-hash.c | 98 ++++++++++- src/cryptonote_config.h | 3 + src/cryptonote_core/cryptonote_basic.h | 127 +++++++++++++- .../cryptonote_format_utils.cpp | 160 +++++++++++++++++- src/cryptonote_core/cryptonote_format_utils.h | 14 +- src/cryptonote_core/tx_extra.h | 52 +++++- src/main.cc | 100 ++++++++++- src/serialization/binary_utils.h | 2 + src/serialization/crypto.h | 4 + src/serialization/json_utils.h | 2 + src/serialization/serialization.h | 11 +- 13 files changed, 565 insertions(+), 21 deletions(-) diff --git a/src/crypto/hash-ops.h b/src/crypto/hash-ops.h index 950923d..4b73745 100644 --- a/src/crypto/hash-ops.h +++ b/src/crypto/hash-ops.h @@ -61,3 +61,6 @@ void hash_extra_jh(const void *data, size_t length, char *hash); void hash_extra_skein(const void *data, size_t length, char *hash); void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash); +size_t tree_depth(size_t count); +void tree_branch(const char (*hashes)[HASH_SIZE], size_t count, char (*branch)[HASH_SIZE]); +void tree_hash_from_branch(const char (*branch)[HASH_SIZE], size_t depth, const char *leaf, const void *path, char *root_hash); diff --git a/src/crypto/hash.h b/src/crypto/hash.h index fb65494..90bf339 100644 --- a/src/crypto/hash.h +++ b/src/crypto/hash.h @@ -45,6 +45,16 @@ namespace crypto { tree_hash(reinterpret_cast(hashes), count, reinterpret_cast(&root_hash)); } + inline void tree_branch(const hash* hashes, std::size_t count, hash* branch) + { + tree_branch(reinterpret_cast(hashes), count, reinterpret_cast(branch)); + } + + inline void tree_hash_from_branch(const hash* branch, std::size_t depth, const hash& leaf, const void* path, hash& root_hash) + { + tree_hash_from_branch(reinterpret_cast(branch), depth, reinterpret_cast(&leaf), path, reinterpret_cast(&root_hash)); + } + } CRYPTO_MAKE_HASHABLE(hash) diff --git a/src/crypto/tree-hash.c b/src/crypto/tree-hash.c index a2b0eea..19a6a9f 100644 --- a/src/crypto/tree-hash.c +++ b/src/crypto/tree-hash.c @@ -19,14 +19,14 @@ void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) { size_t i, j; size_t cnt = count - 1; char (*ints)[HASH_SIZE]; - for (i = 1; i < sizeof(size_t); i <<= 1) { + for (i = 1; i < sizeof(size_t) << 3; i <<= 1) { cnt |= cnt >> i; } cnt &= ~(cnt >> 1); ints = alloca(cnt * HASH_SIZE); memcpy(ints, hashes, (2 * cnt - count) * HASH_SIZE); for (i = 2 * cnt - count, j = 2 * cnt - count; j < cnt; i += 2, ++j) { - cn_fast_hash(hashes[i], 64, ints[j]); + cn_fast_hash(hashes[i], 2 * HASH_SIZE, ints[j]); } assert(i == count); while (cnt > 2) { @@ -35,6 +35,98 @@ void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) { cn_fast_hash(ints[i], 64, ints[j]); } } - cn_fast_hash(ints[0], 64, root_hash); + cn_fast_hash(ints[0], 2 * HASH_SIZE, root_hash); } } + +size_t tree_depth(size_t count) +{ + size_t i; + size_t depth = 0; + assert(count > 0); + for (i = sizeof(size_t) << 2; i > 0; i >>= 1) + { + if (count >> i > 0) + { + count >>= i; + depth += i; + } + } + return depth; +} + +void tree_branch(const char (*hashes)[HASH_SIZE], size_t count, char (*branch)[HASH_SIZE]) +{ + size_t i, j; + size_t cnt = 1; + size_t depth = 0; + char (*ints)[HASH_SIZE]; + assert(count > 0); + for (i = sizeof(size_t) << 2; i > 0; i >>= 1) + { + if (cnt << i <= count) + { + cnt <<= i; + depth += i; + } + } + assert(cnt == 1ULL << depth); + assert(depth == tree_depth(count)); + ints = alloca((cnt - 1) * HASH_SIZE); + memcpy(ints, hashes + 1, (2 * cnt - count - 1) * HASH_SIZE); + for (i = 2 * cnt - count, j = 2 * cnt - count - 1; j < cnt - 1; i += 2, ++j) + { + cn_fast_hash(hashes[i], 2 * HASH_SIZE, ints[j]); + } + assert(i == count); + while (depth > 0) + { + assert(cnt == 1ULL << depth); + cnt >>= 1; + --depth; + memcpy(branch[depth], ints[0], HASH_SIZE); + for (i = 1, j = 0; j < cnt - 1; i += 2, ++j) + { + cn_fast_hash(ints[i], 2 * HASH_SIZE, ints[j]); + } + } +} + +void tree_hash_from_branch(const char (*branch)[HASH_SIZE], size_t depth, const char* leaf, const void* path, char* root_hash) +{ + if (depth == 0) + { + memcpy(root_hash, leaf, HASH_SIZE); + } + else + { + char buffer[2][HASH_SIZE]; + int from_leaf = 1; + char *leaf_path, *branch_path; + while (depth > 0) + { + --depth; + if (path && (((const char*) path)[depth >> 3] & (1 << (depth & 7))) != 0) + { + leaf_path = buffer[1]; + branch_path = buffer[0]; + } + else + { + leaf_path = buffer[0]; + branch_path = buffer[1]; + } + if (from_leaf) + { + memcpy(leaf_path, leaf, HASH_SIZE); + from_leaf = 0; + } + else + { + cn_fast_hash(buffer, 2 * HASH_SIZE, leaf_path); + } + memcpy(branch_path, branch[depth], HASH_SIZE); + } + cn_fast_hash(buffer, 2 * HASH_SIZE, root_hash); + } +} \ No newline at end of file diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 0af2273..f516b24 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -5,6 +5,9 @@ #define CURRENT_BLOCK_MAJOR_VERSION 1 #define CURRENT_BLOCK_MINOR_VERSION 0 +#define BLOCK_MAJOR_VERSION_1 1 +#define BLOCK_MAJOR_VERSION_2 2 + #define COIN ((uint64_t)100000000) // pow(10, 8) #define DEFAULT_FEE ((uint64_t)1000000) // pow(10, 6) diff --git a/src/cryptonote_core/cryptonote_basic.h b/src/cryptonote_core/cryptonote_basic.h index aee48d0..d59e37b 100644 --- a/src/cryptonote_core/cryptonote_basic.h +++ b/src/cryptonote_core/cryptonote_basic.h @@ -6,6 +6,7 @@ #include #include +#include #include #include // memcmp #include @@ -27,6 +28,13 @@ namespace cryptonote { + struct block; + class transaction; + struct tx_extra_merge_mining_tag; + + // Implemented in cryptonote_format_utils.cpp + bool get_transaction_hash(const transaction& t, crypto::hash& res); + bool get_mm_tag_from_extra(const std::vector& tx, tx_extra_merge_mining_tag& mm_tag); const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash); const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey); @@ -346,35 +354,148 @@ namespace cryptonote /************************************************************************/ /* */ /************************************************************************/ + + const uint8_t CURRENT_BYTECOIN_BLOCK_MAJOR_VERSION = 1; + + struct bytecoin_block + { + uint8_t major_version; + uint8_t minor_version; + crypto::hash prev_id; + uint32_t nonce; + size_t number_of_transactions; + std::vector miner_tx_branch; + transaction miner_tx; + std::vector blockchain_branch; + }; + + struct serializable_bytecoin_block + { + bytecoin_block& b; + uint64_t& timestamp; + bool hashing_serialization; + bool header_only; + + serializable_bytecoin_block(bytecoin_block& b_, uint64_t& timestamp_, bool hashing_serialization_, bool header_only_) : + b(b_), timestamp(timestamp_), hashing_serialization(hashing_serialization_), header_only(header_only_) + { + } + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD_N("major_version", b.major_version); + if(b.major_version > CURRENT_BYTECOIN_BLOCK_MAJOR_VERSION) return false; + VARINT_FIELD_N("minor_version", b.minor_version); + VARINT_FIELD(timestamp); + FIELD_N("prev_id", b.prev_id); + FIELD_N("nonce", b.nonce); + + if (hashing_serialization) + { + crypto::hash miner_tx_hash; + if (!get_transaction_hash(b.miner_tx, miner_tx_hash)) + return false; + + crypto::hash merkle_root; + crypto::tree_hash_from_branch(b.miner_tx_branch.data(), b.miner_tx_branch.size(), miner_tx_hash, 0, merkle_root); + + FIELD(merkle_root); + } + + VARINT_FIELD_N("number_of_transactions", b.number_of_transactions); + if (b.number_of_transactions < 1) + return false; + + if (!header_only) + { + ar.tag("miner_tx_branch"); + ar.begin_array(); + size_t branch_size = crypto::tree_depth(b.number_of_transactions); + PREPARE_CUSTOM_VECTOR_SERIALIZATION(branch_size, const_cast(b).miner_tx_branch); + if (b.miner_tx_branch.size() != branch_size) + return false; + for (size_t i = 0; i < branch_size; ++i) + { + FIELDS(b.miner_tx_branch[i]); + if (i + 1 < branch_size) + ar.delimit_array(); + } + ar.end_array(); + + FIELD(b.miner_tx); + + tx_extra_merge_mining_tag mm_tag; + if (!get_mm_tag_from_extra(b.miner_tx.extra, mm_tag)) + return false; + + ar.tag("blockchain_branch"); + ar.begin_array(); + PREPARE_CUSTOM_VECTOR_SERIALIZATION(mm_tag.depth, const_cast(b).blockchain_branch); + if (mm_tag.depth != b.blockchain_branch.size()) + return false; + for (size_t i = 0; i < mm_tag.depth; ++i) + { + FIELDS(b.blockchain_branch[i]); + if (i + 1 < mm_tag.depth) + ar.delimit_array(); + } + ar.end_array(); + } + END_SERIALIZE() + }; + + // Implemented below + inline serializable_bytecoin_block make_serializable_bytecoin_block(const block& b, bool hashing_serialization, bool header_only); + struct block_header { uint8_t major_version; uint8_t minor_version; uint64_t timestamp; - crypto::hash prev_id; + crypto::hash prev_id; uint32_t nonce; BEGIN_SERIALIZE() VARINT_FIELD(major_version) + if(major_version > BLOCK_MAJOR_VERSION_2) return false; VARINT_FIELD(minor_version) - VARINT_FIELD(timestamp) + if (BLOCK_MAJOR_VERSION_1 == major_version) + { + VARINT_FIELD(timestamp) + } FIELD(prev_id) - FIELD(nonce) + if (BLOCK_MAJOR_VERSION_1 == major_version) + { + FIELD(nonce) + } END_SERIALIZE() }; struct block: public block_header { + bytecoin_block parent_block; + transaction miner_tx; std::vector tx_hashes; BEGIN_SERIALIZE_OBJECT() FIELDS(*static_cast(this)) + if (BLOCK_MAJOR_VERSION_2 <= major_version) + { + auto sbb = make_serializable_bytecoin_block(*this, false, false); + FIELD_N("parent_block", sbb); + } FIELD(miner_tx) FIELD(tx_hashes) END_SERIALIZE() }; + inline serializable_bytecoin_block make_serializable_bytecoin_block(const block& b, bool hashing_serialization, bool header_only) + { + block& block_ref = const_cast(b); + return serializable_bytecoin_block(block_ref.parent_block, block_ref.timestamp, hashing_serialization, header_only); + } + + struct bb_block_header { uint8_t major_version; diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index de42ee4..7d8562b 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -11,6 +11,7 @@ using namespace epee; #include "miner.h" #include "crypto/crypto.h" #include "crypto/hash.h" +#include "serialization/binary_utils.h" namespace cryptonote { @@ -239,8 +240,7 @@ namespace cryptonote crypto::public_key get_tx_pub_key_from_extra(const std::vector& tx_extra) { std::vector tx_extra_fields; - if (!parse_tx_extra(tx_extra, tx_extra_fields)) - return null_pkey; + parse_tx_extra(tx_extra, tx_extra_fields); tx_extra_pub_key pub_key_field; if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field)) @@ -278,6 +278,26 @@ namespace cryptonote return true; } //--------------------------------------------------------------- + bool append_mm_tag_to_extra(std::vector& tx_extra, const tx_extra_merge_mining_tag& mm_tag) + { + blobdata blob; + if (!t_serializable_object_to_blob(mm_tag, blob)) + return false; + + tx_extra.push_back(TX_EXTRA_MERGE_MINING_TAG); + std::copy(reinterpret_cast(blob.data()), reinterpret_cast(blob.data() + blob.size()), std::back_inserter(tx_extra)); + return true; + } + //--------------------------------------------------------------- + bool get_mm_tag_from_extra(const std::vector& tx_extra, tx_extra_merge_mining_tag& mm_tag) + { + std::vector tx_extra_fields; + if (!parse_tx_extra(tx_extra, tx_extra_fields)) + return false; + + return find_tx_extra_field_by_type(tx_extra_fields, mm_tag); + } + //--------------------------------------------------------------- void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id) { extra_nonce.clear(); @@ -599,14 +619,22 @@ namespace cryptonote return get_object_hash(t, res, blob_size); } //--------------------------------------------------------------- - blobdata get_block_hashing_blob(const block& b) + bool get_block_hashing_blob(const block& b, blobdata& blob) { - blobdata blob = t_serializable_object_to_blob(static_cast(b)); + blob = t_serializable_object_to_blob(static_cast(b)); crypto::hash tree_root_hash = get_tx_tree_hash(b); - blob.append((const char*)&tree_root_hash, sizeof(tree_root_hash )); + blob.append(reinterpret_cast(&tree_root_hash), sizeof(tree_root_hash)); blob.append(tools::get_varint_data(b.tx_hashes.size()+1)); - return blob; + + return true; } + //--------------------------------------------------------------- + bool get_bytecoin_block_hashing_blob(const block& b, blobdata& blob) + { + auto sbb = make_serializable_bytecoin_block(b, true, true); + return t_serializable_object_to_blob(sbb, blob); + } + blobdata get_block_hashing_blob(const bb_block& b) { blobdata blob = t_serializable_object_to_blob(static_cast(b)); @@ -618,7 +646,21 @@ namespace cryptonote //--------------------------------------------------------------- bool get_block_hash(const block& b, crypto::hash& res) { - return get_object_hash(get_block_hashing_blob(b), res); + blobdata blob; + if (!get_block_hashing_blob(b, blob)) + return false; + + if (BLOCK_MAJOR_VERSION_2 <= b.major_version) + { + blobdata parent_blob; + auto sbb = make_serializable_bytecoin_block(b, true, false); + if (!t_serializable_object_to_blob(sbb, parent_blob)) + return false; + + blob.append(parent_blob); + } + + return get_object_hash(blob, res); } //--------------------------------------------------------------- crypto::hash get_block_hash(const block& b) @@ -628,6 +670,15 @@ namespace cryptonote return p; } //--------------------------------------------------------------- + bool get_block_header_hash(const block& b, crypto::hash& res) + { + blobdata blob; + if (!get_block_hashing_blob(b, blob)) + return false; + + return get_object_hash(blob, res); + } + //--------------------------------------------------------------- bool generate_genesis_block(block& bl) { //genesis block @@ -655,10 +706,36 @@ namespace cryptonote return true; } //--------------------------------------------------------------- + bool get_genesis_block_hash(crypto::hash& h) + { + static std::atomic cached(false); + static crypto::hash genesis_block_hash; + if (!cached) + { + static std::mutex m; + std::unique_lock lock(m); + if (!cached) + { + block genesis_block; + if (!generate_genesis_block(genesis_block)) + return false; + + if (!get_block_hash(genesis_block, genesis_block_hash)) + return false; + + cached = true; + } + } + + h = genesis_block_hash; + return true; + } + //--------------------------------------------------------------- bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height) { - block b_local = b; //workaround to avoid const errors with do_serialize - blobdata bd = get_block_hashing_blob(b); + blobdata bd; + if(!get_block_hashing_blob(b, bd)) + return false; crypto::cn_slow_hash(bd.data(), bd.size(), res); return true; } @@ -690,6 +767,15 @@ namespace cryptonote return p; } //--------------------------------------------------------------- + bool get_bytecoin_block_longhash(const block& b, crypto::hash& res) + { + blobdata bd; + if(!get_bytecoin_block_hashing_blob(b, bd)) + return false; + crypto::cn_slow_hash(bd.data(), bd.size(), res); + return true; + } + //--------------------------------------------------------------- bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b) { std::stringstream ss; @@ -763,4 +849,60 @@ namespace cryptonote return get_tx_tree_hash(txs_ids); } //--------------------------------------------------------------- + bool check_proof_of_work_v1(const block& bl, difficulty_type current_diffic, crypto::hash& proof_of_work) + { + if (BLOCK_MAJOR_VERSION_1 != bl.major_version) + return false; + + proof_of_work = get_block_longhash(bl, 0); + return check_hash(proof_of_work, current_diffic); + } + //--------------------------------------------------------------- + bool check_proof_of_work_v2(const block& bl, difficulty_type current_diffic, crypto::hash& proof_of_work) + { + if (BLOCK_MAJOR_VERSION_2 != bl.major_version) + return false; + + if (!get_bytecoin_block_longhash(bl, proof_of_work)) + return false; + if (!check_hash(proof_of_work, current_diffic)) + return false; + + tx_extra_merge_mining_tag mm_tag; + if (!get_mm_tag_from_extra(bl.parent_block.miner_tx.extra, mm_tag)) + { + LOG_ERROR("merge mining tag wasn't found in extra of the parent block miner transaction"); + return false; + } + + crypto::hash genesis_block_hash; + if (!get_genesis_block_hash(genesis_block_hash)) + return false; + + if (8 * sizeof(genesis_block_hash) < bl.parent_block.blockchain_branch.size()) + return false; + + crypto::hash aux_block_header_hash; + if (!get_block_header_hash(bl, aux_block_header_hash)) + return false; + + crypto::hash aux_blocks_merkle_root; + crypto::tree_hash_from_branch(bl.parent_block.blockchain_branch.data(), bl.parent_block.blockchain_branch.size(), + aux_block_header_hash, &genesis_block_hash, aux_blocks_merkle_root); + CHECK_AND_NO_ASSERT_MES(aux_blocks_merkle_root == mm_tag.merkle_root, false, "Aux block hash wasn't found in merkle tree"); + + return true; + } + //--------------------------------------------------------------- + bool check_proof_of_work(const block& bl, difficulty_type current_diffic, crypto::hash& proof_of_work) + { + switch (bl.major_version) + { + case BLOCK_MAJOR_VERSION_1: return check_proof_of_work_v1(bl, current_diffic, proof_of_work); + case BLOCK_MAJOR_VERSION_2: return check_proof_of_work_v2(bl, current_diffic, proof_of_work); + } + + CHECK_AND_ASSERT_MES(false, false, "unknown block major version: " << bl.major_version << "." << bl.minor_version); + } + //--------------------------------------------------------------- } diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index 0552760..a91349c 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -5,6 +5,7 @@ #pragma once #include "cryptonote_protocol/cryptonote_protocol_defs.h" #include "cryptonote_core/cryptonote_basic_impl.h" +#include "cryptonote_core/difficulty.h" #include "account.h" #include "include_base_utils.h" #include "crypto/crypto.h" @@ -61,6 +62,8 @@ namespace cryptonote bool add_extra_nonce_to_tx_extra(std::vector& tx_extra, const blobdata& extra_nonce); void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id); bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id); + bool append_mm_tag_to_extra(std::vector& tx_extra, const tx_extra_merge_mining_tag& mm_tag); + bool get_mm_tag_from_extra(const std::vector& tx_extra, tx_extra_merge_mining_tag& mm_tag); bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered); @@ -74,20 +77,23 @@ namespace cryptonote crypto::hash get_transaction_hash(const transaction& t); bool get_transaction_hash(const transaction& t, crypto::hash& res); bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size); - blobdata get_block_hashing_blob(const block& b); + bool get_block_hashing_blob(const block& b, blobdata& blob); + bool get_bytecoin_block_hashing_blob(const block& b, blobdata& blob); blobdata get_block_hashing_blob(const bb_block& b); bool get_block_hash(const block& b, crypto::hash& res); crypto::hash get_block_hash(const block& b); + bool get_block_header_hash(const block& b, crypto::hash& res); bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height); crypto::hash get_block_longhash(const block& b, uint64_t height); + bool get_bytecoin_block_longhash(const block& blk, crypto::hash& res); bool generate_genesis_block(block& bl); + bool get_genesis_block_hash(crypto::hash& h); bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b); bool parse_and_validate_block_from_blob(const blobdata& b_blob, bb_block& b); bool get_inputs_money_amount(const transaction& tx, uint64_t& money); uint64_t get_outs_money_amount(const transaction& tx); bool check_inputs_types_supported(const transaction& tx); bool check_outs_valid(const transaction& tx); - blobdata get_block_hashing_blob(const block& b); bool parse_amount(uint64_t& amount, const std::string& str_amount); bool check_money_overflow(const transaction& tx); @@ -200,6 +206,10 @@ namespace cryptonote crypto::hash get_tx_tree_hash(const block& b); crypto::hash get_tx_tree_hash(const bb_block& b); + bool check_proof_of_work_v1(const block& bl, difficulty_type current_diffic, crypto::hash& proof_of_work); + bool check_proof_of_work_v2(const block& bl, difficulty_type current_diffic, crypto::hash& proof_of_work); + bool check_proof_of_work(const block& bl, difficulty_type current_diffic, crypto::hash& proof_of_work); + #define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val) \ CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \ specific_type& variable_name = boost::get(variant_var); diff --git a/src/cryptonote_core/tx_extra.h b/src/cryptonote_core/tx_extra.h index 8cff085..37a04a4 100644 --- a/src/cryptonote_core/tx_extra.h +++ b/src/cryptonote_core/tx_extra.h @@ -11,6 +11,7 @@ #define TX_EXTRA_TAG_PADDING 0x00 #define TX_EXTRA_TAG_PUBKEY 0x01 #define TX_EXTRA_NONCE 0x02 +#define TX_EXTRA_MERGE_MINING_TAG 0x03 #define TX_EXTRA_NONCE_PAYMENT_ID 0x00 @@ -82,13 +83,62 @@ namespace cryptonote END_SERIALIZE() }; + struct tx_extra_merge_mining_tag + { + struct serialize_helper + { + tx_extra_merge_mining_tag& mm_tag; + + serialize_helper(tx_extra_merge_mining_tag& mm_tag_) : mm_tag(mm_tag_) + { + } + + BEGIN_SERIALIZE() + VARINT_FIELD_N("depth", mm_tag.depth) + FIELD_N("merkle_root", mm_tag.merkle_root) + END_SERIALIZE() + }; + + size_t depth; + crypto::hash merkle_root; + + // load + template