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 }