211 lines
4.1 KiB
C++
211 lines
4.1 KiB
C++
#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);
|
|
}
|