Merge pull request #3278 from JackyWYX/cmd_remove_flags

[cmd] binary CLI overhaul
pull/3299/head
Leo Chen 4 years ago committed by GitHub
commit 03bf274048
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      .gitignore
  2. 105
      cmd/harmony/bls.go
  3. 247
      cmd/harmony/config.go
  4. 81
      cmd/harmony/config_test.go
  5. 149
      cmd/harmony/default.go
  6. 1075
      cmd/harmony/flags.go
  7. 867
      cmd/harmony/flags_test.go
  8. 720
      cmd/harmony/main.go
  9. 46
      cmd/harmony/version.go
  10. 4
      consensus/consensus_service.go
  11. 1
      go.mod
  12. 29
      internal/blsgen/lib.go
  13. 11
      internal/blsgen/utils.go
  14. 17
      internal/cli/flag.go
  15. 19
      internal/cli/parse.go
  16. 43
      internal/configs/node/config.go
  17. 111
      internal/configs/node/network.go
  18. 8
      node/rpc.go
  19. 8
      p2p/host.go
  20. 25
      rpc/rpc.go
  21. 12
      scripts/go_executable_build.sh
  22. 59
      scripts/node.sh
  23. 22
      test/deploy.sh

3
.gitignore vendored

@ -80,3 +80,6 @@ db-127.0.0.1-*
.dht
.dht-*
.tern-port
# testdata
.testdata

@ -1,11 +1,8 @@
package main
import (
"errors"
"flag"
"fmt"
"os"
"strings"
"sync"
"github.com/harmony-one/harmony/internal/blsgen"
@ -13,39 +10,27 @@ import (
"github.com/harmony-one/harmony/multibls"
)
var (
blsKeyFile = flag.String("blskey_file", "", "The encrypted file of bls serialized private key by passphrase.")
blsFolder = flag.String("blsfolder", ".hmy/blskeys", "The folder that stores the bls keys and corresponding passphrases; e.g. <blskey>.key and <blskey>.pass; all bls keys mapped to same shard")
maxBLSKeysPerNode = flag.Int("max_bls_keys_per_node", 10, "Maximum number of bls keys allowed per node (default 4)")
// TODO(jacky): rename it to a better name with cobra alias
blsPass = flag.String("blspass", "default", "The source for bls passphrases. (default, no-prompt, prompt, file:$PASS_FILE, none)")
persistPass = flag.Bool("save-passphrase", false, "Whether the prompt passphrase is saved after prompt.")
awsConfigSource = flag.String("aws-config-source", "default", "The source for aws config. (default, prompt, file:$CONFIG_FILE, none)")
)
var (
multiBLSPriKey multibls.PrivateKeys
onceLoadBLSKey sync.Once
)
// setupConsensusKeys load bls keys and set the keys to nodeConfig. Return the loaded public keys.
func setupConsensusKeys(config *nodeconfig.ConfigType) multibls.PublicKeys {
func setupConsensusKeys(hc harmonyConfig, config *nodeconfig.ConfigType) multibls.PublicKeys {
onceLoadBLSKey.Do(func() {
var err error
multiBLSPriKey, err = loadBLSKeys()
multiBLSPriKey, err = loadBLSKeys(hc.BLSKeys)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR when loading bls key: %v\n", err)
os.Exit(100)
}
fmt.Printf("Successfully loaded %v BLS keys\n", len(multiBLSPriKey))
})
config.ConsensusPriKey = multiBLSPriKey
return multiBLSPriKey.GetPublicKeys()
}
func loadBLSKeys() (multibls.PrivateKeys, error) {
config, err := parseBLSLoadingConfig()
func loadBLSKeys(raw blsConfig) (multibls.PrivateKeys, error) {
config, err := parseBLSLoadingConfig(raw)
if err != nil {
return nil, err
}
@ -56,74 +41,70 @@ func loadBLSKeys() (multibls.PrivateKeys, error) {
if len(keys) == 0 {
return nil, fmt.Errorf("0 bls keys loaded")
}
if len(keys) > *maxBLSKeysPerNode {
return nil, fmt.Errorf("bls keys exceed maximum count %v", *maxBLSKeysPerNode)
if len(keys) > raw.MaxKeys {
return nil, fmt.Errorf("bls keys exceed maximum count %v", raw.MaxKeys)
}
return keys, err
}
func parseBLSLoadingConfig() (blsgen.Config, error) {
func parseBLSLoadingConfig(raw blsConfig) (blsgen.Config, error) {
var (
config blsgen.Config
err error
)
if len(*blsKeyFile) != 0 {
config.MultiBlsKeys = strings.Split(*blsKeyFile, ",")
if len(raw.KeyFiles) != 0 {
config.MultiBlsKeys = raw.KeyFiles
}
config.BlsDir = blsFolder
config.BlsDir = &raw.KeyDir
config, err = parseBLSPass(config, *blsPass)
config, err = parseBLSPassConfig(config, raw)
if err != nil {
return blsgen.Config{}, err
}
config, err = parseAwsConfigSrc(config, *awsConfigSource)
config, err = parseBLSKmsConfig(config, raw)
if err != nil {
return blsgen.Config{}, err
}
return config, nil
}
func parseBLSPass(config blsgen.Config, src string) (blsgen.Config, error) {
methodArgs := strings.SplitN(src, ":", 2)
method := methodArgs[0]
switch method {
case "default", "stdin":
config.PassSrcType = blsgen.PassSrcAuto
func parseBLSPassConfig(cfg blsgen.Config, raw blsConfig) (blsgen.Config, error) {
if !raw.PassEnabled {
cfg.PassSrcType = blsgen.PassSrcNil
return blsgen.Config{}, nil
}
switch raw.PassSrcType {
case "auto":
cfg.PassSrcType = blsgen.PassSrcAuto
case "file":
config.PassSrcType = blsgen.PassSrcFile
if len(methodArgs) < 2 {
return blsgen.Config{}, errors.New("must specify passphrase file")
}
config.PassFile = &methodArgs[1]
case "no-prompt":
config.PassSrcType = blsgen.PassSrcFile
cfg.PassSrcType = blsgen.PassSrcFile
case "prompt":
config.PassSrcType = blsgen.PassSrcPrompt
config.PersistPassphrase = *persistPass
case "none":
config.PassSrcType = blsgen.PassSrcNil
cfg.PassSrcType = blsgen.PassSrcPrompt
default:
return blsgen.Config{}, fmt.Errorf("unknown pass source type [%v]", raw.PassSrcType)
}
config.PersistPassphrase = *persistPass
return config, nil
cfg.PassFile = &raw.PassFile
cfg.PersistPassphrase = raw.SavePassphrase
return cfg, nil
}
func parseAwsConfigSrc(config blsgen.Config, src string) (blsgen.Config, error) {
methodArgs := strings.SplitN(src, ":", 2)
method := methodArgs[0]
switch method {
case "default":
config.AwsCfgSrcType = blsgen.AwsCfgSrcShared
func parseBLSKmsConfig(cfg blsgen.Config, raw blsConfig) (blsgen.Config, error) {
if !raw.KMSEnabled {
cfg.AwsCfgSrcType = blsgen.AwsCfgSrcNil
return cfg, nil
}
switch raw.KMSConfigSrcType {
case "shared":
cfg.AwsCfgSrcType = blsgen.AwsCfgSrcShared
case "file":
config.AwsCfgSrcType = blsgen.AwsCfgSrcFile
if len(methodArgs) < 2 {
return blsgen.Config{}, errors.New("must specify aws config file")
}
config.AwsConfigFile = &methodArgs[1]
cfg.AwsCfgSrcType = blsgen.AwsCfgSrcFile
case "prompt":
config.AwsCfgSrcType = blsgen.AwsCfgSrcPrompt
case "none":
config.AwsCfgSrcType = blsgen.AwsCfgSrcNil
cfg.AwsCfgSrcType = blsgen.AwsCfgSrcPrompt
default:
return blsgen.Config{}, fmt.Errorf("unknown aws config source type [%v]", raw.KMSConfigSrcType)
}
return config, nil
cfg.AwsConfigFile = &raw.KMSConfigFile
return cfg, nil
}

@ -0,0 +1,247 @@
package main
import (
"errors"
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/harmony-one/harmony/internal/cli"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/pelletier/go-toml"
"github.com/spf13/cobra"
)
// harmonyConfig contains all the configs user can set for running harmony binary. Served as the bridge
// from user set flags to internal node configs. Also user can persist this structure to a toml file
// to avoid inputting all arguments.
type harmonyConfig struct {
Version string
General generalConfig
Network networkConfig
P2P p2pConfig
HTTP httpConfig
WS wsConfig
BLSKeys blsConfig
TxPool txPoolConfig
Pprof pprofConfig
Log logConfig
Consensus *consensusConfig `toml:",omitempty"`
Devnet *devnetConfig `toml:",omitempty"`
Revert *revertConfig `toml:",omitempty"`
Legacy *legacyConfig `toml:",omitempty"`
}
type networkConfig struct {
NetworkType string
BootNodes []string
LegacySyncing bool // if true, use LegacySyncingPeerProvider
DNSZone string
DNSPort int
}
type p2pConfig struct {
Port int
KeyFile string
}
type generalConfig struct {
NodeType string
NoStaking bool
ShardID int
IsArchival bool
DataDir string
}
type consensusConfig struct {
MinPeers int
}
type blsConfig struct {
KeyDir string
KeyFiles []string
MaxKeys int
PassEnabled bool
PassSrcType string
PassFile string
SavePassphrase bool
KMSEnabled bool
KMSConfigSrcType string
KMSConfigFile string
}
type txPoolConfig struct {
BlacklistFile string
}
type pprofConfig struct {
Enabled bool
ListenAddr string
}
type logConfig struct {
Folder string
FileName string
RotateSize int
Verbosity int
Context *logContext `toml:",omitempty"`
}
type logContext struct {
IP string
Port int
}
type httpConfig struct {
Enabled bool
IP string
Port int
}
type wsConfig struct {
Enabled bool
IP string
Port int
}
type devnetConfig struct {
NumShards int
ShardSize int
HmyNodeSize int
}
// TODO: make `revert` to a separate command
type revertConfig struct {
RevertBeacon bool
RevertTo int
RevertBefore int
}
type legacyConfig struct {
WebHookConfig *string `toml:",omitempty"`
TPBroadcastInvalidTxn *bool `toml:",omitempty"`
}
// TODO: use specific type wise validation instead of general string types assertion.
func validateHarmonyConfig(config harmonyConfig) error {
var accepts []string
nodeType := config.General.NodeType
accepts = []string{nodeTypeValidator, nodeTypeExplorer}
if err := checkStringAccepted("--run", nodeType, accepts); err != nil {
return err
}
netType := config.Network.NetworkType
parsed := parseNetworkType(netType)
if len(parsed) == 0 {
return fmt.Errorf("unknown network type: %v", netType)
}
passType := config.BLSKeys.PassSrcType
accepts = []string{blsPassTypeAuto, blsPassTypeFile, blsPassTypePrompt}
if err := checkStringAccepted("--bls.pass.src", passType, accepts); err != nil {
return err
}
kmsType := config.BLSKeys.KMSConfigSrcType
accepts = []string{kmsConfigTypeShared, kmsConfigTypePrompt, kmsConfigTypeFile}
if err := checkStringAccepted("--bls.kms.src", kmsType, accepts); err != nil {
return err
}
if config.General.NodeType == nodeTypeExplorer && config.General.ShardID < 0 {
return errors.New("flag --run.shard must be specified for explorer node")
}
return nil
}
func checkStringAccepted(flag string, val string, accepts []string) error {
for _, accept := range accepts {
if val == accept {
return nil
}
}
acceptsStr := strings.Join(accepts, ", ")
return fmt.Errorf("unknown arg for %s: %s (%v)", flag, val, acceptsStr)
}
func getDefaultNetworkConfig(nt nodeconfig.NetworkType) networkConfig {
bn := nodeconfig.GetDefaultBootNodes(nt)
zone := nodeconfig.GetDefaultDNSZone(nt)
port := nodeconfig.GetDefaultDNSPort(nt)
return networkConfig{
NetworkType: string(nt),
BootNodes: bn,
LegacySyncing: false,
DNSZone: zone,
DNSPort: port,
}
}
func parseNetworkType(nt string) nodeconfig.NetworkType {
switch nt {
case "mainnet":
return nodeconfig.Mainnet
case "testnet":
return nodeconfig.Testnet
case "pangaea", "staking", "stk":
return nodeconfig.Pangaea
case "partner":
return nodeconfig.Partner
case "stressnet", "stress", "stn":
return nodeconfig.Stressnet
case "localnet":
return nodeconfig.Localnet
case "devnet", "dev":
return nodeconfig.Devnet
default:
return ""
}
}
var dumpConfigCmd = &cobra.Command{
Use: "dumpconfig [config_file]",
Short: "dump the config file for harmony binary configurations",
Long: "dump the config file for harmony binary configurations",
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
nt := getNetworkType(cmd)
config := getDefaultHmyConfigCopy(nt)
if err := writeHarmonyConfigToFile(config, args[0]); err != nil {
fmt.Println(err)
os.Exit(128)
}
},
}
func registerDumpConfigFlags() error {
return cli.RegisterFlags(dumpConfigCmd, []cli.Flag{networkTypeFlag})
}
func loadHarmonyConfig(file string) (harmonyConfig, error) {
b, err := ioutil.ReadFile(file)
if err != nil {
return harmonyConfig{}, err
}
var config harmonyConfig
if err := toml.Unmarshal(b, &config); err != nil {
return harmonyConfig{}, err
}
return config, nil
}
func writeHarmonyConfigToFile(config harmonyConfig, file string) error {
b, err := toml.Marshal(config)
if err != nil {
return err
}
return ioutil.WriteFile(file, b, 0644)
}

@ -0,0 +1,81 @@
package main
import (
"fmt"
"os"
"path/filepath"
"reflect"
"testing"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
)
type testCfgOpt func(config *harmonyConfig)
func makeTestConfig(nt nodeconfig.NetworkType, opt testCfgOpt) harmonyConfig {
cfg := getDefaultHmyConfigCopy(nt)
if opt != nil {
opt(&cfg)
}
return cfg
}
var testBaseDir = ".testdata"
func init() {
if _, err := os.Stat(testBaseDir); os.IsNotExist(err) {
os.MkdirAll(testBaseDir, 0777)
}
}
func TestPersistConfig(t *testing.T) {
testDir := filepath.Join(testBaseDir, t.Name())
os.RemoveAll(testDir)
os.MkdirAll(testDir, 0777)
tests := []struct {
config harmonyConfig
}{
{
config: makeTestConfig("mainnet", nil),
},
{
config: makeTestConfig("devnet", nil),
},
{
config: makeTestConfig("mainnet", func(cfg *harmonyConfig) {
consensus := getDefaultConsensusConfigCopy()
cfg.Consensus = &consensus
devnet := getDefaultDevnetConfigCopy()
cfg.Devnet = &devnet
revert := getDefaultRevertConfigCopy()
cfg.Revert = &revert
webHook := "web hook"
cfg.Legacy = &legacyConfig{
WebHookConfig: &webHook,
TPBroadcastInvalidTxn: &trueBool,
}
logCtx := getDefaultLogContextCopy()
cfg.Log.Context = &logCtx
}),
},
}
for i, test := range tests {
file := filepath.Join(testDir, fmt.Sprintf("%d.conf", i))
if err := writeHarmonyConfigToFile(test.config, file); err != nil {
t.Fatal(err)
}
config, err := loadHarmonyConfig(file)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(config, test.config) {
t.Errorf("Test %v: unexpected config \n\t%+v \n\t%+v", i, config, test.config)
}
}
}

@ -0,0 +1,149 @@
package main
import nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
const tomlConfigVersion = "1.0.0"
const (
defNetworkType = nodeconfig.Mainnet
)
var defaultConfig = harmonyConfig{
Version: tomlConfigVersion,
General: generalConfig{
NodeType: "validator",
NoStaking: false,
ShardID: -1,
IsArchival: false,
DataDir: "./",
},
Network: getDefaultNetworkConfig(defNetworkType),
P2P: p2pConfig{
Port: nodeconfig.DefaultP2PPort,
KeyFile: "./.hmykey",
},
HTTP: httpConfig{
Enabled: true,
IP: "127.0.0.1",
Port: nodeconfig.DefaultRPCPort,
},
WS: wsConfig{
Enabled: true,
IP: "127.0.0.1",
Port: nodeconfig.DefaultWSPort,
},
BLSKeys: blsConfig{
KeyDir: "./.hmy/blskeys",
KeyFiles: []string{},
MaxKeys: 10,
PassEnabled: true,
PassSrcType: blsPassTypeAuto,
PassFile: "",
SavePassphrase: false,
KMSEnabled: true,
KMSConfigSrcType: kmsConfigTypeShared,
KMSConfigFile: "",
},
TxPool: txPoolConfig{
BlacklistFile: "./.hmy/blacklist.txt",
},
Pprof: pprofConfig{
Enabled: false,
ListenAddr: "127.0.0.1:6060",
},
Log: logConfig{
Folder: "./latest",
FileName: "harmony.log",
RotateSize: 100,
Verbosity: 3,
},
}
var defaultDevnetConfig = devnetConfig{
NumShards: 2,
ShardSize: 10,
HmyNodeSize: 10,
}
var defaultRevertConfig = revertConfig{
RevertBeacon: false,
RevertBefore: 0,
RevertTo: 0,
}
var defaultLogContext = logContext{
IP: "127.0.0.1",
Port: 9000,
}
var defaultConsensusConfig = consensusConfig{
MinPeers: 6,
}
const (
defaultBroadcastInvalidTx = true
)
func getDefaultHmyConfigCopy(nt nodeconfig.NetworkType) harmonyConfig {
config := defaultConfig
config.Network = getDefaultNetworkConfig(nt)
if nt == nodeconfig.Devnet {
devnet := getDefaultDevnetConfigCopy()
config.Devnet = &devnet
}
return config
}
func getDefaultDevnetConfigCopy() devnetConfig {
config := defaultDevnetConfig
return config
}
func getDefaultRevertConfigCopy() revertConfig {
config := defaultRevertConfig
return config
}
func getDefaultLogContextCopy() logContext {
config := defaultLogContext
return config
}
func getDefaultConsensusConfigCopy() consensusConfig {
config := defaultConsensusConfig
return config
}
const (
nodeTypeValidator = "validator"
nodeTypeExplorer = "explorer"
)
const (
blsPassTypeAuto = "auto"
blsPassTypeFile = "file"
blsPassTypePrompt = "prompt"
kmsConfigTypeShared = "shared"
kmsConfigTypePrompt = "prompt"
kmsConfigTypeFile = "file"
legacyBLSPassTypeDefault = "default"
legacyBLSPassTypeStdin = "stdin"
legacyBLSPassTypeDynamic = "no-prompt"
legacyBLSPassTypePrompt = "prompt"
legacyBLSPassTypeStatic = "file"
legacyBLSPassTypeNone = "none"
legacyBLSKmsTypeDefault = "default"
legacyBLSKmsTypePrompt = "prompt"
legacyBLSKmsTypeFile = "file"
legacyBLSKmsTypeNone = "none"
)
const (
localListenIP = "127.0.0.1"
publicListenIP = "0.0.0.0"
)

File diff suppressed because it is too large Load Diff

@ -0,0 +1,867 @@
package main
import (
"fmt"
"reflect"
"strings"
"testing"
"github.com/harmony-one/harmony/internal/cli"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/spf13/cobra"
)
var (
trueBool = true
)
func TestHarmonyFlags(t *testing.T) {
tests := []struct {
argStr string
expConfig harmonyConfig
}{
{
// running staking command from legacy node.sh
argStr: "--bootnodes /ip4/100.26.90.187/tcp/9874/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv," +
"/ip4/54.213.43.194/tcp/9874/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9,/ip4/13.113.101." +
"219/tcp/12019/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX,/ip4/99.81.170.167/tcp/12019/p" +
"2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj --ip 8.8.8.8 --port 9000 --network_type=mainn" +
"et --dns_zone=t.hmny.io --blacklist=./.hmy/blacklist.txt --min_peers=6 --max_bls_keys_per_node=" +
"10 --broadcast_invalid_tx=true --verbosity=3 --is_archival=false --shard_id=-1 --staking=true -" +
"-aws-config-source file:config.json",
expConfig: harmonyConfig{
Version: tomlConfigVersion,
General: generalConfig{
NodeType: "validator",
NoStaking: false,
ShardID: -1,
IsArchival: false,
DataDir: "./",
},
Network: networkConfig{
NetworkType: "mainnet",
BootNodes: []string{
"/ip4/100.26.90.187/tcp/9874/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv",
"/ip4/54.213.43.194/tcp/9874/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9",
"/ip4/13.113.101.219/tcp/12019/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX",
"/ip4/99.81.170.167/tcp/12019/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj",
},
DNSZone: "t.hmny.io",
DNSPort: 9000,
},
P2P: p2pConfig{
Port: 9000,
KeyFile: defaultConfig.P2P.KeyFile,
},
HTTP: httpConfig{
Enabled: true,
IP: "127.0.0.1",
Port: 9500,
},
WS: wsConfig{
Enabled: true,
IP: "127.0.0.1",
Port: 9800,
},
Consensus: &consensusConfig{
MinPeers: 6,
},
BLSKeys: blsConfig{
KeyDir: "./.hmy/blskeys",
KeyFiles: []string{},
MaxKeys: 10,
PassEnabled: true,
PassSrcType: "auto",
PassFile: "",
SavePassphrase: false,
KMSEnabled: true,
KMSConfigSrcType: "file",
KMSConfigFile: "config.json",
},
TxPool: txPoolConfig{
BlacklistFile: "./.hmy/blacklist.txt",
},
Pprof: pprofConfig{
Enabled: false,
ListenAddr: "127.0.0.1:6060",
},
Log: logConfig{
Folder: "./latest",
FileName: "validator-8.8.8.8-9000.log",
RotateSize: 100,
Verbosity: 3,
Context: &logContext{
IP: "8.8.8.8",
Port: 9000,
},
},
Legacy: &legacyConfig{
TPBroadcastInvalidTxn: &trueBool,
},
},
},
}
for i, test := range tests {
ts := newFlagTestSuite(t, getRootFlags(), applyRootFlags)
hc, err := ts.run(strings.Split(test.argStr, " "))
if err != nil {
t.Fatalf("Test %v: %v", i, err)
}
if !reflect.DeepEqual(hc, test.expConfig) {
t.Errorf("Test %v: unexpected config: \n\t%+v\n\t%+v", i, hc, test.expConfig)
}
ts.tearDown()
}
}
func TestGeneralFlags(t *testing.T) {
tests := []struct {
args []string
expConfig generalConfig
expErr error
}{
{
args: []string{},
expConfig: generalConfig{
NodeType: "validator",
NoStaking: false,
ShardID: -1,
IsArchival: false,
DataDir: "./",
},
},
{
args: []string{"--run", "explorer", "--run.legacy", "--run.shard=0",
"--run.archive=true", "--datadir=./.hmy"},
expConfig: generalConfig{
NodeType: "explorer",
NoStaking: true,
ShardID: 0,
IsArchival: true,
DataDir: "./.hmy",
},
},
{
args: []string{"--node_type", "explorer", "--staking", "--shard_id", "0",
"--is_archival", "--db_dir", "./"},
expConfig: generalConfig{
NodeType: "explorer",
NoStaking: false,
ShardID: 0,
IsArchival: true,
DataDir: "./",
},
},
{
args: []string{"--staking=false", "--is_archival=false"},
expConfig: generalConfig{
NodeType: "validator",
NoStaking: true,
ShardID: -1,
IsArchival: false,
DataDir: "./",
},
},
}
for i, test := range tests {
ts := newFlagTestSuite(t, generalFlags, applyGeneralFlags)
got, err := ts.run(test.args)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Fatalf("Test %v: %v", i, assErr)
}
if err != nil || test.expErr != nil {
continue
}
if !reflect.DeepEqual(got.General, test.expConfig) {
t.Errorf("Test %v: unexpected config: \n\t%+v\n\t%+v", i, got.General, test.expConfig)
}
ts.tearDown()
}
}
func TestNetworkFlags(t *testing.T) {
tests := []struct {
args []string
expConfig networkConfig
expErr error
}{
{
args: []string{},
expConfig: networkConfig{
NetworkType: defNetworkType,
BootNodes: nodeconfig.GetDefaultBootNodes(defNetworkType),
LegacySyncing: false,
DNSZone: nodeconfig.GetDefaultDNSZone(defNetworkType),
DNSPort: nodeconfig.GetDefaultDNSPort(defNetworkType),
},
},
{
args: []string{"-n", "stn"},
expConfig: networkConfig{
NetworkType: nodeconfig.Stressnet,
BootNodes: nodeconfig.GetDefaultBootNodes(nodeconfig.Stressnet),
LegacySyncing: false,
DNSZone: nodeconfig.GetDefaultDNSZone(nodeconfig.Stressnet),
DNSPort: nodeconfig.GetDefaultDNSPort(nodeconfig.Stressnet),
},
},
{
args: []string{"--network", "stk", "--bootnodes", "1,2,3,4", "--dns.zone", "8.8.8.8",
"--dns.port", "9001"},
expConfig: networkConfig{
NetworkType: "pangaea",
BootNodes: []string{"1", "2", "3", "4"},
LegacySyncing: false,
DNSZone: "8.8.8.8",
DNSPort: 9001,
},
},
{
args: []string{"--network_type", "stk", "--bootnodes", "1,2,3,4", "--dns_zone", "8.8.8.8",
"--dns_port", "9001"},
expConfig: networkConfig{
NetworkType: "pangaea",
BootNodes: []string{"1", "2", "3", "4"},
LegacySyncing: false,
DNSZone: "8.8.8.8",
DNSPort: 9001,
},
},
{
args: []string{"--dns=false"},
expConfig: networkConfig{
NetworkType: defNetworkType,
BootNodes: nodeconfig.GetDefaultBootNodes(defNetworkType),
LegacySyncing: true,
DNSZone: nodeconfig.GetDefaultDNSZone(defNetworkType),
DNSPort: nodeconfig.GetDefaultDNSPort(defNetworkType),
},
},
}
for i, test := range tests {
ts := newFlagTestSuite(t, networkFlags, func(cmd *cobra.Command, config *harmonyConfig) {
// This is the network related logic in function getHarmonyConfig
nt := getNetworkType(cmd)
config.Network = getDefaultNetworkConfig(nt)
applyNetworkFlags(cmd, config)
})
got, err := ts.run(test.args)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Fatalf("Test %v: %v", i, assErr)
}
if err != nil || test.expErr != nil {
continue
}
if !reflect.DeepEqual(got.Network, test.expConfig) {
t.Errorf("Test %v: unexpected config: \n\t%+v\n\t%+v", i, got.Network, test.expConfig)
}
ts.tearDown()
}
}
func TestP2PFlags(t *testing.T) {
tests := []struct {
args []string
expConfig p2pConfig
expErr error
}{
{
args: []string{},
expConfig: defaultConfig.P2P,
},
{
args: []string{"--p2p.port", "9001", "--p2p.keyfile", "./key.file"},
expConfig: p2pConfig{
Port: 9001,
KeyFile: "./key.file",
},
},
{
args: []string{"--port", "9001", "--key", "./key.file"},
expConfig: p2pConfig{
Port: 9001,
KeyFile: "./key.file",
},
},
}
for i, test := range tests {
ts := newFlagTestSuite(t, append(p2pFlags, legacyMiscFlags...),
func(cmd *cobra.Command, config *harmonyConfig) {
applyLegacyMiscFlags(cmd, config)
applyP2PFlags(cmd, config)
},
)
got, err := ts.run(test.args)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Fatalf("Test %v: %v", i, assErr)
}
if err != nil || test.expErr != nil {
continue
}
if !reflect.DeepEqual(got.P2P, test.expConfig) {
t.Errorf("Test %v: unexpected config: \n\t%+v\n\t%+v", i, got.Network, test.expConfig)
}
ts.tearDown()
}
}
func TestRPCFlags(t *testing.T) {
tests := []struct {
args []string
expConfig httpConfig
expErr error
}{
{
args: []string{},
expConfig: defaultConfig.HTTP,
},
{
args: []string{"--http=false"},
expConfig: httpConfig{
Enabled: false,
IP: defaultConfig.HTTP.IP,
Port: defaultConfig.HTTP.Port,
},
},
{
args: []string{"--http.ip", "8.8.8.8", "--http.port", "9001"},
expConfig: httpConfig{
Enabled: true,
IP: "8.8.8.8",
Port: 9001,
},
},
{
args: []string{"--ip", "8.8.8.8", "--port", "9001", "--public_rpc"},
expConfig: httpConfig{
Enabled: true,
IP: publicListenIP,
Port: 9501,
},
},
}
for i, test := range tests {
ts := newFlagTestSuite(t, append(httpFlags, legacyMiscFlags...),
func(cmd *cobra.Command, config *harmonyConfig) {
applyLegacyMiscFlags(cmd, config)
applyHTTPFlags(cmd, config)
},
)
hc, err := ts.run(test.args)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Fatalf("Test %v: %v", i, assErr)
}
if err != nil || test.expErr != nil {
continue
}
if !reflect.DeepEqual(hc.HTTP, test.expConfig) {
t.Errorf("Test %v: unexpected config: \n\t%+v\n\t%+v", i, hc.HTTP, test.expConfig)
}
ts.tearDown()
}
}
func TestWSFlags(t *testing.T) {
tests := []struct {
args []string
expConfig wsConfig
expErr error
}{
{
args: []string{},
expConfig: defaultConfig.WS,
},
{
args: []string{"--ws=false"},
expConfig: wsConfig{
Enabled: false,
IP: defaultConfig.WS.IP,
Port: defaultConfig.WS.Port,
},
},
{
args: []string{"--ws", "--ws.ip", "8.8.8.8", "--ws.port", "9001"},
expConfig: wsConfig{
Enabled: true,
IP: "8.8.8.8",
Port: 9001,
},
},
{
args: []string{"--ip", "8.8.8.8", "--port", "9001", "--public_rpc"},
expConfig: wsConfig{
Enabled: true,
IP: publicListenIP,
Port: 9801,
},
},
}
for i, test := range tests {
ts := newFlagTestSuite(t, append(wsFlags, legacyMiscFlags...),
func(cmd *cobra.Command, config *harmonyConfig) {
applyLegacyMiscFlags(cmd, config)
applyWSFlags(cmd, config)
},
)
hc, err := ts.run(test.args)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Fatalf("Test %v: %v", i, assErr)
}
if err != nil || test.expErr != nil {
continue
}
if !reflect.DeepEqual(hc.WS, test.expConfig) {
t.Errorf("Test %v: \n\t%+v\n\t%+v", i, hc.WS, test.expConfig)
}
ts.tearDown()
}
}
func TestBLSFlags(t *testing.T) {
tests := []struct {
args []string
expConfig blsConfig
expErr error
}{
{
args: []string{},
expConfig: defaultConfig.BLSKeys,
},
{
args: []string{"--bls.dir", "./blskeys", "--bls.keys", "key1,key2",
"--bls.maxkeys", "8", "--bls.pass", "--bls.pass.src", "auto", "--bls.pass.save",
"--bls.kms", "--bls.kms.src", "shared",
},
expConfig: blsConfig{
KeyDir: "./blskeys",
KeyFiles: []string{"key1", "key2"},
MaxKeys: 8,
PassEnabled: true,
PassSrcType: "auto",
PassFile: "",
SavePassphrase: true,
KMSEnabled: true,
KMSConfigSrcType: "shared",
KMSConfigFile: "",
},
},
{
args: []string{"--bls.pass.file", "xxx.pass", "--bls.kms.config", "config.json"},
expConfig: blsConfig{
KeyDir: defaultConfig.BLSKeys.KeyDir,
KeyFiles: defaultConfig.BLSKeys.KeyFiles,
MaxKeys: defaultConfig.BLSKeys.MaxKeys,
PassEnabled: true,
PassSrcType: "file",
PassFile: "xxx.pass",
SavePassphrase: false,
KMSEnabled: true,
KMSConfigSrcType: "file",
KMSConfigFile: "config.json",
},
},
{
args: []string{"--blskey_file", "key1,key2", "--blsfolder", "./hmykeys",
"--max_bls_keys_per_node", "5", "--blspass", "file:xxx.pass", "--save-passphrase",
"--aws-config-source", "file:config.json",
},
expConfig: blsConfig{
KeyDir: "./hmykeys",
KeyFiles: []string{"key1", "key2"},
MaxKeys: 5,
PassEnabled: true,
PassSrcType: "file",
PassFile: "xxx.pass",
SavePassphrase: true,
KMSEnabled: true,
KMSConfigSrcType: "file",
KMSConfigFile: "config.json",
},
},
}
for i, test := range tests {
ts := newFlagTestSuite(t, blsFlags, applyBLSFlags)
hc, err := ts.run(test.args)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Fatalf("Test %v: %v", i, assErr)
}
if err != nil || test.expErr != nil {
continue
}
if !reflect.DeepEqual(hc.BLSKeys, test.expConfig) {
t.Errorf("Test %v: \n\t%+v\n\t%+v", i, hc.BLSKeys, test.expConfig)
}
ts.tearDown()
}
}
func TestConsensusFlags(t *testing.T) {
tests := []struct {
args []string
expConfig *consensusConfig
expErr error
}{
{
args: []string{},
expConfig: nil,
},
{
args: []string{"--consensus.min-peers", "10"},
expConfig: &consensusConfig{
MinPeers: 10,
},
},
{
args: []string{"--delay_commit", "10ms", "--block_period", "5", "--min_peers", "10"},
expConfig: &consensusConfig{
MinPeers: 10,
},
},
}
for i, test := range tests {
ts := newFlagTestSuite(t, consensusFlags, applyConsensusFlags)
hc, err := ts.run(test.args)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Fatalf("Test %v: %v", i, assErr)
}
if err != nil || test.expErr != nil {
continue
}
if !reflect.DeepEqual(hc.Consensus, test.expConfig) {
t.Errorf("Test %v: unexpected config \n\t%+v\n\t%+v", i, hc.Consensus, test.expConfig)
}
ts.tearDown()
}
}
func TestTxPoolFlags(t *testing.T) {
tests := []struct {
args []string
expConfig txPoolConfig
expErr error
}{
{
args: []string{},
expConfig: txPoolConfig{
BlacklistFile: defaultConfig.TxPool.BlacklistFile,
},
},
{
args: []string{"--txpool.blacklist", "blacklist.file"},
expConfig: txPoolConfig{
BlacklistFile: "blacklist.file",
},
},
{
args: []string{"--blacklist", "blacklist.file"},
expConfig: txPoolConfig{
BlacklistFile: "blacklist.file",
},
},
}
for i, test := range tests {
ts := newFlagTestSuite(t, txPoolFlags, applyTxPoolFlags)
hc, err := ts.run(test.args)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Fatalf("Test %v: %v", i, assErr)
}
if err != nil || test.expErr != nil {
continue
}
if !reflect.DeepEqual(hc.TxPool, test.expConfig) {
t.Errorf("Test %v: unexpected config\n\t%+v\n\t%+v", i, hc.TxPool, test.expConfig)
}
ts.tearDown()
}
}
func TestPprofFlags(t *testing.T) {
tests := []struct {
args []string
expConfig pprofConfig
expErr error
}{
{
args: []string{},
expConfig: defaultConfig.Pprof,
},
{
args: []string{"--pprof"},
expConfig: pprofConfig{
Enabled: true,
ListenAddr: defaultConfig.Pprof.ListenAddr,
},
},
{
args: []string{"--pprof.addr", "8.8.8.8:9001"},
expConfig: pprofConfig{
Enabled: true,
ListenAddr: "8.8.8.8:9001",
},
},
{
args: []string{"--pprof=false", "--pprof.addr", "8.8.8.8:9001"},
expConfig: pprofConfig{
Enabled: false,
ListenAddr: "8.8.8.8:9001",
},
},
}
for i, test := range tests {
ts := newFlagTestSuite(t, pprofFlags, applyPprofFlags)
hc, err := ts.run(test.args)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Fatalf("Test %v: %v", i, assErr)
}
if err != nil || test.expErr != nil {
continue
}
if !reflect.DeepEqual(hc.Pprof, test.expConfig) {
t.Errorf("Test %v: unexpected config\n\t%+v\n\t%+v", i, hc.Pprof, test.expConfig)
}
ts.tearDown()
}
}
func TestLogFlags(t *testing.T) {
tests := []struct {
args []string
expConfig logConfig
expErr error
}{
{
args: []string{},
expConfig: defaultConfig.Log,
},
{
args: []string{"--log.dir", "latest_log", "--log.max-size", "10", "--log.name", "harmony.log",
"--log.verb", "5"},
expConfig: logConfig{
Folder: "latest_log",
FileName: "harmony.log",
RotateSize: 10,
Verbosity: 5,
Context: nil,
},
},
{
args: []string{"--log.ctx.ip", "8.8.8.8", "--log.ctx.port", "9001"},
expConfig: logConfig{
Folder: defaultConfig.Log.Folder,
FileName: defaultConfig.Log.FileName,
RotateSize: defaultConfig.Log.RotateSize,
Verbosity: defaultConfig.Log.Verbosity,
Context: &logContext{
IP: "8.8.8.8",
Port: 9001,
},
},
},
{
args: []string{"--log_folder", "latest_log", "--log_max_size", "10", "--verbosity",
"5", "--ip", "8.8.8.8", "--port", "9001"},
expConfig: logConfig{
Folder: "latest_log",
FileName: "validator-8.8.8.8-9001.log",
RotateSize: 10,
Verbosity: 5,
Context: &logContext{
IP: "8.8.8.8",
Port: 9001,
},
},
},
}
for i, test := range tests {
ts := newFlagTestSuite(t, append(logFlags, legacyMiscFlags...),
func(cmd *cobra.Command, config *harmonyConfig) {
applyLegacyMiscFlags(cmd, config)
applyLogFlags(cmd, config)
},
)
hc, err := ts.run(test.args)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Fatalf("Test %v: %v", i, assErr)
}
if err != nil || test.expErr != nil {
continue
}
if !reflect.DeepEqual(hc.Log, test.expConfig) {
t.Errorf("Test %v:\n\t%+v\n\t%+v", i, hc.Log, test.expConfig)
}
ts.tearDown()
}
}
func TestDevnetFlags(t *testing.T) {
tests := []struct {
args []string
expConfig *devnetConfig
expErr error
}{
{
args: []string{},
expConfig: nil,
},
{
args: []string{"--devnet.num-shard", "3", "--devnet.shard-size", "100",
"--devnet.hmy-node-size", "60"},
expConfig: &devnetConfig{
NumShards: 3,
ShardSize: 100,
HmyNodeSize: 60,
},
},
{
args: []string{"--dn_num_shards", "3", "--dn_shard_size", "100", "--dn_hmy_size",
"60"},
expConfig: &devnetConfig{
NumShards: 3,
ShardSize: 100,
HmyNodeSize: 60,
},
},
}
for i, test := range tests {
ts := newFlagTestSuite(t, devnetFlags, applyDevnetFlags)
hc, err := ts.run(test.args)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Fatalf("Test %v: %v", i, assErr)
}
if err != nil || test.expErr != nil {
continue
}
if !reflect.DeepEqual(hc.Devnet, test.expConfig) {
t.Errorf("Test %v:\n\t%+v\n\t%+v", i, hc.Devnet, test.expConfig)
}
ts.tearDown()
}
}
func TestRevertFlags(t *testing.T) {
tests := []struct {
args []string
expConfig *revertConfig
expErr error
}{
{
args: []string{},
expConfig: nil,
},
{
args: []string{"--revert.beacon"},
expConfig: &revertConfig{
RevertBeacon: true,
RevertTo: defaultRevertConfig.RevertTo,
RevertBefore: defaultRevertConfig.RevertBefore,
},
},
{
args: []string{"--revert.beacon", "--revert.to", "100", "--revert.do-before", "10000"},
expConfig: &revertConfig{
RevertBeacon: true,
RevertTo: 100,
RevertBefore: 10000,
},
},
{
args: []string{"--revert_beacon", "--do_revert_before", "10000", "--revert_to", "100"},
expConfig: &revertConfig{
RevertBeacon: true,
RevertTo: 100,
RevertBefore: 10000,
},
},
}
for i, test := range tests {
ts := newFlagTestSuite(t, revertFlags, applyRevertFlags)
hc, err := ts.run(test.args)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Fatalf("Test %v: %v", i, assErr)
}
if err != nil || test.expErr != nil {
continue
}
if !reflect.DeepEqual(hc.Revert, test.expConfig) {
t.Errorf("Test %v:\n\t%+v\n\t%+v", i, hc.Revert, test.expConfig)
}
ts.tearDown()
}
}
type flagTestSuite struct {
t *testing.T
cmd *cobra.Command
hc harmonyConfig
}
func newFlagTestSuite(t *testing.T, flags []cli.Flag, applyFlags func(*cobra.Command, *harmonyConfig)) *flagTestSuite {
cli.SetParseErrorHandle(func(err error) { t.Fatal(err) })
ts := &flagTestSuite{hc: defaultConfig}
ts.cmd = makeTestCommand(func(cmd *cobra.Command, args []string) {
applyFlags(cmd, &ts.hc)
})
if err := cli.RegisterFlags(ts.cmd, flags); err != nil {
t.Fatal(err)
}
return ts
}
func (ts *flagTestSuite) run(args []string) (harmonyConfig, error) {
ts.cmd.SetArgs(args)
err := ts.cmd.Execute()
return ts.hc, err
}
func (ts *flagTestSuite) tearDown() {
cli.SetParseErrorHandle(func(error) {})
}
func makeTestCommand(run func(cmd *cobra.Command, args []string)) *cobra.Command {
return &cobra.Command{
Use: "test",
Run: run,
}
}
func assertError(gotErr, expErr error) error {
if (gotErr == nil) != (expErr == nil) {
return fmt.Errorf("error unexpected [%v] / [%v]", gotErr, expErr)
}
if gotErr == nil {
return nil
}
if !strings.Contains(gotErr.Error(), expErr.Error()) {
return fmt.Errorf("error unexpected [%v] / [%v]", gotErr, expErr)
}
return nil
}

@ -1,7 +1,6 @@
package main
import (
"flag"
"fmt"
"io/ioutil"
"math/big"
@ -10,7 +9,7 @@ import (
_ "net/http/pprof"
"os"
"os/signal"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
@ -24,10 +23,10 @@ import (
"github.com/harmony-one/harmony/consensus"
"github.com/harmony-one/harmony/consensus/quorum"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/internal/cli"
"github.com/harmony-one/harmony/internal/common"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding"
viperconfig "github.com/harmony-one/harmony/internal/configs/viper"
"github.com/harmony-one/harmony/internal/genesis"
"github.com/harmony-one/harmony/internal/shardchain"
"github.com/harmony-one/harmony/internal/utils"
@ -38,14 +37,7 @@ import (
"github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/webhooks"
"github.com/pkg/errors"
)
// Version string variables
var (
version string
builtBy string
builtAt string
commit string
"github.com/spf13/cobra"
)
// Host
@ -54,93 +46,329 @@ var (
initialAccounts = []*genesis.DeployAccount{}
)
func printVersion() {
fmt.Fprintln(os.Stderr, nodeconfig.GetVersion())
os.Exit(0)
var rootCmd = &cobra.Command{
Use: "harmony",
Short: "harmony is the Harmony node binary file",
Long: `harmony is the Harmony node binary file
Examples usage:
# start a validator node with default bls folder (default bls key files in ./.hmy/blskeys)
./harmony
# start a validator node with customized bls key folder
./harmony --bls.dir [bls_folder]
# start a validator node with open RPC endpoints and customized ports
./harmony --http.ip=0.0.0.0 --http.port=[http_port] --ws.ip=0.0.0.0 --ws.port=[ws_port]
# start an explorer node
./harmony --run=explorer --run.archive --run.shard=[shard_id]
# start a harmony internal node on testnet
./harmony --run.legacy --network
`,
Run: runHarmonyNode,
}
var (
ip = flag.String("ip", "127.0.0.1", "ip of the node")
port = flag.String("port", "9000", "port of the node.")
logFolder = flag.String("log_folder", "latest", "the folder collecting the logs of this execution")
logMaxSize = flag.Int("log_max_size", 100, "the max size in megabytes of the log file before it gets rotated")
freshDB = flag.Bool("fresh_db", false, "true means the existing disk based db will be removed")
pprof = flag.String("pprof", "", "what address and port the pprof profiling server should listen on")
versionFlag = flag.Bool("version", false, "Output version info")
dnsZone = flag.String("dns_zone", "", "if given and not empty, use peers from the zone (default: use libp2p peer discovery instead)")
dnsFlag = flag.Bool("dns", true, "[deprecated] equivalent to -dns_zone t.hmny.io")
dnsPort = flag.String("dns_port", "9000", "port of dns node")
//Leader needs to have a minimal number of peers to start consensus
minPeers = flag.Int("min_peers", 32, "Minimal number of Peers in shard")
// Key file to store the private key
keyFile = flag.String("key", "./.hmykey", "the p2p key file of the harmony node")
// isArchival indicates this node is an archival node that will save and archive current blockchain
isArchival = flag.Bool("is_archival", false, "false will enable cached state pruning")
// delayCommit is the commit-delay timer, used by Harmony nodes
delayCommit = flag.String("delay_commit", "0ms", "how long to delay sending commit messages in consensus, ex: 500ms, 1s")
// nodeType indicates the type of the node: validator, explorer
nodeType = flag.String("node_type", "validator", "node type: validator, explorer")
// networkType indicates the type of the network
networkType = flag.String("network_type", "mainnet", "type of the network: mainnet, testnet, pangaea, partner, stressnet, devnet, localnet")
// blockPeriod indicates the how long the leader waits to propose a new block.
blockPeriod = flag.Int("block_period", 5, "how long in second the leader waits to propose a new block.")
// staking indicates whether the node is operating in staking mode.
stakingFlag = flag.Bool("staking", false, "whether the node should operate in staking mode")
// shardID indicates the shard ID of this node
shardID = flag.Int("shard_id", -1, "the shard ID of this node")
// Sharding configuration parameters for devnet
devnetNumShards = flag.Uint("dn_num_shards", 2, "number of shards for -network_type=devnet (default: 2)")
devnetShardSize = flag.Int("dn_shard_size", 10, "number of nodes per shard for -network_type=devnet (default 10)")
devnetHarmonySize = flag.Int("dn_hmy_size", -1, "number of Harmony-operated nodes per shard for -network_type=devnet; negative (default) means equal to -dn_shard_size")
// logging verbosity
verbosity = flag.Int("verbosity", 5, "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail (default: 5)")
// dbDir is the database directory.
dbDir = flag.String("db_dir", "", "blockchain database directory")
publicRPC = flag.Bool("public_rpc", false, "Enable Public RPC Access (default: false)")
// Bad block revert
doRevertBefore = flag.Int("do_revert_before", 0, "If the current block is less than do_revert_before, revert all blocks until (including) revert_to block")
revertTo = flag.Int("revert_to", 0, "The revert will rollback all blocks until and including block number revert_to")
revertBeacon = flag.Bool("revert_beacon", false, "Whether to revert beacon chain or the chain this node is assigned to")
// Blacklist of addresses
blacklistPath = flag.String("blacklist", "./.hmy/blacklist.txt", "Path to newline delimited file of blacklisted wallet addresses")
broadcastInvalidTx = flag.Bool("broadcast_invalid_tx", false, "Broadcast invalid transactions to sync pool state (default: false)")
webHookYamlPath = flag.String(
"webhook_yaml", "", "path for yaml config reporting double signing",
)
)
var configFlag = cli.StringFlag{
Name: "config",
Usage: "load node config from the config toml file.",
Shorthand: "c",
DefValue: "",
}
func initSetup() {
func init() {
cli.SetParseErrorHandle(func(err error) {
os.Exit(128) // 128 - invalid command line arguments
})
rootCmd.AddCommand(dumpConfigCmd)
rootCmd.AddCommand(versionCmd)
// Setup pprof
if addr := *pprof; addr != "" {
go func() { http.ListenAndServe(addr, nil) }()
if err := registerRootCmdFlags(); err != nil {
os.Exit(2)
}
if err := registerDumpConfigFlags(); err != nil {
os.Exit(2)
}
}
// Configure log parameters
utils.SetLogContext(*port, *ip)
utils.SetLogVerbosity(log.Lvl(*verbosity))
utils.AddLogFile(fmt.Sprintf("%v/validator-%v-%v.log", *logFolder, *ip, *port), *logMaxSize)
func main() {
rootCmd.Execute()
}
func registerRootCmdFlags() error {
flags := getRootFlags()
return cli.RegisterFlags(rootCmd, flags)
}
func runHarmonyNode(cmd *cobra.Command, args []string) {
if cli.GetBoolFlagValue(cmd, versionFlag) {
printVersion()
os.Exit(0)
}
prepareRootCmd(cmd)
cfg, err := getHarmonyConfig(cmd)
if err != nil {
fmt.Println(err)
cmd.Help()
os.Exit(128)
}
setupNodeLog(cfg)
setupPprof(cfg)
setupNodeAndRun(cfg)
}
func prepareRootCmd(cmd *cobra.Command) {
// HACK Force usage of go implementation rather than the C based one. Do the right way, see the
// notes one line 66,67 of https://golang.org/src/net/net.go that say can make the decision at
// build time.
os.Setenv("GODEBUG", "netdns=go")
// Don't set higher than num of CPU. It will make go scheduler slower.
runtime.GOMAXPROCS(runtime.NumCPU())
// Set up randomization seed.
rand.Seed(int64(time.Now().Nanosecond()))
}
// Set port and ip to global config.
nodeconfig.GetDefaultConfig().Port = *port
nodeconfig.GetDefaultConfig().IP = *ip
func getHarmonyConfig(cmd *cobra.Command) (harmonyConfig, error) {
var (
config harmonyConfig
err error
)
if cli.IsFlagChanged(cmd, configFlag) {
configFile := cli.GetStringFlagValue(cmd, configFlag)
config, err = loadHarmonyConfig(configFile)
} else {
nt := getNetworkType(cmd)
config = getDefaultHmyConfigCopy(nt)
}
if err != nil {
return harmonyConfig{}, err
}
// Set sharding schedule
applyRootFlags(cmd, &config)
if err := validateHarmonyConfig(config); err != nil {
return harmonyConfig{}, err
}
return config, nil
}
func applyRootFlags(cmd *cobra.Command, config *harmonyConfig) {
// Misc flags shall be applied first since legacy ip / port is overwritten
// by new ip / port flags
applyLegacyMiscFlags(cmd, config)
applyGeneralFlags(cmd, config)
applyNetworkFlags(cmd, config)
applyP2PFlags(cmd, config)
applyHTTPFlags(cmd, config)
applyWSFlags(cmd, config)
applyBLSFlags(cmd, config)
applyConsensusFlags(cmd, config)
applyTxPoolFlags(cmd, config)
applyPprofFlags(cmd, config)
applyLogFlags(cmd, config)
applyDevnetFlags(cmd, config)
applyRevertFlags(cmd, config)
}
func setupNodeLog(config harmonyConfig) {
logPath := filepath.Join(config.Log.Folder, config.Log.FileName)
rotateSize := config.Log.RotateSize
verbosity := config.Log.Verbosity
utils.AddLogFile(logPath, rotateSize)
utils.SetLogVerbosity(log.Lvl(verbosity))
if config.Log.Context != nil {
ip := config.Log.Context.IP
port := config.Log.Context.Port
utils.SetLogContext(ip, strconv.Itoa(port))
}
}
func setupPprof(config harmonyConfig) {
enabled := config.Pprof.Enabled
addr := config.Pprof.ListenAddr
if enabled {
go func() {
http.ListenAndServe(addr, nil)
}()
}
}
func setupNodeAndRun(hc harmonyConfig) {
var err error
bootNodes := hc.Network.BootNodes
p2p.BootNodes, err = p2p.StringsToAddrs(bootNodes)
if err != nil {
utils.FatalErrMsg(err, "cannot parse bootnode list %#v",
bootNodes)
}
nodeconfigSetShardSchedule(hc)
nodeconfig.SetShardingSchedule(shard.Schedule)
nodeconfig.SetVersion(getHarmonyVersion())
// Set up randomization seed.
rand.Seed(int64(time.Now().Nanosecond()))
if hc.General.NodeType == "validator" {
var err error
if hc.General.NoStaking {
err = setupLegacyNodeAccount(hc)
} else {
err = setupStakingNodeAccount(hc)
}
if err != nil {
fmt.Fprintf(os.Stderr, "cannot set up node account: %s\n", err)
os.Exit(1)
}
}
if hc.General.NodeType == "validator" {
fmt.Printf("%s mode; node key %s -> shard %d\n",
map[bool]string{false: "Legacy", true: "Staking"}[!hc.General.NoStaking],
nodeconfig.GetDefaultConfig().ConsensusPriKey.GetPublicKeys().SerializeToHexStr(),
initialAccounts[0].ShardID)
}
if hc.General.NodeType != "validator" && hc.General.ShardID >= 0 {
for _, initialAccount := range initialAccounts {
utils.Logger().Info().
Uint32("original", initialAccount.ShardID).
Int("override", hc.General.ShardID).
Msg("ShardID Override")
initialAccount.ShardID = uint32(hc.General.ShardID)
}
}
nodeConfig, err := createGlobalConfig(hc)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR cannot configure node: %s\n", err)
os.Exit(1)
}
currentNode := setupConsensusAndNode(hc, nodeConfig)
nodeconfig.GetDefaultConfig().ShardID = nodeConfig.ShardID
// Prepare for graceful shutdown from os signals
osSignal := make(chan os.Signal)
signal.Notify(osSignal, os.Interrupt, syscall.SIGTERM)
go func() {
for sig := range osSignal {
if sig == syscall.SIGTERM || sig == os.Interrupt {
const msg = "Got %s signal. Gracefully shutting down...\n"
utils.Logger().Printf(msg, sig)
fmt.Printf(msg, sig)
currentNode.ShutDown()
}
}
}()
// Parse RPC config
nodeConfig.RPCServer = nodeconfig.RPCServerConfig{
HTTPEnabled: hc.HTTP.Enabled,
HTTPIp: hc.HTTP.IP,
HTTPPort: hc.HTTP.Port,
WSEnabled: hc.WS.Enabled,
WSIp: hc.WS.IP,
WSPort: hc.WS.Port,
}
if nodeConfig.ShardID != shard.BeaconChainShardID {
utils.Logger().Info().
Uint32("shardID", currentNode.Blockchain().ShardID()).
Uint32("shardID", nodeConfig.ShardID).Msg("SupportBeaconSyncing")
currentNode.SupportBeaconSyncing()
}
if hc.Revert != nil && hc.Revert.RevertBefore != 0 && hc.Revert.RevertTo != 0 {
chain := currentNode.Blockchain()
if hc.Revert.RevertBeacon {
chain = currentNode.Beaconchain()
}
curNum := chain.CurrentBlock().NumberU64()
if curNum < uint64(hc.Revert.RevertBefore) && curNum >= uint64(hc.Revert.RevertTo) {
// Remove invalid blocks
for chain.CurrentBlock().NumberU64() >= uint64(hc.Revert.RevertTo) {
curBlock := chain.CurrentBlock()
rollbacks := []ethCommon.Hash{curBlock.Hash()}
chain.Rollback(rollbacks)
lastSig := curBlock.Header().LastCommitSignature()
sigAndBitMap := append(lastSig[:], curBlock.Header().LastCommitBitmap()...)
chain.WriteCommitSig(curBlock.NumberU64()-1, sigAndBitMap)
}
}
}
startMsg := "==== New Harmony Node ===="
if hc.General.NodeType == nodeTypeExplorer {
startMsg = "==== New Explorer Node ===="
}
utils.Logger().Info().
Str("BLSPubKey", nodeConfig.ConsensusPriKey.GetPublicKeys().SerializeToHexStr()).
Uint32("ShardID", nodeConfig.ShardID).
Str("ShardGroupID", nodeConfig.GetShardGroupID().String()).
Str("BeaconGroupID", nodeConfig.GetBeaconGroupID().String()).
Str("ClientGroupID", nodeConfig.GetClientGroupID().String()).
Str("Role", currentNode.NodeConfig.Role().String()).
Str("multiaddress",
fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", publicListenIP, hc.P2P.Port, myHost.GetID().Pretty()),
).
Msg(startMsg)
nodeconfig.SetPeerID(myHost.GetID())
currentNode.SupportSyncing()
currentNode.ServiceManagerSetup()
currentNode.RunServices()
if err := currentNode.StartRPC(); err != nil {
utils.Logger().Warn().
Err(err).
Msg("StartRPC failed")
}
if err := currentNode.BootstrapConsensus(); err != nil {
fmt.Println("could not bootstrap consensus", err.Error())
os.Exit(-1)
}
if err := currentNode.Start(); err != nil {
fmt.Println("could not begin network message handling for node", err.Error())
os.Exit(-1)
}
}
func nodeconfigSetShardSchedule(config harmonyConfig) {
switch config.Network.NetworkType {
case nodeconfig.Mainnet:
shard.Schedule = shardingconfig.MainnetSchedule
case nodeconfig.Testnet:
shard.Schedule = shardingconfig.TestnetSchedule
case nodeconfig.Pangaea:
shard.Schedule = shardingconfig.PangaeaSchedule
case nodeconfig.Localnet:
shard.Schedule = shardingconfig.LocalnetSchedule
case nodeconfig.Partner:
shard.Schedule = shardingconfig.PartnerSchedule
case nodeconfig.Stressnet:
shard.Schedule = shardingconfig.StressNetSchedule
case nodeconfig.Devnet:
var dnConfig devnetConfig
if config.Devnet != nil {
dnConfig = *config.Devnet
} else {
dnConfig = getDefaultDevnetConfigCopy()
}
if len(p2p.BootNodes) == 0 {
bootNodeAddrs, err := p2p.StringsToAddrs(p2p.DefaultBootNodeAddrStrings)
// TODO (leo): use a passing list of accounts here
devnetConfig, err := shardingconfig.NewInstance(
uint32(dnConfig.NumShards), dnConfig.ShardSize, dnConfig.HmyNodeSize, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccounts, nil, shardingconfig.VLBPE)
if err != nil {
utils.FatalErrMsg(err, "cannot parse default bootnode list %#v",
p2p.DefaultBootNodeAddrStrings)
_, _ = fmt.Fprintf(os.Stderr, "ERROR invalid devnet sharding config: %s",
err)
os.Exit(1)
}
p2p.BootNodes = bootNodeAddrs
shard.Schedule = shardingconfig.NewFixedSchedule(devnetConfig)
}
}
@ -154,9 +382,9 @@ func findAccountsByPubKeys(config shardingconfig.Instance, pubKeys multibls.Publ
}
}
func setupLegacyNodeAccount() error {
func setupLegacyNodeAccount(hc harmonyConfig) error {
genesisShardingConfig := shard.Schedule.InstanceForEpoch(big.NewInt(core.GenesisEpoch))
multiBLSPubKey := setupConsensusKeys(nodeconfig.GetDefaultConfig())
multiBLSPubKey := setupConsensusKeys(hc, nodeconfig.GetDefaultConfig())
reshardingEpoch := genesisShardingConfig.ReshardingEpoch()
if len(reshardingEpoch) > 0 {
@ -186,8 +414,8 @@ func setupLegacyNodeAccount() error {
return nil
}
func setupStakingNodeAccount() error {
pubKeys := setupConsensusKeys(nodeconfig.GetDefaultConfig())
func setupStakingNodeAccount(hc harmonyConfig) error {
pubKeys := setupConsensusKeys(hc, nodeconfig.GetDefaultConfig())
shardID, err := nodeconfig.GetDefaultConfig().ShardIDFromConsensusKey()
if err != nil {
return errors.Wrap(err, "cannot determine shard to join")
@ -207,36 +435,36 @@ func setupStakingNodeAccount() error {
return nil
}
func createGlobalConfig() (*nodeconfig.ConfigType, error) {
func createGlobalConfig(hc harmonyConfig) (*nodeconfig.ConfigType, error) {
var err error
if len(initialAccounts) == 0 {
initialAccounts = append(initialAccounts, &genesis.DeployAccount{ShardID: uint32(*shardID)})
initialAccounts = append(initialAccounts, &genesis.DeployAccount{ShardID: uint32(hc.General.ShardID)})
}
nodeConfig := nodeconfig.GetShardConfig(initialAccounts[0].ShardID)
if *nodeType == "validator" {
if hc.General.NodeType == nodeTypeValidator {
// Set up consensus keys.
setupConsensusKeys(nodeConfig)
setupConsensusKeys(hc, nodeConfig)
} else {
// set dummy bls key for consensus object
nodeConfig.ConsensusPriKey = multibls.GetPrivateKeys(&bls.SecretKey{})
}
// Set network type
netType := nodeconfig.NetworkType(*networkType)
netType := nodeconfig.NetworkType(hc.Network.NetworkType)
nodeconfig.SetNetworkType(netType) // sets for both global and shard configs
nodeConfig.SetArchival(*isArchival)
nodeConfig.SetArchival(hc.General.IsArchival)
// P2P private key is used for secure message transfer between p2p nodes.
nodeConfig.P2PPriKey, _, err = utils.LoadKeyFromFile(*keyFile)
nodeConfig.P2PPriKey, _, err = utils.LoadKeyFromFile(hc.P2P.KeyFile)
if err != nil {
return nil, errors.Wrapf(err, "cannot load or create P2P key at %#v",
*keyFile)
hc.P2P.KeyFile)
}
selfPeer := p2p.Peer{
IP: *ip,
Port: *port,
IP: publicListenIP,
Port: strconv.Itoa(hc.P2P.Port),
ConsensusPubKey: nodeConfig.ConsensusPriKey[0].Pub.Object,
}
@ -245,9 +473,10 @@ func createGlobalConfig() (*nodeconfig.ConfigType, error) {
return nil, errors.Wrap(err, "cannot create P2P network host")
}
nodeConfig.DBDir = *dbDir
nodeConfig.DBDir = hc.General.DataDir
if p := *webHookYamlPath; p != "" {
if hc.Legacy != nil && hc.Legacy.WebHookConfig != nil && len(*hc.Legacy.WebHookConfig) != 0 {
p := *hc.Legacy.WebHookConfig
config, err := webhooks.NewWebHooksFromPath(p)
if err != nil {
fmt.Fprintf(
@ -261,10 +490,10 @@ func createGlobalConfig() (*nodeconfig.ConfigType, error) {
return nodeConfig, nil
}
func setupConsensusAndNode(nodeConfig *nodeconfig.ConfigType) *node.Node {
func setupConsensusAndNode(hc harmonyConfig, nodeConfig *nodeconfig.ConfigType) *node.Node {
// Consensus object.
// TODO: consensus object shouldn't start here
decider := quorum.NewDecider(quorum.SuperMajorityVote, uint32(*shardID))
decider := quorum.NewDecider(quorum.SuperMajorityVote, uint32(hc.General.ShardID))
currentConsensus, err := consensus.New(
myHost, nodeConfig.ShardID, p2p.Peer{}, nodeConfig.ConsensusPriKey, decider,
@ -277,15 +506,19 @@ func setupConsensusAndNode(nodeConfig *nodeconfig.ConfigType) *node.Node {
_, _ = fmt.Fprintf(os.Stderr, "Error :%v \n", err)
os.Exit(1)
}
commitDelay, err := time.ParseDuration(*delayCommit)
if err != nil || commitDelay < 0 {
_, _ = fmt.Fprintf(os.Stderr, "ERROR invalid commit delay %#v", *delayCommit)
os.Exit(1)
currentConsensus.SetCommitDelay(time.Duration(0))
// Parse minPeers from harmonyConfig
var minPeers int
if hc.Consensus != nil {
minPeers = hc.Consensus.MinPeers
} else {
minPeers = defaultConsensusConfig.MinPeers
}
currentConsensus.SetCommitDelay(commitDelay)
currentConsensus.MinPeers = *minPeers
currentConsensus.MinPeers = minPeers
blacklist, err := setupBlacklist()
blacklist, err := setupBlacklist(hc)
if err != nil {
utils.Logger().Warn().Msgf("Blacklist setup error: %s", err.Error())
}
@ -293,44 +526,42 @@ func setupConsensusAndNode(nodeConfig *nodeconfig.ConfigType) *node.Node {
// Current node.
chainDBFactory := &shardchain.LDBFactory{RootDir: nodeConfig.DBDir}
currentNode := node.New(myHost, currentConsensus, chainDBFactory, blacklist, *isArchival)
currentNode.BroadcastInvalidTx = *broadcastInvalidTx
currentNode := node.New(myHost, currentConsensus, chainDBFactory, blacklist, hc.General.IsArchival)
switch {
case *networkType == nodeconfig.Localnet:
epochConfig := shard.Schedule.InstanceForEpoch(ethCommon.Big0)
selfPort, err := strconv.ParseUint(*port, 10, 16)
if err != nil {
utils.Logger().Fatal().
Err(err).
Str("self_port_string", *port).
Msg("cannot convert self port string into port number")
}
currentNode.SyncingPeerProvider = node.NewLocalSyncingPeerProvider(
6000, uint16(selfPort), epochConfig.NumShards(), uint32(epochConfig.NumNodesPerShard()))
case *dnsZone != "":
currentNode.SyncingPeerProvider = node.NewDNSSyncingPeerProvider(*dnsZone, syncing.GetSyncingPort(*dnsPort))
case *dnsFlag:
currentNode.SyncingPeerProvider = node.NewDNSSyncingPeerProvider("t.hmny.io", syncing.GetSyncingPort(*dnsPort))
default:
currentNode.SyncingPeerProvider = node.NewLegacySyncingPeerProvider(currentNode)
if hc.Legacy != nil && hc.Legacy.TPBroadcastInvalidTxn != nil {
currentNode.BroadcastInvalidTx = *hc.Legacy.TPBroadcastInvalidTxn
} else {
currentNode.BroadcastInvalidTx = defaultBroadcastInvalidTx
}
if hc.Network.LegacySyncing {
currentNode.SyncingPeerProvider = node.NewLegacySyncingPeerProvider(currentNode)
} else {
if hc.Network.NetworkType == nodeconfig.Localnet {
epochConfig := shard.Schedule.InstanceForEpoch(ethCommon.Big0)
selfPort := hc.P2P.Port
currentNode.SyncingPeerProvider = node.NewLocalSyncingPeerProvider(
6000, uint16(selfPort), epochConfig.NumShards(), uint32(epochConfig.NumNodesPerShard()))
} else {
currentNode.SyncingPeerProvider = node.NewDNSSyncingPeerProvider(hc.Network.DNSZone, syncing.GetSyncingPort(strconv.Itoa(hc.Network.DNSPort)))
}
}
// TODO: refactor the creation of blockchain out of node.New()
currentConsensus.ChainReader = currentNode.Blockchain()
currentNode.NodeConfig.DNSZone = *dnsZone
currentNode.NodeConfig.DNSZone = hc.Network.DNSZone
currentNode.NodeConfig.SetBeaconGroupID(
nodeconfig.NewGroupIDByShardID(shard.BeaconChainShardID),
)
nodeconfig.GetDefaultConfig().DBDir = nodeConfig.DBDir
switch *nodeType {
case "explorer":
switch hc.General.NodeType {
case nodeTypeExplorer:
nodeconfig.SetDefaultRole(nodeconfig.ExplorerNode)
currentNode.NodeConfig.SetRole(nodeconfig.ExplorerNode)
case "validator":
case nodeTypeValidator:
nodeconfig.SetDefaultRole(nodeconfig.Validator)
currentNode.NodeConfig.SetRole(nodeconfig.Validator)
}
@ -341,7 +572,7 @@ func setupConsensusAndNode(nodeConfig *nodeconfig.ConfigType) *node.Node {
// This needs to be executed after consensus setup
if err := currentNode.InitConsensusWithValidators(); err != nil {
utils.Logger().Warn().
Int("shardID", *shardID).
Int("shardID", hc.General.ShardID).
Err(err).
Msg("InitConsensusWithMembers failed")
}
@ -358,15 +589,13 @@ func setupConsensusAndNode(nodeConfig *nodeconfig.ConfigType) *node.Node {
currentConsensus.OnConsensusDone = currentNode.PostConsensusProcessing
// update consensus information based on the blockchain
currentConsensus.SetMode(currentConsensus.UpdateConsensusInformation())
// Setup block period and block due time.
currentConsensus.BlockPeriod = time.Duration(*blockPeriod) * time.Second
currentConsensus.NextBlockDue = time.Now()
return currentNode
}
func setupBlacklist() (map[ethCommon.Address]struct{}, error) {
utils.Logger().Debug().Msgf("Using blacklist file at `%s`", *blacklistPath)
dat, err := ioutil.ReadFile(*blacklistPath)
func setupBlacklist(hc harmonyConfig) (map[ethCommon.Address]struct{}, error) {
utils.Logger().Debug().Msgf("Using blacklist file at `%s`", hc.TxPool.BlacklistFile)
dat, err := ioutil.ReadFile(hc.TxPool.BlacklistFile)
if err != nil {
return nil, err
}
@ -383,220 +612,3 @@ func setupBlacklist() (map[ethCommon.Address]struct{}, error) {
}
return addrMap, nil
}
func setupViperConfig() {
// read from environment
envViper := viperconfig.CreateEnvViper()
//read from config file
configFileViper := viperconfig.CreateConfFileViper("./.hmy", "nodeconfig", "json")
viperconfig.ResetConfString(ip, envViper, configFileViper, "", "ip")
viperconfig.ResetConfString(port, envViper, configFileViper, "", "port")
viperconfig.ResetConfString(logFolder, envViper, configFileViper, "", "log_folder")
viperconfig.ResetConfInt(logMaxSize, envViper, configFileViper, "", "log_max_size")
viperconfig.ResetConfBool(freshDB, envViper, configFileViper, "", "fresh_db")
viperconfig.ResetConfString(pprof, envViper, configFileViper, "", "pprof")
viperconfig.ResetConfBool(versionFlag, envViper, configFileViper, "", "version")
viperconfig.ResetConfString(dnsZone, envViper, configFileViper, "", "dns_zone")
viperconfig.ResetConfBool(dnsFlag, envViper, configFileViper, "", "dns")
viperconfig.ResetConfInt(minPeers, envViper, configFileViper, "", "min_peers")
viperconfig.ResetConfString(keyFile, envViper, configFileViper, "", "key")
viperconfig.ResetConfBool(isArchival, envViper, configFileViper, "", "is_archival")
viperconfig.ResetConfString(delayCommit, envViper, configFileViper, "", "delay_commit")
viperconfig.ResetConfString(nodeType, envViper, configFileViper, "", "node_type")
viperconfig.ResetConfString(networkType, envViper, configFileViper, "", "network_type")
viperconfig.ResetConfInt(blockPeriod, envViper, configFileViper, "", "block_period")
viperconfig.ResetConfBool(stakingFlag, envViper, configFileViper, "", "staking")
viperconfig.ResetConfInt(shardID, envViper, configFileViper, "", "shard_id")
viperconfig.ResetConfString(blsKeyFile, envViper, configFileViper, "", "blskey_file")
viperconfig.ResetConfString(blsFolder, envViper, configFileViper, "", "blsfolder")
viperconfig.ResetConfString(blsPass, envViper, configFileViper, "", "blsPass")
viperconfig.ResetConfUInt(devnetNumShards, envViper, configFileViper, "", "dn_num_shards")
viperconfig.ResetConfInt(devnetShardSize, envViper, configFileViper, "", "dn_shard_size")
viperconfig.ResetConfInt(devnetHarmonySize, envViper, configFileViper, "", "dn_hmy_size")
viperconfig.ResetConfInt(verbosity, envViper, configFileViper, "", "verbosity")
viperconfig.ResetConfString(dbDir, envViper, configFileViper, "", "db_dir")
viperconfig.ResetConfBool(publicRPC, envViper, configFileViper, "", "public_rpc")
viperconfig.ResetConfInt(doRevertBefore, envViper, configFileViper, "", "do_revert_before")
viperconfig.ResetConfInt(revertTo, envViper, configFileViper, "", "revert_to")
viperconfig.ResetConfBool(revertBeacon, envViper, configFileViper, "", "revert_beacon")
viperconfig.ResetConfString(blacklistPath, envViper, configFileViper, "", "blacklist")
viperconfig.ResetConfString(webHookYamlPath, envViper, configFileViper, "", "webhook_yaml")
}
func main() {
// HACK Force usage of go implementation rather than the C based one. Do the right way, see the
// notes one line 66,67 of https://golang.org/src/net/net.go that say can make the decision at
// build time.
os.Setenv("GODEBUG", "netdns=go")
flag.Var(&p2p.BootNodes, "bootnodes", "a list of bootnode multiaddress (delimited by ,)")
flag.Parse()
switch *nodeType {
case "validator":
case "explorer":
break
default:
_, _ = fmt.Fprintf(os.Stderr, "Unknown node type: %s\n", *nodeType)
os.Exit(1)
}
nodeconfig.SetPublicRPC(*publicRPC)
nodeconfig.SetVersion(
fmt.Sprintf("Harmony (C) 2020. %v, version %v-%v (%v %v)",
path.Base(os.Args[0]), version, commit, builtBy, builtAt),
)
if *versionFlag {
printVersion()
}
switch *networkType {
case nodeconfig.Mainnet:
shard.Schedule = shardingconfig.MainnetSchedule
case nodeconfig.Testnet:
shard.Schedule = shardingconfig.TestnetSchedule
case nodeconfig.Pangaea:
shard.Schedule = shardingconfig.PangaeaSchedule
case nodeconfig.Localnet:
shard.Schedule = shardingconfig.LocalnetSchedule
case nodeconfig.Partner:
shard.Schedule = shardingconfig.PartnerSchedule
case nodeconfig.Stressnet:
shard.Schedule = shardingconfig.StressNetSchedule
case nodeconfig.Devnet:
if *devnetHarmonySize < 0 {
*devnetHarmonySize = *devnetShardSize
}
// TODO (leo): use a passing list of accounts here
devnetConfig, err := shardingconfig.NewInstance(
uint32(*devnetNumShards), *devnetShardSize, *devnetHarmonySize, numeric.OneDec(), genesis.HarmonyAccounts, genesis.FoundationalNodeAccounts, nil, shardingconfig.VLBPE)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "ERROR invalid devnet sharding config: %s",
err)
os.Exit(1)
}
shard.Schedule = shardingconfig.NewFixedSchedule(devnetConfig)
default:
_, _ = fmt.Fprintf(os.Stderr, "invalid network type: %#v\n", *networkType)
os.Exit(2)
}
setupViperConfig()
initSetup()
if *nodeType == "validator" {
var err error
if *stakingFlag {
err = setupStakingNodeAccount()
} else {
err = setupLegacyNodeAccount()
}
if err != nil {
fmt.Fprintf(os.Stderr, "cannot set up node account: %s\n", err)
os.Exit(1)
}
}
if *nodeType == "validator" {
fmt.Printf("%s mode; node key %s -> shard %d\n",
map[bool]string{false: "Legacy", true: "Staking"}[*stakingFlag],
nodeconfig.GetDefaultConfig().ConsensusPriKey.GetPublicKeys().SerializeToHexStr(),
initialAccounts[0].ShardID)
}
if *nodeType != "validator" && *shardID >= 0 {
for _, initialAccount := range initialAccounts {
utils.Logger().Info().
Uint32("original", initialAccount.ShardID).
Int("override", *shardID).
Msg("ShardID Override")
initialAccount.ShardID = uint32(*shardID)
}
}
nodeConfig, err := createGlobalConfig()
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR cannot configure node: %s\n", err)
os.Exit(1)
}
currentNode := setupConsensusAndNode(nodeConfig)
nodeconfig.GetDefaultConfig().ShardID = nodeConfig.ShardID
// Prepare for graceful shutdown from os signals
osSignal := make(chan os.Signal)
signal.Notify(osSignal, os.Interrupt, syscall.SIGTERM)
go func() {
for sig := range osSignal {
if sig == syscall.SIGTERM || sig == os.Interrupt {
const msg = "Got %s signal. Gracefully shutting down...\n"
utils.Logger().Printf(msg, sig)
fmt.Printf(msg, sig)
currentNode.ShutDown()
}
}
}()
if nodeConfig.ShardID != shard.BeaconChainShardID {
utils.Logger().Info().
Uint32("shardID", currentNode.Blockchain().ShardID()).
Uint32("shardID", nodeConfig.ShardID).Msg("SupportBeaconSyncing")
currentNode.SupportBeaconSyncing()
}
if uint64(*doRevertBefore) != 0 && uint64(*revertTo) != 0 {
chain := currentNode.Blockchain()
if *revertBeacon {
chain = currentNode.Beaconchain()
}
curNum := chain.CurrentBlock().NumberU64()
if curNum < uint64(*doRevertBefore) && curNum >= uint64(*revertTo) {
// Remove invalid blocks
for chain.CurrentBlock().NumberU64() >= uint64(*revertTo) {
curBlock := chain.CurrentBlock()
rollbacks := []ethCommon.Hash{curBlock.Hash()}
chain.Rollback(rollbacks)
lastSig := curBlock.Header().LastCommitSignature()
sigAndBitMap := append(lastSig[:], curBlock.Header().LastCommitBitmap()...)
chain.WriteCommitSig(curBlock.NumberU64()-1, sigAndBitMap)
}
}
}
startMsg := "==== New Harmony Node ===="
if *nodeType == "explorer" {
startMsg = "==== New Explorer Node ===="
}
utils.Logger().Info().
Str("BLSPubKey", nodeConfig.ConsensusPriKey.GetPublicKeys().SerializeToHexStr()).
Uint32("ShardID", nodeConfig.ShardID).
Str("ShardGroupID", nodeConfig.GetShardGroupID().String()).
Str("BeaconGroupID", nodeConfig.GetBeaconGroupID().String()).
Str("ClientGroupID", nodeConfig.GetClientGroupID().String()).
Str("Role", currentNode.NodeConfig.Role().String()).
Str("multiaddress",
fmt.Sprintf("/ip4/%s/tcp/%s/p2p/%s", *ip, *port, myHost.GetID().Pretty()),
).
Msg(startMsg)
nodeconfig.SetPeerID(myHost.GetID())
currentNode.SupportSyncing()
currentNode.ServiceManagerSetup()
currentNode.RunServices()
if err := currentNode.StartRPC(*port); err != nil {
utils.Logger().Warn().
Err(err).
Msg("StartRPC failed")
}
if err := currentNode.BootstrapConsensus(); err != nil {
fmt.Println("could not bootstrap consensus", err.Error())
os.Exit(-1)
}
if err := currentNode.Start(); err != nil {
fmt.Println("could not begin network message handling for node", err.Error())
os.Exit(-1)
}
}

@ -0,0 +1,46 @@
package main
import (
"fmt"
"os"
"github.com/harmony-one/harmony/internal/cli"
"github.com/spf13/cobra"
)
const (
versionFormat = "Harmony (C) 2020. %v, version %v-%v (%v %v)"
)
// Version string variables
var (
version string
builtBy string
builtAt string
commit string
)
var versionFlag = cli.BoolFlag{
Name: "version",
Shorthand: "V",
Usage: "display version info",
}
var versionCmd = &cobra.Command{
Use: "version",
Short: "print version of the harmony binary",
Long: "print version of the harmony binary",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
printVersion()
os.Exit(0)
},
}
func getHarmonyVersion() string {
return fmt.Sprintf(versionFormat, "harmony", version, commit, builtBy, builtAt)
}
func printVersion() {
fmt.Println(getHarmonyVersion())
}

@ -347,9 +347,7 @@ func (consensus *Consensus) UpdateConsensusInformation() Mode {
}
}
if consensus.ChainReader.Config().IsFiveSeconds(curEpoch) {
consensus.BlockPeriod = time.Duration(5 * time.Second)
}
consensus.BlockPeriod = 5 * time.Second
isFirstTimeStaking := consensus.ChainReader.Config().IsStaking(nextEpoch) &&
len(curHeader.ShardState()) > 0 &&

@ -51,6 +51,7 @@ require (
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/otiai10/copy v1.2.0
github.com/pborman/uuid v1.2.0
github.com/pelletier/go-toml v1.2.0
github.com/pkg/errors v0.9.1
github.com/prometheus/common v0.4.1 // indirect
github.com/prometheus/procfs v0.0.3 // indirect

@ -1,7 +1,6 @@
package blsgen
import (
"bufio"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
@ -11,7 +10,6 @@ import (
"io/ioutil"
"os"
"strings"
"time"
"github.com/aws/aws-sdk-go/service/kms"
ffi_bls "github.com/harmony-one/bls/ffi/go/bls"
@ -72,33 +70,6 @@ func LoadBLSKeyWithPassPhrase(fileName, passphrase string) (*ffi_bls.SecretKey,
return priKey, nil
}
// Readln reads aws configuratoin from prompt with a timeout
func Readln(timeout time.Duration) (string, error) {
s := make(chan string)
e := make(chan error)
go func() {
reader := bufio.NewReader(os.Stdin)
line, err := reader.ReadString('\n')
if err != nil {
e <- err
} else {
s <- line
}
close(s)
close(e)
}()
select {
case line := <-s:
return line, nil
case err := <-e:
return "", err
case <-time.After(timeout):
return "", errors.New("Timeout")
}
}
// LoadAwsCMKEncryptedBLSKey loads aws encrypted bls key.
func LoadAwsCMKEncryptedBLSKey(fileName string, kmsClient *kms.KMS) (*ffi_bls.SecretKey, error) {
encryptedPrivateKeyBytes, err := ioutil.ReadFile(fileName)

@ -3,7 +3,6 @@ package blsgen
import (
"fmt"
"os"
"path/filepath"
"strings"
bls_core "github.com/harmony-one/bls/ffi/go/bls"
@ -43,16 +42,6 @@ func checkIsDir(path string) error {
return nil
}
func checkIsPassFile(path string) error {
if err := checkIsFile(path); err != nil {
return err
}
if filepath.Ext(path) != passExt {
return fmt.Errorf("pass file %v should have extension .pass", path)
}
return nil
}
func keyFileToPassFileFull(keyFile string) string {
return strings.TrimSuffix(keyFile, basicKeyExt) + passExt
}

@ -81,7 +81,8 @@ func (f StringSliceFlag) RegisterTo(fs *pflag.FlagSet) error {
func markHiddenOrDeprecated(fs *pflag.FlagSet, name string, deprecated string, hidden bool) error {
if len(deprecated) != 0 {
if err := fs.MarkDeprecated(name, deprecated); err != nil {
// TODO: after totally removed node.sh, change MarkHidden to MarkDeprecated
if err := fs.MarkHidden(name); err != nil {
return err
}
} else if hidden {
@ -91,3 +92,17 @@ func markHiddenOrDeprecated(fs *pflag.FlagSet, name string, deprecated string, h
}
return nil
}
func getFlagName(flag Flag) string {
switch f := flag.(type) {
case StringFlag:
return f.Name
case IntFlag:
return f.Name
case BoolFlag:
return f.Name
case StringSliceFlag:
return f.Name
}
return ""
}

@ -105,6 +105,25 @@ func getStringSliceFlagValue(fs *pflag.FlagSet, flag StringSliceFlag) []string {
return val
}
// IsFlagChanged returns whether the flag has been changed in command
func IsFlagChanged(cmd *cobra.Command, flag Flag) bool {
name := getFlagName(flag)
return cmd.Flags().Changed(name)
}
// HasFlagsChanged returns whether any of the flags is set by user in the command
func HasFlagsChanged(cmd *cobra.Command, flags []Flag) bool {
fs := cmd.Flags()
for _, flag := range flags {
name := getFlagName(flag)
if fs.Changed(name) {
return true
}
}
return false
}
func handleParseError(err error) {
if parseErrorHandleFunc != nil {
parseErrorHandleFunc(err)

@ -9,9 +9,8 @@ import (
"strings"
"sync"
"github.com/harmony-one/harmony/crypto/bls"
bls_core "github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/crypto/bls"
shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/multibls"
@ -46,6 +45,7 @@ func (role Role) String() string {
type NetworkType string
// Constants for NetworkType
// TODO: replace this with iota. Leave the string parsing in command line
const (
Mainnet = "mainnet"
Testnet = "testnet"
@ -63,20 +63,20 @@ const (
)
var version string
var publicRPC bool // enable public RPC access
var peerID peer.ID // PeerID of the node
// ConfigType is the structure of all node related configuration variables
type ConfigType struct {
// The three groupID design, please refer to https://github.com/harmony-one/harmony/blob/master/node/node.md#libp2p-integration
beacon GroupID // the beacon group ID
group GroupID // the group ID of the shard (note: for beacon chain node, the beacon and shard group are the same)
client GroupID // the client group ID of the shard
isClient bool // whether this node is a client node, such as wallet
ShardID uint32 // ShardID of this node; TODO ek – revisit when resharding
role Role // Role of the node
Port string // Port of the node.
IP string // IP of the node.
beacon GroupID // the beacon group ID
group GroupID // the group ID of the shard (note: for beacon chain node, the beacon and shard group are the same)
client GroupID // the client group ID of the shard
isClient bool // whether this node is a client node, such as wallet
ShardID uint32 // ShardID of this node; TODO ek – revisit when resharding
role Role // Role of the node
Port string // Port of the node.
IP string // IP of the node.
RPCServer RPCServerConfig // RPC server port and ip
StringRole string
P2PPriKey p2p_crypto.PrivKey
ConsensusPriKey multibls.PrivateKeys
@ -91,6 +91,17 @@ type ConfigType struct {
}
}
// RPCServerConfig is the config for rpc listen addresses
type RPCServerConfig struct {
HTTPEnabled bool
HTTPIp string
HTTPPort int
WSEnabled bool
WSIp string
WSPort int
}
// configs is a list of node configuration.
// It has at least one configuration.
// The first one is the default, global node configuration
@ -224,16 +235,6 @@ func GetPeerID() peer.ID {
return peerID
}
// SetPublicRPC set the boolean value of public RPC access
func SetPublicRPC(v bool) {
publicRPC = v
}
// GetPublicRPC get the boolean value of public RPC access
func GetPublicRPC() bool {
return publicRPC
}
// ShardingSchedule returns the sharding schedule for this node config.
func (conf *ConfigType) ShardingSchedule() shardingconfig.Schedule {
return conf.shardingSchedule

@ -0,0 +1,111 @@
package nodeconfig
var (
mainnetBootNodes = []string{
"/ip4/100.26.90.187/tcp/9874/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv",
"/ip4/54.213.43.194/tcp/9874/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9",
"/ip4/13.113.101.219/tcp/12019/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX",
"/ip4/99.81.170.167/tcp/12019/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj",
}
testnetBootNodes = []string{
"/ip4/54.86.126.90/tcp/9867/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv",
"/ip4/52.40.84.2/tcp/9867/p2p/QmbPVwrqWsTYXq1RxGWcxx9SWaTUCfoo1wA6wmdbduWe29",
}
pangaeaBootNodes = []string{
"/ip4/52.40.84.2/tcp/9800/p2p/QmbPVwrqWsTYXq1RxGWcxx9SWaTUCfoo1wA6wmdbduWe29",
"/ip4/54.86.126.90/tcp/9800/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv",
}
partnerBootNodes = []string{
"/ip4/52.40.84.2/tcp/9800/p2p/QmbPVwrqWsTYXq1RxGWcxx9SWaTUCfoo1wA6wmdbduWe29",
"/ip4/54.86.126.90/tcp/9800/p2p/Qmdfjtk6hPoyrH1zVD9PEH4zfWLo38dP2mDvvKXfh3tnEv",
}
stressBootNodes = []string{
"/ip4/52.40.84.2/tcp/9842/p2p/QmbPVwrqWsTYXq1RxGWcxx9SWaTUCfoo1wA6wmdbduWe29",
}
devnetBootNodes = []string{}
)
const (
mainnetDNSZone = "t.hmny.io"
testnetDNSZone = "b.hmny.io"
pangaeaDNSZone = "os.hmny.io"
partnerDNSZone = "ps.hmny.io"
stressnetDNSZone = "stn.hmny.io"
)
const (
// DefaultP2PPort is the key to be used for p2p communication
DefaultP2PPort = 9000
// DefaultDNSPort is the default DNS port. The actual port used is DNSPort - 3000. This is a
// very bad design. Will refactor later
// TODO: refactor all 9000-3000 = 6000 stuff
DefaultDNSPort = 9000
// DefaultRPCPort is the default rpc port. The actual port used is 9000+500
DefaultRPCPort = 9500
// DefaultWSPort is the default port for web socket endpoint. The actual port used is
DefaultWSPort = 9800
)
const (
// rpcHTTPPortOffset is the port offset for RPC HTTP requests
rpcHTTPPortOffset = 500
// rpcWSPortOffSet is the port offset for RPC websocket requests
rpcWSPortOffSet = 800
)
// GetDefaultBootNodes get the default bootnode with the given network type
func GetDefaultBootNodes(networkType NetworkType) []string {
switch networkType {
case Mainnet:
return mainnetBootNodes
case Testnet:
return testnetBootNodes
case Pangaea:
return pangaeaBootNodes
case Partner:
return partnerBootNodes
case Stressnet:
return stressBootNodes
case Devnet:
return devnetBootNodes
}
return nil
}
// GetDefaultDNSZone get the default DNS zone with the given network type
func GetDefaultDNSZone(networkType NetworkType) string {
switch networkType {
case Mainnet:
return mainnetDNSZone
case Testnet:
return testnetDNSZone
case Pangaea:
return pangaeaDNSZone
case Partner:
return partnerDNSZone
case Stressnet:
return stressnetDNSZone
}
return ""
}
// GetDefaultDNSPort get the default DNS port for the given network type
func GetDefaultDNSPort(NetworkType) int {
return DefaultDNSPort
}
// GetHTTPPortFromBase return the HTTP port from base port
func GetHTTPPortFromBase(basePort int) int {
return basePort + rpcHTTPPortOffset
}
// GetWSPortFromBase return the Websocket port from the base port
func GetWSPortFromBase(basePort int) int {
return basePort + rpcWSPortOffSet
}

@ -1,8 +1,6 @@
package node
import (
"strconv"
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/hmy"
@ -63,7 +61,7 @@ func (node *Node) ReportPlainErrorSink() types.TransactionErrorReports {
}
// StartRPC start RPC service
func (node *Node) StartRPC(nodePort string) error {
func (node *Node) StartRPC() error {
harmony := hmy.New(node, node.TxPool, node.CxPool, node.Consensus.ShardID)
// Gather all the possible APIs to surface
@ -73,9 +71,7 @@ func (node *Node) StartRPC(nodePort string) error {
apis = append(apis, service.APIs()...)
}
port, _ := strconv.Atoi(nodePort)
return hmy_rpc.StartServers(harmony, port, apis)
return hmy_rpc.StartServers(harmony, apis, node.NodeConfig.RPCServer)
}
// StopRPC stop RPC service

@ -371,12 +371,8 @@ func StringsToAddrs(addrStrings []string) (maddrs []ma.Multiaddr, err error) {
return
}
// DefaultBootNodeAddrStrings is a list of Harmony
// bootnodes address. Used to find other peers in the network.
var DefaultBootNodeAddrStrings = []string{
"/ip4/127.0.0.1/tcp/19876/p2p/Qmc1V6W7BwX8Ugb42Ti8RnXF1rY5PF7nnZ6bKBryCgi6cv",
}
// BootNodes is a list of boot nodes.
// It is populated either from default or from user CLI input.
// TODO: refactor p2p config into a config structure (now part of config is here, part is in
// nodeconfig)
var BootNodes AddrList

@ -63,22 +63,23 @@ func (n Version) Namespace() string {
}
// StartServers starts the http & ws servers
func StartServers(hmy *hmy.Harmony, port int, apis []rpc.API) error {
ip := ""
if !nodeconfig.GetPublicRPC() {
ip = "127.0.0.1"
}
func StartServers(hmy *hmy.Harmony, apis []rpc.API, config nodeconfig.RPCServerConfig) error {
apis = append(apis, getAPIs(hmy)...)
httpEndpoint = fmt.Sprintf("%v:%v", ip, port+HTTPPortOffset)
if err := startHTTP(apis); err != nil {
return err
if config.HTTPEnabled {
httpEndpoint = fmt.Sprintf("%v:%v", config.HTTPIp, config.HTTPPort)
if err := startHTTP(apis); err != nil {
return err
}
}
wsEndpoint = fmt.Sprintf("%v:%v", ip, port+WSPortOffset)
if err := startWS(apis); err != nil {
return err
if config.WSEnabled {
wsEndpoint = fmt.Sprintf("%v:%v", config.WSIp, config.WSPort)
if err := startWS(apis); err != nil {
return err
}
}
return nil
}

@ -118,10 +118,18 @@ function build_only
fi
fi
if [ "$(uname -s)" == "Linux" ]; then
$BINDIR/$bin -version || $BINDIR/$bin version
if [ $bin = harmony ]; then
$BINDIR/$bin version || $BINDIR/$bin version
else
$BINDIR/$bin --version || $BINDIR/$bin version
fi
fi
if [ "$(uname -s)" == "Darwin" -a "$GOOS" == "darwin" -a -e $BINDIR/$bin ]; then
$BINDIR/$bin -version || $BINDIR/$bin version
if [ $bin = harmony ]; then
$BINDIR/$bin version || $BINDIR/$bin version
else
$BINDIR/$bin --version || $BINDIR/$bin version
fi
fi
fi
done

@ -1,6 +1,6 @@
#!/usr/bin/env bash
version="v1 20200723.1"
version="v2 20200811.1"
unset -v progname
progname="${0##*/}"
@ -309,7 +309,7 @@ do
r) pprof="${OPTARG}";;
v) msg "version: $version"
exit 0 ;;
V) INSTALLED_VERSION=$(LD_LIBRARY_PATH=. ./harmony -version 2>&1)
V) INSTALLED_VERSION=$(LD_LIBRARY_PATH=. ./harmony version 2>&1)
RUNNING_VERSION=$(curl -s --request POST 'http://127.0.0.1:9500/' --header 'Content-Type: application/json' --data-raw '{ "jsonrpc": "2.0", "method": "hmyv2_getNodeMetadata", "params": [], "id": 1}' | grep -Eo '"version":"[^"]*"' | cut -c11- | tr -d \")
echo "Binary Version: $INSTALLED_VERSION"
echo "Running Version: $RUNNING_VERSION"
@ -345,7 +345,7 @@ mainnet)
/ip4/13.113.101.219/tcp/12019/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX
/ip4/99.81.170.167/tcp/12019/p2p/QmRVbTpEYup8dSaURZfF6ByrMTSKa4UyUzJhSjahFzRqNj
)
REL=main
REL=main_v2
network_type=mainnet
dns_zone=t.hmny.io
syncdir=mainnet.min
@ -743,50 +743,53 @@ while :
do
msg "############### Running Harmony Process ###############"
args=(
-bootnodes "${BN_MA}"
-ip "${PUB_IP}"
-port "${NODE_PORT}"
-network_type="${network_type}"
-dns_zone="${dns_zone}"
-blacklist="${blacklist}"
-min_peers="${minpeers}"
-max_bls_keys_per_node="${max_bls_keys_per_node}"
-broadcast_invalid_tx="${broadcast_invalid_tx}"
-verbosity="${log_level}"
-block_period="5"
--bootnodes "${BN_MA}"
--ip "${PUB_IP}"
--port "${NODE_PORT}"
--network_type="${network_type}"
--dns_zone="${dns_zone}"
--blacklist="${blacklist}"
--min_peers="${minpeers}"
--max_bls_keys_per_node="${max_bls_keys_per_node}"
--broadcast_invalid_tx="${broadcast_invalid_tx}"
--verbosity="${log_level}"
)
args+=(
-is_archival="${archival}"
--is_archival="${archival}"
)
if [ ! -z "$BLSKEYFILES" ]; then
args+=(
-blskey_file "${BLSKEYFILES}"
--blskey_file "${BLSKEYFILES}"
)
fi
if [ ! -z "$blsfolder" ]; then
args+=(
-blsfolder "${blsfolder}"
--blsfolder "${blsfolder}"
)
fi
if [ ! -z "$blspass" ]; then
args+=(
-blspass "file:${blspass}"
--blspass "file:${blspass}"
)
else
if $no_bls_pass_prompt; then
args+=(
-blspass no-prompt
--blspass no-prompt
)
fi
fi
if ${public_rpc}; then
args+=(
-public_rpc
--public_rpc
)
else
args+=(
--public_rpc=false
)
fi
if [ ! -z "${pprof}" ]; then
args+=(
-pprof "${pprof}"
--pprof.addr "${pprof}"
)
fi
@ -796,19 +799,21 @@ do
case "${shard_id}" in
?*)
args+=(
-shard_id="${shard_id}"
--shard_id="${shard_id}"
)
if ${staking_mode}
then
args+=(-staking="${staking_mode}")
if [ ${staking_mode} == "false" ]; then
args+=(
--run.legacy
)
fi
;;
esac
;;
explorer)
args+=(
-node_type="${node_type}"
-shard_id="${shard_id}"
--node_type="${node_type}"
--shard_id="${shard_id}"
)
;;
esac

@ -72,7 +72,7 @@ function launch_localnet() {
verbosity=3
fi
base_args=(-log_folder "${log_folder}" -min_peers "${MIN}" -bootnodes "${BN_MA}" "-network_type=$NETWORK" -blspass file:"${ROOT}/.hmy/blspass.txt" "-dns=false" "-verbosity=${verbosity}")
base_args=(--log_folder "${log_folder}" --min_peers "${MIN}" --bootnodes "${BN_MA}" "--network_type=$NETWORK" --blspass file:"${ROOT}/.hmy/blspass.txt" "--dns=false" "--verbosity=${verbosity}")
sleep 2
# Start nodes
@ -82,7 +82,7 @@ function launch_localnet() {
# Read config for i-th node form config file
IFS=' ' read -r ip port mode bls_key shard <<<"${line}"
args=("${base_args[@]}" -ip "${ip}" -port "${port}" -key "/tmp/${ip}-${port}.key" -db_dir "${ROOT}/db-${ip}-${port}" "-broadcast_invalid_tx=true")
args=("${base_args[@]}" --ip "${ip}" --port "${port}" --key "/tmp/${ip}-${port}.key" --db_dir "${ROOT}/db-${ip}-${port}" "--broadcast_invalid_tx=true")
if [[ -z "$ip" || -z "$port" ]]; then
echo "skip empty node"
continue
@ -90,11 +90,11 @@ function launch_localnet() {
# Setup BLS key for i-th localnet node
if [[ ! -e "$bls_key" ]]; then
args=("${args[@]}" -blskey_file "BLSKEY")
args=("${args[@]}" --blskey_file "BLSKEY")
elif [[ -f "$bls_key" ]]; then
args=("${args[@]}" -blskey_file "${ROOT}/${bls_key}")
args=("${args[@]}" --blskey_file "${ROOT}/${bls_key}")
elif [[ -d "$bls_key" ]]; then
args=("${args[@]}" -blsfolder "${ROOT}/${bls_key}")
args=("${args[@]}" --blsfolder "${ROOT}/${bls_key}")
else
echo "skipping unknown node"
continue
@ -103,19 +103,21 @@ function launch_localnet() {
# Setup flags for i-th node based on config
case "${mode}" in
explorer)
args=("${args[@]}" "-node_type=explorer" "-shard_id=${shard}")
args=("${args[@]}" "--node_type=explorer" "--shard_id=${shard}")
;;
archival)
args=("${args[@]}" -is_archival)
args=("${args[@]}" --is_archival --run.legacy)
;;
leader)
args=("${args[@]}" -is_leader)
args=("${args[@]}" --is_leader --run.legacy)
;;
external)
args=("${args[@]}" "-staking=true")
;;
client)
continue
args=("${args[@]}" --run.legacy)
;;
validator)
args=("${args[@]}" --run.legacy)
;;
esac

Loading…
Cancel
Save