天天看點

C++從零開始區塊鍊:一個簡單的總體介紹交易流程程式設計完整代碼

本系列博文對理論性的東西叙述的不多,主要是以代碼為主,本例是模仿比特币實作的一個電子貨币記賬系統。

雖然不打算介紹理論性的東西,但交易流程還是要說一下的,畢竟所有的代碼都是為這個交易流程服務的。

  • 交易流程
  • 程式設計
    • Cryptography
    • P2PNode
    • BlockChain
  • 完整代碼

交易流程

當發起一個交易的時候,交易發起方先準備一條“位址a要向位址b轉賬n個币”的消息,然後用位址a的私鑰進行數字簽名,用以表明發起方對位址a的所有權,最後再把該消息和簽名資訊在P2P網絡上對其他節點進行廣播。

其他節點收到廣播後,先對消息的數字簽名進行驗證,驗證通過後再檢查餘額是否夠用。全部驗證通過後将該交易記在自己的交易清單上。至此,交易流程結束。

雖然交易流程結束了,但還沒有記到區塊鍊上,那怎麼記到區塊鍊上呢?挖礦啊。當一個節點找到了一個工作量證明,就将自己記錄的交易清單打包記到一個區塊上,然後再向所有的節點進行廣播,告訴其他人。

其他節點收到區塊後,對工作量證明進行驗證,驗證後将區塊挂在區塊鍊上,再将該區塊上的交易清單和自己的交易清單進行比對,将自己交易清單中已經在區塊上記錄的消息删除。

當然,比特币中的交易流程要比這複雜的多,我們隻為學習,把流程進行簡化了。

程式設計

綜上所述,可以看出應該有三個主要子產品:數字簽名,P2P網絡和區塊鍊邏輯。以下是對三個子產品的定義:

Cryptography

該類主要用于處理數字簽名,編碼解碼等數學和密碼相關功能。

typedef struct __keydata
{
    size_t len;
    unsigned char key[];
} KeyData;

typedef struct __KeyPair
{
    KeyData pubKey;
    KeyData priKey;
} KeyPair;

class Cryptography
{
public:
    static std::string GetHash(void const* buffer, std::size_t len);
    static std::string Base64Encode(const void*buff, int len);
    static void Base64Decode(const std::string &str64, void *outbuff, size_t outsize, size_t *outlen);
    static void Createkey(KeyPair &keyPair);
    static bool Signature(const KeyData &priKey, const void *data, int datalen, unsigned char *sign, size_t signszie, unsigned int *signlen);
    static int Verify(const KeyData &pubkey, const char *data, int datalen, const unsigned char *sign, size_t signszie, unsigned int signlen);
    static std::string StringToLower(const std::string &str);
    static bool CompareNoCase(const std::string &strA, const std::string &strB);
    static std::vector<std::string> StringSplit(const std::string &str, const char sep);

protected:
    Cryptography();
    virtual ~Cryptography();

private:

};
           

P2PNode

該類主要處理網絡通信相關功能

typedef enum
{
    p2p_transaction = ,
    p2p_bookkeeping,
    p2p_result,
    p2p_merge,
    p2p_blockchain,
    p2p_max
} P2PCommand;

typedef struct st_broadcast
{
    KeyData pubkey;
    char json[];
    unsigned int signlen;
    unsigned char sign[];
} __attribute__((packed))
    BroadcastMessage;

typedef struct st_p2pMessage
{
    int index;
    int total;
    char messHash[];
    P2PCommand cmd;
    size_t length;
    char mess[MAX_P2P_SIZE];
} __attribute__((packed))
    P2PMessage;

typedef struct st_p2pResult
{
    int index;
    char messHash[];

    bool operator == (const struct st_p2pResult & value) const
    {
        return
            this->index == value.index &&
            !strcmp(this->messHash, value.messHash);
    }
} __attribute__((packed))
    P2PResult;

class P2PNode
{
public:
    static P2PNode *Instance(const char *if_name);
    void Listen();
    void Broadcast(P2PCommand cmd, const BroadcastMessage &bm);
    void MergeChain();

protected:
    P2PNode(const char *if_name);
    virtual ~P2PNode();

private:
    int m_sock;
    Node m_selfNode;
    Node m_otherNode;
    char *m_otherIP;
    int m_otherPort;
    pthread_t m_tid;
    pthread_mutex_t m_mutexPack;
    pthread_mutex_t m_mutexResult;

    struct sockaddr_in m_serverAddr;
    struct sockaddr_in m_localAddr;
    struct sockaddr_in m_recvAddr;

    typedef struct st_package
    {
        int total;
        char messHash[];
        P2PCommand cmd;
        std::map<int, std::string> mapMess;

        bool operator == (const struct st_package & value) const
        {
            return
                this->total == value.total &&
                this->cmd == value.cmd &&
                !strcmp(this->messHash, value.messHash);
        }
    } Package;

    std::list<Package> m_lstPackage;
    std::list<P2PResult> m_lstResult;

    static void *threadFunc(void *arg);
    void threadHandler();
    void combinationPackage(P2PMessage &mess);
    int get_local_ip(const char *ifname, char *ip);
    void sendMessage(P2PMessage &mess);
    void sendBlockChain();
};
           

BlockChain

該類處理區塊鍊相關業務邏輯

typedef struct __transactions
{
    std::string sender;
    std::string recipient;
    float amount;

    bool operator == (const struct __transactions & value) const
    {
        return
            this->sender == value.sender &&
            this->recipient == value.recipient &&
            this->amount == value.amount;
    }
}Transactions;

typedef struct __block
{
    int index;
    time_t timestamp;
    std::list<Transactions> lst_ts;
    long int proof;
    std::string previous_hash;

    bool operator == (const struct __block & value) const
    {
        return
            this->index == value.index &&
            this->timestamp == value.timestamp &&
            this->previous_hash == value.previous_hash &&
            this->lst_ts == value.lst_ts &&
            this->proof == value.proof;
    }
} Block;

class BlockChain
{
public:
    static BlockChain *Instance();

    std::string GetJsonFromBlock(Block &block);
    std::string GetJsonFromTransactions(Transactions &ts);
    Block GetBlockFromJson(const std::string &json);
    Transactions GetTransactionsFromJson(const std::string &json);
    std::string GetJsonFromBlockList();
    std::string GetJsonFromTransactionsList();
    std::list<Block> GetBlockListFromJson(const std::string &json);
    void GetTransactionsListFromJson(const std::string &json);
    std::string CreateNewAddress(const KeyPair &keyPair);
    Transactions CreateTransactions(const std::string &sender, const std::string &recipient, float amount);
    Block CreateBlock(int index, time_t timestamp, long int proof);
    int WorkloadProof(int last_proof);
    bool WorkloadVerification(int proof);
    std::string Mining(const std::string &addr);
    int CheckBalances(const std::string &addr);
    void DeleteDuplicateTransactions(const Block &block);
    void MergeBlockChain(const std::string &json);

    inline void InsertBlock(const Block &block)
    {
        pthread_mutex_lock(&m_mutexBlock);
        if (m_lst_block.end() == std::find(m_lst_block.begin(), m_lst_block.end(), block))
        {
            m_lst_block.push_back(block);
        }
        pthread_mutex_unlock(&m_mutexBlock);
    }

    inline void InsertTransactions(const Transactions &ts)
    {
        pthread_mutex_lock(&m_mutexTs);
        if (m_lst_ts.end() == std::find(m_lst_ts.begin(), m_lst_ts.end(), ts))
        {
            m_lst_ts.push_back(ts);
        }
        pthread_mutex_unlock(&m_mutexTs);
    }

    inline Block GetLastBlock()
    {
        Block block;
        pthread_mutex_lock(&m_mutexBlock);
        block = m_lst_block.back();
        pthread_mutex_unlock(&m_mutexBlock);
        return block;
    }

protected:
    BlockChain();
    virtual ~BlockChain();

private:
    std::list<Transactions> m_lst_ts;
    std::list<Block> m_lst_block;
    pthread_mutex_t m_mutexTs;
    pthread_mutex_t m_mutexBlock;
};
           

具體實作後面會細講。

完整代碼

完整代碼戳這裡。