diff --git a/pkg/rpc/client/doc.go b/pkg/rpc/client/doc.go index 5ad1eac12..45c23706c 100644 --- a/pkg/rpc/client/doc.go +++ b/pkg/rpc/client/doc.go @@ -18,6 +18,7 @@ TODO: Supported methods calculatenetworkfee + findstates getapplicationlog getbestblockhash getblock @@ -37,7 +38,9 @@ Supported methods getpeers getrawmempool getrawtransaction + getstate getstateheight + getstateroot getstorage gettransactionheight getunclaimedgas diff --git a/pkg/rpc/client/rpc.go b/pkg/rpc/client/rpc.go index 2f43dd8e4..086876070 100644 --- a/pkg/rpc/client/rpc.go +++ b/pkg/rpc/client/rpc.go @@ -458,10 +458,19 @@ func (c *Client) GetState(stateroot util.Uint256, historicalContractHash util.Ui // If `maxCount` specified, then maximum number of items to be returned equals to `maxCount`. func (c *Client) FindStates(stateroot util.Uint256, historicalContractHash util.Uint160, historicalPrefix []byte, start []byte, maxCount *int) (result.FindStates, error) { + if historicalPrefix == nil { + historicalPrefix = []byte{} + } var ( - params = request.NewRawParams(stateroot.StringLE(), historicalContractHash.StringLE(), historicalPrefix, historicalPrefix, start) + params = request.NewRawParams(stateroot.StringLE(), historicalContractHash.StringLE(), historicalPrefix) resp result.FindStates ) + if start == nil && maxCount != nil { + start = []byte{} + } + if start != nil { + params.Values = append(params.Values, start) + } if maxCount != nil { params.Values = append(params.Values, *maxCount) } @@ -471,6 +480,24 @@ func (c *Client) FindStates(stateroot util.Uint256, historicalContractHash util. return resp, nil } +// GetStateRootByHeight returns state root for the specified height. +func (c *Client) GetStateRootByHeight(height uint32) (*state.MPTRoot, error) { + return c.getStateRoot(request.NewRawParams(height)) +} + +// GetStateRootByBlockHash returns state root for block with specified hash. +func (c *Client) GetStateRootByBlockHash(hash util.Uint256) (*state.MPTRoot, error) { + return c.getStateRoot(request.NewRawParams(hash)) +} + +func (c *Client) getStateRoot(params request.RawParams) (*state.MPTRoot, error) { + var resp = new(state.MPTRoot) + if err := c.performRequest("getstateroot", params, resp); err != nil { + return nil, err + } + return resp, nil +} + // GetStateHeight returns current validated and local node state height. func (c *Client) GetStateHeight() (*result.StateHeight, error) { var ( diff --git a/pkg/rpc/client/rpc_test.go b/pkg/rpc/client/rpc_test.go index c4041c353..51c008785 100644 --- a/pkg/rpc/client/rpc_test.go +++ b/pkg/rpc/client/rpc_test.go @@ -769,6 +769,47 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ }, }, }, + "getstateroot": { + { + name: "positive, by height", + invoke: func(c *Client) (interface{}, error) { + return c.GetStateRootByHeight(5) + }, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"version":0,"index":5,"roothash":"0x65d19151694321e70c6d184b37a2bcf7af4a2c60c099af332a4f7815e3670686","witnesses":[]}}`, + result: func(c *Client) interface{} { + h, err := util.Uint256DecodeStringLE("65d19151694321e70c6d184b37a2bcf7af4a2c60c099af332a4f7815e3670686") + if err != nil { + panic(err) + } + return &state.MPTRoot{ + Version: 0, + Index: 5, + Root: h, + Witness: []transaction.Witness{}, + } + }, + }, + { + name: "positive, by hash", + invoke: func(c *Client) (interface{}, error) { + hash, err := util.Uint256DecodeStringLE("86fe1061140b2ea791b0739fb9732abc6e5e47de4927228a1ac41de3d93eb7cb") + if err != nil { + panic(err) + } + return c.GetStateRootByBlockHash(hash) + }, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"version":0,"index":5,"roothash":"0x65d19151694321e70c6d184b37a2bcf7af4a2c60c099af332a4f7815e3670686","witnesses":[]}}`, + result: func(c *Client) interface{} { + h, _ := util.Uint256DecodeStringLE("65d19151694321e70c6d184b37a2bcf7af4a2c60c099af332a4f7815e3670686") + return &state.MPTRoot{ + Version: 0, + Index: 5, + Root: h, + Witness: []transaction.Witness{}, + } + }, + }, + }, "getstate": { { name: "positive", diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 6ea513586..cd5f25763 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -1235,11 +1235,11 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) { } csHash, err := ps.Value(1).GetUint160FromHex() if err != nil { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, errors.New("invalid contract hash")) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Errorf("invalid contract hash: %w", err)) } prefix, err := ps.Value(2).GetBytesBase64() if err != nil { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, errors.New("invalid prefix")) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Errorf("invalid prefix: %w", err)) } var ( key []byte @@ -1248,7 +1248,7 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) { if len(ps) > 3 { key, err = ps.Value(3).GetBytesBase64() if err != nil { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, errors.New("invalid key")) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Errorf("invalid key: %w", err)) } if len(key) > 0 { if !bytes.HasPrefix(key, prefix) { @@ -1263,7 +1263,7 @@ func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) { if len(ps) > 4 { count, err = ps.Value(4).GetInt() if err != nil { - return nil, response.WrapErrorWithData(response.ErrInvalidParams, errors.New("invalid count")) + return nil, response.WrapErrorWithData(response.ErrInvalidParams, fmt.Errorf("invalid count: %w", err)) } if count > s.config.MaxFindResultItems { count = s.config.MaxFindResultItems