aboutsummaryrefslogblamecommitdiff
path: root/src/hotstuff_app.cpp
blob: 1a63776e06044053f8ec85492772d3b558baa5d7 (plain) (tree)






























































                                                                            
                         








                                                                             


                                                                     
                                 

                                                      


                                                             



































































































































                                                                                    


                                                                    


                             

                                


                                                                                                         
                            




                                                                                         
                  
                               
                                




                                  
                                               



                                       
                                                                        



                                

                                                                            
                           
                                  
                                    
           








                                                                                       
                                             


                            
























                                                                  
#include <iostream>
#include <cstring>
#include <cassert>
#include <algorithm>
#include <random>
#include <unistd.h>
#include <signal.h>
#include <event2/event.h>

#include "salticidae/stream.h"
#include "salticidae/util.h"
#include "salticidae/network.h"
#include "salticidae/msg.h"

#include "hotstuff/promise.hpp"
#include "hotstuff/type.h"
#include "hotstuff/entity.h"
#include "hotstuff/util.h"
#include "hotstuff/client.h"
#include "hotstuff/hotstuff.h"

using salticidae::MsgNetwork;
using salticidae::ClientNetwork;
using salticidae::ElapsedTime;
using salticidae::Config;
using salticidae::_1;
using salticidae::_2;
using salticidae::static_pointer_cast;
using salticidae::trim_all;
using salticidae::split;

using hotstuff::Event;
using hotstuff::EventContext;
using hotstuff::NetAddr;
using hotstuff::HotStuffError;
using hotstuff::CommandDummy;
using hotstuff::Finality;
using hotstuff::command_t;
using hotstuff::uint256_t;
using hotstuff::bytearray_t;
using hotstuff::DataStream;
using hotstuff::ReplicaID;
using hotstuff::MsgClient;
using hotstuff::get_hash;
using hotstuff::promise_t;

using HotStuff = hotstuff::HotStuffSecp256k1;

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

class HotStuffApp: public HotStuff {
    double stat_period;
    /** libevent handle */
    EventContext eb;
    /** network messaging between a replica and its client */
    ClientNetwork<MsgClient> cn;
    /** timer object to schedule a periodic printing of system statistics */
    Event ev_stat_timer;
    /** the binding address for client RPC */
    NetAddr clisten_addr;
    int32_t parent_limit;

    using conn_client_t = MsgNetwork<MsgClient>::conn_t;

    /** Client  */
    /** submits a new command */
    inline void client_request_cmd_handler(const MsgClient &, conn_client_t);
    /** checks if a cmd is decided */
    inline void client_check_cmd_handler(const MsgClient &, conn_client_t);

    Finality get_finality(const uint256_t cmd_hash) const {
        command_t cmd = storage->find_cmd(cmd_hash);
        hotstuff::block_t blk = cmd ? cmd->get_container() : nullptr;
        return Finality(get_id(),
                        cmd ? cmd->get_decision() : 0,
                        cmd_hash,
                        blk ? blk->get_hash() : uint256_t());
    }

    /** The callback function to print stat */
    inline void print_stat_cb(evutil_socket_t, short);

    command_t parse_cmd(DataStream &s) override {
        auto cmd = new CommandDummy();
        s >> *cmd;
        return cmd;
    }

    public:
    HotStuffApp(uint32_t blk_size,
                int32_t parent_limit,
                double stat_period,
                ReplicaID idx,
                const bytearray_t &raw_privkey,
                NetAddr plisten_addr,
                NetAddr clisten_addr,
                const EventContext &eb);

    void start();
};


std::pair<std::string, std::string> split_ip_port_cport(const std::string &s) {
    auto ret = trim_all(split(s, ";"));
    if (ret.size() != 2)
        throw std::invalid_argument("invalid cport format");
    return std::make_pair(ret[0], ret[1]);
}

void signal_handler(int) {
    throw HotStuffError("got terminal signal");
}

salticidae::BoxObj<HotStuffApp> papp = nullptr;

int main(int argc, char **argv) {
    Config config("hotstuff.conf");

    ElapsedTime elapsed;
    elapsed.start();

    signal(SIGTERM, signal_handler);
    signal(SIGINT, signal_handler);

    auto opt_blk_size = Config::OptValInt::create(1);
    auto opt_parent_limit = Config::OptValInt::create(-1);
    auto opt_stat_period = Config::OptValDouble::create(10);
    auto opt_replicas = Config::OptValStrVec::create();
    auto opt_idx = Config::OptValInt::create(0);
    auto opt_client_port = Config::OptValInt::create(-1);
    auto opt_privkey = Config::OptValStr::create();
    auto opt_help = Config::OptValFlag::create(false);

    config.add_opt("block-size", opt_blk_size, Config::SET_VAL);
    config.add_opt("parent-limit", opt_parent_limit, Config::SET_VAL);
    config.add_opt("stat-period", opt_stat_period, Config::SET_VAL);
    config.add_opt("replica", opt_replicas, Config::APPEND);
    config.add_opt("idx", opt_idx, Config::SET_VAL);
    config.add_opt("cport", opt_client_port, Config::SET_VAL);
    config.add_opt("privkey", opt_privkey, Config::SET_VAL);
    config.add_opt("help", opt_help, Config::SWITCH_ON, 'h', "show this help info");

    EventContext eb;
#ifndef HOTSTUFF_ENABLE_LOG_DEBUG
    try {
#endif
        config.parse(argc, argv);
        if (opt_help->get())
        {
            config.print_help();
            exit(0);
        }
        auto idx = opt_idx->get();
        auto client_port = opt_client_port->get();
        std::vector<std::pair<std::string, std::string>> replicas;
        for (const auto &s: opt_replicas->get())
        {
            auto res = trim_all(split(s, ","));
            if (res.size() != 2)
                throw HotStuffError("invalid replica info");
            replicas.push_back(std::make_pair(res[0], res[1]));
        }

        if (!(0 <= idx && (size_t)idx < replicas.size()))
            throw HotStuffError("replica idx out of range");
        std::string binding_addr = replicas[idx].first;
        if (client_port == -1)
        {
            auto p = split_ip_port_cport(binding_addr);
            size_t idx;
            try {
                client_port = stoi(p.second, &idx);
            } catch (std::invalid_argument &) {
                throw HotStuffError("client port not specified");
            }
        }

        NetAddr plisten_addr{split_ip_port_cport(binding_addr).first};

        papp = new HotStuffApp(opt_blk_size->get(),
                            opt_parent_limit->get(),
                            opt_stat_period->get(),
                            idx,
                            hotstuff::from_hex(opt_privkey->get()),
                            plisten_addr,
                            NetAddr("0.0.0.0", client_port),
                            eb);