diff --git a/pkg/rpc/README.md b/pkg/rpc/README.md index 2a2fe0d55..e3768c8b9 100644 --- a/pkg/rpc/README.md +++ b/pkg/rpc/README.md @@ -88,11 +88,11 @@ which would yield the response: | Method | Implemented | Required to implement | | ------- | ------------| --------------------- | | `getblock` | Yes | - | -| `getaccountstate` | No | Result struct & wallet functionality | +| `getaccountstate` | Yes | - | | `invokescript` | No | VM | | `invokefunction` | No | VM | | `sendrawtransaction` | No | Needs to be implemented in `pkg/core/blockchain.go` | -| `validateaddress` | No | Needs to be implemented in `pkg/core/blockchain.go` | +| `validateaddress` | Yes | - | | `getblocksysfee` | No | N/A | | `getcontractstate` | No | Needs to be implemented in `pkg/core/blockchain.go` | | `getrawmempool` | No | Needs to be implemented on in `pkg/network/server.go` | diff --git a/pkg/rpc/server.go b/pkg/rpc/server.go index 2dd5fcf82..acf946a24 100644 --- a/pkg/rpc/server.go +++ b/pkg/rpc/server.go @@ -181,15 +181,21 @@ Methods: results = peers - case "validateaddress", "getblocksysfee", "getcontractstate", "getrawmempool", "getrawtransaction", "getstorage", "submitblock", "gettxout", "invoke", "invokefunction", "invokescript", "sendrawtransaction": + case "getblocksysfee", "getcontractstate", "getrawmempool", "getrawtransaction", "getstorage", "submitblock", "gettxout", "invoke", "invokefunction", "invokescript", "sendrawtransaction": results = "TODO" + case "validateaddress": + param, err := reqParams.Value(0) + if err != nil { + resultsErr = err + break + } + results = wrappers.ValidateAddress(param.RawValue) + case "getassetstate": - var err error - param, exists := reqParams.ValueAtAndType(0, "string") - if !exists { - err = errors.New("expected param at index 0 to be a valid string assetID parameter") - resultsErr = NewInvalidParamsError(err.Error(), err) + param, errRes := reqParams.ValueWithType(0, "string") + if errRes != nil { + resultsErr = errRes break } diff --git a/pkg/rpc/server_test.go b/pkg/rpc/server_test.go index 02d2e12f5..5a739e8ad 100644 --- a/pkg/rpc/server_test.go +++ b/pkg/rpc/server_test.go @@ -56,7 +56,7 @@ func TestHandler(t *testing.T) { {`{"jsonrpc": "2.0", "id": 1, "method": "getassetstate", "params": [123] }`, "getassetstate_4", - `{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Params","data":"expected param at index 0 to be a valid string assetID parameter"},"id":1}`}, + `{"jsonrpc":"2.0","error":{"code":-2146233033,"message":"One of the identified items was in an invalid format."},"id":1}`}, {`{"jsonrpc": "2.0", "id": 1, "method": "getblockhash", "params": [10] }`, "getblockhash_1", @@ -117,6 +117,34 @@ func TestHandler(t *testing.T) { method: "getaccountstate_4", expectedResult: `{"jsonrpc":"2.0","error":{"code":-2146233086,"message":"Index was out of range. Must be non-negative and less than the size of the collection.\nParameter name: index"},"id":1}`, }, + + // Good case, valid address + { + rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "validateaddress", "params": ["AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i"] }`, + method: "validateaddress_1", + expectedResult: `{"jsonrpc":"2.0","result":{"address":"AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i","isvalid":true},"id":1}`, + }, + + // Bad case, invalid address + { + rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "validateaddress", "params": ["152f1muMCNa7goXYhYAQC61hxEgGacmncB"] }`, + method: "validateaddress_2", + expectedResult: `{"jsonrpc":"2.0","result":{"address":"152f1muMCNa7goXYhYAQC61hxEgGacmncB","isvalid":false},"id":1}`, + }, + + // Bad case, not string + { + rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "validateaddress", "params": [1] }`, + method: "validateaddress_3", + expectedResult: `{"jsonrpc":"2.0","result":{"address":1,"isvalid":false},"id":1}`, + }, + + // Bad case, empty params + { + rpcCall: `{ "jsonrpc": "2.0", "id": 1, "method": "validateaddress", "params": [] }`, + method: "validateaddress_4", + expectedResult: `{"jsonrpc":"2.0","error":{"code":-2146233086,"message":"Index was out of range. Must be non-negative and less than the size of the collection.\nParameter name: index"},"id":1}`, + }, } for _, tc := range testCases { diff --git a/pkg/rpc/wrappers/validate_address.go b/pkg/rpc/wrappers/validate_address.go new file mode 100644 index 000000000..83390976d --- /dev/null +++ b/pkg/rpc/wrappers/validate_address.go @@ -0,0 +1,21 @@ +package wrappers + +import ( + "github.com/CityOfZion/neo-go/pkg/crypto" +) + +type ValidateAddressResponse struct { + Address interface{} `json:"address"` + IsValid bool `json:"isvalid"` +} + +// ValidateAddress verifies that the address is a correct NEO address +// see https://docs.neo.org/en-us/node/cli/2.9.4/api/validateaddress.html +func ValidateAddress(address interface{}) ValidateAddressResponse { + resp := ValidateAddressResponse{Address: address} + if address, ok := address.(string); ok { + _, err := crypto.Uint160DecodeAddress(address) + resp.IsValid = err == nil + } + return resp +}