Add version command to JSON-RPC API for API versioning

This commit is contained in:
Alex 2016-12-15 14:10:06 -07:00
parent 602232500e
commit 9f962b60d6
8 changed files with 163 additions and 3 deletions

View file

@ -1,6 +1,7 @@
ISC License ISC License
Copyright (c) 2013-2016 The btcsuite developers 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 Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above

View file

@ -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 // Use of this source code is governed by an ISC
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -89,6 +90,19 @@ func NewGetCurrentNetCmd() *GetCurrentNetCmd {
return &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() { func init() {
// No special flags for commands in this file. // No special flags for commands in this file.
flags := UsageFlag(0) flags := UsageFlag(0)
@ -98,4 +112,5 @@ func init() {
MustRegisterCmd("generate", (*GenerateCmd)(nil), flags) MustRegisterCmd("generate", (*GenerateCmd)(nil), flags)
MustRegisterCmd("getbestblock", (*GetBestBlockCmd)(nil), flags) MustRegisterCmd("getbestblock", (*GetBestBlockCmd)(nil), flags)
MustRegisterCmd("getcurrentnet", (*GetCurrentNetCmd)(nil), flags) MustRegisterCmd("getcurrentnet", (*GetCurrentNetCmd)(nil), flags)
MustRegisterCmd("version", (*VersionCmd)(nil), flags)
} }

View file

@ -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 // Use of this source code is governed by an ISC
// license that can be found in the LICENSE file. // 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}`, marshalled: `{"jsonrpc":"1.0","method":"getcurrentnet","params":[],"id":1}`,
unmarshalled: &btcjson.GetCurrentNetCmd{}, 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)) t.Logf("Running %d tests", len(tests))

20
btcjson/btcdextresults.go Normal file
View file

@ -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"`
}

View file

@ -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
}
}
}

View file

@ -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| |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| |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| |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.|
<a name="ExtMethodDetails" /> <a name="ExtMethodDetails" />
@ -664,6 +665,19 @@ The following is an overview of the RPC methods which are implemented by btcd, b
*** ***
<a name="version"/>
| | |
|---|---|
|Method|version|
|Parameters|None|
|Description|Returns the version of the JSON-RPC API built into this release of btcd.|
|Returns|`{ (json object)`<br />&nbsp;&nbsp;`"btcdjsonrpcapi": {`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"versionstring": "x.y.z", (string) the version of the JSON-RPC API`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"major": x, (numeric) the major version of the JSON-RPC API`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"minor": y, (numeric) the minor version of the JSON-RPC API`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"patch": z, (numeric) the patch version of the JSON-RPC API`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"prerelease": "", (string) prerelease info for the JSON-RPC API`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"buildmetadata": "" (string) metadata about the server build`<br />&nbsp;&nbsp;`}`<br />`}`|
|Example Return|`{`<br />&nbsp;&nbsp;`"btcdjsonrpcapi": {`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"versionstring": "1.0.0",`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"major": 1, `<br />&nbsp;&nbsp;&nbsp;&nbsp;`"minor": 0,`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"patch": 0,`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"prerelease": "",`<br />&nbsp;&nbsp;&nbsp;&nbsp;`"buildmetadata": ""`<br />&nbsp;&nbsp;`}`<br />`}`|
[Return to Overview](#MethodOverview)<br />
***
<a name="WSExtMethods" /> <a name="WSExtMethods" />
### 7. Websocket Extension Methods (Websocket-specific) ### 7. Websocket Extension Methods (Websocket-specific)

View file

@ -1,4 +1,5 @@
// Copyright (c) 2013-2016 The btcsuite developers // Copyright (c) 2013-2016 The btcsuite developers
// Copyright (c) 2015-2016 The Decred developers
// Use of this source code is governed by an ISC // Use of this source code is governed by an ISC
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -42,6 +43,14 @@ import (
"github.com/btcsuite/websocket" "github.com/btcsuite/websocket"
) )
// API version constants
const (
jsonrpcSemverString = "1.0.0"
jsonrpcSemverMajor = 1
jsonrpcSemverMinor = 0
jsonrpcSemverPatch = 0
)
const ( const (
// rpcAuthTimeoutSeconds is the number of seconds a connection to the // rpcAuthTimeoutSeconds is the number of seconds a connection to the
// RPC server is allowed to stay open without authenticating before it // RPC server is allowed to stay open without authenticating before it
@ -175,6 +184,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
"validateaddress": handleValidateAddress, "validateaddress": handleValidateAddress,
"verifychain": handleVerifyChain, "verifychain": handleVerifyChain,
"verifymessage": handleVerifyMessage, "verifymessage": handleVerifyMessage,
"version": handleVersion,
} }
// list of commands that we recognize, but for which btcd has no support because // list of commands that we recognize, but for which btcd has no support because
@ -271,6 +281,7 @@ var rpcLimited = map[string]struct{}{
"submitblock": {}, "submitblock": {},
"validateaddress": {}, "validateaddress": {},
"verifymessage": {}, "verifymessage": {},
"version": {},
} }
// builderScript is a convenience function which is used for hard-coded scripts // 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 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, // rpcServer holds the items the rpc server may need to access (config,
// shutdown, main server, etc.) // shutdown, main server, etc.)
type rpcServer struct { type rpcServer struct {

View file

@ -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 // Use of this source code is governed by an ISC
// license that can be found in the LICENSE file. // 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-addresses": "List of addresses to include in the rescan",
"rescan-outpoints": "List of transaction outpoints to include in the rescan", "rescan-outpoints": "List of transaction outpoints to include in the rescan",
"rescan-endblock": "Hash of final block to 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. // rpcResultTypes specifies the result types that each RPC command can return.
@ -652,6 +667,7 @@ var rpcResultTypes = map[string][]interface{}{
"validateaddress": {(*btcjson.ValidateAddressChainResult)(nil)}, "validateaddress": {(*btcjson.ValidateAddressChainResult)(nil)},
"verifychain": {(*bool)(nil)}, "verifychain": {(*bool)(nil)},
"verifymessage": {(*bool)(nil)}, "verifymessage": {(*bool)(nil)},
"version": {(*map[string]btcjson.VersionResult)(nil)},
// Websocket commands. // Websocket commands.
"session": {(*btcjson.SessionResult)(nil)}, "session": {(*btcjson.SessionResult)(nil)},