diff --git a/cmd/harmony/main.go b/cmd/harmony/main.go index 05d2cf64b..18e53a507 100644 --- a/cmd/harmony/main.go +++ b/cmd/harmony/main.go @@ -9,6 +9,8 @@ import ( "runtime" "time" + "github.com/harmony-one/harmony/internal/utils/contract" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/harmony-one/harmony/consensus" @@ -119,18 +121,28 @@ func createGlobalConfig() *nodeconfig.ConfigType { // Currently we hardcode only one shard. nodeConfig.ShardIDString = "0" - nodeConfig.StakingPriKey = node.LoadStakingKeyFromFile(*stakingKeyFile, *accountIndex) + // Key Setup ================= [Start] + // Staking private key is the ecdsa key used for token related transaction signing (especially the staking txs). + stakingPriKey := "" + if *isBeacon { + stakingPriKey = contract.InitialBeaconChainAccounts[*accountIndex].Private + } else { + stakingPriKey = contract.NewNodeAccounts[*accountIndex].Private + } + nodeConfig.StakingPriKey = node.StoreStakingKeyFromFile(*stakingKeyFile, stakingPriKey) + // P2p private key is used for secure message transfer between p2p nodes. nodeConfig.P2pPriKey, _, err = utils.LoadKeyFromFile(*keyFile) if err != nil { panic(err) } - // Setup Bls keys + // Consensus keys are the BLS12-381 keys used to sign consensus messages nodeConfig.ConsensusPriKey, nodeConfig.ConsensusPubKey = utils.GenKey(*ip, *port) if nodeConfig.ConsensusPriKey == nil || nodeConfig.ConsensusPubKey == nil { panic(fmt.Errorf("generate key error")) } + // Key Setup ================= [End] // Initialize leveldb for main blockchain and beacon. if nodeConfig.MainDB, err = InitLDBDatabase(*ip, *port, *freshDB, false); err != nil { diff --git a/core/blockchain.go b/core/blockchain.go index 5a468b52d..4b662bcf4 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1653,7 +1653,7 @@ func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscript return bc.scope.Track(bc.logsFeed.Subscribe(ch)) } -// GetShardState retrives sharding state given block hash and block number +// GetShardState retrieves sharding state given block hash and block number func (bc *BlockChain) GetShardState(hash common.Hash, number uint64) types.ShardState { if cached, ok := bc.shardStateCache.Get(hash); ok { shardState := cached.(types.ShardState) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 61df9bf6b..42f0ea2dd 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -374,7 +374,7 @@ func FindCommonAncestor(db DatabaseReader, a, b *types.Header) *types.Header { return a } -// ReadShardState retrieves sharding state +// ReadShardState retrieves sharding state. func ReadShardState(db DatabaseReader, hash common.Hash, number uint64) types.ShardState { data, _ := db.Get(shardStateKey(number, hash)) if len(data) == 0 { @@ -388,7 +388,7 @@ func ReadShardState(db DatabaseReader, hash common.Hash, number uint64) types.Sh return shardState } -// WriteShardState stores sharding state into database +// WriteShardState stores sharding state into database. func WriteShardState(db DatabaseWriter, hash common.Hash, number uint64, shardState types.ShardState) { data, err := rlp.EncodeToBytes(shardState) if err != nil { diff --git a/core/resharding.go b/core/resharding.go index 4241dadd0..d4ae206d9 100644 --- a/core/resharding.go +++ b/core/resharding.go @@ -86,6 +86,7 @@ func (ss *ShardingState) assignLeaders() { func (ss *ShardingState) UpdateShardState(newNodeList []types.NodeID, percent float64) { rand.Seed(int64(ss.rnd)) ss.sortCommitteeBySize() + // TODO: separate shuffling and leader assignment ss.assignLeaders() ss.assignNewNodes(newNodeList) ss.cuckooResharding(percent) @@ -124,7 +125,7 @@ func GetShardingStateFromBlockChain(bc *BlockChain, epoch uint64) *ShardingState return &ShardingState{epoch: epoch, rnd: rndSeed, shardState: shardState, numShards: len(shardState)} } -// CalculateNewShardState get sharding state from previous epoch and calcualte sharding state for new epoch +// CalculateNewShardState get sharding state from previous epoch and calculate sharding state for new epoch // TODO: currently, we just mock everything func CalculateNewShardState(bc *BlockChain, epoch uint64) types.ShardState { if epoch == FirstEpoch { diff --git a/internal/utils/contract/constants.go b/internal/utils/contract/constants.go index f9de9a692..0f9bbb3f4 100644 --- a/internal/utils/contract/constants.go +++ b/internal/utils/contract/constants.go @@ -38,18 +38,8 @@ var GenesisBeaconAccountPublicKey = GenesisBeaconAccountPriKey.PublicKey // DeployedContractAddress is the deployed contract address of the staking smart contract in beacon chain. var DeployedContractAddress = crypto.CreateAddress(crypto.PubkeyToAddress(GenesisBeaconAccountPublicKey), uint64(0)) -// StakingAccounts is the accounts only used for staking. -var StakingAccounts = [...]DeployAccount{ - {Address: "0xE2bD4413172C98d5094B94de1A8AC6a383d68b84", Private: "e401343197a852f361e38ce6b46c99f1d6d1f80499864c6ae7effee42b46ab6b", Public: "0xE2bD4413172C98d5094B94de1A8AC6a383d68b84"}, - {Address: "0x183418934Fd8A97c98E086151317B2df6259b8A8", Private: "a7d764439a7619f703c97ee2a2cf0be2cd62ad4c9deebd5423d6f28de417b907", Public: "0x183418934Fd8A97c98E086151317B2df6259b8A8"}, - {Address: "0x9df0e70D4cb3E9beC0548D8Ac56F46596D1BcdB6", Private: "4e3f7c819a15249d2824834cd7ce20fe24d6eab8eb39ac63b78cb3713362cf78", Public: "0x9df0e70D4cb3E9beC0548D8Ac56F46596D1BcdB6"}, - {Address: "0x64570B8D2f9028b850340b6710bB0027baC5EFa2", Private: "8565eded3f70b2f8608495fa7e301fefc36cbc03286c0f4e75ffde7e02b49791", Public: "0x64570B8D2f9028b850340b6710bB0027baC5EFa2"}, - {Address: "0x7E653426a7E0c1D210A652bf0E74B15838059b80", Private: "23176da901759e231d7b2d8761f3448220fcfd0232ed0b9644689a6ad7d50990", Public: "0x7E653426a7E0c1D210A652bf0E74B15838059b80"}, - {Address: "0xAe44500A96756112C69F88008388037F6C6dd723", Private: "a9b4c273ffa398a1b1c8eeab63c40cef2c2fb2fc1fc4de9ab73a61f12e4d990a", Public: "0xAe44500A96756112C69F88008388037F6C6dd723"}, -} - -// FakeAccounts is the accounts only used for development purpose. -var FakeAccounts = [...]DeployAccount{ +// InitialBeaconChainAccounts are the accounts for the initial beacon chain node. +var InitialBeaconChainAccounts = [...]DeployAccount{ {Address: "0xE2bD4413172C98d5094B94de1A8AC6a383d68b84", Private: "e401343197a852f361e38ce6b46c99f1d6d1f80499864c6ae7effee42b46ab6b", Public: "0xE2bD4413172C98d5094B94de1A8AC6a383d68b84"}, {Address: "0x183418934Fd8A97c98E086151317B2df6259b8A8", Private: "a7d764439a7619f703c97ee2a2cf0be2cd62ad4c9deebd5423d6f28de417b907", Public: "0x183418934Fd8A97c98E086151317B2df6259b8A8"}, {Address: "0x9df0e70D4cb3E9beC0548D8Ac56F46596D1BcdB6", Private: "4e3f7c819a15249d2824834cd7ce20fe24d6eab8eb39ac63b78cb3713362cf78", Public: "0x9df0e70D4cb3E9beC0548D8Ac56F46596D1BcdB6"}, @@ -60,6 +50,10 @@ var FakeAccounts = [...]DeployAccount{ {Address: "0x6f7659765a8784F782fc6Bcdb153e915076bb9F0", Private: "24be53d408b360cc1a3608d54fa8ba070692bbe8f594062c30a5e9e89cee9794", Public: "0x6f7659765a8784F782fc6Bcdb153e915076bb9F0"}, {Address: "0xfA24E616BaE95160878C7F1150d1e014904809E9", Private: "41d628799eee7637bd79ae9fc2fd1321cffbb4b858348d6abf5b4247b78fd492", Public: "0xfA24E616BaE95160878C7F1150d1e014904809E9"}, {Address: "0x47DF74d43fa4Ca1D814897eBD8Cf07e6bA024f75", Private: "d5a62757aa51f2ae883c5cb8631d312750ecc31f3934fffd95bcd969bd190c94", Public: "0x47DF74d43fa4Ca1D814897eBD8Cf07e6bA024f75"}, +} + +// NewNodeAccounts is the accounts used for new node to stake and join the network. +var NewNodeAccounts = [...]DeployAccount{ {Address: "0x1a3e7a44ee21101d7D64FBf29B0F6F1fc295F723", Private: "27978f895b11d9c737e1ab1623fde722c04b4f9ccb4ab776bf15932cc72d7c66", Public: "0x1a3e7a44ee21101d7D64FBf29B0F6F1fc295F723"}, {Address: "0x10A02A0a6e95a676AE23e2db04BEa3D1B8b7ca2E", Private: "371cb68abe6a6101ac88603fc847e0c013a834253acee5315884d2c4e387ebca", Public: "0x10A02A0a6e95a676AE23e2db04BEa3D1B8b7ca2E"}, {Address: "0x3e881F6C36A3A14a2D1816b0A5471d1caBB16F33", Private: "3f8af52063c6648be37d4b33559f784feb16d8e5ffaccf082b3657ea35b05977", Public: "0x3e881F6C36A3A14a2D1816b0A5471d1caBB16F33"}, diff --git a/node/contract.go b/node/contract.go index 22c0cbf1f..46e35771e 100644 --- a/node/contract.go +++ b/node/contract.go @@ -16,7 +16,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/harmony-one/harmony/core/types" - "github.com/harmony-one/harmony/internal/utils/contract" contract_constants "github.com/harmony-one/harmony/internal/utils/contract" ) @@ -158,16 +157,3 @@ func (node *Node) callGetFreeTokenWithNonce(address common.Address, nonce uint64 node.addPendingTransactions(types.Transactions{tx}) return tx.Hash() } - -// DepositToStakingAccounts invokes the faucet contract to give the staking accounts initial money -func (node *Node) DepositToStakingAccounts() { - state, err := node.blockchain.State() - if err != nil { - log.Error("Failed to get chain state", "Error", err) - } - nonce := state.GetNonce(crypto.PubkeyToAddress(node.ContractDeployerKey.PublicKey)) + 1 // + 1 because deployer key is already used for faucet contract deployment - for i, deployAccount := range contract.StakingAccounts { - address := common.HexToAddress(deployAccount.Address) - node.callGetFreeTokenWithNonce(address, nonce+uint64(i)) - } -} diff --git a/node/node.go b/node/node.go index 08c428c8c..2a7c6a976 100644 --- a/node/node.go +++ b/node/node.go @@ -254,7 +254,6 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, db ethdb.Database) *N node.AddFaucetContractToPendingTransactions() node.CurrentStakes = make(map[common.Address]*big.Int) node.AddStakingContractToPendingTransactions() //This will save the latest information about staked nodes in current staked - node.DepositToStakingAccounts() } node.ContractCaller = contracts.NewContractCaller(&db, node.blockchain, params.TestChainConfig) diff --git a/node/node_genesis.go b/node/node_genesis.go index 9525024d7..4b373a651 100644 --- a/node/node_genesis.go +++ b/node/node_genesis.go @@ -6,6 +6,9 @@ import ( "math/rand" "strings" + "github.com/ethereum/go-ethereum/common" + "github.com/harmony-one/harmony/internal/utils/contract" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" @@ -16,14 +19,17 @@ import ( const ( // FakeAddressNumber is the number of fake address. FakeAddressNumber = 100 - // TotalInitFund is the initial total fund to the faucet. + // TotalInitFund is the initial total fund for the contract deployer. TotalInitFund = 9000000 ) // GenesisBlockSetup setups a genesis blockchain. func (node *Node) GenesisBlockSetup(db ethdb.Database) (*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) @@ -31,6 +37,9 @@ func (node *Node) GenesisBlockSetup(db ethdb.Database) (*core.BlockChain, error) genesisAlloc[contractDeployerAddress] = core.GenesisAccount{Balance: contractDeployerFunds} node.ContractDeployerKey = contractDeployerKey + // Accounts used by validator/nodes to stake and participate in the network. + AddNodeAddressesToGenesisAlloc(genesisAlloc) + chainConfig := params.TestChainConfig chainConfig.ChainID = big.NewInt(int64(node.Consensus.ShardID)) // Use ChainID as piggybacked ShardID gspec := core.Genesis{ @@ -45,7 +54,7 @@ func (node *Node) GenesisBlockSetup(db ethdb.Database) (*core.BlockChain, error) } // CreateGenesisAllocWithTestingAddresses create the genesis block allocation that contains deterministically -// generated testing addressess with tokens. +// generated testing addressess 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) @@ -66,3 +75,20 @@ func (node *Node) CreateGenesisAllocWithTestingAddresses(numAddress int) core.Ge } 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.InitialBeaconChainAccounts { + testBankFunds := big.NewInt(100) + 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(100) + testBankFunds = testBankFunds.Mul(testBankFunds, big.NewInt(params.Ether)) + address := common.HexToAddress(account.Address) + genesisAlloc[address] = core.GenesisAccount{Balance: testBankFunds} + } +} diff --git a/node/staking.go b/node/staking.go index e34a99671..424c85b34 100644 --- a/node/staking.go +++ b/node/staking.go @@ -9,8 +9,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/harmony-one/harmony/internal/utils/contract" - "github.com/harmony-one/harmony/internal/utils" "github.com/ethereum/go-ethereum/common/hexutil" @@ -84,14 +82,10 @@ func decodeFuncSign(data []byte) string { return funcSign } -// LoadStakingKeyFromFile load staking private key from keyfile -// If the private key is not loadable or no file, it will generate -// a new random private key -// Currently for deploy_newnode.sh, we hard-coded the first fake account as staking account and -// it is minted in genesis block. See genesis_node.go -func LoadStakingKeyFromFile(keyfile string, accountIndex int) *ecdsa.PrivateKey { +// StoreStakingKeyFromFile load the staking private key and store it in local keyfile +func StoreStakingKeyFromFile(keyfile string, priKey string) *ecdsa.PrivateKey { // contract.FakeAccounts[0] gets minted tokens in genesis block of beacon chain. - key, err := crypto.HexToECDSA(contract.StakingAccounts[accountIndex].Private) + key, err := crypto.HexToECDSA(priKey) if err != nil { utils.GetLogInstance().Error("Unable to get staking key") os.Exit(1) diff --git a/test/configs/beaconchain.txt b/test/configs/beaconchain.txt new file mode 100644 index 000000000..a6cfdea2e --- /dev/null +++ b/test/configs/beaconchain.txt @@ -0,0 +1,10 @@ +127.0.0.1 9000 leader 0 +127.0.0.1 9001 validator 0 +127.0.0.1 9002 validator 0 +127.0.0.1 9003 validator 0 +127.0.0.1 9004 validator 0 +127.0.0.1 9005 validator 0 +127.0.0.1 9006 validator 0 +127.0.0.1 9007 validator 0 +127.0.0.1 9008 validator 0 +127.0.0.1 9009 validator 0