Add sources
This commit is contained in:
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[submodule "external/crypto-algorithms"]
|
||||||
|
path = external/crypto-algorithms
|
||||||
|
url = https://github.com/B-Con/crypto-algorithms
|
||||||
|
[submodule "external/containers"]
|
||||||
|
path = external/containers
|
||||||
|
url = https://github.com/magestik/containers
|
||||||
21
CMakeLists.txt
Normal file
21
CMakeLists.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.3)
|
||||||
|
|
||||||
|
project(blockchain)
|
||||||
|
|
||||||
|
IF(NOT CMAKE_BUILD_TYPE)
|
||||||
|
SET(CMAKE_BUILD_TYPE Debug)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
|
||||||
|
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
|
||||||
|
|
||||||
|
option(ENABLE_ASAN OFF)
|
||||||
|
|
||||||
|
if (ENABLE_ASAN)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
|
endif (ENABLE_ASAN)
|
||||||
|
|
||||||
|
add_subdirectory(external)
|
||||||
|
add_subdirectory(src)
|
||||||
|
add_subdirectory(test)
|
||||||
37
external/CMakeLists.txt
vendored
Normal file
37
external/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
add_subdirectory(containers)
|
||||||
|
|
||||||
|
#############################################
|
||||||
|
|
||||||
|
# MD2
|
||||||
|
|
||||||
|
add_library(md2 STATIC crypto-algorithms/md2.c crypto-algorithms/md2.h)
|
||||||
|
target_include_directories(md2 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/crypto-algorithms/)
|
||||||
|
|
||||||
|
add_executable(md2_test crypto-algorithms/md2_test.c)
|
||||||
|
target_link_libraries(md2_test PRIVATE md2)
|
||||||
|
|
||||||
|
# MD5
|
||||||
|
|
||||||
|
add_library(md5 STATIC crypto-algorithms/md5.c crypto-algorithms/md5.h)
|
||||||
|
target_include_directories(md5 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/crypto-algorithms/)
|
||||||
|
|
||||||
|
add_executable(md5_test crypto-algorithms/md5_test.c)
|
||||||
|
target_link_libraries(md5_test PRIVATE md5)
|
||||||
|
|
||||||
|
# SHA1
|
||||||
|
|
||||||
|
add_library(sha1 STATIC crypto-algorithms/sha1.c crypto-algorithms/sha1.h)
|
||||||
|
target_include_directories(sha1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/crypto-algorithms/)
|
||||||
|
|
||||||
|
add_executable(sha1_test crypto-algorithms/sha1_test.c)
|
||||||
|
target_link_libraries(sha1_test PRIVATE sha1)
|
||||||
|
|
||||||
|
# SHA256
|
||||||
|
|
||||||
|
add_library(sha256 STATIC crypto-algorithms/sha256.c crypto-algorithms/sha256.h)
|
||||||
|
target_include_directories(sha1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/crypto-algorithms/)
|
||||||
|
|
||||||
|
add_executable(sha256_test crypto-algorithms/sha256_test.c)
|
||||||
|
target_link_libraries(sha256_test PRIVATE sha256)
|
||||||
|
|
||||||
1
external/containers
vendored
Submodule
1
external/containers
vendored
Submodule
Submodule external/containers added at 67fa335974
1
external/crypto-algorithms
vendored
Submodule
1
external/crypto-algorithms
vendored
Submodule
Submodule external/crypto-algorithms added at cfbde48414
35
src/Allocator.h
Normal file
35
src/Allocator.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdlib.h> // for malloc/free & realloc
|
||||||
|
|
||||||
|
class HeapAllocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
HeapAllocator(void)
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
~HeapAllocator(void)
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
void * allocate(unsigned int size)
|
||||||
|
{
|
||||||
|
void * ptr = malloc(size);
|
||||||
|
return(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void release(void * ptr)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * resize(void * ptr, unsigned int size)
|
||||||
|
{
|
||||||
|
ptr = realloc(ptr, size);
|
||||||
|
return(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
1
src/Block.cpp
Normal file
1
src/Block.cpp
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include "Block.h"
|
||||||
109
src/Block.h
Normal file
109
src/Block.h
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "base_types.h"
|
||||||
|
|
||||||
|
template<typename HashHeader, typename HashData>
|
||||||
|
struct BlockHeader
|
||||||
|
{
|
||||||
|
BlockHeader(void)
|
||||||
|
{
|
||||||
|
version = 1;
|
||||||
|
timestamp = 0;
|
||||||
|
previousHash = 0;
|
||||||
|
dataHash = 0;
|
||||||
|
nonce = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockHeader(uint32_t version_, uint32_t timestamp_, const HashHeader & previousHash_, const HashData & dataHash_, uint32_t nonce_)
|
||||||
|
{
|
||||||
|
version = version_;
|
||||||
|
timestamp = timestamp_;
|
||||||
|
previousHash = previousHash_;
|
||||||
|
dataHash = dataHash_;
|
||||||
|
nonce = nonce_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getVersion(void) const
|
||||||
|
{
|
||||||
|
return(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getTimestamp(void) const
|
||||||
|
{
|
||||||
|
return(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const HashHeader & getPreviousHash(void) const
|
||||||
|
{
|
||||||
|
return(previousHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
const HashData & getDataHash(void) const
|
||||||
|
{
|
||||||
|
return(dataHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getNonce(void) const
|
||||||
|
{
|
||||||
|
return(nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t timestamp;
|
||||||
|
HashHeader previousHash;
|
||||||
|
HashData dataHash;
|
||||||
|
uint32_t nonce;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<unsigned int BLOCK_SIZE, typename HASH_HEADER, typename HASH_DATA>
|
||||||
|
struct Block
|
||||||
|
{
|
||||||
|
typedef BlockHeader<HASH_HEADER, HASH_DATA> HEADER;
|
||||||
|
typedef HASH_HEADER HASH;
|
||||||
|
enum { SIZE = BLOCK_SIZE };
|
||||||
|
|
||||||
|
Block(void) : header()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < SIZE; ++i)
|
||||||
|
{
|
||||||
|
data[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Block(uint32_t version, uint32_t timestamp, const HASH & previousHash, uint32_t nonce, byte * data_) : header()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < SIZE; ++i)
|
||||||
|
{
|
||||||
|
data[i] = data_[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
HASH_DATA dataHash;
|
||||||
|
dataHash.initFromData(data_, SIZE);
|
||||||
|
|
||||||
|
header = HEADER(version, timestamp, previousHash, dataHash, nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool computeHash(HASH & output_hash) const
|
||||||
|
{
|
||||||
|
// it's ok to compute header hash only
|
||||||
|
// -> the header contains the data hash
|
||||||
|
return(output_hash.initFromData((byte*)&header, sizeof(HEADER)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const HEADER & getHeader(void) const
|
||||||
|
{
|
||||||
|
return(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
const byte * getData(void) const
|
||||||
|
{
|
||||||
|
return(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
HEADER header;
|
||||||
|
byte data [SIZE];
|
||||||
|
};
|
||||||
2
src/Blockchain.cpp
Normal file
2
src/Blockchain.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#include "Blockchain.h"
|
||||||
|
|
||||||
176
src/Blockchain.h
Normal file
176
src/Blockchain.h
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "base_types.h"
|
||||||
|
|
||||||
|
#include "Block.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "Array.h"
|
||||||
|
#include "Allocator.h"
|
||||||
|
|
||||||
|
template<typename BLOCK>
|
||||||
|
class Blockchain
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
INITIAL_VERSION = 1,
|
||||||
|
CURRENT_VERSION = INITIAL_VERSION,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default Constructor
|
||||||
|
*/
|
||||||
|
Blockchain(void) : difficulty(0)
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor with initial difficulty
|
||||||
|
* @param difficulty_
|
||||||
|
*/
|
||||||
|
Blockchain(unsigned int difficulty_) : difficulty(difficulty_)
|
||||||
|
{
|
||||||
|
if (difficulty > BLOCK::HASH::SIZE)
|
||||||
|
{
|
||||||
|
difficulty = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get Current Hash computation difficulty
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
inline unsigned int getCurrentDifficulty(void) const
|
||||||
|
{
|
||||||
|
return(difficulty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get Genesis Block
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
inline const BLOCK & getGenesisBlock(void) const
|
||||||
|
{
|
||||||
|
return(*blocks[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get Genesis Block
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
inline const BLOCK & getCurrentBlock(void) const
|
||||||
|
{
|
||||||
|
return(*blocks[blocks.count()-1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create Genesis Block without data
|
||||||
|
* @param version
|
||||||
|
* @param timestamp
|
||||||
|
* @param output_block
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool CreateGenesisBlock(uint32_t version, uint32_t timestamp, uint32_t nonce, BLOCK & output_block)
|
||||||
|
{
|
||||||
|
return(CreateGenesisBlock(version, timestamp, nonce, nullptr, 0, output_block));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create Genesis Block with data
|
||||||
|
* @param version
|
||||||
|
* @param timestamp
|
||||||
|
* @param output_block
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool CreateGenesisBlock(uint32_t version, uint32_t timestamp, uint32_t nonce, byte * data, unsigned int dataSize, BLOCK & output_block)
|
||||||
|
{
|
||||||
|
if (version != CURRENT_VERSION)
|
||||||
|
{
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
typename BLOCK::HASH empty_hash;
|
||||||
|
|
||||||
|
return(CreateBlockInternal(version, timestamp, empty_hash, nonce, data, dataSize, output_block));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create Block
|
||||||
|
* @param version
|
||||||
|
* @param timestamp
|
||||||
|
* @param previousHash
|
||||||
|
* @param nonce
|
||||||
|
* @param data
|
||||||
|
* @param dataSize
|
||||||
|
* @param output_block
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool CreateBlock(uint32_t version, uint32_t timestamp, const typename BLOCK::HASH & previousHash, uint32_t nonce, byte * data, unsigned int dataSize, BLOCK & output_block)
|
||||||
|
{
|
||||||
|
if (version != CURRENT_VERSION)
|
||||||
|
{
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data == nullptr || dataSize == 0 || dataSize > BLOCK::SIZE)
|
||||||
|
{
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(CreateBlockInternal(version, timestamp, previousHash, nonce, data, dataSize, output_block));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create Block without checking parameters
|
||||||
|
* @param version
|
||||||
|
* @param timestamp
|
||||||
|
* @param previousHash
|
||||||
|
* @param nonce
|
||||||
|
* @param data
|
||||||
|
* @param dataSize
|
||||||
|
* @param output_block
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool CreateBlockInternal(uint32_t version, uint32_t timestamp, const typename BLOCK::HASH & previousHash, uint32_t nonce, byte * data, unsigned int dataSize, BLOCK & output_block)
|
||||||
|
{
|
||||||
|
byte blockData [BLOCK::SIZE];
|
||||||
|
memset(blockData, 0, BLOCK::SIZE);
|
||||||
|
|
||||||
|
if (nullptr != data)
|
||||||
|
{
|
||||||
|
memcpy(blockData, data, dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCK newBlock(version, timestamp, previousHash, nonce, blockData);
|
||||||
|
|
||||||
|
typename BLOCK::HASH H;
|
||||||
|
newBlock.computeHash(H);
|
||||||
|
|
||||||
|
for (int i = 0; i < difficulty; ++i)
|
||||||
|
{
|
||||||
|
if (H[i] != 0)
|
||||||
|
{
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output_block = newBlock;
|
||||||
|
|
||||||
|
blocks.add(&output_block);
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
unsigned int difficulty;
|
||||||
|
|
||||||
|
Array<BLOCK*, HeapAllocator> blocks;
|
||||||
|
};
|
||||||
|
|
||||||
5
src/CMakeLists.txt
Normal file
5
src/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
add_library(blockchain STATIC Block.cpp Block.h Blockchain.cpp Blockchain.h base_types.h)
|
||||||
|
|
||||||
|
target_include_directories(blockchain PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
target_link_libraries(blockchain PUBLIC containers)
|
||||||
5
src/base_types.h
Normal file
5
src/base_types.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
typedef uint8_t byte;
|
||||||
4
test/CMakeLists.txt
Normal file
4
test/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
add_executable(compute_hash compute_hash.cpp Hash.cpp Hash.h)
|
||||||
|
|
||||||
|
target_link_libraries(compute_hash PRIVATE blockchain md5 sha1 sha256)
|
||||||
1
test/Hash.cpp
Normal file
1
test/Hash.cpp
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include "Hash.h"
|
||||||
187
test/Hash.h
Normal file
187
test/Hash.h
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "base_types.h"
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include "md5.h"
|
||||||
|
#include "sha1.h"
|
||||||
|
#include "sha256.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned int HASH_SIZE>
|
||||||
|
struct HashNull
|
||||||
|
{
|
||||||
|
enum { SIZE = HASH_SIZE };
|
||||||
|
|
||||||
|
HashNull(void)
|
||||||
|
{
|
||||||
|
setBytes(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initFromData(const byte * data, unsigned int size)
|
||||||
|
{
|
||||||
|
setBytes(0);
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
HashNull<SIZE> & operator = (byte data)
|
||||||
|
{
|
||||||
|
setBytes(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte operator [] (unsigned int index) const
|
||||||
|
{
|
||||||
|
return(checksum[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void setBytes(byte data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < SIZE; ++i)
|
||||||
|
{
|
||||||
|
checksum[i] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
byte checksum [SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HashMd5
|
||||||
|
{
|
||||||
|
enum { SIZE = 16 }; // 128 bits
|
||||||
|
|
||||||
|
HashMd5(void)
|
||||||
|
{
|
||||||
|
setBytes(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initFromData(byte * data, unsigned int size)
|
||||||
|
{
|
||||||
|
MD5_CTX context;
|
||||||
|
|
||||||
|
md5_init(&context);
|
||||||
|
md5_update(&context, data, size);
|
||||||
|
md5_final(&context, checksum);
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMd5 & operator = (byte data)
|
||||||
|
{
|
||||||
|
setBytes(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte operator [] (unsigned int index) const
|
||||||
|
{
|
||||||
|
return(checksum[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void setBytes(byte data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < SIZE; ++i)
|
||||||
|
{
|
||||||
|
checksum[i] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
byte checksum [SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HashSha1
|
||||||
|
{
|
||||||
|
enum { SIZE = 20 }; // 160 bits
|
||||||
|
|
||||||
|
HashSha1(void)
|
||||||
|
{
|
||||||
|
setBytes(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initFromData(byte * data, unsigned int size)
|
||||||
|
{
|
||||||
|
SHA1_CTX context;
|
||||||
|
|
||||||
|
sha1_init(&context);
|
||||||
|
sha1_update(&context, data, size);
|
||||||
|
sha1_final(&context, checksum);
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
HashSha1 & operator = (byte data)
|
||||||
|
{
|
||||||
|
setBytes(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte operator [] (unsigned int index) const
|
||||||
|
{
|
||||||
|
return(checksum[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void setBytes(byte data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < SIZE; ++i)
|
||||||
|
{
|
||||||
|
checksum[i] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
byte checksum [SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HashSha256
|
||||||
|
{
|
||||||
|
enum { SIZE = 32 }; // 256 bits
|
||||||
|
|
||||||
|
HashSha256(void)
|
||||||
|
{
|
||||||
|
setBytes(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initFromData(byte * data, unsigned int size)
|
||||||
|
{
|
||||||
|
SHA256_CTX context;
|
||||||
|
|
||||||
|
sha256_init(&context);
|
||||||
|
sha256_update(&context, data, size);
|
||||||
|
sha256_final(&context, checksum);
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
HashSha256 & operator = (byte data)
|
||||||
|
{
|
||||||
|
setBytes(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte operator [] (unsigned int index) const
|
||||||
|
{
|
||||||
|
return(checksum[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void setBytes(byte data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < SIZE; ++i)
|
||||||
|
{
|
||||||
|
checksum[i] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
byte checksum [SIZE];
|
||||||
|
};
|
||||||
210
test/compute_hash.cpp
Normal file
210
test/compute_hash.cpp
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
#include "Blockchain.h"
|
||||||
|
|
||||||
|
#include "Hash.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
typedef HashSha256 HASH_HEADER;
|
||||||
|
typedef HashMd5 HASH_DATA;
|
||||||
|
|
||||||
|
typedef Block<1024, HASH_HEADER, HASH_DATA> BLOCK;
|
||||||
|
typedef Blockchain<BLOCK> BLOCKCHAIN;
|
||||||
|
|
||||||
|
const unsigned int DIFFICULTY = 2;
|
||||||
|
|
||||||
|
static inline uint32_t getCurrentTimestamp()
|
||||||
|
{
|
||||||
|
time_t unix_timestamp = time(nullptr);
|
||||||
|
|
||||||
|
if (-1 == unix_timestamp)
|
||||||
|
{
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t timestamp = unix_timestamp & 0xFFFFFFFF; // should be ok for now
|
||||||
|
|
||||||
|
return(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MiningBlockHeader
|
||||||
|
{
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t timestamp;
|
||||||
|
HASH_HEADER previousHash;
|
||||||
|
HASH_DATA dataHash;
|
||||||
|
uint32_t nonce;
|
||||||
|
|
||||||
|
MiningBlockHeader(const BLOCK::HASH & previousBlockHash, byte * data, unsigned int size)
|
||||||
|
{
|
||||||
|
version = 1;
|
||||||
|
timestamp = getCurrentTimestamp();
|
||||||
|
previousHash = previousBlockHash;
|
||||||
|
if (data != nullptr)
|
||||||
|
{
|
||||||
|
dataHash.initFromData(data, size);
|
||||||
|
}
|
||||||
|
nonce = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void print_hash(unsigned char * data, unsigned int size)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
printf("%02x", (unsigned)(*(data+i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool print_block_info(const BLOCK & block)
|
||||||
|
{
|
||||||
|
BLOCK::HASH H;
|
||||||
|
bool success = block.computeHash(H);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Block ");
|
||||||
|
print_hash((unsigned char*)&H, BLOCK::HASH::SIZE);
|
||||||
|
printf(" : \n");
|
||||||
|
|
||||||
|
printf("\t Version : %d\n", block.getHeader().getVersion());
|
||||||
|
printf("\t Timestamp : %d\n", block.getHeader().getTimestamp());
|
||||||
|
|
||||||
|
printf("\t Previous Block : ");
|
||||||
|
print_hash((unsigned char*)&block.getHeader().getPreviousHash(), HASH_HEADER::SIZE);
|
||||||
|
printf(" \n");
|
||||||
|
|
||||||
|
printf("\t Data Hash : ");
|
||||||
|
print_hash((unsigned char*)&block.getHeader().getDataHash(), HASH_DATA::SIZE);
|
||||||
|
printf(" \n");
|
||||||
|
|
||||||
|
printf("\t Nonce : %d\n", block.getHeader().getNonce());
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isHashValidForBlockchain(BLOCKCHAIN & blockchain, const BLOCK::HASH & H)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < blockchain.getCurrentDifficulty(); ++i)
|
||||||
|
{
|
||||||
|
if (H[i] != 0)
|
||||||
|
{
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ComputeNonce(BLOCKCHAIN & blockchain, MiningBlockHeader & parameters)
|
||||||
|
{
|
||||||
|
BLOCK::HASH H;
|
||||||
|
H.initFromData((byte*)¶meters, sizeof(parameters));
|
||||||
|
|
||||||
|
while (!isHashValidForBlockchain(blockchain, H))
|
||||||
|
{
|
||||||
|
++parameters.nonce;
|
||||||
|
if (!H.initFromData((byte*)¶meters, sizeof(parameters)))
|
||||||
|
{
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateGenesisBlock(BLOCKCHAIN & blockchain, byte * data, unsigned int size)
|
||||||
|
{
|
||||||
|
BLOCK::HASH empty_hash;
|
||||||
|
MiningBlockHeader parameters(empty_hash, data, size);
|
||||||
|
ComputeNonce(blockchain, parameters);
|
||||||
|
|
||||||
|
BLOCK block;
|
||||||
|
if (!blockchain.CreateGenesisBlock(parameters.version, parameters.timestamp, parameters.nonce, data, size, block))
|
||||||
|
{
|
||||||
|
printf("Block creation failed !\n");
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCK::HASH H;
|
||||||
|
bool success = block.computeHash(H);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
print_block_info(block);
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreateEmptyGenesisBlock(BLOCKCHAIN & blockchain)
|
||||||
|
{
|
||||||
|
byte no_data [BLOCK::SIZE];
|
||||||
|
memset(no_data, 0, BLOCK::SIZE);
|
||||||
|
|
||||||
|
return(CreateGenesisBlock(blockchain, no_data, BLOCK::SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AddDataToBlockChain(BLOCKCHAIN & blockchain, const BLOCK::HASH & previousBlockHash, byte * data, unsigned int size)
|
||||||
|
{
|
||||||
|
MiningBlockHeader parameters(previousBlockHash, data, size);
|
||||||
|
ComputeNonce(blockchain, parameters);
|
||||||
|
|
||||||
|
BLOCK block;
|
||||||
|
if (!blockchain.CreateBlock(parameters.version, parameters.timestamp, parameters.previousHash, parameters.nonce, data, size, block))
|
||||||
|
{
|
||||||
|
printf("Block creation failed !\n");
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCK::HASH H;
|
||||||
|
bool success = block.computeHash(H);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
print_block_info(block);
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char ** argv)
|
||||||
|
{
|
||||||
|
BLOCKCHAIN blockchain(DIFFICULTY);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create Genesis Block
|
||||||
|
if (!CreateEmptyGenesisBlock(blockchain))
|
||||||
|
{
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCK::HASH H;
|
||||||
|
|
||||||
|
const BLOCK & genesis = blockchain.getGenesisBlock();
|
||||||
|
genesis.computeHash(H);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create some Block
|
||||||
|
byte random_data [BLOCK::SIZE];
|
||||||
|
memset(random_data, 0, BLOCK::SIZE);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
{
|
||||||
|
AddDataToBlockChain(blockchain, H, random_data, BLOCK::SIZE);
|
||||||
|
|
||||||
|
const BLOCK & current = blockchain.getCurrentBlock();
|
||||||
|
current.computeHash(H);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user