package node import ( "crypto/ecdsa" "math/big" "math/rand" "strings" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core/vm" "github.com/harmony-one/harmony/internal/utils/contract" ) const ( // FakeAddressNumber is the number of fake address. FakeAddressNumber = 100 // TotalInitFund is the initial total fund for the contract deployer. TotalInitFund = 9000000 // InitFreeFundInEther is the initial fund for sample accounts. InitFreeFundInEther = 1000 ) // GenesisBlockSetup setups a genesis blockchain. func (node *Node) GenesisBlockSetup(db ethdb.Database, shardID uint32, isArchival bool) (*core.BlockChain, error) { // Initialize genesis block and blockchain // Tests account for txgen to use genesisAlloc := node.CreateGenesisAllocWithTestingAddresses(FakeAddressNumber) // Smart contract deployer account used to deploy protocol-level smart contract contractDeployerKey, _ := ecdsa.GenerateKey(crypto.S256(), strings.NewReader("Test contract key string stream that is fixed so that generated test key are deterministic every time")) contractDeployerAddress := crypto.PubkeyToAddress(contractDeployerKey.PublicKey) contractDeployerFunds := big.NewInt(TotalInitFund) contractDeployerFunds = contractDeployerFunds.Mul(contractDeployerFunds, big.NewInt(params.Ether)) genesisAlloc[contractDeployerAddress] = core.GenesisAccount{Balance: contractDeployerFunds} node.ContractDeployerKey = contractDeployerKey if shardID == 0 { // Accounts used by validator/nodes to stake and participate in the network. AddNodeAddressesToGenesisAlloc(genesisAlloc) } // TODO: create separate chain config instead of using the same pointer reference chainConfig := *params.TestChainConfig chainConfig.ChainID = big.NewInt(int64(shardID)) // Use ChainID as piggybacked ShardID gspec := core.Genesis{ Config: &chainConfig, Alloc: genesisAlloc, ShardID: shardID, ShardStateHash: core.GetInitShardState().Hash(), } // Store genesis block into db. gspec.MustCommit(db) cacheConfig := core.CacheConfig{} if isArchival { cacheConfig = core.CacheConfig{Disabled: true, TrieNodeLimit: 256 * 1024 * 1024, TrieTimeLimit: 30 * time.Second} } return core.NewBlockChain(db, &cacheConfig, gspec.Config, node.Consensus, vm.Config{}, nil) } // CreateGenesisAllocWithTestingAddresses create the genesis block allocation that contains deterministically // generated testing addresses with tokens. This is mostly used for generated simulated transactions in txgen. // TODO: Remove it later when moving to production. func (node *Node) CreateGenesisAllocWithTestingAddresses(numAddress int) core.GenesisAlloc { rand.Seed(0) len := 1000000 bytes := make([]byte, len) for i := 0; i < len; i++ { bytes[i] = byte(rand.Intn(100)) } reader := strings.NewReader(string(bytes)) genesisAloc := make(core.GenesisAlloc) for i := 0; i < numAddress; i++ { testBankKey, _ := ecdsa.GenerateKey(crypto.S256(), reader) testBankAddress := crypto.PubkeyToAddress(testBankKey.PublicKey) testBankFunds := big.NewInt(InitFreeFundInEther) testBankFunds = testBankFunds.Mul(testBankFunds, big.NewInt(params.Ether)) genesisAloc[testBankAddress] = core.GenesisAccount{Balance: testBankFunds} node.TestBankKeys = append(node.TestBankKeys, testBankKey) } return genesisAloc } // AddNodeAddressesToGenesisAlloc adds to the genesis block allocation the accounts used for network validators/nodes, // including the account used by the nodes of the initial beacon chain and later new nodes. func AddNodeAddressesToGenesisAlloc(genesisAlloc core.GenesisAlloc) { for _, account := range contract.GenesisAccounts { testBankFunds := big.NewInt(InitFreeFundInEther) testBankFunds = testBankFunds.Mul(testBankFunds, big.NewInt(params.Ether)) address := common.HexToAddress(account.Address) genesisAlloc[address] = core.GenesisAccount{Balance: testBankFunds} } for _, account := range contract.NewNodeAccounts { testBankFunds := big.NewInt(InitFreeFundInEther) testBankFunds = testBankFunds.Mul(testBankFunds, big.NewInt(params.Ether)) address := common.HexToAddress(account.Address) genesisAlloc[address] = core.GenesisAccount{Balance: testBankFunds} } for _, account := range contract.DemoAccounts { testBankFunds := big.NewInt(InitFreeFundInEther) testBankFunds = testBankFunds.Mul(testBankFunds, big.NewInt(params.Ether)) address := common.HexToAddress(account.Address) genesisAlloc[address] = core.GenesisAccount{Balance: testBankFunds} } }