[DEV-317] Update JSON-RPC API call GetBlock to allow filtering by SubNetworkID (#180)

* [DEV-317] Update JSON-RPC API call GetBlock to allow filtering by SubNetworkID

* [DEV-317] Changed comments, messages and refactored code
This commit is contained in:
Evgeny Khirin 2019-02-05 16:38:21 +02:00 committed by stasatdaglabs
parent 0bc7a11551
commit 3eeff11231
8 changed files with 85 additions and 25 deletions

View File

@ -151,7 +151,7 @@ func TestMethodUsageText(t *testing.T) {
{
name: "getBlock",
method: "getBlock",
expected: `getBlock "hash" (verbose=true verbosetx=false)`,
expected: `getBlock "hash" (verbose=true verbosetx=false "subnetwork")`,
},
}

View File

@ -135,9 +135,10 @@ func NewGetBestBlockHashCmd() *GetBestBlockHashCmd {
// GetBlockCmd defines the getBlock JSON-RPC command.
type GetBlockCmd struct {
Hash string
Verbose *bool `jsonrpcdefault:"true"`
VerboseTx *bool `jsonrpcdefault:"false"`
Hash string
Verbose *bool `jsonrpcdefault:"true"`
VerboseTx *bool `jsonrpcdefault:"false"`
Subnetwork *string
}
// NewGetBlockCmd returns a new instance which can be used to issue a getBlock
@ -145,11 +146,12 @@ type GetBlockCmd struct {
//
// The parameters which are pointers indicate they are optional. Passing nil
// for optional parameters will use the default value.
func NewGetBlockCmd(hash string, verbose, verboseTx *bool) *GetBlockCmd {
func NewGetBlockCmd(hash string, verbose, verboseTx *bool, subnetworkID *string) *GetBlockCmd {
return &GetBlockCmd{
Hash: hash,
Verbose: verbose,
VerboseTx: verboseTx,
Hash: hash,
Verbose: verbose,
VerboseTx: verboseTx,
Subnetwork: subnetworkID,
}
}

View File

@ -131,7 +131,7 @@ func TestDAGSvrCmds(t *testing.T) {
return btcjson.NewCmd("getBlock", "123")
},
staticCmd: func() interface{} {
return btcjson.NewGetBlockCmd("123", nil, nil)
return btcjson.NewGetBlockCmd("123", nil, nil, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"getBlock","params":["123"],"id":1}`,
unmarshalled: &btcjson.GetBlockCmd{
@ -150,7 +150,7 @@ func TestDAGSvrCmds(t *testing.T) {
return btcjson.NewCmd("getBlock", "123", &verbosePtr)
},
staticCmd: func() interface{} {
return btcjson.NewGetBlockCmd("123", btcjson.Bool(true), nil)
return btcjson.NewGetBlockCmd("123", btcjson.Bool(true), nil, nil)
},
marshalled: `{"jsonrpc":"1.0","method":"getBlock","params":["123",true],"id":1}`,
unmarshalled: &btcjson.GetBlockCmd{
@ -165,7 +165,7 @@ func TestDAGSvrCmds(t *testing.T) {
return btcjson.NewCmd("getBlock", "123", true, true)
},
staticCmd: func() interface{} {
return btcjson.NewGetBlockCmd("123", btcjson.Bool(true), btcjson.Bool(true))
return btcjson.NewGetBlockCmd("123", btcjson.Bool(true), btcjson.Bool(true), nil)
},
marshalled: `{"jsonrpc":"1.0","method":"getBlock","params":["123",true,true],"id":1}`,
unmarshalled: &btcjson.GetBlockCmd{
@ -174,6 +174,22 @@ func TestDAGSvrCmds(t *testing.T) {
VerboseTx: btcjson.Bool(true),
},
},
{
name: "getBlock required optional3",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getBlock", "123", true, true, "456")
},
staticCmd: func() interface{} {
return btcjson.NewGetBlockCmd("123", btcjson.Bool(true), btcjson.Bool(true), btcjson.String("456"))
},
marshalled: `{"jsonrpc":"1.0","method":"getBlock","params":["123",true,true,"456"],"id":1}`,
unmarshalled: &btcjson.GetBlockCmd{
Hash: "123",
Verbose: btcjson.Bool(true),
VerboseTx: btcjson.Bool(true),
Subnetwork: btcjson.String("456"),
},
},
{
name: "getBlockDagInfo",
newCmd: func() (interface{}, error) {

View File

@ -21,7 +21,7 @@ func ExampleMarshalCmd() {
// convenience function for creating a pointer out of a primitive for
// optional parameters.
blockHash := "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
gbCmd := btcjson.NewGetBlockCmd(blockHash, btcjson.Bool(false), nil)
gbCmd := btcjson.NewGetBlockCmd(blockHash, btcjson.Bool(false), nil, nil)
// Marshal the command to the format suitable for sending to the RPC
// server. Typically the client would increment the id here which is
@ -86,6 +86,9 @@ func ExampleUnmarshalCmd() {
fmt.Println("Hash:", gbCmd.Hash)
fmt.Println("Verbose:", *gbCmd.Verbose)
fmt.Println("VerboseTx:", *gbCmd.VerboseTx)
if gbCmd.Subnetwork != nil {
fmt.Println("Subnetwork:", *gbCmd.Subnetwork)
}
// Output:
// Hash: 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f

View File

@ -439,7 +439,7 @@ func (h *Harness) GenerateAndSubmitBlockWithCustomCoinbaseOutputs(
if err != nil {
return nil, err
}
mBlock, err := h.Node.GetBlock(parentBlockHash)
mBlock, err := h.Node.GetBlock(parentBlockHash, nil)
if err != nil {
return nil, err
}

View File

@ -91,13 +91,13 @@ func (r FutureGetBlockResult) Receive() (*wire.MsgBlock, error) {
// returned instance.
//
// See GetBlock for the blocking version and more details.
func (c *Client) GetBlockAsync(blockHash *daghash.Hash) FutureGetBlockResult {
func (c *Client) GetBlockAsync(blockHash *daghash.Hash, subnetworkID *string) FutureGetBlockResult {
hash := ""
if blockHash != nil {
hash = blockHash.String()
}
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(false), nil)
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(false), btcjson.Bool(false), subnetworkID)
return c.sendCmd(cmd)
}
@ -105,8 +105,8 @@ func (c *Client) GetBlockAsync(blockHash *daghash.Hash) FutureGetBlockResult {
//
// See GetBlockVerbose to retrieve a data structure with information about the
// block instead.
func (c *Client) GetBlock(blockHash *daghash.Hash) (*wire.MsgBlock, error) {
return c.GetBlockAsync(blockHash).Receive()
func (c *Client) GetBlock(blockHash *daghash.Hash, subnetworkID *string) (*wire.MsgBlock, error) {
return c.GetBlockAsync(blockHash, subnetworkID).Receive()
}
// FutureGetBlockVerboseResult is a future promise to deliver the result of a
@ -135,13 +135,13 @@ func (r FutureGetBlockVerboseResult) Receive() (*btcjson.GetBlockVerboseResult,
// the returned instance.
//
// See GetBlockVerbose for the blocking version and more details.
func (c *Client) GetBlockVerboseAsync(blockHash *daghash.Hash) FutureGetBlockVerboseResult {
func (c *Client) GetBlockVerboseAsync(blockHash *daghash.Hash, subnetworkID *string) FutureGetBlockVerboseResult {
hash := ""
if blockHash != nil {
hash = blockHash.String()
}
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(true), nil)
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(true), btcjson.Bool(false), subnetworkID)
return c.sendCmd(cmd)
}
@ -150,8 +150,8 @@ func (c *Client) GetBlockVerboseAsync(blockHash *daghash.Hash) FutureGetBlockVer
//
// See GetBlockVerboseTx to retrieve transaction data structures as well.
// See GetBlock to retrieve a raw block instead.
func (c *Client) GetBlockVerbose(blockHash *daghash.Hash) (*btcjson.GetBlockVerboseResult, error) {
return c.GetBlockVerboseAsync(blockHash).Receive()
func (c *Client) GetBlockVerbose(blockHash *daghash.Hash, subnetworkID *string) (*btcjson.GetBlockVerboseResult, error) {
return c.GetBlockVerboseAsync(blockHash, subnetworkID).Receive()
}
// GetBlockVerboseTxAsync returns an instance of a type that can be used to get
@ -159,13 +159,13 @@ func (c *Client) GetBlockVerbose(blockHash *daghash.Hash) (*btcjson.GetBlockVerb
// the returned instance.
//
// See GetBlockVerboseTx or the blocking version and more details.
func (c *Client) GetBlockVerboseTxAsync(blockHash *daghash.Hash) FutureGetBlockVerboseResult {
func (c *Client) GetBlockVerboseTxAsync(blockHash *daghash.Hash, subnetworkID *string) FutureGetBlockVerboseResult {
hash := ""
if blockHash != nil {
hash = blockHash.String()
}
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(true), btcjson.Bool(true))
cmd := btcjson.NewGetBlockCmd(hash, btcjson.Bool(true), btcjson.Bool(true), subnetworkID)
return c.sendCmd(cmd)
}
@ -174,8 +174,8 @@ func (c *Client) GetBlockVerboseTxAsync(blockHash *daghash.Hash) FutureGetBlockV
//
// See GetBlockVerbose if only transaction hashes are preferred.
// See GetBlock to retrieve a raw block instead.
func (c *Client) GetBlockVerboseTx(blockHash *daghash.Hash) (*btcjson.GetBlockVerboseResult, error) {
return c.GetBlockVerboseTxAsync(blockHash).Receive()
func (c *Client) GetBlockVerboseTx(blockHash *daghash.Hash, subnetworkID *string) (*btcjson.GetBlockVerboseResult, error) {
return c.GetBlockVerboseTxAsync(blockHash, subnetworkID).Receive()
}
// FutureGetBlockCountResult is a future promise to deliver the result of a

View File

@ -6,6 +6,7 @@
package rpc
import (
"bufio"
"bytes"
"crypto/sha256"
"crypto/subtle"
@ -47,6 +48,7 @@ import (
"github.com/daglabs/btcd/util"
"github.com/daglabs/btcd/util/fs"
"github.com/daglabs/btcd/util/network"
"github.com/daglabs/btcd/util/subnetworkid"
"github.com/daglabs/btcd/version"
"github.com/daglabs/btcd/wire"
)
@ -1107,6 +1109,42 @@ func handleGetBlock(s *Server, cmd interface{}, closeChan <-chan struct{}) (inte
}
}
// Handle partial blocks
if c.Subnetwork != nil {
requestSubnetworkID, err := subnetworkid.NewFromStr(*c.Subnetwork)
if err != nil {
return nil, &btcjson.RPCError{
Code: btcjson.ErrRPCInvalidRequest.Code,
Message: "invalid subnetwork string",
}
}
nodeSubnetworkID := config.MainConfig().SubnetworkID
if !requestSubnetworkID.IsEqual(&wire.SubnetworkIDSupportsAll) {
if !nodeSubnetworkID.IsEqual(&wire.SubnetworkIDSupportsAll) {
if !nodeSubnetworkID.IsEqual(requestSubnetworkID) {
return nil, &btcjson.RPCError{
Code: btcjson.ErrRPCInvalidRequest.Code,
Message: "subnetwork does not match this partial node",
}
}
// nothing to do - partial node stores partial blocks
} else {
// Deserialize the block.
var msgBlock wire.MsgBlock
err = msgBlock.Deserialize(bytes.NewReader(blkBytes))
if err != nil {
context := "Failed to deserialize block"
return nil, internalRPCError(err.Error(), context)
}
msgBlock.ConvertToPartial(requestSubnetworkID)
var b bytes.Buffer
msgBlock.Serialize(bufio.NewWriter(&b))
blkBytes = b.Bytes()
}
}
}
// When the verbose flag isn't set, simply return the serialized block
// as a hex-encoded string.
if c.Verbose != nil && !*c.Verbose {

View File

@ -169,6 +169,7 @@ var helpDescsEnUS = map[string]string{
"getBlock-hash": "The hash of the block",
"getBlock-verbose": "Specifies the block is returned as a JSON object instead of hex-encoded string",
"getBlock-verboseTx": "Specifies that each transaction is returned as a JSON object and only applies if the verbose flag is true (btcd extension)",
"getBlock-subnetwork": "If passed, the returned block will be a partial block of the specified subnetwork",
"getBlock--condition0": "verbose=false",
"getBlock--condition1": "verbose=true",
"getBlock-acceptedTx": "Specifies if the transaction got accepted",