Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/crypto/hash-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
10 changes: 10 additions & 0 deletions src/crypto/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
98 changes: 95 additions & 3 deletions src/crypto/tree-hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
}
}
3 changes: 3 additions & 0 deletions src/cryptonote_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
127 changes: 124 additions & 3 deletions src/cryptonote_core/cryptonote_basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <boost/variant.hpp>
#include <boost/functional/hash/hash.hpp>
#include <iostream>
#include <vector>
#include <cstring> // memcmp
#include <sstream>
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
Loading