github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/neatio/init.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 8 "github.com/neatlab/neatio/chain/core/rawdb" 9 "github.com/neatlab/neatio/chain/log" 10 "github.com/neatlab/neatio/neatabi/abi" 11 "github.com/neatlab/neatio/utilities/common/hexutil" 12 "github.com/neatlab/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 "github.com/neatlab/neatio/chain/accounts/keystore" 25 "github.com/neatlab/neatio/chain/consensus/neatcon/types" 26 "github.com/neatlab/neatio/chain/core" 27 "github.com/neatlab/neatio/params" 28 "github.com/neatlab/neatio/utilities/common" 29 "github.com/neatlab/neatio/utilities/utils" 30 cmn "github.com/neatlib/common-go" 31 cfg "github.com/neatlib/config-go" 32 dbm "github.com/neatlib/db-go" 33 "github.com/pkg/errors" 34 ) 35 36 const ( 37 TotalMintingReward = "44471380000000000000000000" 38 TotalMintingYears = 15 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: 8760, 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(142976401748971000) 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: 2400, 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: 8760, 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: 2400, 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 }