github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/chain/neatio/init.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/neatio-net/neatio/chain/core/rawdb"
     9  	"github.com/neatio-net/neatio/chain/log"
    10  	"github.com/neatio-net/neatio/neatabi/abi"
    11  	"github.com/neatio-net/neatio/utilities/common/hexutil"
    12  	"github.com/neatio-net/neatio/utilities/common/math"
    13  
    14  	"gopkg.in/urfave/cli.v1"
    15  
    16  	"encoding/json"
    17  	"io/ioutil"
    18  	"math/big"
    19  	"regexp"
    20  	"strconv"
    21  	"strings"
    22  	"time"
    23  
    24  	cmn "github.com/neatio-net/common-go"
    25  	cfg "github.com/neatio-net/config-go"
    26  	dbm "github.com/neatio-net/db-go"
    27  	"github.com/neatio-net/neatio/chain/accounts/keystore"
    28  	"github.com/neatio-net/neatio/chain/consensus/neatcon/types"
    29  	"github.com/neatio-net/neatio/chain/core"
    30  	"github.com/neatio-net/neatio/params"
    31  	"github.com/neatio-net/neatio/utilities/common"
    32  	"github.com/neatio-net/neatio/utilities/utils"
    33  	"github.com/pkg/errors"
    34  )
    35  
    36  const (
    37  	TotalMintingReward = "32000000000000000000000000" // 32M
    38  	TotalMintingYears  = 10
    39  
    40  	DefaultAccountPassword = "neatio"
    41  )
    42  
    43  type BalaceAmount struct {
    44  	balance string
    45  	amount  string
    46  }
    47  
    48  type InvalidArgs struct {
    49  	args string
    50  }
    51  
    52  func (invalid InvalidArgs) Error() string {
    53  	return "invalid args:" + invalid.args
    54  }
    55  
    56  func initNeatGenesis(ctx *cli.Context) error {
    57  	log.Info("this is init-neatio")
    58  	args := ctx.Args()
    59  	if len(args) != 1 {
    60  		utils.Fatalf("len of args is %d", len(args))
    61  		return nil
    62  	}
    63  	balance_str := args[0]
    64  
    65  	chainId := MainChain
    66  	isMainnet := true
    67  	if ctx.GlobalBool(utils.TestnetFlag.Name) {
    68  		chainId = TestnetChain
    69  		isMainnet = false
    70  	}
    71  	log.Infof("this is init-neatio chainId %v", chainId)
    72  	log.Info("this is init-neatio" + ctx.GlobalString(utils.DataDirFlag.Name) + "--" + ctx.Args()[0])
    73  	return init_neat_genesis(utils.GetNeatConConfig(chainId, ctx), balance_str, isMainnet)
    74  }
    75  
    76  func init_neat_genesis(config cfg.Config, balanceStr string, isMainnet bool) error {
    77  
    78  	balanceAmounts, err := parseBalaceAmount(balanceStr)
    79  	if err != nil {
    80  		utils.Fatalf("init neatio failed")
    81  		return err
    82  	}
    83  
    84  	validators := createPriValidators(config, len(balanceAmounts))
    85  	extraData, _ := hexutil.Decode("0x0")
    86  
    87  	var chainConfig *params.ChainConfig
    88  	if isMainnet {
    89  		chainConfig = params.MainnetChainConfig
    90  	} else {
    91  		chainConfig = params.TestnetChainConfig
    92  	}
    93  
    94  	var coreGenesis = core.Genesis{
    95  		Config:     chainConfig,
    96  		Nonce:      0x0,
    97  		Timestamp:  uint64(time.Now().Unix()),
    98  		ParentHash: common.Hash{},
    99  		ExtraData:  extraData,
   100  		GasLimit:   0xe0000000,
   101  		Difficulty: new(big.Int).SetUint64(0x01),
   102  		Mixhash:    common.Hash{},
   103  		Coinbase:   common.Address{},
   104  		Alloc:      core.GenesisAlloc{},
   105  	}
   106  	for i, validator := range validators {
   107  		coreGenesis.Alloc[validator.Address] = core.GenesisAccount{
   108  			Balance: math.MustParseBig256(balanceAmounts[i].balance),
   109  			Amount:  math.MustParseBig256(balanceAmounts[i].amount),
   110  		}
   111  	}
   112  
   113  	contents, err := json.MarshalIndent(coreGenesis, "", "\t")
   114  	if err != nil {
   115  		utils.Fatalf("marshal coreGenesis failed")
   116  		return err
   117  	}
   118  	neatGenesisPath := config.GetString("neat_genesis_file")
   119  
   120  	if err = ioutil.WriteFile(neatGenesisPath, contents, 0654); err != nil {
   121  		utils.Fatalf("write neat_genesis_file failed")
   122  		return err
   123  	}
   124  	return nil
   125  }
   126  
   127  func initCmd(ctx *cli.Context) error {
   128  
   129  	neatGenesisPath := ctx.Args().First()
   130  	fmt.Printf("int genesis path %v\n", neatGenesisPath)
   131  	if len(neatGenesisPath) == 0 {
   132  		utils.Fatalf("must supply path to genesis JSON file")
   133  	}
   134  
   135  	chainId := ctx.Args().Get(1)
   136  	if chainId == "" {
   137  		chainId = MainChain
   138  		if ctx.GlobalBool(utils.TestnetFlag.Name) {
   139  			chainId = TestnetChain
   140  		}
   141  	}
   142  
   143  	return init_cmd(ctx, utils.GetNeatConConfig(chainId, ctx), chainId, neatGenesisPath)
   144  }
   145  
   146  func InitSideChainCmd(ctx *cli.Context) error {
   147  
   148  	chainInfoDb := dbm.NewDB("chaininfo", "leveldb", ctx.GlobalString(utils.DataDirFlag.Name))
   149  	if chainInfoDb == nil {
   150  		return errors.New("could not open chain info database")
   151  	}
   152  	defer chainInfoDb.Close()
   153  
   154  	sideChainIds := ctx.GlobalString("sideChain")
   155  	if sideChainIds == "" {
   156  		return errors.New("please provide side chain id to initialization")
   157  	}
   158  
   159  	chainIds := strings.Split(sideChainIds, ",")
   160  	for _, chainId := range chainIds {
   161  		ethGenesis, ntcGenesis := core.LoadChainGenesis(chainInfoDb, chainId)
   162  		if ethGenesis == nil || ntcGenesis == nil {
   163  			return errors.New(fmt.Sprintf("unable to retrieve the genesis file for side chain %s", chainId))
   164  		}
   165  
   166  		sideConfig := utils.GetNeatConConfig(chainId, ctx)
   167  
   168  		ethGenesisPath := sideConfig.GetString("neat_genesis_file")
   169  		if err := ioutil.WriteFile(ethGenesisPath, ethGenesis, 0644); err != nil {
   170  			utils.Fatalf("write neat_genesis_file failed")
   171  			return err
   172  		}
   173  
   174  		init_neatchain(chainId, ethGenesisPath, ctx)
   175  
   176  		if err := ioutil.WriteFile(sideConfig.GetString("genesis_file"), ntcGenesis, 0644); err != nil {
   177  			utils.Fatalf("write ntc genesis_file failed")
   178  			return err
   179  		}
   180  
   181  	}
   182  
   183  	return nil
   184  }
   185  
   186  func init_cmd(ctx *cli.Context, config cfg.Config, chainId string, neatGenesisPath string) error {
   187  
   188  	init_neatchain(chainId, neatGenesisPath, ctx)
   189  
   190  	init_em_files(config, chainId, neatGenesisPath, nil)
   191  
   192  	return nil
   193  }
   194  
   195  func init_neatchain(chainId string, neatGenesisPath string, ctx *cli.Context) {
   196  
   197  	dbPath := filepath.Join(utils.MakeDataDir(ctx), chainId, clientIdentifier, "/chaindata")
   198  	log.Infof("init_neatchain 0 with dbPath: %s", dbPath)
   199  
   200  	chainDb, err := rawdb.NewLevelDBDatabase(filepath.Join(utils.MakeDataDir(ctx), chainId, clientIdentifier, "/chaindata"), 0, 0, "neatio/db/chaindata/")
   201  	if err != nil {
   202  		utils.Fatalf("could not open database: %v", err)
   203  	}
   204  	defer chainDb.Close()
   205  
   206  	log.Info("init_neatchain 1")
   207  	genesisFile, err := os.Open(neatGenesisPath)
   208  	if err != nil {
   209  		utils.Fatalf("failed to read genesis file: %v", err)
   210  	}
   211  	defer genesisFile.Close()
   212  
   213  	log.Info("init_neatchain 2")
   214  	block, err := core.WriteGenesisBlock(chainDb, genesisFile)
   215  	if err != nil {
   216  		utils.Fatalf("failed to write genesis block: %v", err)
   217  	}
   218  
   219  	log.Info("init_neatchain end")
   220  	log.Infof("successfully wrote genesis block and/or chain rule set: %x", block.Hash())
   221  }
   222  
   223  func init_em_files(config cfg.Config, chainId string, genesisPath string, validators []types.GenesisValidator) error {
   224  	gensisFile, err := os.Open(genesisPath)
   225  	defer gensisFile.Close()
   226  	if err != nil {
   227  		utils.Fatalf("failed to read neatio genesis file: %v", err)
   228  		return err
   229  	}
   230  	contents, err := ioutil.ReadAll(gensisFile)
   231  	if err != nil {
   232  		utils.Fatalf("failed to read neatio genesis file: %v", err)
   233  		return err
   234  	}
   235  	var coreGenesis = core.Genesis{}
   236  	if err := json.Unmarshal(contents, &coreGenesis); err != nil {
   237  		return err
   238  	}
   239  
   240  	var privValidator *types.PrivValidator
   241  
   242  	if validators == nil {
   243  		privValPath := config.GetString("priv_validator_file")
   244  		if _, err := os.Stat(privValPath); os.IsNotExist(err) {
   245  			log.Info("priv_validator_file not exist, probably you are running in non-mining mode")
   246  			return nil
   247  		}
   248  
   249  		privValidator = types.LoadPrivValidator(privValPath)
   250  	}
   251  
   252  	if err := createGenesisDoc(config, chainId, &coreGenesis, privValidator, validators); err != nil {
   253  		utils.Fatalf("failed to write genesis file: %v", err)
   254  		return err
   255  	}
   256  	return nil
   257  }
   258  
   259  func createGenesisDoc(config cfg.Config, chainId string, coreGenesis *core.Genesis, privValidator *types.PrivValidator, validators []types.GenesisValidator) error {
   260  	genFile := config.GetString("genesis_file")
   261  	if _, err := os.Stat(genFile); os.IsNotExist(err) {
   262  
   263  		posReward, _ := new(big.Int).SetString(TotalMintingReward, 10)
   264  		totalYear := TotalMintingYears
   265  		rewardFirstYear := new(big.Int).Div(posReward, big.NewInt(int64(totalYear)))
   266  
   267  		var rewardScheme types.RewardSchemeDoc
   268  		if chainId == MainChain || chainId == TestnetChain {
   269  			rewardScheme = types.RewardSchemeDoc{
   270  				TotalReward:        posReward,
   271  				RewardFirstYear:    rewardFirstYear,
   272  				EpochNumberPerYear: 365,
   273  				TotalMintingYears:  uint64(totalYear),
   274  			}
   275  		} else {
   276  			rewardScheme = types.RewardSchemeDoc{
   277  				TotalReward:        big.NewInt(0),
   278  				RewardFirstYear:    big.NewInt(0),
   279  				EpochNumberPerYear: 1,
   280  				TotalMintingYears:  0,
   281  			}
   282  		}
   283  
   284  		var rewardPerBlock *big.Int
   285  		if chainId == MainChain || chainId == TestnetChain {
   286  			rewardPerBlock = big.NewInt(507356671740000000)
   287  		} else {
   288  			rewardPerBlock = big.NewInt(0)
   289  		}
   290  
   291  		fmt.Printf("init reward block %v\n", rewardPerBlock)
   292  		genDoc := types.GenesisDoc{
   293  			ChainID:      chainId,
   294  			Consensus:    types.CONSENSUS_NEATCON,
   295  			GenesisTime:  time.Now(),
   296  			RewardScheme: rewardScheme,
   297  			CurrentEpoch: types.OneEpochDoc{
   298  				Number:         0,
   299  				RewardPerBlock: rewardPerBlock,
   300  				StartBlock:     0,
   301  				EndBlock:       17280,
   302  				Status:         0,
   303  			},
   304  		}
   305  
   306  		if privValidator != nil {
   307  			coinbase, amount, checkErr := checkAccount(*coreGenesis)
   308  			if checkErr != nil {
   309  				log.Infof(checkErr.Error())
   310  				cmn.Exit(checkErr.Error())
   311  			}
   312  
   313  			genDoc.CurrentEpoch.Validators = []types.GenesisValidator{{
   314  				EthAccount: coinbase,
   315  				PubKey:     privValidator.PubKey,
   316  				Amount:     amount,
   317  			}}
   318  		} else if validators != nil {
   319  			genDoc.CurrentEpoch.Validators = validators
   320  		}
   321  		genDoc.SaveAs(genFile)
   322  	}
   323  	return nil
   324  }
   325  
   326  func generateNTCGenesis(sideChainID string, validators []types.GenesisValidator) ([]byte, error) {
   327  	var rewardScheme = types.RewardSchemeDoc{
   328  		TotalReward:        big.NewInt(0),
   329  		RewardFirstYear:    big.NewInt(0),
   330  		EpochNumberPerYear: 365,
   331  		TotalMintingYears:  0,
   332  	}
   333  
   334  	genDoc := types.GenesisDoc{
   335  		ChainID:      sideChainID,
   336  		Consensus:    types.CONSENSUS_NEATCON,
   337  		GenesisTime:  time.Now(),
   338  		RewardScheme: rewardScheme,
   339  		CurrentEpoch: types.OneEpochDoc{
   340  			Number:         0,
   341  			RewardPerBlock: big.NewInt(0),
   342  			StartBlock:     0,
   343  			EndBlock:       17280,
   344  			Status:         0,
   345  			Validators:     validators,
   346  		},
   347  	}
   348  
   349  	contents, err := json.Marshal(genDoc)
   350  	if err != nil {
   351  		utils.Fatalf("marshal ntc Genesis failed")
   352  		return nil, err
   353  	}
   354  	return contents, nil
   355  }
   356  
   357  func parseBalaceAmount(s string) ([]*BalaceAmount, error) {
   358  	r, _ := regexp.Compile("\\{[\\ \\t]*\\d+(\\.\\d+)?[\\ \\t]*\\,[\\ \\t]*\\d+(\\.\\d+)?[\\ \\t]*\\}")
   359  	parse_strs := r.FindAllString(s, -1)
   360  	if len(parse_strs) == 0 {
   361  		return nil, InvalidArgs{s}
   362  	}
   363  	balanceAmounts := make([]*BalaceAmount, len(parse_strs))
   364  	for i, v := range parse_strs {
   365  		length := len(v)
   366  		balanceAmount := strings.Split(v[1:length-1], ",")
   367  		if len(balanceAmount) != 2 {
   368  			return nil, InvalidArgs{s}
   369  		}
   370  		balanceAmounts[i] = &BalaceAmount{strings.TrimSpace(balanceAmount[0]), strings.TrimSpace(balanceAmount[1])}
   371  	}
   372  	return balanceAmounts, nil
   373  }
   374  
   375  func createPriValidators(config cfg.Config, num int) []*types.PrivValidator {
   376  	validators := make([]*types.PrivValidator, num)
   377  
   378  	ks := keystore.NewKeyStore(config.GetString("keystore"), keystore.StandardScryptN, keystore.StandardScryptP)
   379  
   380  	privValFile := config.GetString("priv_validator_file_root")
   381  	for i := 0; i < num; i++ {
   382  
   383  		account, err := ks.NewAccount(DefaultAccountPassword)
   384  		if err != nil {
   385  			utils.Fatalf("Failed to create NeatIO account: %v", err)
   386  		}
   387  
   388  		validators[i] = types.GenPrivValidatorKey(account.Address)
   389  		log.Info("createPriValidators", "account:", validators[i].Address, "pwd:", DefaultAccountPassword)
   390  		if i > 0 {
   391  			validators[i].SetFile(privValFile + strconv.Itoa(i) + ".json")
   392  		} else {
   393  			validators[i].SetFile(privValFile + ".json")
   394  		}
   395  		validators[i].Save()
   396  	}
   397  	return validators
   398  }
   399  
   400  func checkAccount(coreGenesis core.Genesis) (common.Address, *big.Int, error) {
   401  
   402  	coinbase := coreGenesis.Coinbase
   403  	log.Infof("checkAccount(), coinbase is %v", coinbase.String())
   404  
   405  	var act common.Address
   406  	amount := big.NewInt(-1)
   407  	balance := big.NewInt(-1)
   408  	found := false
   409  	for address, account := range coreGenesis.Alloc {
   410  		log.Infof("checkAccount(), address is %v, balance is %v, amount is %v", address.String(), account.Balance, account.Amount)
   411  		balance = account.Balance
   412  		amount = account.Amount
   413  		act = address
   414  		found = true
   415  		break
   416  	}
   417  
   418  	if !found {
   419  		log.Error("invalidate eth_account")
   420  		return common.Address{}, nil, errors.New("invalidate eth_account")
   421  	}
   422  
   423  	if balance.Sign() == -1 || amount.Sign() == -1 {
   424  		log.Errorf("balance / amount can't be negative integer, balance is %v, amount is %v", balance, amount)
   425  		return common.Address{}, nil, errors.New("no enough balance")
   426  	}
   427  
   428  	return act, amount, nil
   429  }
   430  
   431  func initEthGenesisFromExistValidator(sideChainID string, sideConfig cfg.Config, validators []types.GenesisValidator) error {
   432  
   433  	contents, err := generateETHGenesis(sideChainID, validators)
   434  	if err != nil {
   435  		return err
   436  	}
   437  	ethGenesisPath := sideConfig.GetString("neat_genesis_file")
   438  	if err = ioutil.WriteFile(ethGenesisPath, contents, 0654); err != nil {
   439  		utils.Fatalf("write neat_genesis_file failed")
   440  		return err
   441  	}
   442  	return nil
   443  }
   444  
   445  func generateETHGenesis(sideChainID string, validators []types.GenesisValidator) ([]byte, error) {
   446  	var coreGenesis = core.Genesis{
   447  		Config:     params.NewSideChainConfig(sideChainID),
   448  		Nonce:      0xdeadbeefdeadbeef,
   449  		Timestamp:  0x0,
   450  		ParentHash: common.Hash{},
   451  		ExtraData:  []byte("0x0"),
   452  		GasLimit:   0x8000000,
   453  		Difficulty: new(big.Int).SetUint64(0x400),
   454  		Mixhash:    common.Hash{},
   455  		Coinbase:   common.Address{},
   456  		Alloc:      core.GenesisAlloc{},
   457  	}
   458  	for _, validator := range validators {
   459  		coreGenesis.Alloc[validator.EthAccount] = core.GenesisAccount{
   460  			Balance: big.NewInt(0),
   461  			Amount:  validator.Amount,
   462  		}
   463  	}
   464  
   465  	coreGenesis.Alloc[abi.NeatioSideChainsAddress] = core.GenesisAccount{
   466  		Balance: new(big.Int).Mul(big.NewInt(100000), big.NewInt(1e+18)),
   467  		Amount:  common.Big0,
   468  	}
   469  
   470  	contents, err := json.Marshal(coreGenesis)
   471  	if err != nil {
   472  		utils.Fatalf("marshal coreGenesis failed")
   473  		return nil, err
   474  	}
   475  	return contents, nil
   476  }