github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/consensus/ipbft/node.go (about)

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