@ -28,42 +28,27 @@ import (
func main ( ) {
func main ( ) {
// Account subcommands
// Account subcommands
accountImportCommand := flag . NewFlagSet ( "import" , flag . ExitOnError )
accountImportCommand := flag . NewFlagSet ( "import" , flag . ExitOnError )
transferCommand := flag . NewFlagSet ( "transfer" , flag . ExitOnError )
//accountListCommand := flag.NewFlagSet("list", flag.ExitOnError)
//
//// Transaction subcommands
//transactionNewCommand := flag.NewFlagSet("new", flag.ExitOnError)
//
//// Account subcommand flag pointers
//// Adding a new choice for --metric of 'substring' and a new --substring flag
accountImportPtr := accountImportCommand . String ( "privateKey" , "" , "Specify the private key to import" )
accountImportPtr := accountImportCommand . String ( "privateKey" , "" , "Specify the private key to import" )
// Transfer subcommands
transferCommand := flag . NewFlagSet ( "transfer" , flag . ExitOnError )
transferSenderPtr := transferCommand . String ( "sender" , "0" , "Specify the sender account address or index" )
transferSenderPtr := transferCommand . String ( "sender" , "0" , "Specify the sender account address or index" )
transferReceiverPtr := transferCommand . String ( "receiver" , "" , "Specify the receiver account" )
transferReceiverPtr := transferCommand . String ( "receiver" , "" , "Specify the receiver account" )
transferAmountPtr := transferCommand . Int ( "amount" , 0 , "Specify the amount to transfer" )
transferAmountPtr := transferCommand . Int ( "amount" , 0 , "Specify the amount to transfer" )
//accountListPtr := accountNewCommand.Bool("new", false, "N/A")
//
//// Transaction subcommand flag pointers
//transactionNewPtr := transactionNewCommand.String("text", "", "Text to parse. (Required)")
// Verify that a subcommand has been provided
// Verify that a subcommand has been provided
// os.Arg[0] is the main command
// os.Arg[0] is the main command
// os.Arg[1] will be the subcommand
// os.Arg[1] will be the subcommand
if len ( os . Args ) < 2 {
if len ( os . Args ) < 2 {
fmt . Println ( "account or transaction subcommand is required" )
fmt . Println ( "account or transfer subcommand is required" )
os . Exit ( 1 )
os . Exit ( 1 )
}
}
// Switch on the subcommand
// Switch on the subcommand
// Parse the flags for appropriate FlagSet
// FlagSet.Parse() requires a set of arguments to parse as input
// os.Args[2:] will be all arguments starting after the subcommand at os.Args[1]
switch os . Args [ 1 ] {
switch os . Args [ 1 ] {
case "account" :
case "account" :
switch os . Args [ 2 ] {
switch os . Args [ 2 ] {
case "new" :
case "new" :
fmt . Println ( "Creating new account..." )
randomBytes := [ 32 ] byte { }
randomBytes := [ 32 ] byte { }
_ , err := io . ReadFull ( rand . Reader , randomBytes [ : ] )
_ , err := io . ReadFull ( rand . Reader , randomBytes [ : ] )
@ -74,7 +59,7 @@ func main() {
priKey := crypto . Ed25519Curve . Scalar ( ) . SetBytes ( randomBytes [ : ] )
priKey := crypto . Ed25519Curve . Scalar ( ) . SetBytes ( randomBytes [ : ] )
priKeyBytes , err := priKey . MarshalBinary ( )
priKeyBytes , err := priKey . MarshalBinary ( )
if err != nil {
if err != nil {
panic ( "Failed to generat e private key" )
panic ( "Failed to serialize th e private key" )
}
}
pubKey := pki . GetPublicKeyFromScalar ( priKey )
pubKey := pki . GetPublicKeyFromScalar ( priKey )
address := pki . GetAddressFromPublicKey ( pubKey )
address := pki . GetAddressFromPublicKey ( pubKey )
@ -82,13 +67,12 @@ func main() {
fmt . Printf ( "New account created:\nAddress: {%x}\n" , address )
fmt . Printf ( "New account created:\nAddress: {%x}\n" , address )
case "list" :
case "list" :
for i , address := range ReadAddresses ( ) {
for i , address := range ReadAddresses ( ) {
fmt . Printf ( "Account %d:\n {%x}\n" , i + 1 , address )
fmt . Printf ( "Account %d:\n {%x}\n" , i + 1 , address )
}
}
case "clearAll" :
case "clearAll" :
fmt . Println ( "Deleting existing accounts..." )
ClearKeystore ( )
DeletePrivateKey ( )
fmt . Println ( "All existing accounts deleted..." )
case "import" :
case "import" :
fmt . Println ( "Importing private key..." )
accountImportCommand . Parse ( os . Args [ 3 : ] )
accountImportCommand . Parse ( os . Args [ 3 : ] )
priKey := * accountImportPtr
priKey := * accountImportPtr
if ! accountImportCommand . Parsed ( ) {
if ! accountImportCommand . Parsed ( ) {
@ -99,15 +83,10 @@ func main() {
panic ( "Failed to parse the private key into bytes" )
panic ( "Failed to parse the private key into bytes" )
}
}
StorePrivateKey ( priKeyBytes )
StorePrivateKey ( priKeyBytes )
fmt . Println ( "Private key imported..." )
case "showBalance" :
case "showBalance" :
configr := client_config . NewConfig ( )
walletNode := CreateWalletServerNode ( )
configr . ReadConfigFile ( "local_config_shards.txt" )
go walletNode . StartServer ( walletNode . ClientPeer . Port )
leaders , _ := configr . GetLeadersAndShardIds ( )
clientPeer := configr . GetClientPeer ( )
walletNode := node . New ( nil , nil )
walletNode . Client = client . NewClient ( & leaders )
walletNode . ClientPeer = clientPeer
go walletNode . StartServer ( clientPeer . Port )
shardUtxoMap , err := FetchUtxos ( ReadAddresses ( ) , walletNode )
shardUtxoMap , err := FetchUtxos ( ReadAddresses ( ) , walletNode )
if err != nil {
if err != nil {
@ -115,6 +94,7 @@ func main() {
}
}
PrintUtxoBalance ( shardUtxoMap )
PrintUtxoBalance ( shardUtxoMap )
case "test" :
case "test" :
// Testing code
priKey := pki . GetPrivateKeyScalarFromInt ( 444 )
priKey := pki . GetPrivateKeyScalarFromInt ( 444 )
address := pki . GetAddressFromPrivateKey ( priKey )
address := pki . GetAddressFromPrivateKey ( priKey )
priKeyBytes , err := priKey . MarshalBinary ( )
priKeyBytes , err := priKey . MarshalBinary ( )
@ -138,7 +118,7 @@ func main() {
}
}
priKeys := ReadPrivateKeys ( )
priKeys := ReadPrivateKeys ( )
if len ( priKeys ) == 0 {
if len ( priKeys ) == 0 {
fmt . Println ( "No existing account to send money from ." )
fmt . Println ( "No imported account to use ." )
return
return
}
}
senderIndex , err := strconv . Atoi ( sender )
senderIndex , err := strconv . Atoi ( sender )
@ -153,7 +133,7 @@ func main() {
}
}
}
}
if senderIndex == - 1 {
if senderIndex == - 1 {
fmt . Println ( "S pecified sender account is not imported yet." )
fmt . Println ( "The s pecified sender account is not imported yet." )
break
break
}
}
}
}
@ -163,7 +143,7 @@ func main() {
}
}
receiverAddress , err := hex . DecodeString ( receiver )
receiverAddress , err := hex . DecodeString ( receiver )
if err != nil || len ( receiverAddress ) != 20 {
if err != nil || len ( receiverAddress ) != 20 {
fmt . Println ( "The receiver address is not a valid address ." )
fmt . Println ( "The receiver address is not a valid." )
return
return
}
}
@ -175,14 +155,8 @@ func main() {
senderAddressBytes := pki . GetAddressFromPrivateKey ( senderPriKey )
senderAddressBytes := pki . GetAddressFromPrivateKey ( senderPriKey )
// Start client server
// Start client server
configr := client_config . NewConfig ( )
walletNode := CreateWalletServerNode ( )
configr . ReadConfigFile ( "local_config_shards.txt" )
go walletNode . StartServer ( walletNode . ClientPeer . Port )
leaders , _ := configr . GetLeadersAndShardIds ( )
clientPeer := configr . GetClientPeer ( )
walletNode := node . New ( nil , nil )
walletNode . Client = client . NewClient ( & leaders )
walletNode . ClientPeer = clientPeer
go walletNode . StartServer ( clientPeer . Port )
shardUtxoMap , err := FetchUtxos ( [ ] [ 20 ] byte { senderAddressBytes } , walletNode )
shardUtxoMap , err := FetchUtxos ( [ ] [ 20 ] byte { senderAddressBytes } , walletNode )
if err != nil {
if err != nil {
@ -227,21 +201,37 @@ func main() {
fmt . Println ( "Failed to deserialize public key" , "error" , err )
fmt . Println ( "Failed to deserialize public key" , "error" , err )
}
}
ExecuteTransaction ( tx , walletNode )
err = ExecuteTransaction ( tx , walletNode )
if err != nil {
fmt . Println ( err )
} else {
fmt . Println ( "Transaction submitted successfully" )
}
default :
default :
flag . PrintDefaults ( )
flag . PrintDefaults ( )
os . Exit ( 1 )
os . Exit ( 1 )
}
}
}
}
func CreateWalletServerNode ( ) * node . Node {
configr := client_config . NewConfig ( )
configr . ReadConfigFile ( "local_config_shards.txt" )
leaders , _ := configr . GetLeadersAndShardIds ( )
clientPeer := configr . GetClientPeer ( )
walletNode := node . New ( nil , nil )
walletNode . Client = client . NewClient ( & leaders )
walletNode . ClientPeer = clientPeer
return walletNode
}
// Issue the transaction to the Harmony network
func ExecuteTransaction ( tx blockchain . Transaction , walletNode * node . Node ) error {
func ExecuteTransaction ( tx blockchain . Transaction , walletNode * node . Node ) error {
if tx . IsCrossShard ( ) {
if tx . IsCrossShard ( ) {
walletNode . Client . PendingCrossTxsMutex . Lock ( )
walletNode . Client . PendingCrossTxsMutex . Lock ( )
walletNode . Client . PendingCrossTxs [ tx . ID ] = & tx
walletNode . Client . PendingCrossTxs [ tx . ID ] = & tx
walletNode . Client . PendingCrossTxsMutex . Unlock ( )
walletNode . Client . PendingCrossTxsMutex . Unlock ( )
}
}
fmt . Println ( "Sending transaction..." )
msg := proto_node . ConstructTransactionListMessage ( [ ] * blockchain . Transaction { & tx } )
msg := proto_node . ConstructTransactionListMessage ( [ ] * blockchain . Transaction { & tx } )
p2p . BroadcastMessage ( * walletNode . Client . Leaders , msg )
p2p . BroadcastMessage ( * walletNode . Client . Leaders , msg )
@ -261,10 +251,11 @@ func ExecuteTransaction(tx blockchain.Transaction, walletNode *node.Node) error
time . Sleep ( 100 * time . Millisecond )
time . Sleep ( 100 * time . Millisecond )
return nil
return nil
case <- time . After ( 5 * time . Second ) :
case <- time . After ( 5 * time . Second ) :
return errors . New ( "Cross-shard tx timed out" )
return errors . New ( "Cross-shard Transaction processing timed out" )
}
}
}
}
// Fetch utxos of specified address from the Harmony network
func FetchUtxos ( addresses [ ] [ 20 ] byte , walletNode * node . Node ) ( map [ uint32 ] blockchain . UtxoMap , error ) {
func FetchUtxos ( addresses [ ] [ 20 ] byte , walletNode * node . Node ) ( map [ uint32 ] blockchain . UtxoMap , error ) {
fmt . Println ( "Fetching account balance..." )
fmt . Println ( "Fetching account balance..." )
walletNode . Client . ShardUtxoMap = make ( map [ uint32 ] blockchain . UtxoMap )
walletNode . Client . ShardUtxoMap = make ( map [ uint32 ] blockchain . UtxoMap )
@ -310,6 +301,7 @@ func PrintUtxoBalance(shardUtxoMap map[uint32]blockchain.UtxoMap) {
}
}
}
}
// Read the addresses stored in local keystore
func ReadAddresses ( ) [ ] [ 20 ] byte {
func ReadAddresses ( ) [ ] [ 20 ] byte {
priKeys := ReadPrivateKeys ( )
priKeys := ReadPrivateKeys ( )
addresses := [ ] [ 20 ] byte { }
addresses := [ ] [ 20 ] byte { }
@ -319,6 +311,7 @@ func ReadAddresses() [][20]byte {
return addresses
return addresses
}
}
// Store the specified private key in local keystore
func StorePrivateKey ( priKey [ ] byte ) {
func StorePrivateKey ( priKey [ ] byte ) {
for _ , address := range ReadAddresses ( ) {
for _ , address := range ReadAddresses ( ) {
if address == pki . GetAddressFromPrivateKey ( crypto . Ed25519Curve . Scalar ( ) . SetBytes ( priKey ) ) {
if address == pki . GetAddressFromPrivateKey ( crypto . Ed25519Curve . Scalar ( ) . SetBytes ( priKey ) ) {
@ -339,10 +332,12 @@ func StorePrivateKey(priKey []byte) {
f . Close ( )
f . Close ( )
}
}
func DeletePrivateKey ( ) {
// Delete all data in the local keystore
func ClearKeystore ( ) {
ioutil . WriteFile ( "keystore" , [ ] byte { } , 0644 )
ioutil . WriteFile ( "keystore" , [ ] byte { } , 0644 )
}
}
// Read all the private key stored in local keystore
func ReadPrivateKeys ( ) [ ] kyber . Scalar {
func ReadPrivateKeys ( ) [ ] kyber . Scalar {
keys , err := ioutil . ReadFile ( "keystore" )
keys , err := ioutil . ReadFile ( "keystore" )
if err != nil {
if err != nil {