Merge branch 'fantomcoin_support'
commit
a3a3cb69af
|
@ -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 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);
|
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);
|
||||||
|
|
|
@ -45,6 +45,16 @@ namespace crypto {
|
||||||
tree_hash(reinterpret_cast<const char (*)[HASH_SIZE]>(hashes), count, reinterpret_cast<char *>(&root_hash));
|
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)
|
CRYPTO_MAKE_HASHABLE(hash)
|
||||||
|
|
|
@ -19,14 +19,14 @@ void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) {
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
size_t cnt = count - 1;
|
size_t cnt = count - 1;
|
||||||
char (*ints)[HASH_SIZE];
|
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 >> i;
|
||||||
}
|
}
|
||||||
cnt &= ~(cnt >> 1);
|
cnt &= ~(cnt >> 1);
|
||||||
ints = alloca(cnt * HASH_SIZE);
|
ints = alloca(cnt * HASH_SIZE);
|
||||||
memcpy(ints, hashes, (2 * cnt - count) * HASH_SIZE);
|
memcpy(ints, hashes, (2 * cnt - count) * HASH_SIZE);
|
||||||
for (i = 2 * cnt - count, j = 2 * cnt - count; j < cnt; i += 2, ++j) {
|
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);
|
assert(i == count);
|
||||||
while (cnt > 2) {
|
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[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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,9 @@
|
||||||
#define CURRENT_BLOCK_MAJOR_VERSION 1
|
#define CURRENT_BLOCK_MAJOR_VERSION 1
|
||||||
#define CURRENT_BLOCK_MINOR_VERSION 0
|
#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 COIN ((uint64_t)100000000) // pow(10, 8)
|
||||||
#define DEFAULT_FEE ((uint64_t)1000000) // pow(10, 6)
|
#define DEFAULT_FEE ((uint64_t)1000000) // pow(10, 6)
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
#include <boost/variant.hpp>
|
||||||
#include <boost/functional/hash/hash.hpp>
|
#include <boost/functional/hash/hash.hpp>
|
||||||
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstring> // memcmp
|
#include <cstring> // memcmp
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -27,6 +28,13 @@
|
||||||
|
|
||||||
namespace cryptonote
|
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::hash null_hash = AUTO_VAL_INIT(null_hash);
|
||||||
const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey);
|
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
|
struct block_header
|
||||||
{
|
{
|
||||||
uint8_t major_version;
|
uint8_t major_version;
|
||||||
uint8_t minor_version;
|
uint8_t minor_version;
|
||||||
uint64_t timestamp;
|
uint64_t timestamp;
|
||||||
crypto::hash prev_id;
|
crypto::hash prev_id;
|
||||||
uint32_t nonce;
|
uint32_t nonce;
|
||||||
|
|
||||||
BEGIN_SERIALIZE()
|
BEGIN_SERIALIZE()
|
||||||
VARINT_FIELD(major_version)
|
VARINT_FIELD(major_version)
|
||||||
|
if(major_version > BLOCK_MAJOR_VERSION_2) return false;
|
||||||
VARINT_FIELD(minor_version)
|
VARINT_FIELD(minor_version)
|
||||||
VARINT_FIELD(timestamp)
|
if (BLOCK_MAJOR_VERSION_1 == major_version)
|
||||||
|
{
|
||||||
|
VARINT_FIELD(timestamp)
|
||||||
|
}
|
||||||
FIELD(prev_id)
|
FIELD(prev_id)
|
||||||
FIELD(nonce)
|
if (BLOCK_MAJOR_VERSION_1 == major_version)
|
||||||
|
{
|
||||||
|
FIELD(nonce)
|
||||||
|
}
|
||||||
END_SERIALIZE()
|
END_SERIALIZE()
|
||||||
};
|
};
|
||||||
|
|
||||||
struct block: public block_header
|
struct block: public block_header
|
||||||
{
|
{
|
||||||
|
bytecoin_block parent_block;
|
||||||
|
|
||||||
transaction miner_tx;
|
transaction miner_tx;
|
||||||
std::vector<crypto::hash> tx_hashes;
|
std::vector<crypto::hash> tx_hashes;
|
||||||
|
|
||||||
BEGIN_SERIALIZE_OBJECT()
|
BEGIN_SERIALIZE_OBJECT()
|
||||||
FIELDS(*static_cast<block_header *>(this))
|
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(miner_tx)
|
||||||
FIELD(tx_hashes)
|
FIELD(tx_hashes)
|
||||||
END_SERIALIZE()
|
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
|
struct bb_block_header
|
||||||
{
|
{
|
||||||
uint8_t major_version;
|
uint8_t major_version;
|
||||||
|
|
|
@ -11,6 +11,7 @@ using namespace epee;
|
||||||
#include "miner.h"
|
#include "miner.h"
|
||||||
#include "crypto/crypto.h"
|
#include "crypto/crypto.h"
|
||||||
#include "crypto/hash.h"
|
#include "crypto/hash.h"
|
||||||
|
#include "serialization/binary_utils.h"
|
||||||
|
|
||||||
namespace cryptonote
|
namespace cryptonote
|
||||||
{
|
{
|
||||||
|
@ -239,8 +240,7 @@ namespace cryptonote
|
||||||
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra)
|
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra)
|
||||||
{
|
{
|
||||||
std::vector<tx_extra_field> tx_extra_fields;
|
std::vector<tx_extra_field> tx_extra_fields;
|
||||||
if (!parse_tx_extra(tx_extra, tx_extra_fields))
|
parse_tx_extra(tx_extra, tx_extra_fields);
|
||||||
return null_pkey;
|
|
||||||
|
|
||||||
tx_extra_pub_key pub_key_field;
|
tx_extra_pub_key pub_key_field;
|
||||||
if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field))
|
if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field))
|
||||||
|
@ -278,6 +278,26 @@ namespace cryptonote
|
||||||
return true;
|
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)
|
void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id)
|
||||||
{
|
{
|
||||||
extra_nonce.clear();
|
extra_nonce.clear();
|
||||||
|
@ -599,14 +619,22 @@ namespace cryptonote
|
||||||
return get_object_hash(t, res, blob_size);
|
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);
|
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));
|
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 get_block_hashing_blob(const bb_block& b)
|
||||||
{
|
{
|
||||||
blobdata blob = t_serializable_object_to_blob(static_cast<bb_block_header>(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)
|
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)
|
crypto::hash get_block_hash(const block& b)
|
||||||
|
@ -628,6 +670,15 @@ namespace cryptonote
|
||||||
return p;
|
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)
|
bool generate_genesis_block(block& bl)
|
||||||
{
|
{
|
||||||
//genesis block
|
//genesis block
|
||||||
|
@ -655,10 +706,36 @@ namespace cryptonote
|
||||||
return true;
|
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)
|
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;
|
||||||
blobdata bd = get_block_hashing_blob(b);
|
if(!get_block_hashing_blob(b, bd))
|
||||||
|
return false;
|
||||||
crypto::cn_slow_hash(bd.data(), bd.size(), res);
|
crypto::cn_slow_hash(bd.data(), bd.size(), res);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -690,6 +767,15 @@ namespace cryptonote
|
||||||
return p;
|
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)
|
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -763,4 +849,60 @@ namespace cryptonote
|
||||||
return get_tx_tree_hash(txs_ids);
|
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);
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||||
#include "cryptonote_core/cryptonote_basic_impl.h"
|
#include "cryptonote_core/cryptonote_basic_impl.h"
|
||||||
|
#include "cryptonote_core/difficulty.h"
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "include_base_utils.h"
|
#include "include_base_utils.h"
|
||||||
#include "crypto/crypto.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);
|
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);
|
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 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 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, 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);
|
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);
|
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);
|
||||||
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size);
|
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);
|
blobdata get_block_hashing_blob(const bb_block& b);
|
||||||
bool get_block_hash(const block& b, crypto::hash& res);
|
bool get_block_hash(const block& b, crypto::hash& res);
|
||||||
crypto::hash get_block_hash(const block& b);
|
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);
|
bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height);
|
||||||
crypto::hash get_block_longhash(const block& b, 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 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, block& b);
|
||||||
bool parse_and_validate_block_from_blob(const blobdata& b_blob, bb_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);
|
bool get_inputs_money_amount(const transaction& tx, uint64_t& money);
|
||||||
uint64_t get_outs_money_amount(const transaction& tx);
|
uint64_t get_outs_money_amount(const transaction& tx);
|
||||||
bool check_inputs_types_supported(const transaction& tx);
|
bool check_inputs_types_supported(const transaction& tx);
|
||||||
bool check_outs_valid(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 parse_amount(uint64_t& amount, const std::string& str_amount);
|
||||||
|
|
||||||
bool check_money_overflow(const transaction& tx);
|
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 block& b);
|
||||||
crypto::hash get_tx_tree_hash(const bb_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) \
|
#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()); \
|
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);
|
specific_type& variable_name = boost::get<specific_type>(variant_var);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#define TX_EXTRA_TAG_PADDING 0x00
|
#define TX_EXTRA_TAG_PADDING 0x00
|
||||||
#define TX_EXTRA_TAG_PUBKEY 0x01
|
#define TX_EXTRA_TAG_PUBKEY 0x01
|
||||||
#define TX_EXTRA_NONCE 0x02
|
#define TX_EXTRA_NONCE 0x02
|
||||||
|
#define TX_EXTRA_MERGE_MINING_TAG 0x03
|
||||||
|
|
||||||
#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
|
#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
|
||||||
|
|
||||||
|
@ -82,13 +83,62 @@ namespace cryptonote
|
||||||
END_SERIALIZE()
|
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:
|
// tx_extra_field format, except tx_extra_padding and tx_extra_pub_key:
|
||||||
// varint tag;
|
// varint tag;
|
||||||
// varint size;
|
// varint size;
|
||||||
// varint data[];
|
// 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_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_pub_key, TX_EXTRA_TAG_PUBKEY);
|
||||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE);
|
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);
|
||||||
|
|
100
src/main.cc
100
src/main.cc
|
@ -32,6 +32,49 @@ blobdata uint64be_to_blob(uint64_t num) {
|
||||||
return res;
|
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) {
|
Handle<Value> convert_blob(const Arguments& args) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
|
@ -48,10 +91,62 @@ Handle<Value> convert_blob(const Arguments& args) {
|
||||||
|
|
||||||
//convert
|
//convert
|
||||||
block b = AUTO_VAL_INIT(b);
|
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");
|
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());
|
Buffer* buff = Buffer::New(output.data(), output.size());
|
||||||
return scope.Close(buff->handle_);
|
return scope.Close(buff->handle_);
|
||||||
|
@ -108,6 +203,7 @@ Handle<Value> address_decode(const Arguments& args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(Handle<Object> exports) {
|
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"), FunctionTemplate::New(convert_blob)->GetFunction());
|
||||||
exports->Set(String::NewSymbol("convert_blob_bb"), FunctionTemplate::New(convert_blob_bb)->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());
|
exports->Set(String::NewSymbol("address_decode"), FunctionTemplate::New(address_decode)->GetFunction());
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Distributed under the MIT/X11 software license, see the accompanying
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "binary_archive.h"
|
#include "binary_archive.h"
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
// Distributed under the MIT/X11 software license, see the accompanying
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "serialization.h"
|
#include "serialization.h"
|
||||||
#include "debug_archive.h"
|
#include "debug_archive.h"
|
||||||
#include "crypto/chacha8.h"
|
#include "crypto/chacha8.h"
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
// Distributed under the MIT/X11 software license, see the accompanying
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "json_archive.h"
|
#include "json_archive.h"
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <boost/type_traits/is_integral.hpp>
|
#include <boost/type_traits/is_integral.hpp>
|
||||||
|
#include <boost/type_traits/integral_constant.hpp>
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct is_blob_type { typedef boost::false_type type; };
|
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; \
|
if (!r || !ar.stream().good()) return false; \
|
||||||
} while(0);
|
} while(0);
|
||||||
#define FIELDS(f) \
|
#define FIELDS(f) \
|
||||||
|
do { \
|
||||||
bool r = ::do_serialize(ar, f); \
|
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) \
|
#define FIELD(f) \
|
||||||
do { \
|
do { \
|
||||||
ar.tag(#f); \
|
ar.tag(#f); \
|
||||||
|
@ -93,6 +96,12 @@ inline bool do_serialize(Archive &ar, T &v)
|
||||||
ar.serialize_varint(f); \
|
ar.serialize_varint(f); \
|
||||||
if (!ar.stream().good()) return false; \
|
if (!ar.stream().good()) return false; \
|
||||||
} while(0);
|
} 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 serialization {
|
||||||
namespace detail
|
namespace detail
|
||||||
|
|
Loading…
Reference in New Issue