From d1646b2765c6e4ad3a65dd51281de5af252e9cb5 Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Thu, 21 Mar 2019 07:09:53 +0000 Subject: [PATCH 1/4] [wallet] simply the wallet code by hardcode IP of RPC servers Signed-off-by: Leo Chen --- api/client/service/client.go | 32 ++---- cmd/client/wallet/main.go | 184 ++++++++++++++++++++++++----------- 2 files changed, 135 insertions(+), 81 deletions(-) diff --git a/api/client/service/client.go b/api/client/service/client.go index 59c7b9658..673081299 100644 --- a/api/client/service/client.go +++ b/api/client/service/client.go @@ -3,7 +3,6 @@ package client import ( "context" "fmt" - "log" "time" "github.com/ethereum/go-ethereum/common" @@ -20,18 +19,17 @@ type Client struct { } // NewClient setups a Client given ip and port. -func NewClient(ip, port string) *Client { +func NewClient(ip, port string) (*Client, error) { client := Client{} client.opts = append(client.opts, grpc.WithInsecure()) var err error client.conn, err = grpc.Dial(fmt.Sprintf("%s:%s", ip, port), client.opts...) if err != nil { - log.Fatalf("fail to dial: %v", err) - return nil + return nil, err } client.clientServiceClient = proto.NewClientServiceClient(client.conn) - return &client + return &client, nil } // Close closes the Client. @@ -40,37 +38,25 @@ func (client *Client) Close() { } // GetBalance gets account balance from the client service. -func (client *Client) GetBalance(address common.Address) *proto.FetchAccountStateResponse { +func (client *Client) GetBalance(address common.Address) (*proto.FetchAccountStateResponse, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() request := &proto.FetchAccountStateRequest{Address: address.Bytes()} - response, err := client.clientServiceClient.FetchAccountState(ctx, request) - if err != nil { - log.Fatalf("Error getting balance: %s", err) - } - return response + return client.clientServiceClient.FetchAccountState(ctx, request) } // GetFreeToken requests free token from the faucet contract. -func (client *Client) GetFreeToken(address common.Address) *proto.GetFreeTokenResponse { +func (client *Client) GetFreeToken(address common.Address) (*proto.GetFreeTokenResponse, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() request := &proto.GetFreeTokenRequest{Address: address.Bytes()} - response, err := client.clientServiceClient.GetFreeToken(ctx, request) - if err != nil { - log.Fatalf("Error getting free token: %s", err) - } - return response + return client.clientServiceClient.GetFreeToken(ctx, request) } // GetStakingContractInfo gets necessary info for staking. -func (client *Client) GetStakingContractInfo(address common.Address) *proto.StakingContractInfoResponse { +func (client *Client) GetStakingContractInfo(address common.Address) (*proto.StakingContractInfoResponse, error) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() request := &proto.StakingContractInfoRequest{Address: address.Bytes()} - response, err := client.clientServiceClient.GetStakingContractInfo(ctx, request) - if err != nil { - log.Fatalf("Error getting free token: %s", err) - } - return response + return client.clientServiceClient.GetStakingContractInfo(ctx, request) } diff --git a/cmd/client/wallet/main.go b/cmd/client/wallet/main.go index 625511a59..e28ae4853 100644 --- a/cmd/client/wallet/main.go +++ b/cmd/client/wallet/main.go @@ -2,7 +2,7 @@ package main import ( "crypto/ecdsa" - "crypto/rand" + cRand "crypto/rand" "encoding/base64" "encoding/hex" "flag" @@ -10,6 +10,7 @@ import ( "io" "io/ioutil" "math/big" + "math/rand" "os" "path" "strconv" @@ -20,10 +21,15 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/harmony-one/harmony/api/client" clientService "github.com/harmony-one/harmony/api/client/service" "github.com/harmony-one/harmony/core/types" + nodeconfig "github.com/harmony-one/harmony/internal/configs/node" + "github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/internal/wallet/wallet" "github.com/harmony-one/harmony/node" + "github.com/harmony-one/harmony/p2p" + "github.com/harmony-one/harmony/p2p/p2pimpl" ) var ( @@ -44,6 +50,10 @@ type AccountState struct { nonce uint64 } +const ( + rpcRetry = 3 +) + var ( // Account subcommands accountImportCommand = flag.NewFlagSet("import", flag.ExitOnError) @@ -54,7 +64,7 @@ var ( transferSenderPtr = transferCommand.String("from", "0", "Specify the sender account address or index") transferReceiverPtr = transferCommand.String("to", "", "Specify the receiver account") transferAmountPtr = transferCommand.Float64("amount", 0, "Specify the amount to transfer") - transferShardIDPtr = transferCommand.Int("shardID", -1, "Specify the shard ID for the transfer") + transferShardIDPtr = transferCommand.Int("shardID", 0, "Specify the shard ID for the transfer") transferInputDataPtr = transferCommand.String("inputData", "", "Base64-encoded input data to embed in the transaction") freeTokenCommand = flag.NewFlagSet("getFreeToken", flag.ExitOnError) @@ -67,20 +77,38 @@ var ( stopChan = make(chan struct{}) // Print out progress char tick = time.NewTicker(time.Second) - // Flag to keep waiting for async call finished + // Flag to wait for async command: transfer async = true ) +var ( + // list of bootnodes + addrStrings = []string{"/ip4/100.26.90.187/tcp/9876/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9", "/ip4/54.213.43.194/tcp/9876/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX"} + + // list of rpc servers + rpcServers = []struct { + IP string + Port string + }{ + {"18.236.96.207", "14555"}, + {"18.206.91.170", "14555"}, + {"54.213.63.26", "14555"}, + {"13.229.96.10", "14555"}, + {"34.243.2.56", "14555"}, + } +) + // setupLog setup log for verbose output func setupLog() { // enable logging for wallet - h := log.StreamHandler(os.Stdout, log.TerminalFormat(false)) + h := log.StreamHandler(os.Stdout, log.TerminalFormat(true)) log.Root().SetHandler(h) } // The main wallet program entrance. Note the this wallet program is for demo-purpose only. It does not implement // the secure storage of keys. func main() { + rand.Seed(int64(time.Now().Nanosecond())) // Verify that a subcommand has been provided // os.Arg[0] is the main command @@ -118,18 +146,20 @@ func main() { case "-version": printVersion(os.Args[0]) case "new": - go processNewCommnad() + processNewCommnad() case "list": - go processListCommand() + processListCommand() case "removeAll": - go clearKeystore() - fmt.Println("All existing accounts deleted...") + clearKeystore() case "import": - go processImportCommnad() + processImportCommnad() case "balances": - go processBalancesCommand() + processBalancesCommand() case "getFreeToken": - go processGetFreeToken() + processGetFreeToken() + } + + switch os.Args[1] { case "transfer": go processTransferCommand() default: @@ -150,14 +180,39 @@ func main() { } } +// createWalletNode creates wallet server node. +func createWalletNode() *node.Node { + bootNodeAddrs, err := utils.StringsToAddrs(addrStrings) + if err != nil { + panic(err) + } + utils.BootNodes = bootNodeAddrs + + shardIDs := []uint32{0} + + // dummy host for wallet + self := p2p.Peer{IP: "127.0.0.1", Port: "6999"} + priKey, _, _ := utils.GenKeyP2P("127.0.0.1", "6999") + host, err := p2pimpl.NewHost(&self, priKey) + if err != nil { + panic(err) + } + w := node.New(host, nil, nil) + w.Client = client.NewClient(w.GetHost(), shardIDs) + + w.NodeConfig.SetRole(nodeconfig.ClientNode) + w.ServiceManagerSetup() + w.RunServices() + return w +} + func processNewCommnad() { randomBytes := [32]byte{} - _, err := io.ReadFull(rand.Reader, randomBytes[:]) + _, err := io.ReadFull(cRand.Reader, randomBytes[:]) if err != nil { fmt.Println("Failed to get randomness for the private key...") - async = false - return + os.Exit(0) } priKey, err := crypto2.GenerateKey() if err != nil { @@ -166,7 +221,7 @@ func processNewCommnad() { storePrivateKey(crypto2.FromECDSA(priKey)) fmt.Printf("New account created with address:{%s}\n", crypto2.PubkeyToAddress(priKey.PublicKey).Hex()) fmt.Printf("Please keep a copy of the private key:{%s}\n", hex.EncodeToString(crypto2.FromECDSA(priKey))) - async = false + os.Exit(0) } func processListCommand() { @@ -174,7 +229,7 @@ func processListCommand() { fmt.Printf("Account %d:{%s}\n", i, crypto2.PubkeyToAddress(key.PublicKey).Hex()) fmt.Printf(" PrivateKey:{%s}\n", hex.EncodeToString(key.D.Bytes())) } - async = false + os.Exit(0) } func processImportCommnad() { @@ -182,8 +237,7 @@ func processImportCommnad() { priKey := *accountImportPtr if priKey == "" { fmt.Println("Error: --privateKey is required") - async = false - return + os.Exit(0) } if !accountImportCommand.Parsed() { fmt.Println("Failed to parse flags") @@ -194,44 +248,39 @@ func processImportCommnad() { } storePrivateKey(priKeyBytes) fmt.Println("Private key imported...") - async = false + os.Exit(0) } func processBalancesCommand() { balanceCommand.Parse(os.Args[2:]) - walletNode := wallet.CreateWalletNode() if *balanceAddressPtr == "" { for i, address := range ReadAddresses() { fmt.Printf("Account %d: %s:\n", i, address.Hex()) - for shardID, balanceNonce := range FetchBalance(address, walletNode) { + for shardID, balanceNonce := range FetchBalance(address) { fmt.Printf(" Balance in Shard %d: %s, nonce: %v \n", shardID, convertBalanceIntoReadableFormat(balanceNonce.balance), balanceNonce.nonce) } } } else { address := common.HexToAddress(*balanceAddressPtr) fmt.Printf("Account: %s:\n", address.Hex()) - for shardID, balanceNonce := range FetchBalance(address, walletNode) { + for shardID, balanceNonce := range FetchBalance(address) { fmt.Printf(" Balance in Shard %d: %s, nonce: %v \n", shardID, convertBalanceIntoReadableFormat(balanceNonce.balance), balanceNonce.nonce) } } - async = false + os.Exit(0) } func processGetFreeToken() { freeTokenCommand.Parse(os.Args[2:]) - walletNode := wallet.CreateWalletNode() if *freeTokenAddressPtr == "" { fmt.Println("Error: --address is required") - async = false - return + } else { + address := common.HexToAddress(*freeTokenAddressPtr) + GetFreeToken(address) } - address := common.HexToAddress(*freeTokenAddressPtr) - - GetFreeToken(address, walletNode) - - async = false + os.Exit(0) } func processTransferCommand() { @@ -302,8 +351,10 @@ func processTransferCommand() { // Generate transaction senderPriKey := priKeys[senderIndex] senderAddress := addresses[senderIndex] - walletNode := wallet.CreateWalletNode() - shardIDToAccountState := FetchBalance(senderAddress, walletNode) + + walletNode := createWalletNode() + + shardIDToAccountState := FetchBalance(senderAddress) state, ok := shardIDToAccountState[uint32(shardID)] if !ok { @@ -367,38 +418,53 @@ func convertBalanceIntoReadableFormat(balance *big.Int) string { // FetchBalance fetches account balance of specified address from the Harmony network // TODO add support for non beacon chain shards -func FetchBalance(address common.Address, walletNode *node.Node) map[uint32]AccountState { +func FetchBalance(address common.Address) map[uint32]AccountState { result := make(map[uint32]AccountState) - peers := wallet.GetPeersFromBeaconChain(walletNode) - if len(peers) == 0 { - fmt.Printf("[FATAL] Can't find peers\n") - return nil - } - peer := peers[0] - port, _ := strconv.Atoi(peer.Port) - client := clientService.NewClient(peer.IP, strconv.Itoa(port+node.ClientServicePortDiff)) - response := client.GetBalance(address) balance := big.NewInt(0) - balance.SetBytes(response.Balance) - result[0] = AccountState{balance, response.Nonce} + result[0] = AccountState{balance, 0} + + for retry := 0; retry < rpcRetry; retry++ { + server := rpcServers[rand.Intn(len(rpcServers))] + client, err := clientService.NewClient(server.IP, server.Port) + if err != nil { + continue + } + + log.Debug("FetchBalance", "server", server) + response, err := client.GetBalance(address) + if err != nil { + log.Info("failed to get balance, retrying ...") + continue + } + log.Debug("FetchBalance", "response", response) + balance.SetBytes(response.Balance) + result[0] = AccountState{balance, response.Nonce} + break + } return result } // GetFreeToken requests for token test token on each shard -func GetFreeToken(address common.Address, walletNode *node.Node) { - peers := wallet.GetPeersFromBeaconChain(walletNode) - if len(peers) == 0 { - fmt.Printf("[FATAL] Can't find peers\n") - return - } - peer := peers[0] - port, _ := strconv.Atoi(peer.Port) - client := clientService.NewClient(peer.IP, strconv.Itoa(port+node.ClientServicePortDiff)) - response := client.GetFreeToken(address) +func GetFreeToken(address common.Address) { + for retry := 0; retry < rpcRetry; retry++ { + server := rpcServers[0] + client, err := clientService.NewClient(server.IP, server.Port) + if err != nil { + continue + } - txID := common.Hash{} - txID.SetBytes(response.TxId) - fmt.Printf("Transaction Id requesting free token in shard %d: %s\n", int(0), txID.Hex()) + log.Debug("GetFreeToken", "server", server) + response, err := client.GetFreeToken(address) + if err != nil { + log.Info("failed to get free token, retrying ...") + continue + } + log.Debug("GetFreeToken", "response", response) + txID := common.Hash{} + txID.SetBytes(response.TxId) + fmt.Printf("Transaction Id requesting free token in shard %d: %s\n", int(0), txID.Hex()) + break + } } // ReadAddresses reads the addresses stored in local keystore @@ -439,6 +505,8 @@ func storePrivateKey(priKey []byte) { // clearKeystore deletes all data in the local keystore func clearKeystore() { ioutil.WriteFile("keystore", []byte{}, 0644) + fmt.Println("All existing accounts deleted...") + os.Exit(0) } // readPrivateKeys reads all the private key stored in local keystore From 7f04ddb9179a2faa8353e78f16679f8c23bbd100 Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Thu, 21 Mar 2019 07:13:24 +0000 Subject: [PATCH 2/4] [wallet] return to sync mode Signed-off-by: Leo Chen --- cmd/client/wallet/main.go | 31 ++----------------------------- internal/wallet/wallet/lib.go | 5 +---- 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/cmd/client/wallet/main.go b/cmd/client/wallet/main.go index e28ae4853..0877ce851 100644 --- a/cmd/client/wallet/main.go +++ b/cmd/client/wallet/main.go @@ -72,13 +72,6 @@ var ( balanceCommand = flag.NewFlagSet("getFreeToken", flag.ExitOnError) balanceAddressPtr = balanceCommand.String("address", "", "Specify the account address to check balance for") - - // Quit the program once stopChan received message - stopChan = make(chan struct{}) - // Print out progress char - tick = time.NewTicker(time.Second) - // Flag to wait for async command: transfer - async = true ) var ( @@ -161,23 +154,12 @@ func main() { switch os.Args[1] { case "transfer": - go processTransferCommand() + processTransferCommand() default: fmt.Printf("Unknown action: %s\n", os.Args[1]) flag.PrintDefaults() os.Exit(1) } - - // Waiting for async call finished and print out some progress - for async { - select { - case <-tick.C: - fmt.Printf("=") - case <-stopChan: - fmt.Println("Done.") - os.Exit(0) - } - } } // createWalletNode creates wallet server node. @@ -298,24 +280,20 @@ func processTransferCommand() { if err != nil { fmt.Printf("Cannot base64-decode input data (%s): %s\n", base64InputData, err) - async = false return } if shardID == -1 { fmt.Println("Please specify the shard ID for the transfer (e.g. --shardID=0)") - async = false return } if amount <= 0 { fmt.Println("Please specify positive amount to transfer") - async = false return } priKeys := readPrivateKeys() if len(priKeys) == 0 { fmt.Println("No imported account to use.") - async = false return } senderIndex, err := strconv.Atoi(sender) @@ -330,21 +308,18 @@ func processTransferCommand() { } if senderIndex == -1 { fmt.Println("The specified sender account does not exist in the wallet.") - async = false return } } if senderIndex >= len(priKeys) { fmt.Println("Sender account index out of bounds.") - async = false return } receiverAddress := common.HexToAddress(receiver) if len(receiverAddress) != 20 { fmt.Println("The receiver address is not valid.") - async = false return } @@ -359,21 +334,19 @@ func processTransferCommand() { state, ok := shardIDToAccountState[uint32(shardID)] if !ok { fmt.Printf("Failed connecting to the shard %d\n", shardID) - async = false return } balance := state.balance balance = balance.Div(balance, big.NewInt(params.GWei)) if amount > float64(balance.Uint64())/params.GWei { fmt.Printf("Balance is not enough for the transfer, current balance is %.6f\n", float64(balance.Uint64())/params.GWei) - async = false return } amountBigInt := big.NewInt(int64(amount * params.GWei)) amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(params.GWei)) tx, _ := types.SignTx(types.NewTransaction(state.nonce, receiverAddress, uint32(shardID), amountBigInt, params.TxGas, nil, inputData), types.HomesteadSigner{}, senderPriKey) - wallet.SubmitTransaction(tx, walletNode, uint32(shardID), stopChan) + wallet.SubmitTransaction(tx, walletNode, uint32(shardID)) } func convertBalanceIntoReadableFormat(balance *big.Int) string { diff --git a/internal/wallet/wallet/lib.go b/internal/wallet/wallet/lib.go index 3938ecae0..9e1655c3a 100644 --- a/internal/wallet/wallet/lib.go +++ b/internal/wallet/wallet/lib.go @@ -57,7 +57,7 @@ func GetPeersFromBeaconChain(walletNode *node.Node) []p2p.Peer { } // SubmitTransaction submits the transaction to the Harmony network -func SubmitTransaction(tx *types.Transaction, walletNode *node.Node, shardID uint32, stopChan chan struct{}) error { +func SubmitTransaction(tx *types.Transaction, walletNode *node.Node, shardID uint32) error { msg := proto_node.ConstructTransactionListMessageAccount(types.Transactions{tx}) err := walletNode.GetHost().SendMessageToGroups([]p2p.GroupID{p2p.GroupIDBeaconClient}, p2p_host.ConstructP2pMessage(byte(0), msg)) if err != nil { @@ -68,9 +68,6 @@ func SubmitTransaction(tx *types.Transaction, walletNode *node.Node, shardID uin // FIXME (leo): how to we know the tx was successful sent to the network // this is a hacky way to wait for sometime time.Sleep(2 * time.Second) - if stopChan != nil { - stopChan <- struct{}{} - } return nil } From 9d629855a0f4d7fdeda501bdf3c5cea0720aaf35 Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Thu, 21 Mar 2019 07:23:27 +0000 Subject: [PATCH 3/4] [cleanup] remove unused wallet library Signed-off-by: Leo Chen --- cmd/client/wallet/main.go | 20 +++++++- internal/wallet/wallet/lib.go | 82 ------------------------------ internal/wallet/wallet/lib_test.go | 47 ----------------- 3 files changed, 18 insertions(+), 131 deletions(-) delete mode 100644 internal/wallet/wallet/lib.go delete mode 100644 internal/wallet/wallet/lib_test.go diff --git a/cmd/client/wallet/main.go b/cmd/client/wallet/main.go index 0877ce851..961a1290b 100644 --- a/cmd/client/wallet/main.go +++ b/cmd/client/wallet/main.go @@ -23,12 +23,13 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/harmony-one/harmony/api/client" clientService "github.com/harmony-one/harmony/api/client/service" + proto_node "github.com/harmony-one/harmony/api/proto/node" "github.com/harmony-one/harmony/core/types" nodeconfig "github.com/harmony-one/harmony/internal/configs/node" "github.com/harmony-one/harmony/internal/utils" - "github.com/harmony-one/harmony/internal/wallet/wallet" "github.com/harmony-one/harmony/node" "github.com/harmony-one/harmony/p2p" + p2p_host "github.com/harmony-one/harmony/p2p/host" "github.com/harmony-one/harmony/p2p/p2pimpl" ) @@ -346,7 +347,7 @@ func processTransferCommand() { amountBigInt := big.NewInt(int64(amount * params.GWei)) amountBigInt = amountBigInt.Mul(amountBigInt, big.NewInt(params.GWei)) tx, _ := types.SignTx(types.NewTransaction(state.nonce, receiverAddress, uint32(shardID), amountBigInt, params.TxGas, nil, inputData), types.HomesteadSigner{}, senderPriKey) - wallet.SubmitTransaction(tx, walletNode, uint32(shardID)) + submitTransaction(tx, walletNode, uint32(shardID)) } func convertBalanceIntoReadableFormat(balance *big.Int) string { @@ -499,3 +500,18 @@ func readPrivateKeys() []*ecdsa.PrivateKey { } return priKeys } + +// submitTransaction submits the transaction to the Harmony network +func submitTransaction(tx *types.Transaction, walletNode *node.Node, shardID uint32) error { + msg := proto_node.ConstructTransactionListMessageAccount(types.Transactions{tx}) + err := walletNode.GetHost().SendMessageToGroups([]p2p.GroupID{p2p.GroupIDBeaconClient}, p2p_host.ConstructP2pMessage(byte(0), msg)) + if err != nil { + fmt.Printf("Error in SubmitTransaction: %v\n", err) + return err + } + fmt.Printf("Transaction Id for shard %d: %s\n", int(shardID), tx.Hash().Hex()) + // FIXME (leo): how to we know the tx was successful sent to the network + // this is a hacky way to wait for sometime + time.Sleep(2 * time.Second) + return nil +} diff --git a/internal/wallet/wallet/lib.go b/internal/wallet/wallet/lib.go deleted file mode 100644 index 9e1655c3a..000000000 --- a/internal/wallet/wallet/lib.go +++ /dev/null @@ -1,82 +0,0 @@ -package wallet - -import ( - "fmt" - "time" - - "github.com/harmony-one/harmony/api/client" - proto_node "github.com/harmony-one/harmony/api/proto/node" - "github.com/harmony-one/harmony/core/types" - nodeconfig "github.com/harmony-one/harmony/internal/configs/node" - "github.com/harmony-one/harmony/internal/utils" - "github.com/harmony-one/harmony/node" - "github.com/harmony-one/harmony/p2p" - p2p_host "github.com/harmony-one/harmony/p2p/host" - "github.com/harmony-one/harmony/p2p/p2pimpl" - ma "github.com/multiformats/go-multiaddr" -) - -// CreateWalletNode creates wallet server node. -func CreateWalletNode() *node.Node { - utils.BootNodes = getBootNodes() - shardIDs := []uint32{0} - - // dummy host for wallet - self := p2p.Peer{IP: "127.0.0.1", Port: "6999"} - priKey, _, _ := utils.GenKeyP2P("127.0.0.1", "6999") - host, err := p2pimpl.NewHost(&self, priKey) - if err != nil { - panic(err) - } - walletNode := node.New(host, nil, nil) - walletNode.Client = client.NewClient(walletNode.GetHost(), shardIDs) - - walletNode.NodeConfig.SetRole(nodeconfig.ClientNode) - walletNode.ServiceManagerSetup() - walletNode.RunServices() - // wait for networkinfo/discovery service to start fully - // FIXME (leo): use async mode or channel to communicate - time.Sleep(2 * time.Second) - return walletNode -} - -// GetPeersFromBeaconChain get peers from beacon chain -// TODO: add support for normal shards -func GetPeersFromBeaconChain(walletNode *node.Node) []p2p.Peer { - peers := []p2p.Peer{} - - // wait until we got beacon peer - // FIXME (chao): use async channel for communiation - time.Sleep(4 * time.Second) - walletNode.BeaconNeighbors.Range(func(k, v interface{}) bool { - peers = append(peers, v.(p2p.Peer)) - return true - }) - utils.GetLogInstance().Debug("GetPeersFromBeaconChain", "peers:", peers) - return peers -} - -// SubmitTransaction submits the transaction to the Harmony network -func SubmitTransaction(tx *types.Transaction, walletNode *node.Node, shardID uint32) error { - msg := proto_node.ConstructTransactionListMessageAccount(types.Transactions{tx}) - err := walletNode.GetHost().SendMessageToGroups([]p2p.GroupID{p2p.GroupIDBeaconClient}, p2p_host.ConstructP2pMessage(byte(0), msg)) - if err != nil { - fmt.Printf("Error in SubmitTransaction: %v\n", err) - return err - } - fmt.Printf("Transaction Id for shard %d: %s\n", int(shardID), tx.Hash().Hex()) - // FIXME (leo): how to we know the tx was successful sent to the network - // this is a hacky way to wait for sometime - time.Sleep(2 * time.Second) - return nil -} - -func getBootNodes() []ma.Multiaddr { - // These are the bootnodes of banjo testnet - addrStrings := []string{"/ip4/100.26.90.187/tcp/9876/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9", "/ip4/54.213.43.194/tcp/9876/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX"} - bootNodeAddrs, err := utils.StringsToAddrs(addrStrings) - if err != nil { - panic(err) - } - return bootNodeAddrs -} diff --git a/internal/wallet/wallet/lib_test.go b/internal/wallet/wallet/lib_test.go deleted file mode 100644 index 923b9da24..000000000 --- a/internal/wallet/wallet/lib_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package wallet - -import ( - "testing" - "time" - - "github.com/golang/mock/gomock" - "github.com/harmony-one/harmony/api/client" - proto_node "github.com/harmony-one/harmony/api/proto/node" - "github.com/harmony-one/harmony/api/service/networkinfo" - "github.com/harmony-one/harmony/core/types" - "github.com/harmony-one/harmony/node" - "github.com/harmony-one/harmony/p2p" - p2p_host "github.com/harmony-one/harmony/p2p/host" - mock_host "github.com/harmony-one/harmony/p2p/host/mock" -) - -func TestCreateWalletNode(test *testing.T) { - // shorten the retry time - networkinfo.ConnectionRetry = 3 - - walletNode := CreateWalletNode() - - if walletNode.Client == nil { - test.Errorf("Wallet node's client is not initialized") - } -} - -func TestSubmitTransaction(test *testing.T) { - ctrl := gomock.NewController(test) - defer ctrl.Finish() - - m := mock_host.NewMockHost(ctrl) - - m.EXPECT().GetSelfPeer().AnyTimes() - - walletNode := node.New(m, nil, nil) - walletNode.Client = client.NewClient(walletNode.GetHost(), []uint32{0}) - - tx := &types.Transaction{} - msg := proto_node.ConstructTransactionListMessageAccount(types.Transactions{tx}) - m.EXPECT().SendMessageToGroups([]p2p.GroupID{p2p.GroupIDBeaconClient}, p2p_host.ConstructP2pMessage(byte(0), msg)) - - SubmitTransaction(tx, walletNode, 0, nil) - - time.Sleep(1 * time.Second) -} From da1967dca1b7168e3396280ae31dba20c1a7c25b Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Thu, 21 Mar 2019 17:41:46 +0000 Subject: [PATCH 4/4] [wallet] clean up on excessive os.Exit call Signed-off-by: Leo Chen --- cmd/client/wallet/main.go | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/cmd/client/wallet/main.go b/cmd/client/wallet/main.go index 961a1290b..c6928e547 100644 --- a/cmd/client/wallet/main.go +++ b/cmd/client/wallet/main.go @@ -80,6 +80,8 @@ var ( addrStrings = []string{"/ip4/100.26.90.187/tcp/9876/p2p/QmZJJx6AdaoEkGLrYG4JeLCKeCKDjnFz2wfHNHxAqFSGA9", "/ip4/54.213.43.194/tcp/9876/p2p/QmQayinFSgMMw5cSpDUiD9pQ2WeP6WNmGxpZ6ou3mdVFJX"} // list of rpc servers + // TODO; (leo) take build time parameters or environment parameters to add rpcServers + // Then this can be automated rpcServers = []struct { IP string Port string @@ -151,9 +153,6 @@ func main() { processBalancesCommand() case "getFreeToken": processGetFreeToken() - } - - switch os.Args[1] { case "transfer": processTransferCommand() default: @@ -174,6 +173,8 @@ func createWalletNode() *node.Node { shardIDs := []uint32{0} // dummy host for wallet + // TODO: potentially, too many dummy IP may flush out good IP address from our bootnode DHT + // we need to understand the impact to bootnode DHT with this dummy host ip added self := p2p.Peer{IP: "127.0.0.1", Port: "6999"} priKey, _, _ := utils.GenKeyP2P("127.0.0.1", "6999") host, err := p2pimpl.NewHost(&self, priKey) @@ -195,7 +196,7 @@ func processNewCommnad() { if err != nil { fmt.Println("Failed to get randomness for the private key...") - os.Exit(0) + return } priKey, err := crypto2.GenerateKey() if err != nil { @@ -204,7 +205,6 @@ func processNewCommnad() { storePrivateKey(crypto2.FromECDSA(priKey)) fmt.Printf("New account created with address:{%s}\n", crypto2.PubkeyToAddress(priKey.PublicKey).Hex()) fmt.Printf("Please keep a copy of the private key:{%s}\n", hex.EncodeToString(crypto2.FromECDSA(priKey))) - os.Exit(0) } func processListCommand() { @@ -212,7 +212,6 @@ func processListCommand() { fmt.Printf("Account %d:{%s}\n", i, crypto2.PubkeyToAddress(key.PublicKey).Hex()) fmt.Printf(" PrivateKey:{%s}\n", hex.EncodeToString(key.D.Bytes())) } - os.Exit(0) } func processImportCommnad() { @@ -220,7 +219,7 @@ func processImportCommnad() { priKey := *accountImportPtr if priKey == "" { fmt.Println("Error: --privateKey is required") - os.Exit(0) + return } if !accountImportCommand.Parsed() { fmt.Println("Failed to parse flags") @@ -231,7 +230,6 @@ func processImportCommnad() { } storePrivateKey(priKeyBytes) fmt.Println("Private key imported...") - os.Exit(0) } func processBalancesCommand() { @@ -251,7 +249,6 @@ func processBalancesCommand() { fmt.Printf(" Balance in Shard %d: %s, nonce: %v \n", shardID, convertBalanceIntoReadableFormat(balanceNonce.balance), balanceNonce.nonce) } } - os.Exit(0) } func processGetFreeToken() { @@ -263,13 +260,13 @@ func processGetFreeToken() { address := common.HexToAddress(*freeTokenAddressPtr) GetFreeToken(address) } - os.Exit(0) } func processTransferCommand() { transferCommand.Parse(os.Args[2:]) if !transferCommand.Parsed() { fmt.Println("Failed to parse flags") + return } sender := *transferSenderPtr receiver := *transferReceiverPtr @@ -391,7 +388,7 @@ func convertBalanceIntoReadableFormat(balance *big.Int) string { } // FetchBalance fetches account balance of specified address from the Harmony network -// TODO add support for non beacon chain shards +// TODO: (chao) add support for non beacon chain shards func FetchBalance(address common.Address) map[uint32]AccountState { result := make(map[uint32]AccountState) balance := big.NewInt(0) @@ -480,7 +477,6 @@ func storePrivateKey(priKey []byte) { func clearKeystore() { ioutil.WriteFile("keystore", []byte{}, 0644) fmt.Println("All existing accounts deleted...") - os.Exit(0) } // readPrivateKeys reads all the private key stored in local keystore