diff --git a/README.md b/README.md index 0c63329..65936f8 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,84 @@ bitcoind =========== -[![Build Status](https://travis-ci.org/Toorop/go-bitcoind.svg)](https://travis-ci.org/Toorop/go-bitcoind) - A Golang client library wrapping the bitcoind JSON RPC API -Work in progress, stay tuned + +Installation +----- + $ go get https://github.com/Toorop/go-bitcoind + + +Usage +---- + + package main + + import ( + "github.com/toorop/go-bitcoind" + "log" + ) + + const ( + SERVER_HOST = "You server host" + SERVER_PORT = port (int) + USER = "user" + PASSWD = "passwd" + USESSL = false + WALLET_PASSPHRASE = "WalletPassphrase" +) + + func main() { + bc, err := bitcoind.New(SERVER_HOST, SERVER_PORT, USER, PASSWD, USESSL) + if err != nil { + log.Fatalln(err) + } + + //walletpassphrase + err = bc.WalletPassphrase(WALLET_PASSPHRASE, 3600) + log.Println(err) + + // backupwallet + err = bc.BackupWallet("/tmp/wallet.dat") + log.Println(err) + + + // dumpprivkey + privKey, err := bc.DumpPrivKey("1KU5DX7jKECLxh1nYhmQ7CahY7GMNMVLP3") + log.Println(err, privKey) + + } + +Mores examples in example.go (in examples folder) Documentation ----- -[![GoDoc](https://godoc.org/github.com/Toorop/go-bitcoind?status.png)](https://godoc.org/github.com/Toorop/go-bitcoind) +[![GoDoc](https://godoc.org/github.com/Toorop/go-bitcoind?status.png)](https://godoc.org/github.com/Toorop/go-bitcoind) + +Unit tests +---- +[![Build Status](https://travis-ci.org/Toorop/go-bitcoind.svg)](https://travis-ci.org/Toorop/go-bitcoind) + +More than 100 unit tests are made. + +To run tests: + + $ go get github.com/onsi/ginkgo/ginkgo + $ go get github.com/onsi/gomega + $ ginkgo + + Running Suite: Bitcoind Suite + ============================= + Random Seed: 1401120770 + Will run 112 of 112 specs + + ••••••••••••••••••••••••••••••••••• + Ran 112 of 112 Specs in 0.001 seconds + SUCCESS! -- 112 Passed | 0 Failed | 0 Pending | 0 Skipped PASS + + Ginkgo ran in 10.856335553s + Test Suite Passed + Todo ----- @@ -17,14 +86,7 @@ Todo * GetBlockTemplate * sendrawtransaction * signrawtransaction -* settxfee -* signmessage -* stop * submitblock -* validateaddress -* verifymessage -* walletlock -* walletpassphrasechange Donation ------ diff --git a/bitcoind.go b/bitcoind.go index 8b778ba..5772113 100644 --- a/bitcoind.go +++ b/bitcoind.go @@ -594,8 +594,74 @@ func (b *Bitcoind) SetGenerate(generate bool, genProcLimit int32) error { return handleError(err, &r) } +// SetTxFee set the transaction fee per kB +func (b *Bitcoind) SetTxFee(amount float64) error { + r, err := b.client.call("settxfee", []interface{}{amount}) + return handleError(err, &r) +} + +// Stop stop bitcoin server. +func (b *Bitcoind) Stop() error { + r, err := b.client.call("stop", nil) + return handleError(err, &r) +} + +// SignMessage sign a message with the private key of an address +func (b *Bitcoind) SignMessage(address, message string) (sig string, err error) { + r, err := b.client.call("signmessage", []interface{}{address, message}) + if err = handleError(err, &r); err != nil { + return + } + err = json.Unmarshal(r.Result, &sig) + return +} + +// Verifymessage Verify a signed message. +func (b *Bitcoind) VerifyMessage(address, sign, message string) (success bool, err error) { + r, err := b.client.call("verifymessage", []interface{}{address, sign, message}) + if err = handleError(err, &r); err != nil { + return + } + err = json.Unmarshal(r.Result, &success) + return +} + +// ValidateAddressResponse represents a response to "validateaddress" call +type ValidateAddressResponse struct { + IsValid bool `json:"isvalid"` + Address string `json:"address"` + IsMine bool `json:"ismine"` + IsScript bool `json:"isscript"` + PubKey string `json:"pubkey"` + IsCompressed bool `json:"iscompressed"` + Account string `json:"account"` +} + +// ValidateAddress return information about . +func (b *Bitcoind) ValidateAddress(address string) (va ValidateAddressResponse, err error) { + r, err := b.client.call("validateaddress", []interface{}{address}) + if err = handleError(err, &r); err != nil { + return + } + err = json.Unmarshal(r.Result, &va) + return +} + +// WalletLock Removes the wallet encryption key from memory, locking the wallet. +// After calling this method, you will need to call walletpassphrase again before being +// able to call any methods which require the wallet to be unlocked. +func (b *Bitcoind) WalletLock() error { + r, err := b.client.call("walletlock", nil) + return handleError(err, &r) +} + // walletPassphrase stores the wallet decryption key in memory for seconds. func (b *Bitcoind) WalletPassphrase(passPhrase string, timeout uint64) error { r, err := b.client.call("walletpassphrase", []interface{}{passPhrase, timeout}) return handleError(err, &r) } + +func (b *Bitcoind) WalletPassphraseChange(oldPassphrase, newPassprhase string) error { + r, err := b.client.call("walletpassphrasechange", []interface{}{oldPassphrase, newPassprhase}) + return handleError(err, &r) +} diff --git a/bitcoind_test.go b/bitcoind_test.go index fdc4b85..1664b32 100644 --- a/bitcoind_test.go +++ b/bitcoind_test.go @@ -1904,7 +1904,132 @@ var _ = Describe("Bitcoind", func() { }) }) - /*Describe("walletpassphrase", func() { + Describe("Testing SetTxFee", func() { + Context("when success", func() { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, `{"result":true,"error":null,"id":1401115696421261167}`) + }) + ts, host, port, err := getNewTestServer(handler) + if err != nil { + log.Fatalln(err) + } + defer ts.Close() + bitcoindClient, _ := New(host, port, "x", "fake", false) + err = bitcoindClient.SetTxFee(0.0001) + It("should not error", func() { + Expect(err).NotTo(HaveOccurred()) + }) + }) + }) + + Describe("Testing SignMessage", func() { + Context("when success", func() { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, `{"result":"ILImxcrK6iELcUSqH9ntxGYrpd9MuYwx0rXnLHron1NEG9Jog36RbFCQzaRSO0/XXu6msoWiz4n1Q64kCNv4nH8=","error":null,"id":1401117539316610969}`) + }) + ts, host, port, err := getNewTestServer(handler) + if err != nil { + log.Fatalln(err) + } + defer ts.Close() + bitcoindClient, _ := New(host, port, "x", "fake", false) + sig, err := bitcoindClient.SignMessage("1Pyizp4HK7Bfz7CdbSwHHtprk7Ghumhxmy", "test message") + It("should not error", func() { + Expect(err).NotTo(HaveOccurred()) + }) + It("should return a string sig ", func() { + Expect(sig).Should(Equal("ILImxcrK6iELcUSqH9ntxGYrpd9MuYwx0rXnLHron1NEG9Jog36RbFCQzaRSO0/XXu6msoWiz4n1Q64kCNv4nH8=")) + }) + }) + }) + + Describe("Testing Stop", func() { + Context("when success", func() { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, `{"result":"Bitcoin server stopping","error":null,"id":1401118273551801323}`) + }) + ts, host, port, err := getNewTestServer(handler) + if err != nil { + log.Fatalln(err) + } + defer ts.Close() + bitcoindClient, _ := New(host, port, "x", "fake", false) + err = bitcoindClient.Stop() + It("should not error", func() { + Expect(err).NotTo(HaveOccurred()) + }) + }) + }) + + Describe("Testing ValidateAddress", func() { + Context("when success", func() { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, `{"result":{"isvalid":true,"address":"1Pyizp4HK7Bfz7CdbSwHHtprk7Ghumhxmy","ismine":true,"isscript":false,"pubkey":"02dc7ecd8baec59cf018bf40d1e948519dc0dcf256eb3bc3ed121bc3ee83c98b01","iscompressed":true,"account":"tests"},"error":null,"id":1401119296578850111}`) + }) + ts, host, port, err := getNewTestServer(handler) + if err != nil { + log.Fatalln(err) + } + defer ts.Close() + bitcoindClient, _ := New(host, port, "x", "fake", false) + resp, err := bitcoindClient.ValidateAddress("1Pyizp4HK7Bfz7CdbSwHHtprk7Ghumhxmy") + It("should not error", func() { + Expect(err).NotTo(HaveOccurred()) + }) + It("should return a string sig ", func() { + Expect(resp).Should(Equal(ValidateAddressResponse{ + IsValid: true, + Address: "1Pyizp4HK7Bfz7CdbSwHHtprk7Ghumhxmy", + IsMine: true, + IsScript: false, + PubKey: "02dc7ecd8baec59cf018bf40d1e948519dc0dcf256eb3bc3ed121bc3ee83c98b01", + IsCompressed: true, + Account: "tests", + })) + }) + }) + }) + + Describe("Testing VerifyMessage", func() { + Context("when success", func() { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, `{"result":true,"error":null,"id":1401117539369759914}`) + }) + ts, host, port, err := getNewTestServer(handler) + if err != nil { + log.Fatalln(err) + } + defer ts.Close() + bitcoindClient, _ := New(host, port, "x", "fake", false) + success, err := bitcoindClient.VerifyMessage("1Pyizp4HK7Bfz7CdbSwHHtprk7Ghumhxmy", "fake_sig", "test message") + It("should not error", func() { + Expect(err).NotTo(HaveOccurred()) + }) + It("succes should be true", func() { + Expect(success).To(BeTrue()) + }) + }) + }) + + Describe("Testing WalletLock", func() { + Context("when success", func() { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, `{"result":null,"error":null,"id":1401119933934255494}`) + }) + ts, host, port, err := getNewTestServer(handler) + if err != nil { + log.Fatalln(err) + } + defer ts.Close() + bitcoindClient, _ := New(host, port, "x", "fake", false) + err = bitcoindClient.WalletLock() + It("should not error", func() { + Expect(err).NotTo(HaveOccurred()) + }) + }) + }) + + Describe("walletpassphrase", func() { Context("when success", func() { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, `{"result":null,"error":null,"id":1400433627531460562}`) @@ -1920,5 +2045,25 @@ var _ = Describe("Bitcoind", func() { Expect(err).NotTo(HaveOccurred()) }) }) - })*/ + }) + + Describe("Testing WalletPassphraseChange", func() { + Context("when success", func() { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, `{"result":null,"error":null,"id":1401120599336429525}`) + }) + ts, host, port, err := getNewTestServer(handler) + if err != nil { + log.Fatalln(err) + } + defer ts.Close() + bitcoindClient, _ := New(host, port, "x", "fake", false) + err = bitcoindClient.WalletPassphraseChange("fakePassPhrase", "fake passphrase") + It("should not error", func() { + Expect(err).NotTo(HaveOccurred()) + }) + }) + }) + + // {"result":null,"error":null,"id":1401120599336429525} }) diff --git a/rpcClient.go b/rpcClient.go index eb3ec7b..145fa8a 100644 --- a/rpcClient.go +++ b/rpcClient.go @@ -108,10 +108,9 @@ func (c *rpcClient) call(method string, params interface{}) (rr rpcResponse, err return } if resp.StatusCode != 200 { - err = errors.New(resp.Status) + err = errors.New("HTTP error: " + resp.Status) + return } - err = json.Unmarshal(data, &rr) - return }