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 }