github.com/Gessiux/neatchain@v1.3.1/chain/consensus/neatcon/node.go (about)

     1  package neatcon
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"strings"
     7  
     8  	cmn "github.com/Gessiux/go-common"
     9  	cfg "github.com/Gessiux/go-config"
    10  	dbm "github.com/Gessiux/go-db"
    11  	"github.com/Gessiux/neatchain/chain/consensus/neatcon/consensus"
    12  	"github.com/Gessiux/neatchain/chain/consensus/neatcon/epoch"
    13  	"github.com/Gessiux/neatchain/chain/consensus/neatcon/types"
    14  	"github.com/Gessiux/neatchain/chain/core"
    15  	"github.com/Gessiux/neatchain/chain/log"
    16  	"github.com/Gessiux/neatchain/params"
    17  )
    18  
    19  type Node struct {
    20  	cmn.BaseService
    21  
    22  	//genesisDoc    *types.GenesisDoc    // initial validator set
    23  	privValidator *types.PrivValidator // local node's validator key
    24  
    25  	epochDB dbm.DB
    26  
    27  	// services
    28  	evsw types.EventSwitch // pub/sub for services
    29  	//blockStore       *bc.BlockStore              // store the blockchain to disk
    30  	consensusState   *consensus.ConsensusState   // latest consensus state
    31  	consensusReactor *consensus.ConsensusReactor // for participating in the consensus
    32  
    33  	cch    core.CrossChainHelper
    34  	logger log.Logger
    35  }
    36  
    37  func NewNodeNotStart(backend *backend, config cfg.Config, chainConfig *params.ChainConfig, cch core.CrossChainHelper, genDoc *types.GenesisDoc) *Node {
    38  	// Get PrivValidator
    39  	var privValidator *types.PrivValidator
    40  	privValidatorFile := config.GetString("priv_validator_file")
    41  	if _, err := os.Stat(privValidatorFile); err == nil {
    42  		privValidator = types.LoadPrivValidator(privValidatorFile)
    43  	}
    44  
    45  	// Initial Epoch
    46  	epochDB := dbm.NewDB("epoch", config.GetString("db_backend"), config.GetString("db_dir"))
    47  	ep := epoch.InitEpoch(epochDB, genDoc, backend.logger)
    48  
    49  	// We should start mine if we are in the ValidatorSet
    50  	if privValidator != nil && ep.Validators.HasAddress(privValidator.Address[:]) {
    51  		backend.shouldStart = true
    52  	} else {
    53  		backend.shouldStart = false
    54  	}
    55  
    56  	// Make ConsensusReactor
    57  	consensusState := consensus.NewConsensusState(backend, config, chainConfig, cch, ep)
    58  	if privValidator != nil {
    59  		consensusState.SetPrivValidator(privValidator)
    60  	}
    61  	consensusReactor := consensus.NewConsensusReactor(consensusState /*, fastSync*/)
    62  
    63  	// Add Reactor to P2P Switch
    64  	//sw.AddReactor(config.GetString("chain_id"), "CONSENSUS", consensusReactor)
    65  
    66  	// Make event switch
    67  	eventSwitch := types.NewEventSwitch()
    68  	// add the event switch to all services
    69  	// they should all satisfy events.Eventable
    70  	SetEventSwitch(eventSwitch, consensusReactor)
    71  
    72  	node := &Node{
    73  		privValidator: privValidator,
    74  
    75  		epochDB: epochDB,
    76  
    77  		evsw: eventSwitch,
    78  
    79  		cch: cch,
    80  
    81  		consensusState:   consensusState,
    82  		consensusReactor: consensusReactor,
    83  
    84  		logger: backend.logger,
    85  	}
    86  	node.BaseService = *cmn.NewBaseService(backend.logger, "Node", node)
    87  
    88  	return node
    89  }
    90  
    91  func (n *Node) OnStart() error {
    92  
    93  	n.logger.Info("(n *Node) OnStart()")
    94  
    95  	// Check Private Validator has been set
    96  	if n.privValidator == nil {
    97  		return ErrNoPrivValidator
    98  	}
    99  
   100  	/*
   101  		state, epoch := n.consensusState.InitStateAndEpoch()
   102  		n.consensusState.Initialize()
   103  		n.consensusState.UpdateToStateAndEpoch(state, epoch)
   104  	*/
   105  	_, err := n.evsw.Start()
   106  	if err != nil {
   107  		n.logger.Errorf("Failed to start switch: %v", err)
   108  		return err
   109  	}
   110  
   111  	// Start the Consensus Reactor for this Chain
   112  	_, err = n.consensusReactor.Start()
   113  	if err != nil {
   114  		n.logger.Errorf("Failed to start Consensus Reactor. Error: %v", err)
   115  		return err
   116  	}
   117  
   118  	n.consensusReactor.AfterStart()
   119  
   120  	return nil
   121  }
   122  
   123  func (n *Node) OnStop() {
   124  	n.logger.Info("(n *Node) OnStop() called")
   125  	n.BaseService.OnStop()
   126  
   127  	//n.sw.StopChainReactor(n.consensusState.GetState().NTCExtra.ChainID)
   128  	n.evsw.Stop()
   129  	n.consensusReactor.Stop()
   130  }
   131  
   132  //update the state with new insert block information
   133  //func (n *Node) SaveState(block *neatTypes.Block) {
   134  //
   135  //	epoch := n.consensusState.Epoch
   136  //	state := n.consensusState.GetState()
   137  //
   138  //	fmt.Printf("(n *Node) SaveState(block *neatTypes.Block) with state.height = %v, block.height = %v\n",
   139  //		uint64(state.NTCExtra.Height), block.NumberU64())
   140  //
   141  //	if uint64(state.NTCExtra.Height) != block.NumberU64() {
   142  //		fmt.Printf("(n *Node) SaveState(block *neatTypes.Block), block height not equal\n")
   143  //	}
   144  //
   145  //	epoch.Save()
   146  //	//state.Save()
   147  //
   148  //	n.consensusState.StartNewHeight()
   149  //}
   150  
   151  func (n *Node) RunForever() {
   152  	// Sleep forever and then...
   153  	cmn.TrapSignal(func() {
   154  		n.Stop()
   155  	})
   156  }
   157  
   158  // Add the event switch to reactors, mempool, etc.
   159  func SetEventSwitch(evsw types.EventSwitch, eventables ...types.Eventable) {
   160  	for _, e := range eventables {
   161  		e.SetEventSwitch(evsw)
   162  	}
   163  }
   164  
   165  func (n *Node) ConsensusState() *consensus.ConsensusState {
   166  	return n.consensusState
   167  }
   168  
   169  func (n *Node) ConsensusReactor() *consensus.ConsensusReactor {
   170  	return n.consensusReactor
   171  }
   172  
   173  func (n *Node) EventSwitch() types.EventSwitch {
   174  	return n.evsw
   175  }
   176  
   177  // XXX: for convenience
   178  func (n *Node) PrivValidator() *types.PrivValidator {
   179  	return n.privValidator
   180  }
   181  
   182  /*
   183  func (n *Node) GenesisDoc() *types.GenesisDoc {
   184  	return n.genesisDoc
   185  }
   186  */
   187  
   188  //------------------------------------------------------------------------------
   189  // Users wishing to:
   190  //	* use an external signer for their validators
   191  //	* supply an in-proc abci app
   192  // should fork neatcon/neatcon and implement RunNode to
   193  // call NewNode with their custom priv validator and/or custom
   194  // proxy.ClientCreator interface
   195  /*
   196  func RunNode(config cfg.Config, app *app.EthermintApplication) {
   197  	// Wait until the genesis doc becomes available
   198  	genDocFile := config.GetString("genesis_file")
   199  	if !cmn.FileExists(genDocFile) {
   200  		log.Notice(cmn.Fmt("Waiting for genesis file %v...", genDocFile))
   201  		for {
   202  			time.Sleep(time.Second)
   203  			if !cmn.FileExists(genDocFile) {
   204  				continue
   205  			}
   206  			jsonBlob, err := ioutil.ReadFile(genDocFile)
   207  			if err != nil {
   208  				cmn.Exit(cmn.Fmt("Couldn't read GenesisDoc file: %v", err))
   209  			}
   210  			genDoc, err := types.GenesisDocFromJSON(jsonBlob)
   211  			if err != nil {
   212  				cmn.PanicSanity(cmn.Fmt("Genesis doc parse json error: %v", err))
   213  			}
   214  			if genDoc.ChainID == "" {
   215  				cmn.PanicSanity(cmn.Fmt("Genesis doc %v must include non-empty chain_id", genDocFile))
   216  			}
   217  			config.Set("chain_id", genDoc.ChainID)
   218  		}
   219  	}
   220  
   221  	// Create & start node
   222  	n := NewNodeDefault(config, nil)
   223  
   224  	//protocol, address := ProtocolAndAddress(config.GetString("node_laddr"))
   225  	//l := p2p.NewDefaultListener(protocol, address, config.GetBool("skip_upnp"))
   226  	//n.AddListener(l)
   227  	err := n.OnStart()
   228  	if err != nil {
   229  		cmn.Exit(cmn.Fmt("Failed to start node: %v", err))
   230  	}
   231  
   232  	//log.Notice("Started node", "nodeInfo", n.sw.NodeInfo())
   233  	// If seedNode is provided by config, dial out.
   234  	if config.GetString("seeds") != "" {
   235  		seeds := strings.Split(config.GetString("seeds"), ",")
   236  		n.DialSeeds(seeds)
   237  	}
   238  
   239  	// Run the RPC server.
   240  	if config.GetString("rpc_laddr") != "" {
   241  		_, err := n.StartRPC()
   242  		if err != nil {
   243  			cmn.PanicCrisis(err)
   244  		}
   245  	}
   246  	// Sleep forever and then...
   247  	cmn.TrapSignal(func() {
   248  		n.Stop()
   249  	})
   250  }
   251  */
   252  
   253  //func (n *Node) NodeInfo() *p2p.NodeInfo {
   254  //	return n.sw.NodeInfo()
   255  //}
   256  //
   257  //func (n *Node) DialSeeds(seeds []string) error {
   258  //	return n.sw.DialSeeds(n.addrBook, seeds)
   259  //}
   260  
   261  // Defaults to tcp
   262  func ProtocolAndAddress(listenAddr string) (string, string) {
   263  	protocol, address := "tcp", listenAddr
   264  	parts := strings.SplitN(address, "://", 2)
   265  	if len(parts) == 2 {
   266  		protocol, address = parts[0], parts[1]
   267  	}
   268  	return protocol, address
   269  }
   270  
   271  func MakeNeatConNode(backend *backend, config cfg.Config, chainConfig *params.ChainConfig, cch core.CrossChainHelper) *Node {
   272  
   273  	var genDoc *types.GenesisDoc
   274  	genDocFile := config.GetString("genesis_file")
   275  
   276  	if !cmn.FileExists(genDocFile) {
   277  		if chainConfig.NeatChainId == params.MainnetChainConfig.NeatChainId {
   278  			genDoc, _ = types.GenesisDocFromJSON([]byte(types.MainnetGenesisJSON))
   279  		} else if chainConfig.NeatChainId == params.TestnetChainConfig.NeatChainId {
   280  			genDoc, _ = types.GenesisDocFromJSON([]byte(types.TestnetGenesisJSON))
   281  		} else {
   282  			return nil
   283  		}
   284  	} else {
   285  		genDoc = readGenesisFromFile(genDocFile)
   286  	}
   287  	config.Set("chain_id", genDoc.ChainID)
   288  
   289  	return NewNodeNotStart(backend, config, chainConfig, cch, genDoc)
   290  }
   291  
   292  func readGenesisFromFile(genDocFile string) *types.GenesisDoc {
   293  	jsonBlob, err := ioutil.ReadFile(genDocFile)
   294  	if err != nil {
   295  		cmn.Exit(cmn.Fmt("Couldn't read GenesisDoc file: %v", err))
   296  	}
   297  	genDoc, err := types.GenesisDocFromJSON(jsonBlob)
   298  	if err != nil {
   299  		cmn.PanicSanity(cmn.Fmt("Genesis doc parse json error: %v", err))
   300  	}
   301  	if genDoc.ChainID == "" {
   302  		cmn.PanicSanity(cmn.Fmt("Genesis doc %v must include non-empty chain_id", genDocFile))
   303  	}
   304  	return genDoc
   305  }