diff --git a/address.go b/address.go index 400fd23..6c9e425 100644 --- a/address.go +++ b/address.go @@ -5,6 +5,14 @@ type AddressBalance struct { Received uint64 `json:"received"` } +type AddressTxidsRequest struct { + Addresses []string `json:"addresses"` + Start uint64 `json:"start"` + End uint64 `json:"end"` +} + +type AddressTxids []string + type AddressHistoryRequest struct { Addresses []string `json:"addresses"` Start uint64 `json:"start"` diff --git a/go.mod b/go.mod index 847b6ed..a812be5 100644 --- a/go.mod +++ b/go.mod @@ -5,4 +5,5 @@ go 1.13 require ( github.com/onsi/ginkgo v1.14.0 github.com/onsi/gomega v1.10.1 + go.uber.org/zap v1.16.0 // indirect ) diff --git a/go.sum b/go.sum index 564ed20..ac90977 100644 --- a/go.sum +++ b/go.sum @@ -72,6 +72,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -174,6 +175,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -183,17 +185,27 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= @@ -251,7 +263,10 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= @@ -293,3 +308,4 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/navcoind.go b/navcoind.go index 18c22b7..9cbdab6 100644 --- a/navcoind.go +++ b/navcoind.go @@ -21,14 +21,14 @@ type Navcoind struct { } // New return a new navcoind -func New(host string, port int, user, passwd string, useSSL bool, timeoutParam ...int) (*Navcoind, error) { +func New(host string, port int, user, passwd string, useSSL, debug bool, timeoutParam ...int) (*Navcoind, error) { var timeout int = RPCCLIENT_TIMEOUT // If the timeout is specified in timeoutParam, allow it. if len(timeoutParam) != 0 { timeout = timeoutParam[0] } - rpcClient, err := newClient(host, port, user, passwd, useSSL, timeout) + rpcClient, err := newClient(host, port, user, passwd, useSSL, timeout, debug) if err != nil { return nil, err } @@ -103,6 +103,26 @@ func (b *Navcoind) GetAddressBalance(address string) (addresses *AddressBalance, return } +func (b *Navcoind) GetAddressTxids(start, end *uint64, addresses ...string) (txids AddressTxids, err error) { + req := new(AddressTxidsRequest) + + for _, a := range addresses { + req.Addresses = append(req.Addresses, a) + } + if start != nil && end != nil { + req.Start = *start + req.End = *end + } + + r, err := b.client.call("getaddresstxids", []AddressTxidsRequest{*req}) + if err = handleError(err, &r); err != nil { + return + } + err = json.Unmarshal(r.Result, &txids) + + return +} + func (b *Navcoind) GetAddressHistory(start, end *uint64, addresses ...string) (history []*AddressHistory, err error) { req := new(AddressHistoryRequest) diff --git a/rpcClient.go b/rpcClient.go index 241c35a..a73a397 100644 --- a/rpcClient.go +++ b/rpcClient.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "go.uber.org/zap" "io/ioutil" "net/http" "time" @@ -18,6 +19,7 @@ type rpcClient struct { passwd string httpClient *http.Client timeout int + debug bool } // rpcRequest represent a RCP request @@ -56,7 +58,7 @@ type rpcResponse struct { Err *RPCError `json:"error"` } -func newClient(host string, port int, user, passwd string, useSSL bool, timeout int) (c *rpcClient, err error) { +func newClient(host string, port int, user, passwd string, useSSL bool, timeout int, debug bool) (c *rpcClient, err error) { if len(host) == 0 { err = errors.New("Bad call missing argument host") return @@ -73,7 +75,14 @@ func newClient(host string, port int, user, passwd string, useSSL bool, timeout serverAddr = "http://" httpClient = &http.Client{} } - c = &rpcClient{serverAddr: fmt.Sprintf("%s%s:%d", serverAddr, host, port), user: user, passwd: passwd, httpClient: httpClient, timeout: timeout} + c = &rpcClient{ + fmt.Sprintf("%s%s:%d", serverAddr, host, port), + user, + passwd, + httpClient, + timeout, + debug, + } return } @@ -99,15 +108,20 @@ func (c *rpcClient) doTimeoutRequest(timer *time.Timer, req *http.Request) (*htt // call prepare & exec the request func (c *rpcClient) call(method string, params interface{}) (rr rpcResponse, err error) { - connectTimer := time.NewTimer(time.Duration(c.timeout) * time.Second) rpcR := rpcRequest{method, params, time.Now().UnixNano(), "1.0"} payloadBuffer := &bytes.Buffer{} jsonEncoder := json.NewEncoder(payloadBuffer) err = jsonEncoder.Encode(rpcR) - if err != nil { return } + + if c.debug { + zap.L().With( + zap.String("request", payloadBuffer.String()), + ).Debug("Navcoind: RPC Request") + } + req, err := http.NewRequest("POST", c.serverAddr, payloadBuffer) if err != nil { return @@ -120,9 +134,8 @@ func (c *rpcClient) call(method string, params interface{}) (rr rpcResponse, err req.SetBasicAuth(c.user, c.passwd) } - resp, err := c.doTimeoutRequest(connectTimer, req) + resp, err := c.doTimeoutRequest(time.NewTimer(time.Duration(c.timeout)*time.Second), req) if err != nil { - err = errors.New("Failed to complete request") return } defer resp.Body.Close() @@ -132,6 +145,12 @@ func (c *rpcClient) call(method string, params interface{}) (rr rpcResponse, err return } + if c.debug { + zap.L().With( + zap.String("response", string(data)), + ).Debug("Navcoind: RPC Response") + } + err = json.Unmarshal(data, &rr) return }