diff --git a/cmd/client/wallet/main.go b/cmd/client/wallet/main.go index eacad1d5a..8c974f767 100644 --- a/cmd/client/wallet/main.go +++ b/cmd/client/wallet/main.go @@ -646,7 +646,7 @@ func processTransferCommand() { shardIDToAccountState := FetchBalance(senderAddress) state := shardIDToAccountState[shardID] - if state != nil { + if state == nil { fmt.Printf("Failed connecting to the shard %d\n", shardID) return } diff --git a/cmd/harmony/main.go b/cmd/harmony/main.go index eeb9a5f94..c322a0917 100644 --- a/cmd/harmony/main.go +++ b/cmd/harmony/main.go @@ -97,6 +97,8 @@ var ( delayCommit = flag.String("delay_commit", "0ms", "how long to delay sending commit messages in consensus, ex: 500ms, 1s") // isExplorer indicates this node is a node to serve explorer isExplorer = flag.Bool("is_explorer", false, "true means this node is a node to serve explorer") + // networkType indicates the type of the network + networkType = flag.String("network_type", "mainnet", "type of the network: mainnet, testnet, devnet...") // isNewNode indicates this node is a new node isNewNode = flag.Bool("is_newnode", false, "true means this node is a new node") shardID = flag.Int("shard_id", -1, "the shard ID of this node") @@ -245,6 +247,18 @@ func createGlobalConfig() *nodeconfig.ConfigType { nodeConfig = nodeconfig.GetShardConfig(uint32(*shardID)) } + // Set network type + switch *networkType { + case "mainnet": + nodeConfig.SetNetworkType(nodeconfig.Mainnet) + case "testnet": + nodeConfig.SetNetworkType(nodeconfig.Testnet) + case "devnet": + nodeConfig.SetNetworkType(nodeconfig.Devnet) + default: + panic(fmt.Sprintf("invalid network type: %s", *networkType)) + } + nodeConfig.SelfPeer = p2p.Peer{IP: *ip, Port: *port, ConsensusPubKey: nodeConfig.ConsensusPubKey} if accountIndex < core.GenesisShardNum && !*isExplorer { // The first node in a shard is the leader at genesis diff --git a/common/config/global_config.go b/common/config/global_config.go deleted file mode 100644 index eb9dd717c..000000000 --- a/common/config/global_config.go +++ /dev/null @@ -1,14 +0,0 @@ -package config - -// NetworkType describes the type of Harmony network -type NetworkType int - -// Constants for NetworkType -const ( - Mainnet NetworkType = 0 - Testnet NetworkType = 1 - Devnet NetworkType = 2 -) - -// Network is the type of Harmony network -var Network = Testnet diff --git a/internal/configs/node/config.go b/internal/configs/node/config.go index 946a6f195..e1ff1d52c 100644 --- a/internal/configs/node/config.go +++ b/internal/configs/node/config.go @@ -55,6 +55,31 @@ func (role Role) String() string { return "Unknown" } +// NetworkType describes the type of Harmony network +type NetworkType int + +// Constants for NetworkType +const ( + Mainnet NetworkType = iota + Testnet + Devnet +) + +func (network NetworkType) String() string { + switch network { + case Mainnet: + return "Mainnet" + case Testnet: + return "Testnet" + case Devnet: + return "Devnet" + } + return "Unknown" +} + +// Network is the type of Harmony network +var Network = Testnet + // Global is the index of the global node configuration const ( Global = 0 @@ -87,6 +112,8 @@ type ConfigType struct { SelfPeer p2p.Peer Leader p2p.Peer + + networkType NetworkType } // configs is a list of node configuration. @@ -202,3 +229,13 @@ func (conf *ConfigType) IsLeader() bool { func (conf *ConfigType) Role() Role { return conf.role } + +// SetNetworkType set the networkType +func (conf *ConfigType) SetNetworkType(networkType NetworkType) { + conf.networkType = networkType +} + +// GetNetworkType gets the networkType +func (conf *ConfigType) GetNetworkType() NetworkType { + return conf.networkType +} diff --git a/node/node.go b/node/node.go index efd8de139..20e8404b5 100644 --- a/node/node.go +++ b/node/node.go @@ -10,7 +10,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" "github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/harmony/accounts" "github.com/harmony-one/harmony/api/client" @@ -289,22 +288,21 @@ func (node *Node) GetSyncID() [SyncIDLength]byte { // New creates a new node. func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardchain.DBFactory, isArchival bool) *Node { - var err error - node := Node{} + + // Get the node config that's created in the harmony.go program. + if consensusObj != nil { + node.NodeConfig = nodeconfig.GetShardConfig(consensusObj.ShardID) + } else { + node.NodeConfig = nodeconfig.GetDefaultConfig() + } + copy(node.syncID[:], GenerateRandomString(SyncIDLength)) if host != nil { node.host = host node.SelfPeer = host.GetSelfPeer() } - // Create test keys. Genesis will later need this. - node.TestBankKeys, err = CreateTestBankKeys(TestAccountNumber) - if err != nil { - utils.GetLogInstance().Crit("Error while creating test keys", - "error", err) - } - collection := shardchain.NewCollection( chainDBFactory, &genesisInitializer{&node}, consensusObj) if isArchival { @@ -332,27 +330,37 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardc // Add Faucet contract to all shards, so that on testnet, we can demo wallet in explorer // TODO (leo): we need to have support of cross-shard tx later so that the token can be transferred from beacon chain shard to other tx shards. - if node.isFirstTime { - // Setup one time smart contracts - //node.AddFaucetContractToPendingTransactions() - } else { - node.AddContractKeyAndAddress(scFaucet) - } - - if node.Consensus.ShardID == 0 { - // Contracts only exist in beacon chain + if node.NodeConfig.GetNetworkType() != nodeconfig.Mainnet { if node.isFirstTime { // Setup one time smart contracts - node.CurrentStakes = make(map[common.Address]*structs.StakeInfo) - node.AddStakingContractToPendingTransactions() //This will save the latest information about staked nodes in current staked + node.AddFaucetContractToPendingTransactions() } else { - node.AddContractKeyAndAddress(scStaking) + node.AddContractKeyAndAddress(scFaucet) + } + + if node.Consensus.ShardID == 0 { + // Contracts only exist in beacon chain + if node.isFirstTime { + // Setup one time smart contracts + node.CurrentStakes = make(map[common.Address]*structs.StakeInfo) + node.AddStakingContractToPendingTransactions() //This will save the latest information about staked nodes in current staked + } else { + node.AddContractKeyAndAddress(scStaking) + } + } + + node.ContractCaller = contracts.NewContractCaller(node.Blockchain(), node.Blockchain().Config()) + + // Create test keys. Genesis will later need this. + var err error + node.TestBankKeys, err = CreateTestBankKeys(TestAccountNumber) + if err != nil { + utils.GetLogInstance().Crit("Error while creating test keys", + "error", err) } } } - node.ContractCaller = contracts.NewContractCaller(node.Blockchain(), params.TestChainConfig) - if consensusObj != nil && nodeconfig.GetDefaultConfig().IsLeader() { node.State = NodeLeader } else { @@ -375,13 +383,6 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, chainDBFactory shardc node.startConsensus = make(chan struct{}) - // Get the node config that's created in the harmony.go program. - if consensusObj != nil { - node.NodeConfig = nodeconfig.GetShardConfig(consensusObj.ShardID) - } else { - node.NodeConfig = nodeconfig.GetDefaultConfig() - } - return &node } diff --git a/node/node_genesis.go b/node/node_genesis.go index 00d5bc71d..7c788cf67 100644 --- a/node/node_genesis.go +++ b/node/node_genesis.go @@ -6,7 +6,9 @@ import ( "math/rand" "strings" - "github.com/harmony-one/harmony/common/config" + nodeconfig "github.com/harmony-one/harmony/internal/configs/node" + + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" @@ -17,18 +19,19 @@ import ( "github.com/harmony-one/harmony/core" "github.com/harmony-one/harmony/core/types" common2 "github.com/harmony-one/harmony/internal/common" - "github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/genesis" "github.com/harmony-one/harmony/internal/utils" ) const ( - // TestAccountNumber is the number of test accounts + // GenesisFund is the initial total fund in the genesis block for mainnet. + GenesisFund = 12600000000 + // TestAccountNumber is the number of test accounts for testnet/devnet/ TestAccountNumber = 100 - // TotalInitFund is the initial total fund for the contract deployer. - TotalInitFund = 12600000000 - // InitFreeFundInEther is the initial fund for permissioned accounts. - InitFreeFundInEther = 100 + // ContractDeployerInitFund is the initial fund for the contract deployer account in testnet/devnet. + ContractDeployerInitFund = 100000000 + // InitFreeFund is the initial fund for permissioned accounts for testnet/devnet/ + InitFreeFund = 100 ) // genesisInitializer is a shardchain.DBInitializer adapter. @@ -47,14 +50,12 @@ func (gi *genesisInitializer) InitChainDB(db ethdb.Database, shardID uint32) err } shardState = types.ShardState{*c} } - if err := gi.node.SetupGenesisBlock(db, shardID, shardState); err != nil { - return ctxerror.New("cannot setup genesis block").WithCause(err) - } + gi.node.SetupGenesisBlock(db, shardID, shardState) return nil } // SetupGenesisBlock sets up a genesis blockchain. -func (node *Node) SetupGenesisBlock(db ethdb.Database, shardID uint32, myShardState types.ShardState) error { +func (node *Node) SetupGenesisBlock(db ethdb.Database, shardID uint32, myShardState types.ShardState) { utils.GetLogger().Info("setting up a brand new chain database", "shardID", shardID) if shardID == node.Consensus.ShardID { @@ -66,10 +67,15 @@ func (node *Node) SetupGenesisBlock(db ethdb.Database, shardID uint32, myShardSt genesisAlloc := make(core.GenesisAlloc) chainConfig := params.ChainConfig{} - switch config.Network { - case config.Mainnet: + switch node.NodeConfig.GetNetworkType() { + case nodeconfig.Mainnet: chainConfig = *params.MainnetChainConfig - case config.Testnet: + foundationAddress := common.HexToAddress("0xE25ABC3f7C3d5fB7FB81EAFd421FF1621A61107c") + genesisFunds := big.NewInt(GenesisFund) + genesisFunds = genesisFunds.Mul(genesisFunds, big.NewInt(denominations.One)) + genesisAlloc[foundationAddress] = core.GenesisAccount{Balance: genesisFunds} + case nodeconfig.Testnet: + case nodeconfig.Devnet: chainConfig = *params.TestnetChainConfig // Tests account for txgen to use node.AddTestingAddresses(genesisAlloc, TestAccountNumber) @@ -77,20 +83,16 @@ func (node *Node) SetupGenesisBlock(db ethdb.Database, shardID uint32, myShardSt // Smart contract deployer account used to deploy initial 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 := big.NewInt(ContractDeployerInitFund) contractDeployerFunds = contractDeployerFunds.Mul(contractDeployerFunds, big.NewInt(denominations.One)) 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) - } - // Initialize shard state // TODO: add ShardID into chainconfig and change ChainID to NetworkID chainConfig.ChainID = big.NewInt(int64(shardID)) // Use ChainID as piggybacked ShardID + gspec := core.Genesis{ Config: &chainConfig, Alloc: genesisAlloc, @@ -100,9 +102,7 @@ func (node *Node) SetupGenesisBlock(db ethdb.Database, shardID uint32, myShardSt } // Store genesis block into db. - _, err := gspec.Commit(db) - - return err + gspec.MustCommit(db) } // CreateTestBankKeys deterministically generates testing addresses. @@ -128,7 +128,7 @@ func CreateTestBankKeys(numAddresses int) (keys []*ecdsa.PrivateKey, err error) func (node *Node) AddTestingAddresses(gAlloc core.GenesisAlloc, numAddress int) { for _, testBankKey := range node.TestBankKeys { testBankAddress := crypto.PubkeyToAddress(testBankKey.PublicKey) - testBankFunds := big.NewInt(InitFreeFundInEther) + testBankFunds := big.NewInt(InitFreeFund) testBankFunds = testBankFunds.Mul(testBankFunds, big.NewInt(denominations.One)) gAlloc[testBankAddress] = core.GenesisAccount{Balance: testBankFunds} } @@ -138,7 +138,7 @@ func (node *Node) AddTestingAddresses(gAlloc core.GenesisAlloc, numAddress int) // including the account used by the nodes of the initial beacon chain and later new nodes. func AddNodeAddressesToGenesisAlloc(genesisAlloc core.GenesisAlloc) { for _, account := range genesis.HarmonyAccounts { - testBankFunds := big.NewInt(InitFreeFundInEther) + testBankFunds := big.NewInt(InitFreeFund) testBankFunds = testBankFunds.Mul(testBankFunds, big.NewInt(denominations.One)) address := common2.ParseAddr(account.Address) genesisAlloc[address] = core.GenesisAccount{Balance: testBankFunds} diff --git a/node/node_handler.go b/node/node_handler.go index 5b44d0240..c7ab6c6a0 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -403,56 +403,55 @@ func (node *Node) PostConsensusProcessing(newBlock *types.Block) { node.AddNewBlock(newBlock) - // Update contract deployer's nonce so default contract like faucet can issue transaction with current nonce - nonce := node.GetNonceOfAddress(crypto.PubkeyToAddress(node.ContractDeployerKey.PublicKey)) - atomic.StoreUint64(&node.ContractDeployerCurrentNonce, nonce) - - for _, tx := range newBlock.Transactions() { - msg, err := tx.AsMessage(types.HomesteadSigner{}) - if err != nil { - utils.GetLogInstance().Error("Error when parsing tx into message") - } - if _, ok := node.AddressNonce.Load(msg.From()); ok { - nonce := node.GetNonceOfAddress(msg.From()) - node.AddressNonce.Store(msg.From(), nonce) - } - } - - if node.Consensus.ShardID == 0 { + if node.NodeConfig.GetNetworkType() != nodeconfig.Mainnet { // Update contract deployer's nonce so default contract like faucet can issue transaction with current nonce nonce := node.GetNonceOfAddress(crypto.PubkeyToAddress(node.ContractDeployerKey.PublicKey)) atomic.StoreUint64(&node.ContractDeployerCurrentNonce, nonce) - // TODO: enable drand only for beacon chain - // ConfirmedBlockChannel which is listened by drand leader who will initiate DRG if its a epoch block (first block of a epoch) - if node.DRand != nil { - go func() { - node.ConfirmedBlockChannel <- newBlock - }() + for _, tx := range newBlock.Transactions() { + msg, err := tx.AsMessage(types.HomesteadSigner{}) + if err != nil { + utils.GetLogInstance().Error("Error when parsing tx into message") + } + if _, ok := node.AddressNonce.Load(msg.From()); ok { + nonce := node.GetNonceOfAddress(msg.From()) + node.AddressNonce.Store(msg.From(), nonce) + } } - // TODO: update staking information once per epoch. - node.UpdateStakingList(node.QueryStakeInfo()) - node.printStakingList() - } - newBlockHeader := newBlock.Header() - if newBlockHeader.ShardStateHash != (common.Hash{}) { + // TODO: Enable the following after v0 if node.Consensus.ShardID == 0 { - // TODO ek – this is a temp hack until beacon chain sync is fixed - // End-of-epoch block on beacon chain; block's EpochState is the - // master resharding table. Broadcast it to the network. - if err := node.broadcastEpochShardState(newBlock); err != nil { - e := ctxerror.New("cannot broadcast shard state").WithCause(err) + // TODO: enable drand only for beacon chain + // ConfirmedBlockChannel which is listened by drand leader who will initiate DRG if its a epoch block (first block of a epoch) + if node.DRand != nil { + go func() { + node.ConfirmedBlockChannel <- newBlock + }() + } + + // TODO: update staking information once per epoch. + node.UpdateStakingList(node.QueryStakeInfo()) + node.printStakingList() + } + newBlockHeader := newBlock.Header() + if newBlockHeader.ShardStateHash != (common.Hash{}) { + if node.Consensus.ShardID == 0 { + // TODO ek – this is a temp hack until beacon chain sync is fixed + // End-of-epoch block on beacon chain; block's EpochState is the + // master resharding table. Broadcast it to the network. + if err := node.broadcastEpochShardState(newBlock); err != nil { + e := ctxerror.New("cannot broadcast shard state").WithCause(err) + ctxerror.Log15(utils.GetLogInstance().Error, e) + } + } + shardState, err := newBlockHeader.GetShardState() + if err != nil { + e := ctxerror.New("cannot get shard state from header").WithCause(err) ctxerror.Log15(utils.GetLogInstance().Error, e) + } else { + node.transitionIntoNextEpoch(shardState) } } - shardState, err := newBlockHeader.GetShardState() - if err != nil { - e := ctxerror.New("cannot get shard state from header").WithCause(err) - ctxerror.Log15(utils.GetLogInstance().Error, e) - } else { - node.transitionIntoNextEpoch(shardState) - } } } diff --git a/node/node_syncing.go b/node/node_syncing.go index 439e6c988..3d7e3d3d5 100644 --- a/node/node_syncing.go +++ b/node/node_syncing.go @@ -237,7 +237,7 @@ func (node *Node) CalculateResponse(request *downloader_pb.DownloaderRequest) (* copy(startHashHeader[:], request.BlockHash[:]) startBlock := node.Blockchain().GetBlockByHash(startHashHeader) if startBlock == nil { - return response, fmt.Errorf("[SYNC] GetBlockHashes Request cannot find startHash %v", startHashHeader) + return response, fmt.Errorf("[SYNC] GetBlockHashes Request cannot find startHash %s", startHashHeader.Hex()) } startHeight := startBlock.NumberU64() endHeight := node.Blockchain().CurrentBlock().NumberU64() diff --git a/test/deploy.sh b/test/deploy.sh index 4397d0e04..cac983182 100755 --- a/test/deploy.sh +++ b/test/deploy.sh @@ -176,7 +176,7 @@ while IFS='' read -r line || [[ -n "$line" ]]; do args=("${base_args[@]}" -ip "${ip}" -port "${port}" -key "/tmp/${ip}-${port}.key" -db_dir "db-${ip}-${port}" -accounts "${account}" -blspass file:blspass.txt -blskey_file "${blspub}.key") fi - args=("${base_args[@]}" -ip "${ip}" -port "${port}" -key "/tmp/${ip}-${port}.key" -db_dir "db-${ip}-${port}" -blspass file:blspass.txt -blskey_file "${blspub}.key") + args=("${base_args[@]}" -ip "${ip}" -port "${port}" -key "/tmp/${ip}-${port}.key" -db_dir "db-${ip}-${port}" -blspass file:blspass.txt -blskey_file "${blspub}.key" -dns=false -network_type="testnet") case "${mode}" in leader*|validator*) args=("${args[@]}" -is_genesis);; esac