在以太坊区块链上添加一个区块

发布时间 2023-10-26 21:40:55作者: 真昼小天使daisuki

包括json库的相关读取,proof-of-work算法的实现,Merkel Tree的构建,使用hash创建新块等内容,使用本地json文件模拟mempool和block chain,C++编写。

#include <iostream>
#include <fstream>
#include <string>
#include <nlohmann/json.hpp>
#include <zlib.h>
#include <openssl/sha.h>

using namespace std;
using json = nlohmann::json;

/*{"header":{
"difficulty":3,
"height":120,
"miner":"0xca4388fb6d0ee25d59c24360e49c2dd4c9d02727",  
"nonce":320,
"hash":"0x000a3698e344f2549cb88537e129a37ac78e195c08006486f928cc465bcc0550",
"previous_block_header_hash":"0x000232491f11addef82c7217de3c8f03873975442192fe6e41437bd6584585c8",
"timestamp":1697413800,
"transactions_count":70,
"transactions_merkle_root":"0xdc73d314ad97973cfcebff8ae6c5f06d545156a543be949ed237f1ca9ac3f70f"},*/

/*transaction
{
" receiver ": "0 xb0d7e24e8818e78878c116e73ea6a081d1f12b7d ",
" lock_time ": 0,
" transaction_fee ": 86 ,
" amount ": 72619 ,
" sender ": "0 x3a55c9e459c0c5b744fa4839d5e833af96c503be ",
" signature ": "0 x305930130 ... f78a667 "
}*/


string sha256_my(const string str)
{
    char buf[2];
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    SHA256_Update(&sha256, str.c_str(), str.size());
    SHA256_Final(hash, &sha256);
    std::string NewString = "";
    for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        sprintf(buf,"%02x",hash[i]);
        NewString = NewString + buf;
    }
        return NewString;
}

string H(string a, string b)
{
    string res = "0x";
    if (a < b)
    {
        res += sha256_my(a + b);
    }
    else
    {
        res += sha256_my(b + a);
    }
    return res;
}

int main()
{
    /*have decompressed the gz to json*/
    /* get header from blockchain.json.gz */
    std::ifstream f("blockchain.json");
    json blockchain = json::parse(f);
    /* Load the most recent block header hash*/
    json recent_block = *blockchain.rbegin();


    /*part 2: use proof-of-work algorithm to produce new block*/
    std::ifstream f2("mempool.json");
    json mempool = json::parse(f2);


    /*part2-1*/
    int blockTimestamp = recent_block["header"]["timestamp"];
    //int transactions_count = recent_block["header"]["transactions_count"];
    const int max_txn_num = 100;
    json profitableTransactions;

    for(auto it = mempool.begin(); it != mempool.end(); it++) {

        /*fliter*/
        if((*it)["lock_time"] <= blockTimestamp) {
            profitableTransactions.push_back(*it);
        }

        if(profitableTransactions.size() >= max_txn_num) {
            break;
        }
    }

    sort(profitableTransactions.begin(), profitableTransactions.end(), mycomp);//lexicographic order???

    /*part2-2 construct the markle tree*/
    /*get txn hash*/
    //2-AVL? : markle tree
    vector<string> txn_sha;
    for(auto it = profitableTransactions.begin(); it != profitableTransactions.end(); it++) {
        // serialised transaction
        string serialised_txn = "";
        auto one_txn = *it;
        for(auto it2 = one_txn.begin(); it2 != one_txn.end(); it2++) {
            one_txn += it2.value();
            if(it2 != one_txn.begin())
                one_txn += ",";
        }
        txn_sha.push_back(sha256_my(serialised_txn));
    }

    vector<string> MerkleTree(txn_sha);
    if(MerkleTree.empty()) {
        cout<<"error: MerkleTree empty"<<endl;
        exit(-1);
    }

    while(MerkleTree.size() != 1) {
        vector<string> temp;
        for(int i=1;i<MerkleTree.size();i+=2) {
            temp.push_back(H(MerkleTree[i-1], MerkleTree[i]));
        }
        if(MerkleTree.size() % 2 == 1) {
            temp.push_back(H(*MerkleTree.rbegin(), ""));//take "" as 0
        }
        temp.swap(MerkleTree);
    }
    string MerkleRoot = MerkleTree[0];

    //part2-3: 
    json new_block = recent_block;

    //fill header
    new_block["header"]["height"] += 1;
    new_block["header"]["miner"] ="0x00132b386d939d081bffad6dbaef99e7d4618862";
    new_block["header"]["nonce"] = 0;
    new_block["header"]["previous_block_header_hash"] = recent_block["header"]["hash"];
    new_block["header"]["timestamp"] += 10;
    new_block["header"]["transactions_count"] = profitableTransactions.size();
    new_block["header"]["transactions_merkle_root"] = MerkleRoot;

    //fill transactions
    new_block["transactions"].clear();
    for(auto it = profitableTransactions.begin(); it != profitableTransactions.end(); it++) {
        new_block["transactions"].push_back(*it);
    }

    // part2-4:Mine the block, Proof-of-Work algorithm
    string str_to_hash1 = "";
    str_to_hash1 += to_string(new_block["header"]["difficulty"]) + ",";
    str_to_hash1 += to_string(new_block["header"]["height"]) + ",";
    str_to_hash1 += new_block["header"]["miner"] + ",";

    string str_to_hash2 = ",";
    str_to_hash2 += new_block["header"]["previous_block_header_hash"] + ",";
    str_to_hash2 += to_string(new_block["header"]["timestamp"]) + ",";
    str_to_hash2 += to_string(new_block["header"]["transactions_count"]) + ",";
    str_to_hash2 += new_block["header"]["transactions_merkle_root"];

    for (int i = 0;; i++) {
        string str = str_to_hash1 + to_string(i) + str_to_hash2;
        string res = sha256_my(str);
        string effective_pos = res.substr(0, new_block["header"]["difficulty"]);
        if(effective_pos.find_last_not_of("0") == string::npos) {
            new_block["header"]["hash"] = "0x" + res;
            break;
        }

        if(i % 100000 == 0) {
            cout<<"i"<<endl;
        }
    }

    //part3: write back
    std::ofstream o("blockchain1.json");
    o << new_block;

    return 0;
}