diff --git a/btcjson/dagsvrcmds.go b/btcjson/dagsvrcmds.go index 1d7676cc1..b3583a7b3 100644 --- a/btcjson/dagsvrcmds.go +++ b/btcjson/dagsvrcmds.go @@ -498,6 +498,19 @@ func NewGetRawTransactionCmd(txHash string, verbose *int) *GetRawTransactionCmd } } +// GetSubnetworkCmd defines the getSubnetwork JSON-RPC command. +type GetSubnetworkCmd struct { + SubnetworkID string +} + +// NewGetSubnetworkCmd returns a new instance which can be used to issue a +// getSubnetworkCmd command. +func NewGetSubnetworkCmd(subnetworkID string) *GetSubnetworkCmd { + return &GetSubnetworkCmd{ + SubnetworkID: subnetworkID, + } +} + // GetTxOutCmd defines the getTxOut JSON-RPC command. type GetTxOutCmd struct { TxID string @@ -792,6 +805,7 @@ func init() { MustRegisterCmd("getPeerInfo", (*GetPeerInfoCmd)(nil), flags) MustRegisterCmd("getRawMempool", (*GetRawMempoolCmd)(nil), flags) MustRegisterCmd("getRawTransaction", (*GetRawTransactionCmd)(nil), flags) + MustRegisterCmd("getSubnetwork", (*GetSubnetworkCmd)(nil), flags) MustRegisterCmd("getTxOut", (*GetTxOutCmd)(nil), flags) MustRegisterCmd("getTxOutProof", (*GetTxOutProofCmd)(nil), flags) MustRegisterCmd("getTxOutSetInfo", (*GetTxOutSetInfoCmd)(nil), flags) diff --git a/btcjson/dagsvrcmds_test.go b/btcjson/dagsvrcmds_test.go index e484c214f..5e591dd63 100644 --- a/btcjson/dagsvrcmds_test.go +++ b/btcjson/dagsvrcmds_test.go @@ -596,6 +596,19 @@ func TestDAGSvrCmds(t *testing.T) { Verbose: btcjson.Int(1), }, }, + { + name: "getSubnetwork", + newCmd: func() (interface{}, error) { + return btcjson.NewCmd("getSubnetwork", "123") + }, + staticCmd: func() interface{} { + return btcjson.NewGetSubnetworkCmd("123") + }, + marshalled: `{"jsonrpc":"1.0","method":"getSubnetwork","params":["123"],"id":1}`, + unmarshalled: &btcjson.GetSubnetworkCmd{ + SubnetworkID: "123", + }, + }, { name: "getTxOut", newCmd: func() (interface{}, error) { diff --git a/btcjson/dagsvrresults.go b/btcjson/dagsvrresults.go index 8859c20e4..8827c3c3f 100644 --- a/btcjson/dagsvrresults.go +++ b/btcjson/dagsvrresults.go @@ -276,6 +276,11 @@ type ScriptPubKeyResult struct { Addresses []string `json:"addresses,omitempty"` } +// GetSubnetworkResult models the data from the getSubnetwork command. +type GetSubnetworkResult struct { + GasLimit uint64 `json:"gasLimit"` +} + // GetTxOutResult models the data from the gettxout command. type GetTxOutResult struct { BestBlock string `json:"bestBlock"` diff --git a/btcjson/jsonrpcerr.go b/btcjson/jsonrpcerr.go index c9431c5a9..ae2b51de5 100644 --- a/btcjson/jsonrpcerr.go +++ b/btcjson/jsonrpcerr.go @@ -65,17 +65,18 @@ const ( // server are most likely to see. Generally, the codes should match one of the // more general errors above. const ( - ErrRPCBlockNotFound RPCErrorCode = -5 - ErrRPCBlockCount RPCErrorCode = -5 - ErrRPCBestBlockHash RPCErrorCode = -5 - ErrRPCDifficulty RPCErrorCode = -5 - ErrRPCOutOfRange RPCErrorCode = -1 - ErrRPCNoTxInfo RPCErrorCode = -5 - ErrRPCNoCFIndex RPCErrorCode = -5 - ErrRPCNoNewestBlockInfo RPCErrorCode = -5 - ErrRPCInvalidTxVout RPCErrorCode = -5 - ErrRPCRawTxString RPCErrorCode = -32602 - ErrRPCDecodeHexString RPCErrorCode = -22 + ErrRPCBlockNotFound RPCErrorCode = -5 + ErrRPCBlockCount RPCErrorCode = -5 + ErrRPCBestBlockHash RPCErrorCode = -5 + ErrRPCDifficulty RPCErrorCode = -5 + ErrRPCOutOfRange RPCErrorCode = -1 + ErrRPCNoTxInfo RPCErrorCode = -5 + ErrRPCNoCFIndex RPCErrorCode = -5 + ErrRPCNoNewestBlockInfo RPCErrorCode = -5 + ErrRPCInvalidTxVout RPCErrorCode = -5 + ErrRPCSubnetworkNotFound RPCErrorCode = -5 + ErrRPCRawTxString RPCErrorCode = -32602 + ErrRPCDecodeHexString RPCErrorCode = -22 ) // Errors that are specific to btcd. diff --git a/rpcclient/dag.go b/rpcclient/dag.go index 2e4bb5983..5ee9e5638 100644 --- a/rpcclient/dag.go +++ b/rpcclient/dag.go @@ -594,6 +594,41 @@ func (c *Client) EstimateFee(numBlocks int64) (float64, error) { return c.EstimateFeeAsync(numBlocks).Receive() } +// FutureGetSubnetworkResult is a future promise to deliver the result of a +// GetSubnetworkAsync RPC invocation (or an applicable error). +type FutureGetSubnetworkResult chan *response + +func (r FutureGetSubnetworkResult) Receive() (*btcjson.GetSubnetworkResult, error) { + res, err := receiveFuture(r) + if err != nil { + return nil, err + } + + // Unmarshal result as a getSubnetwork result object. + var getSubnetworkResult *btcjson.GetSubnetworkResult + err = json.Unmarshal(res, &getSubnetworkResult) + if err != nil { + return nil, err + } + + return getSubnetworkResult, nil +} + +// GetSubnetworkAsync returns an instance of a type that can be used to get the result +// of the RPC at some future time by invoking the Receive function on the +// returned instance. +// +// See GetSubnetwork for the blocking version and more details. +func (c *Client) GetSubnetworkAsync(subnetworkID string) FutureGetSubnetworkResult { + cmd := btcjson.NewGetSubnetworkCmd(subnetworkID) + return c.sendCmd(cmd) +} + +// GetSubnetwork provides information about a subnetwork given its ID. +func (c *Client) GetSubnetwork(subnetworkID string) (*btcjson.GetSubnetworkResult, error) { + return c.GetSubnetworkAsync(subnetworkID).Receive() +} + // FutureGetTxOutResult is a future promise to deliver the result of a // GetTxOutAsync RPC invocation (or an applicable error). type FutureGetTxOutResult chan *response diff --git a/server/rpc/rpcserver.go b/server/rpc/rpcserver.go index 3582a3f81..19ccb21cb 100644 --- a/server/rpc/rpcserver.go +++ b/server/rpc/rpcserver.go @@ -171,6 +171,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{ "getPeerInfo": handleGetPeerInfo, "getRawMempool": handleGetRawMempool, "getRawTransaction": handleGetRawTransaction, + "getSubnetwork": handleGetSubnetwork, "getTxOut": handleGetTxOut, "help": handleHelp, "node": handleNode, @@ -2665,6 +2666,29 @@ func handleGetRawTransaction(s *Server, cmd interface{}, closeChan <-chan struct return *rawTxn, nil } +// handleGetSubnetwork handles the getSubnetwork command. +func handleGetSubnetwork(s *Server, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { + c := cmd.(*btcjson.GetSubnetworkCmd) + + subnetworkID, err := subnetworkid.NewFromStr(c.SubnetworkID) + if err != nil { + return nil, rpcDecodeHexError(c.SubnetworkID) + } + + gasLimit, err := s.cfg.DAG.SubnetworkStore.GasLimit(subnetworkID) + if err != nil { + return nil, &btcjson.RPCError{ + Code: btcjson.ErrRPCSubnetworkNotFound, + Message: "Subnetwork not found.", + } + } + + subnetworkReply := &btcjson.GetSubnetworkResult{ + GasLimit: gasLimit, + } + return subnetworkReply, nil +} + // handleGetTxOut handles getTxOut commands. func handleGetTxOut(s *Server, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) { c := cmd.(*btcjson.GetTxOutCmd) diff --git a/server/rpc/rpcserverhelp.go b/server/rpc/rpcserverhelp.go index c98e88540..fcf2e88c5 100644 --- a/server/rpc/rpcserverhelp.go +++ b/server/rpc/rpcserverhelp.go @@ -507,6 +507,13 @@ var helpDescsEnUS = map[string]string{ "getRawTransaction--condition1": "verbose=true", "getRawTransaction--result0": "Hex-encoded bytes of the serialized transaction", + // GetSubnetworkCmd help. + "getSubnetwork--synopsis": "Returns information about a subnetwork given its ID.", + "getSubnetwork-subnetworkId": "The ID of the subnetwork", + + // GetSubnetworkResult help. + "getSubnetworkResult-gasLimit": "The gas limit of the subnetwork", + // GetTxOutResult help. "getTxOutResult-bestBlock": "The block hash that contains the transaction output", "getTxOutResult-confirmations": "The number of confirmations (Will be 'null' if txindex is not disabled)", @@ -698,6 +705,7 @@ var rpcResultTypes = map[string][]interface{}{ "getPeerInfo": {(*[]btcjson.GetPeerInfoResult)(nil)}, "getRawMempool": {(*[]string)(nil), (*btcjson.GetRawMempoolVerboseResult)(nil)}, "getRawTransaction": {(*string)(nil), (*btcjson.TxRawResult)(nil)}, + "getSubnetwork": {(*btcjson.GetSubnetworkResult)(nil)}, "getTxOut": {(*btcjson.GetTxOutResult)(nil)}, "node": nil, "help": {(*string)(nil), (*string)(nil)},