diff --git a/pkg/rpc/prometheus.go b/pkg/rpc/prometheus.go index 686d09853..dd17124c4 100644 --- a/pkg/rpc/prometheus.go +++ b/pkg/rpc/prometheus.go @@ -44,6 +44,14 @@ var ( }, ) + getcontractstateCalled = prometheus.NewCounter( + prometheus.CounterOpts{ + Help: "Number of calls to getcontractstate rpc endpoint", + Name: "getcontractstate_called", + Namespace: "neogo", + }, + ) + getversionCalled = prometheus.NewCounter( prometheus.CounterOpts{ Help: "Number of calls to getversion rpc endpoint", @@ -124,6 +132,7 @@ func init() { getblockcountCalled, getblockHashCalled, getconnectioncountCalled, + getcontractstateCalled, getversionCalled, getpeersCalled, validateaddressCalled, diff --git a/pkg/rpc/server.go b/pkg/rpc/server.go index 27616b5ce..cc0d5217f 100644 --- a/pkg/rpc/server.go +++ b/pkg/rpc/server.go @@ -241,6 +241,10 @@ Methods: getaccountstateCalled.Inc() results, resultsErr = s.getAccountState(reqParams, false) + case "getcontractstate": + getcontractstateCalled.Inc() + results, resultsErr = s.getContractState(reqParams) + case "getrawtransaction": getrawtransactionCalled.Inc() results, resultsErr = s.getrawtransaction(reqParams) @@ -349,6 +353,26 @@ func (s *Server) getTxOut(ps Params) (interface{}, error) { return wrappers.NewTxOutput(&out), nil } +// getContractState returns contract state (contract information, according to the contract script hash). +func (s *Server) getContractState(reqParams Params) (interface{}, error) { + var results interface{} + + param, ok := reqParams.ValueWithType(0, stringT) + if !ok { + return nil, errInvalidParams + } else if scriptHash, err := param.GetUint160FromHex(); err != nil { + return nil, errInvalidParams + } else { + cs := s.chain.GetContractState(scriptHash) + if cs != nil { + results = wrappers.NewContractState(cs) + } else { + return nil, NewRPCError("Unknown contract", "", nil) + } + } + return results, nil +} + // getAccountState returns account state either in short or full (unspents included) form. func (s *Server) getAccountState(reqParams Params, unspents bool) (interface{}, error) { var resultsErr error diff --git a/pkg/rpc/wrappers/contract_state.go b/pkg/rpc/wrappers/contract_state.go new file mode 100644 index 000000000..ca1b11716 --- /dev/null +++ b/pkg/rpc/wrappers/contract_state.go @@ -0,0 +1,56 @@ +package wrappers + +import ( + "github.com/CityOfZion/neo-go/pkg/core/state" + "github.com/CityOfZion/neo-go/pkg/smartcontract" + "github.com/CityOfZion/neo-go/pkg/util" +) + +// ContractState wrapper used for the representation of +// state.Contract on the RPC Server. +type ContractState struct { + Version byte `json:"version"` + ScriptHash util.Uint160 `json:"hash"` + Script []byte `json:"script"` + ParamList []smartcontract.ParamType `json:"parameters"` + ReturnType smartcontract.ParamType `json:"returntype"` + Name string `json:"name"` + CodeVersion string `json:"code_version"` + Author string `json:"author"` + Email string `json:"email"` + Description string `json:"description"` + Properties Properties `json:"properties"` +} + +// Properties response wrapper. +type Properties struct { + HasStorage bool `json:"storage"` + HasDynamicInvoke bool `json:"dynamic_invoke"` + IsPayable bool `json:"is_payable"` +} + +// NewContractState creates a new Contract wrapper. +func NewContractState(c *state.Contract) ContractState { + // reverse scriptHash to be consistent with other client + scriptHash := c.ScriptHash().Reverse() + + properties := Properties{ + HasStorage: c.HasStorage(), + HasDynamicInvoke: c.HasDynamicInvoke(), + IsPayable: c.IsPayable(), + } + + return ContractState{ + Version: 0, + ScriptHash: scriptHash, + Script: c.Script, + ParamList: c.ParamList, + ReturnType: c.ReturnType, + Properties: properties, + Name: c.Name, + CodeVersion: c.CodeVersion, + Author: c.Author, + Email: c.Email, + Description: c.Description, + } +}