aboutsummaryrefslogblamecommitdiffstats
path: root/simulation/validator.go
blob: 8a672c555264bb894654d0b8056ea40b3ec5acac (plain) (tree)



















                                                                               
             
              

              



                                                                     
                                                                 




                                                                            
                       

                              
                                     

                                   
                                     
                                

                                         
                              

                                         
                                       
                                        



                                              
                                 
                                 
                                
                                     
 

                                                      

                                               


                          
                                                             
                          
                               

                                     

                                    
                                                   
                                
                               
                                                







                                               

                            

                                              
 
                                                              

                                                   







                                                 



                                                         

                                     
                                      



                                                                              
         
                                           

                                         
                                    
                                              
                                             
                                 

                                                 

                          
                   


                                            















                                                                     
                                                     




                                                  


                                                                     
                              
                                  
 
             





                                          


                                          
                                           

                                                                             
                         
                                               



                                                                                 



                                                                            



                 
                                                               
                                                                      



                                                  
                                              
 
 

                                                                        



                                                     
                   




                                         
                                              
                                                           
                 
                                                                                         

                                  
                                     



                                                                       
                                               


                                               
                                               



                                                

         
// Copyright 2018 The dexon-consensus-core Authors
// This file is part of the dexon-consensus-core library.
//
// The dexon-consensus-core library is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// The dexon-consensus-core library is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
// General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the dexon-consensus-core library. If not, see
// <http://www.gnu.org/licenses/>.

package simulation

import (
    "fmt"
    "sort"
    "time"

    "github.com/dexon-foundation/dexon-consensus-core/blockdb"
    "github.com/dexon-foundation/dexon-consensus-core/common"
    "github.com/dexon-foundation/dexon-consensus-core/core"
    "github.com/dexon-foundation/dexon-consensus-core/core/types"
    "github.com/dexon-foundation/dexon-consensus-core/crypto"
    "github.com/dexon-foundation/dexon-consensus-core/simulation/config"
)

// Validator represents a validator in DexCon.
type Validator struct {
    network Network
    app     *simApp
    gov     *simGovernance
    db      blockdb.BlockDatabase

    config     config.Validator
    msgChannel <-chan interface{}
    isFinished chan struct{}

    ID              types.ValidatorID
    chainID         uint64
    prvKey          crypto.PrivateKey
    sigToPub        core.SigToPubFn
    consensus       *core.Consensus
    compactionChain *core.BlockChain
}

// NewValidator returns a new empty validator.
func NewValidator(
    prvKey crypto.PrivateKey,
    sigToPub core.SigToPubFn,
    config config.Validator,
    network Network) *Validator {

    id := types.NewValidatorID(prvKey.PublicKey())

    db, err := blockdb.NewMemBackedBlockDB(
        id.String() + ".blockdb")
    if err != nil {
        panic(err)
    }
    gov := newSimGovernance(config.Num, config.Consensus)
    return &Validator{
        ID:         id,
        prvKey:     prvKey,
        sigToPub:   sigToPub,
        config:     config,
        network:    network,
        app:        newSimApp(id, network),
        gov:        gov,
        db:         db,
        isFinished: make(chan struct{}),
    }
}

// GetID returns the ID of validator.
func (v *Validator) GetID() types.ValidatorID {
    return v.ID
}

// Run starts the validator.
func (v *Validator) Run() {
    v.network.Join(v)
    v.msgChannel = v.network.ReceiveChan()

    hashes := make(common.Hashes, 0, v.network.NumPeers())
    for _, vID := range v.network.Endpoints() {
        v.gov.addValidator(vID)
        hashes = append(hashes, vID.Hash)
    }
    sort.Sort(hashes)
    for i, hash := range hashes {
        if hash == v.ID.Hash {
            v.chainID = uint64(i)
            break
        }
    }
    v.consensus = core.NewConsensus(
        v.app, v.gov, v.db, v.prvKey, v.sigToPub)

    genesisBlock := &types.Block{
        ProposerID: v.ID,
        ChainID:    v.chainID,
    }
    err := v.consensus.PrepareGenesisBlock(genesisBlock, time.Now().UTC())
    if err != nil {
        panic(err)
    }
    isStopped := make(chan struct{}, 2)
    isShutdown := make(chan struct{})

    v.app.addBlock(genesisBlock)
    v.consensus.ProcessBlock(genesisBlock)
    v.BroadcastGenesisBlock(genesisBlock)
    go v.MsgServer(isStopped)
    go v.CheckServerInfo(isShutdown)
    go v.BlockProposer(isStopped, isShutdown)

    // Blocks forever.
    <-isStopped
    if err := v.db.Close(); err != nil {
        fmt.Println(err)
    }
    v.network.NotifyServer(Message{
        Type: shutdownAck,
    })
    v.isFinished <- struct{}{}
}

// Wait for the validator to stop (if peerServer told it to).
func (v *Validator) Wait() {
    <-v.isFinished
}

// CheckServerInfo will check the info from the peerServer and update
// validator's status if needed.
func (v *Validator) CheckServerInfo(isShutdown chan struct{}) {
    for {
        infoMsg := v.network.GetServerInfo()
        if infoMsg.Status == statusShutdown {
            isShutdown <- struct{}{}
            break
        }
        time.Sleep(250 * time.Millisecond)
    }
}

// MsgServer listen to the network channel for message and handle it.
func (v *Validator) MsgServer(
    isStopped chan struct{}) {

    for {
        var msg interface{}
        select {
        case msg = <-v.msgChannel:
        case <-isStopped:
            return
        }

        switch val := msg.(type) {
        case *types.Block:
            v.app.addBlock(val)
            if err := v.consensus.ProcessBlock(val); err != nil {
                fmt.Println(err)
            }
            types.RecycleBlock(val)
        case *types.NotaryAck:
            if err := v.consensus.ProcessNotaryAck(val); err != nil {
                fmt.Println(err)
            }
        case *types.Vote:
            if err := v.consensus.ProcessVote(val); err != nil {
                fmt.Println(err)
            }
        }
    }
}

// BroadcastGenesisBlock broadcasts genesis block to all peers.
func (v *Validator) BroadcastGenesisBlock(genesisBlock *types.Block) {
    // Wait until all peer joined the network.
    for v.network.NumPeers() != v.config.Num {
        time.Sleep(time.Second)
    }
    v.network.BroadcastBlock(genesisBlock)
}

// BlockProposer propose blocks to be send to the DEXON network.
func (v *Validator) BlockProposer(isStopped, isShutdown chan struct{}) {
    model := &NormalNetwork{
        Sigma: v.config.ProposeIntervalSigma,
        Mean:  v.config.ProposeIntervalMean,
    }
ProposingBlockLoop:
    for {
        time.Sleep(model.Delay())

        block := &types.Block{
            ProposerID: v.ID,
            ChainID:    v.chainID,
            Hash:       common.NewRandomHash(),
        }
        if err := v.consensus.PrepareBlock(block, time.Now().UTC()); err != nil {
            panic(err)
        }
        v.app.addBlock(block)
        if err := v.consensus.ProcessBlock(block); err != nil {
            fmt.Println(err)
            //panic(err)
        }
        v.network.BroadcastBlock(block)
        select {
        case <-isShutdown:
            isStopped <- struct{}{}
            isStopped <- struct{}{}
            break ProposingBlockLoop
        default:
            break
        }
    }
}