Major update! Added support for FantomCoin blocks

This commit is contained in:
CliffordST
2014-07-03 14:31:22 +04:00
parent 71f1a6d8c2
commit 8c6c331544
13 changed files with 565 additions and 21 deletions
+124 -3
View File
@@ -6,6 +6,7 @@
#include <boost/variant.hpp>
#include <boost/functional/hash/hash.hpp>
#include <iostream>
#include <vector>
#include <cstring> // memcmp
#include <sstream>
@@ -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<uint8_t>& 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<crypto::hash> miner_tx_branch;
transaction miner_tx;
std::vector<crypto::hash> 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<bytecoin_block&>(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<bytecoin_block&>(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<crypto::hash> tx_hashes;
BEGIN_SERIALIZE_OBJECT()
FIELDS(*static_cast<block_header *>(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<block&>(b);
return serializable_bytecoin_block(block_ref.parent_block, block_ref.timestamp, hashing_serialization, header_only);
}
struct bb_block_header
{
uint8_t major_version;
+151 -9
View File
@@ -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<uint8_t>& tx_extra)
{
std::vector<tx_extra_field> 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<uint8_t>& 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<const uint8_t*>(blob.data()), reinterpret_cast<const uint8_t*>(blob.data() + blob.size()), std::back_inserter(tx_extra));
return true;
}
//---------------------------------------------------------------
bool get_mm_tag_from_extra(const std::vector<uint8_t>& tx_extra, tx_extra_merge_mining_tag& mm_tag)
{
std::vector<tx_extra_field> 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<block_header>(b));
blob = t_serializable_object_to_blob(static_cast<const block_header&>(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<const char*>(&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<bb_block_header>(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<bool> cached(false);
static crypto::hash genesis_block_hash;
if (!cached)
{
static std::mutex m;
std::unique_lock<std::mutex> 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);
}
//---------------------------------------------------------------
}
+12 -2
View File
@@ -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<uint8_t>& 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<uint8_t>& tx_extra, const tx_extra_merge_mining_tag& mm_tag);
bool get_mm_tag_from_extra(const std::vector<uint8_t>& 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<size_t>& outs, uint64_t& money_transfered);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& 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<specific_type>(variant_var);
+51 -1
View File
@@ -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 <template <bool> class Archive>
bool do_serialize(Archive<false>& ar)
{
std::string field;
if(!::do_serialize(ar, field))
return false;
std::istringstream iss(field);
binary_archive<false> iar(iss);
serialize_helper helper(*this);
return ::serialization::serialize(iar, helper);
}
// store
template <template <bool> class Archive>
bool do_serialize(Archive<true>& ar)
{
std::ostringstream oss;
binary_archive<true> oar(oss);
serialize_helper helper(*this);
if(!::do_serialize(oar, helper))
return false;
std::string field = oss.str();
return ::serialization::serialize(ar, field);
}
};
// tx_extra_field format, except tx_extra_padding and tx_extra_pub_key:
// varint tag;
// varint size;
// varint data[];
typedef boost::variant<tx_extra_padding, tx_extra_pub_key, tx_extra_nonce> tx_extra_field;
typedef boost::variant<tx_extra_padding, tx_extra_pub_key, tx_extra_nonce, tx_extra_merge_mining_tag> tx_extra_field;
}
VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_pub_key, TX_EXTRA_TAG_PUBKEY);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG);