github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/cmd/intchain/init.go (about)

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