github.com/Gessiux/neatchain@v1.3.1/chain/neatchain/init.go (about)

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