diff --git a/LICENSE b/LICENSE index 49de9195..684c6004 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ ISC License Copyright (c) 2013-2016 The btcsuite developers +Copyright (c) 2015-2016 The Decred developers Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above diff --git a/btcjson/btcdextcmds.go b/btcjson/btcdextcmds.go index 7d416395..25af8d21 100644 --- a/btcjson/btcdextcmds.go +++ b/btcjson/btcdextcmds.go @@ -1,4 +1,5 @@ -// Copyright (c) 2014 The btcsuite developers +// Copyright (c) 2014-2016 The btcsuite developers +// Copyright (c) 2015-2016 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -89,6 +90,19 @@ func NewGetCurrentNetCmd() *GetCurrentNetCmd { return &GetCurrentNetCmd{} } +// VersionCmd defines the version JSON-RPC command. +// +// NOTE: This is a btcsuite extension ported from +// github.com/decred/dcrd/dcrjson. +type VersionCmd struct{} + +// NewVersionCmd returns a new instance which can be used to issue a JSON-RPC +// version command. +// +// NOTE: This is a btcsuite extension ported from +// github.com/decred/dcrd/dcrjson. +func NewVersionCmd() *VersionCmd { return new(VersionCmd) } + func init() { // No special flags for commands in this file. flags := UsageFlag(0) @@ -98,4 +112,5 @@ func init() { MustRegisterCmd("generate", (*GenerateCmd)(nil), flags) MustRegisterCmd("getbestblock", (*GetBestBlockCmd)(nil), flags) MustRegisterCmd("getcurrentnet", (*GetCurrentNetCmd)(nil), flags) + MustRegisterCmd("version", (*VersionCmd)(nil), flags) } diff --git a/btcjson/btcdextcmds_test.go b/btcjson/btcdextcmds_test.go index c4d8d498..1d87f7c4 100644 --- a/btcjson/btcdextcmds_test.go +++ b/btcjson/btcdextcmds_test.go @@ -1,4 +1,5 @@ -// Copyright (c) 2014 The btcsuite developers +// Copyright (c) 2014-2016 The btcsuite developers +// Copyright (c) 2015-2016 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -135,6 +136,17 @@ func TestBtcdExtCmds(t *testing.T) { marshalled: `{"jsonrpc":"1.0","method":"getcurrentnet","params":[],"id":1}`, unmarshalled: &btcjson.GetCurrentNetCmd{}, }, + { + name: "version", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("version") + }, + staticCmd: func() interface{} { + return btcjson.NewVersionCmd() + }, + marshalled: `{"jsonrpc":"1.0","method":"version","params":[],"id":1}`, + unmarshalled: &btcjson.VersionCmd{}, + }, } t.Logf("Running %d tests", len(tests)) diff --git a/btcjson/btcdextresults.go b/btcjson/btcdextresults.go new file mode 100644 index 00000000..86cda258 --- /dev/null +++ b/btcjson/btcdextresults.go @@ -0,0 +1,20 @@ +// Copyright (c) 2016 The btcsuite developers +// Copyright (c) 2015-2016 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcjson + +// VersionResult models objects included in the version response. In the actual +// result, these objects are keyed by the program or API name. +// +// NOTE: This is a btcsuite extension ported from +// github.com/decred/dcrd/dcrjson. +type VersionResult struct { + VersionString string `json:"versionstring"` + Major uint32 `json:"major"` + Minor uint32 `json:"minor"` + Patch uint32 `json:"patch"` + Prerelease string `json:"prerelease"` + BuildMetadata string `json:"buildmetadata"` +} diff --git a/btcjson/btcdextresults_test.go b/btcjson/btcdextresults_test.go new file mode 100644 index 00000000..c4d7462b --- /dev/null +++ b/btcjson/btcdextresults_test.go @@ -0,0 +1,55 @@ +// Copyright (c) 2016 The btcsuite developers +// Copyright (c) 2015-2016 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package btcjson_test + +import ( + "encoding/json" + "testing" + + "github.com/btcsuite/btcd/btcjson" +) + +// TestBtcdExtCustomResults ensures any results that have custom marshalling +// work as inteded. +// and unmarshal code of results are as expected. +func TestBtcdExtCustomResults(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + result interface{} + expected string + }{ + { + name: "versionresult", + result: &btcjson.VersionResult{ + VersionString: "1.0.0", + Major: 1, + Minor: 0, + Patch: 0, + Prerelease: "pr", + BuildMetadata: "bm", + }, + expected: `{"versionstring":"1.0.0","major":1,"minor":0,"patch":0,"prerelease":"pr","buildmetadata":"bm"}`, + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + marshalled, err := json.Marshal(test.result) + if err != nil { + t.Errorf("Test #%d (%s) unexpected error: %v", i, + test.name, err) + continue + } + if string(marshalled) != test.expected { + t.Errorf("Test #%d (%s) unexpected marhsalled data - "+ + "got %s, want %s", i, test.name, marshalled, + test.expected) + continue + } + } +} diff --git a/docs/json_rpc_api.md b/docs/json_rpc_api.md index 103f4ce1..27d36caf 100644 --- a/docs/json_rpc_api.md +++ b/docs/json_rpc_api.md @@ -583,6 +583,7 @@ The following is an overview of the RPC methods which are implemented by btcd, b |4|[searchrawtransactions](#searchrawtransactions)|Y|Query for transactions related to a particular address.|None| |5|[node](#node)|N|Attempts to add or remove a peer. |None| |6|[generate](#generate)|N|When in simnet or regtest mode, generate a set number of blocks. |None| +|7|[version](#version)|Y|Returns the JSON-RPC API version.| @@ -664,6 +665,19 @@ The following is an overview of the RPC methods which are implemented by btcd, b *** + + +| | | +|---|---| +|Method|version| +|Parameters|None| +|Description|Returns the version of the JSON-RPC API built into this release of btcd.| +|Returns|`{ (json object)`
  `"btcdjsonrpcapi": {`
    `"versionstring": "x.y.z", (string) the version of the JSON-RPC API`
    `"major": x, (numeric) the major version of the JSON-RPC API`
    `"minor": y, (numeric) the minor version of the JSON-RPC API`
    `"patch": z, (numeric) the patch version of the JSON-RPC API`
    `"prerelease": "", (string) prerelease info for the JSON-RPC API`
    `"buildmetadata": "" (string) metadata about the server build`
  `}`
`}`| +|Example Return|`{`
  `"btcdjsonrpcapi": {`
    `"versionstring": "1.0.0",`
    `"major": 1, `
    `"minor": 0,`
    `"patch": 0,`
    `"prerelease": "",`
    `"buildmetadata": ""`
  `}`
`}`| +[Return to Overview](#MethodOverview)
+ +*** +
### 7. Websocket Extension Methods (Websocket-specific) diff --git a/rpcserver.go b/rpcserver.go index 77bc7f08..c34af5c1 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1,4 +1,5 @@ // Copyright (c) 2013-2016 The btcsuite developers +// Copyright (c) 2015-2016 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -42,6 +43,14 @@ import ( "github.com/btcsuite/websocket" ) +// API version constants +const ( + jsonrpcSemverString = "1.0.0" + jsonrpcSemverMajor = 1 + jsonrpcSemverMinor = 0 + jsonrpcSemverPatch = 0 +) + const ( // rpcAuthTimeoutSeconds is the number of seconds a connection to the // RPC server is allowed to stay open without authenticating before it @@ -175,6 +184,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{ "validateaddress": handleValidateAddress, "verifychain": handleVerifyChain, "verifymessage": handleVerifyMessage, + "version": handleVersion, } // list of commands that we recognize, but for which btcd has no support because @@ -271,6 +281,7 @@ var rpcLimited = map[string]struct{}{ "submitblock": {}, "validateaddress": {}, "verifymessage": {}, + "version": {}, } // builderScript is a convenience function which is used for hard-coded scripts @@ -3789,6 +3800,22 @@ func handleVerifyMessage(s *rpcServer, cmd interface{}, closeChan <-chan struct{ return address.EncodeAddress() == c.Address, nil } +// handleVersion implements the version command. +// +// NOTE: This is a btcsuite extension ported from +// github.com/decred/dcrd. +func handleVersion(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { + result := map[string]btcjson.VersionResult{ + "btcdjsonrpcapi": { + VersionString: jsonrpcSemverString, + Major: jsonrpcSemverMajor, + Minor: jsonrpcSemverMinor, + Patch: jsonrpcSemverPatch, + }, + } + return result, nil +} + // rpcServer holds the items the rpc server may need to access (config, // shutdown, main server, etc.) type rpcServer struct { diff --git a/rpcserverhelp.go b/rpcserverhelp.go index 213f3cd6..80dfb3a5 100644 --- a/rpcserverhelp.go +++ b/rpcserverhelp.go @@ -1,4 +1,5 @@ -// Copyright (c) 2015 The btcsuite developers +// Copyright (c) 2015-2016 The btcsuite developers +// Copyright (c) 2015-2016 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -605,6 +606,20 @@ var helpDescsEnUS = map[string]string{ "rescan-addresses": "List of addresses to include in the rescan", "rescan-outpoints": "List of transaction outpoints to include in the rescan", "rescan-endblock": "Hash of final block to rescan", + + // Version help. + "version--synopsis": "Returns the JSON-RPC API version (semver)", + "version--result0--desc": "Version objects keyed by the program or API name", + "version--result0--key": "Program or API name", + "version--result0--value": "Object containing the semantic version", + + // VersionResult help. + "versionresult-versionstring": "The JSON-RPC API version (semver)", + "versionresult-major": "The major component of the JSON-RPC API version", + "versionresult-minor": "The minor component of the JSON-RPC API version", + "versionresult-patch": "The patch component of the JSON-RPC API version", + "versionresult-prerelease": "Prerelease info about the current build", + "versionresult-buildmetadata": "Metadata about the current build", } // rpcResultTypes specifies the result types that each RPC command can return. @@ -652,6 +667,7 @@ var rpcResultTypes = map[string][]interface{}{ "validateaddress": {(*btcjson.ValidateAddressChainResult)(nil)}, "verifychain": {(*bool)(nil)}, "verifymessage": {(*bool)(nil)}, + "version": {(*map[string]btcjson.VersionResult)(nil)}, // Websocket commands. "session": {(*btcjson.SessionResult)(nil)},