Major update! Added support for FantomCoin blocks

fantomcoin_support
CliffordST 2014-07-03 14:31:22 +04:00
parent 71f1a6d8c2
commit 8c6c331544
13 changed files with 565 additions and 21 deletions

View File

@ -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);

View File

@ -45,6 +45,16 @@ namespace crypto {
tree_hash(reinterpret_cast<const char (*)[HASH_SIZE]>(hashes), count, reinterpret_cast<char *>(&root_hash));
}
inline void tree_branch(const hash* hashes, std::size_t count, hash* branch)
{
tree_branch(reinterpret_cast<const char (*)[HASH_SIZE]>(hashes), count, reinterpret_cast<char (*)[HASH_SIZE]>(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<const char (*)[HASH_SIZE]>(branch), depth, reinterpret_cast<const char*>(&leaf), path, reinterpret_cast<char*>(&root_hash));
}
}
CRYPTO_MAKE_HASHABLE(hash)

View File

@ -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);
}
}

View File

@ -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)

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;

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);
}
//---------------------------------------------------------------
}

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);

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);

View File

@ -32,6 +32,49 @@ blobdata uint64be_to_blob(uint64_t num) {
return res;
}
static bool fillExtra(cryptonote::block& block1, const cryptonote::block& block2) {
cryptonote::tx_extra_merge_mining_tag mm_tag;
mm_tag.depth = 0;
if (!cryptonote::get_block_header_hash(block2, mm_tag.merkle_root))
return false;
block1.miner_tx.extra.clear();
if (!cryptonote::append_mm_tag_to_extra(block1.miner_tx.extra, mm_tag))
return false;
return true;
}
static bool mergeBlocks(const cryptonote::block& block1, cryptonote::block& block2, const std::vector<crypto::hash>& branch2) {
block2.timestamp = block1.timestamp;
block2.parent_block.major_version = block1.major_version;
block2.parent_block.minor_version = block1.minor_version;
block2.parent_block.prev_id = block1.prev_id;
block2.parent_block.nonce = block1.nonce;
block2.parent_block.miner_tx = block1.miner_tx;
block2.parent_block.number_of_transactions = block1.tx_hashes.size() + 1;
block2.parent_block.miner_tx_branch.resize(crypto::tree_depth(block1.tx_hashes.size() + 1));
std::vector<crypto::hash> transactionHashes;
transactionHashes.push_back(cryptonote::get_transaction_hash(block1.miner_tx));
std::copy(block1.tx_hashes.begin(), block1.tx_hashes.end(), std::back_inserter(transactionHashes));
tree_branch(transactionHashes.data(), transactionHashes.size(), block2.parent_block.miner_tx_branch.data());
block2.parent_block.blockchain_branch = branch2;
return true;
}
static bool construct_parent_block(const cryptonote::block& b, cryptonote::block& parent_block) {
parent_block.major_version = 1;
parent_block.minor_version = 0;
parent_block.timestamp = b.timestamp;
parent_block.prev_id = b.prev_id;
parent_block.nonce = b.parent_block.nonce;
parent_block.miner_tx.version = CURRENT_TRANSACTION_VERSION;
parent_block.miner_tx.unlock_time = 0;
return fillExtra(parent_block, b);
}
Handle<Value> convert_blob(const Arguments& args) {
HandleScope scope;
@ -48,10 +91,62 @@ Handle<Value> convert_blob(const Arguments& args) {
//convert
block b = AUTO_VAL_INIT(b);
if (!parse_and_validate_block_from_blob(input, b)) {
if (!parse_and_validate_block_from_blob(input, b))
return except("Failed to parse block");
if (b.major_version < BLOCK_MAJOR_VERSION_2) {
if (!get_block_hashing_blob(b, output))
return except("Failed to create mining block");
} else {
block parent_block;
if (!construct_parent_block(b, parent_block))
return except("Failed to construct parent block");
if (!get_block_hashing_blob(parent_block, output))
return except("Failed to create mining block");
}
output = get_block_hashing_blob(b);
Buffer* buff = Buffer::New(output.data(), output.size());
return scope.Close(buff->handle_);
}
Handle<Value> construct_block_blob(const Arguments& args) {
HandleScope scope;
if (args.Length() < 2)
return except("You must provide two arguments.");
Local<Object> block_template_buf = args[0]->ToObject();
Local<Object> nonce_buf = args[1]->ToObject();
if (!Buffer::HasInstance(block_template_buf) || !Buffer::HasInstance(nonce_buf))
return except("Both arguments should be buffer objects.");
if (Buffer::Length(nonce_buf) != 4)
return except("Nonce buffer has invalid size.");
uint32_t nonce = *reinterpret_cast<uint32_t*>(Buffer::Data(nonce_buf));
blobdata block_template_blob = std::string(Buffer::Data(block_template_buf), Buffer::Length(block_template_buf));
blobdata output = "";
block b = AUTO_VAL_INIT(b);
if (!parse_and_validate_block_from_blob(block_template_blob, b))
return except("Failed to parse block");
b.nonce = nonce;
if (b.major_version == BLOCK_MAJOR_VERSION_2) {
block parent_block;
b.parent_block.nonce = nonce;
if (!construct_parent_block(b, parent_block))
return except("Failed to construct parent block");
if (!mergeBlocks(parent_block, b, std::vector<crypto::hash>()))
return except("Failed to postprocess mining block");
}
if (!block_to_blob(b, output))
return except("Failed to convert block to blob");
Buffer* buff = Buffer::New(output.data(), output.size());
return scope.Close(buff->handle_);
@ -108,6 +203,7 @@ Handle<Value> address_decode(const Arguments& args) {
}
void init(Handle<Object> exports) {
exports->Set(String::NewSymbol("construct_block_blob"), FunctionTemplate::New(construct_block_blob)->GetFunction());
exports->Set(String::NewSymbol("convert_blob"), FunctionTemplate::New(convert_blob)->GetFunction());
exports->Set(String::NewSymbol("convert_blob_bb"), FunctionTemplate::New(convert_blob_bb)->GetFunction());
exports->Set(String::NewSymbol("address_decode"), FunctionTemplate::New(address_decode)->GetFunction());

View File

@ -2,6 +2,8 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include <sstream>
#include "binary_archive.h"

View File

@ -2,6 +2,10 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include <vector>
#include "serialization.h"
#include "debug_archive.h"
#include "crypto/chacha8.h"

View File

@ -2,6 +2,8 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include <sstream>
#include "json_archive.h"

View File

@ -10,6 +10,7 @@
#include <vector>
#include <string>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/integral_constant.hpp>
template <class T>
struct is_blob_type { typedef boost::false_type type; };
@ -79,8 +80,10 @@ inline bool do_serialize(Archive &ar, T &v)
if (!r || !ar.stream().good()) return false; \
} while(0);
#define FIELDS(f) \
do { \
bool r = ::do_serialize(ar, f); \
if (!r || !ar.stream().good()) return false;
if (!r || !ar.stream().good()) return false; \
} while(0);
#define FIELD(f) \
do { \
ar.tag(#f); \
@ -93,6 +96,12 @@ inline bool do_serialize(Archive &ar, T &v)
ar.serialize_varint(f); \
if (!ar.stream().good()) return false; \
} while(0);
#define VARINT_FIELD_N(t, f) \
do { \
ar.tag(t); \
ar.serialize_varint(f); \
if (!ar.stream().good()) return false; \
} while(0);
namespace serialization {
namespace detail