diff --git a/src/gethdep.go b/src/gethdep.go index 056f33a13..d745a8ae9 100644 --- a/src/gethdep.go +++ b/src/gethdep.go @@ -3,9 +3,12 @@ package main import ( "errors" "fmt" + "io/ioutil" + "time" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/node" errextra "github.com/pkg/errors" @@ -23,17 +26,23 @@ func createAccount(password, keydir string) (string, string, error) { w := true accman := accounts.NewManager(keydir, scryptN, scryptP, sync) + // generate the account account, err := accman.NewAccount(password, w) if err != nil { return "", "", errextra.Wrap(err, "Account manager could not create the account") } - address := fmt.Sprintf("%x", account.Address) - key, err := crypto.LoadECDSA(account.File) + + // recover the public key to return + keyContents, err := ioutil.ReadFile(account.File) if err != nil { - return address, "", errextra.Wrap(err, "Could not load the key") + return address, "", errextra.Wrap(err, "Could not load the key contents") } - pubKey := string(crypto.FromECDSAPub(&key.PublicKey)) + key, err := accounts.DecryptKey(keyContents, password) + if err != nil { + return address, "", errextra.Wrap(err, "Could not recover the key") + } + pubKey := common.ToHex(crypto.FromECDSAPub(&key.PrivateKey.PublicKey)) return address, pubKey, nil @@ -42,7 +51,7 @@ func createAccount(password, keydir string) (string, string, error) { // unlockAccount unlocks an existing account for a certain duration and // inject the account as a whisper identity if the account was created as // a whisper enabled account -func unlockAccount(address, password string) error { +func unlockAccount(address, password string, seconds int) error { if currentNode != nil { @@ -52,7 +61,7 @@ func unlockAccount(address, password string) error { return errextra.Wrap(err, "Could not retrieve account from address") } - err = accman.Unlock(account, password) + err = accman.TimedUnlock(account, password, time.Duration(seconds)*time.Second) if err != nil { return errextra.Wrap(err, "Could not decrypt account") } @@ -69,7 +78,7 @@ func unlockAccount(address, password string) error { // node running locally func createAndStartNode(datadir string) error { - currentNode := MakeNode(datadir) + currentNode = MakeNode(datadir) if currentNode != nil { StartNode(currentNode) return nil diff --git a/src/gethdep_test.go b/src/gethdep_test.go new file mode 100644 index 000000000..31a330115 --- /dev/null +++ b/src/gethdep_test.go @@ -0,0 +1,41 @@ +package main + +import ( + "fmt" + "os" + "testing" + "time" +) + +// TestAccountBindings makes sure we can create an account and subsequently +// unlock that account +func TestAccountBindings(t *testing.T) { + + // create an account + address, _, err := createAccount("badpassword", ".ethereumtest/keystore") + if err != nil { + fmt.Println(err.Error()) + t.Error("Test failed: could not create account") + } + + // start geth node and wait for it to initialize + go createAndStartNode(".ethereumtest") + time.Sleep(5 * time.Second) + if currentNode == nil { + t.Error("Test failed: could not start geth node") + } + + // unlock the created account + err = unlockAccount(address, "badpassword", 10) + if err != nil { + fmt.Println(err) + t.Error("Test failed: could not unlock account") + } + + // clean up + err = os.RemoveAll(".ethereumtest") + if err != nil { + t.Error("Test failed: could not clean up temporary datadir") + } + +} diff --git a/src/library.go b/src/library.go index b50ee292d..e496a5c5e 100644 --- a/src/library.go +++ b/src/library.go @@ -2,42 +2,57 @@ package main import "C" import ( + "encoding/json" "fmt" "os" ) //export doCreateAccount -func doCreateAccount(password, keydir *C.char) (*C.char, *C.char, C.int) { +func doCreateAccount(password, keydir *C.char) *C.char { // This is equivalent to creating an account from the command line, // just modified to handle the function arg passing address, pubKey, err := createAccount(C.GoString(password), C.GoString(keydir)) + out := AccountInfo{ + Address: address, + PubKey: pubKey, + Error: err.Error(), + } if err != nil { fmt.Fprintln(os.Stderr, err) - return C.CString(""), C.CString(""), -1 } - return C.CString(address), C.CString(pubKey), 0 + outBytes, _ := json.Marshal(&out) + return C.CString(string(outBytes)) + } //export doUnlockAccount -func doUnlockAccount(address, password *C.char) C.int { +func doUnlockAccount(address, password *C.char, seconds int) *C.char { // This is equivalent to unlocking an account from the command line, // just modified to unlock the account for the currently running geth node // based on the provided arguments - if err := unlockAccount(C.GoString(address), C.GoString(password)); err != nil { - fmt.Fprintln(os.Stderr, err) - return -1 + err := unlockAccount(C.GoString(address), C.GoString(password), seconds) + out := JSONError{ + Error: err.Error(), } - return 0 + if err != nil { + fmt.Fprintln(os.Stderr, err) + } + outBytes, _ := json.Marshal(&out) + return C.CString(string(outBytes)) } //export doStartNode -func doStartNode(datadir *C.char) C.int { +func doStartNode(datadir *C.char) *C.char { // This starts a geth node with the given datadir - if err := createAndStartNode(C.GoString(datadir)); err != nil { - fmt.Fprintln(os.Stderr, err) - return -1 + err := createAndStartNode(C.GoString(datadir)) + out := JSONError{ + Error: err.Error(), } - return 0 + if err != nil { + fmt.Fprintln(os.Stderr, err) + } + outBytes, _ := json.Marshal(&out) + return C.CString(string(outBytes)) } //export parse diff --git a/src/types.go b/src/types.go new file mode 100644 index 000000000..2bd82534f --- /dev/null +++ b/src/types.go @@ -0,0 +1,11 @@ +package main + +type AccountInfo struct { + Address string `json:"address"` + PubKey string `json:"pubkey"` + Error string `json:"error"` +} + +type JSONError struct { + Error string `json:"error"` +}