aboutsummaryrefslogblamecommitdiff
path: root/src/consensus.cpp
blob: ac7e56a7693ace1ecdbf83a76e36857a121e58b9 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12











                                    
                                                      

                                        
                                                   






                                      









                                                               
                                                                    













                                                        
                                                        















                                                                         
                                                       





                                                      
                                                                 

                                














                                                                          
                                
                                                         
      



                                                                   
     
              


                                                      
                                               






                                                   





                                                                  

                                
                                            





                                                       
                              
                                    
                  





































                                                              




                                               










                                                               
                   







                                                          
                                                   
                                     
                                        

                       
                                                     



                                              
                                                       




                                     






                                                              




























                                                                          











































                                                                       
                        


 
#include <cassert>
#include <stack>

#include "hotstuff/util.h"
#include "hotstuff/consensus.h"

#define LOG_INFO HOTSTUFF_LOG_INFO
#define LOG_DEBUG HOTSTUFF_LOG_DEBUG
#define LOG_WARN HOTSTUFF_LOG_WARN

namespace hotstuff {

/* The core logic of HotStuff, is fairly simple :). */
/*** begin HotStuff protocol logic ***/
HotStuffCore::HotStuffCore(ReplicaID id,
                            privkey_bt &&priv_key):
        b0(new Block(true, 1)),
        bqc(b0),
        bexec(b0),
        vheight(0),
        priv_key(std::move(priv_key)),
        tails{bqc},
        id(id),
        storage(new EntityStorage()) {
    storage->add_blk(b0);
    b0->qc_ref = b0;
}

void HotStuffCore::sanity_check_delivered(const block_t &blk) {
    if (!blk->delivered)
        throw std::runtime_error("block not delivered");
}

block_t HotStuffCore::get_delivered_blk(const uint256_t &blk_hash) {
    block_t blk = storage->find_blk(blk_hash);
    if (blk == nullptr || !blk->delivered)
        throw std::runtime_error("block not delivered");
    return std::move(blk);
}

bool HotStuffCore::on_deliver_blk(const block_t &blk) {
    if (blk->delivered)
    {
        LOG_WARN("attempt to deliver a block twice");
        return false;
    }
    blk->parents.clear();
    for (const auto &hash: blk->parent_hashes)
        blk->parents.push_back(get_delivered_blk(hash));
    blk->height = blk->parents[0]->height + 1;
    for (const auto &cmd: blk->cmds)
        cmd->container = blk;

    if (blk->qc)
    {
        block_t _blk = storage->find_blk(blk->qc->get_blk_hash());
        if (_blk == nullptr)
            throw std::runtime_error("block referred by qc not fetched");
        blk->qc_ref = std::move(_blk);
    } // otherwise blk->qc_ref remains null

    for (auto pblk: blk->parents) tails.erase(pblk);
    tails.insert(blk);

    blk->delivered = true;
    LOG_DEBUG("deliver %s", std::string(*blk).c_str());
    return true;
}

void HotStuffCore::check_commit(const block_t &_blk) {
    const block_t &blk = _blk->qc_ref;
    if (blk->qc_ref == nullptr) return;
    /* decided blk could possible be incomplete due to pruning */
    if (blk->decision) return;
    block_t p = blk->parents[0];
    /* commit requires direct parent */
    if (p != blk->qc_ref) return;
    /* otherwise commit */
    std::vector<block_t> commit_queue;
    block_t b;
    for (b = p; b->height > bexec->height; b = b->parents[0])
    { /* TODO: also commit the uncles/aunts */
        commit_queue.push_back(b);
    }
    if (b != bexec)
        throw std::runtime_error("safety breached :(");
    for (auto it = commit_queue.rbegin(); it != commit_queue.rend(); it++)
    {
        const block_t &blk = *it;
        blk->decision = 1;
#ifdef HOTSTUFF_ENABLE_LOG_PROTO
        LOG_INFO("commit %s", std::string(*blk).c_str());
#endif
        size_t idx = 0;
        for (auto cmd: blk->cmds)
            do_decide(Finality(id, 1, idx, blk->height,
                                cmd->get_hash(), blk->get_hash()));
    }
    bexec = p;
}

bool HotStuffCore::update(const uint256_t &bqc_hash) {
    block_t _bqc = get_delivered_blk(bqc_hash);
    if (_bqc->qc_ref == nullptr) return false;
    check_commit(_bqc);
    if (_bqc->qc_ref->height > bqc->qc_ref->height)
        bqc = _bqc;
    return true;
}

void HotStuffCore::on_propose(const std::vector<command_t> &cmds,
                            const std::vector<block_t> &parents) {
    if (parents.empty())
        throw std::runtime_error("empty parents");
    for (const auto &_: parents) tails.erase(_);
    block_t p = parents[0];
    quorum_cert_bt qc = nullptr;
    block_t qc_ref = nullptr;
    /* a block can optionally carray a QC */
    if (p != b0 && p->voted.size() >= config.nmajority)
    {
        qc = p->self_qc->clone();
        qc->compute();
        qc_ref = p;
    }
    /* create the new block */
    block_t bnew = storage->add_blk(
        new Block(
            parents,
            cmds,
            p->height + 1,