Skip to content

Commit

Permalink
rpc: allow to getcontractstate by id or name
Browse files Browse the repository at this point in the history
close #1423
  • Loading branch information
AnnaShaleva committed Sep 25, 2020
1 parent e4d82f5 commit 86d5a92
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 5 deletions.
9 changes: 9 additions & 0 deletions pkg/core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,15 @@ func (bc *Blockchain) GetContractScriptHash(id int32) (util.Uint160, error) {
return bc.dao.GetContractScriptHash(id)
}

// GetNativeContractScriptHash returns native contract script hash by its name.
func (bc *Blockchain) GetNativeContractScriptHash(name string) (util.Uint160, error) {
c := bc.contracts.ByName(name)
if c != nil {
return c.Metadata().Hash, nil
}
return util.Uint160{}, errors.New("Unknown native contract")
}

// GetConfig returns the config stored in the blockchain.
func (bc *Blockchain) GetConfig() config.ProtocolConfiguration {
return bc.config
Expand Down
1 change: 1 addition & 0 deletions pkg/core/blockchainer/blockchainer.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type Blockchainer interface {
HasBlock(util.Uint256) bool
HasTransaction(util.Uint256) bool
GetAppExecResult(util.Uint256) (*state.AppExecResult, error)
GetNativeContractScriptHash(string) (util.Uint160, error)
GetNextBlockValidators() ([]*keys.PublicKey, error)
GetNEP5Balances(util.Uint160) *state.NEP5Balances
GetValidators() ([]*keys.PublicKey, error)
Expand Down
10 changes: 10 additions & 0 deletions pkg/core/native/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ func (cs *Contracts) ByHash(h util.Uint160) interop.Contract {
return nil
}

// ByName returns native contract with the specified name.
func (cs *Contracts) ByName(name string) interop.Contract {
for _, ctr := range cs.Contracts {
if ctr.Metadata().Name == name {
return ctr
}
}
return nil
}

// NewContracts returns new set of native contracts with new GAS, NEO and Policy
// contracts.
func NewContracts() *Contracts {
Expand Down
3 changes: 3 additions & 0 deletions pkg/network/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ func (chain testChain) GetContractState(hash util.Uint160) *state.Contract {
func (chain testChain) GetContractScriptHash(id int32) (util.Uint160, error) {
panic("TODO")
}
func (chain testChain) GetNativeContractScriptHash(name string) (util.Uint160, error) {
panic("TODO")
}
func (chain testChain) GetHeaderHash(int) util.Uint256 {
return util.Uint256{}
}
Expand Down
43 changes: 40 additions & 3 deletions pkg/rpc/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,42 @@ func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Err
return result, nil
}

// getContractHashFromParam returns the contract hash by hex contract hash, id or native contract name.
func (s *Server) contractHashFromParam(param *request.Param) (util.Uint160, *response.Error) {
var result util.Uint160
if param == nil {
return result, response.ErrInvalidParams
}
switch param.Type {
case request.StringT:
var err error
result, err = param.GetUint160FromHex()
if err == nil {
return result, nil
}
name, err := param.GetString()
if err != nil {
return result, response.ErrInvalidParams
}
result, err = s.chain.GetNativeContractScriptHash(name)
if err != nil {
return result, response.NewRPCError("Unknown contract: querying by name is supported for native contracts only", "", nil)
}
case request.NumberT:
id, err := param.GetInt()
if err != nil {
return result, response.ErrInvalidParams
}
result, err = s.chain.GetContractScriptHash(int32(id))
if err != nil {
return result, response.NewRPCError("Unknown contract", "", err)
}
default:
return result, response.ErrInvalidParams
}
return result, nil
}

func (s *Server) getStorage(ps request.Params) (interface{}, *response.Error) {
id, rErr := s.contractIDFromParam(ps.Value(0))
if rErr == response.ErrUnknown {
Expand Down Expand Up @@ -821,11 +857,12 @@ func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response
return height, nil
}

// getContractState returns contract state (contract information, according to the contract script hash).
// getContractState returns contract state (contract information, according to the contract script hash,
// contract id or native contract name).
func (s *Server) getContractState(reqParams request.Params) (interface{}, *response.Error) {
scriptHash, err := reqParams.ValueWithType(0, request.StringT).GetUint160FromHex()
scriptHash, err := s.contractHashFromParam(reqParams.Value(0))
if err != nil {
return nil, response.ErrInvalidParams
return nil, err
}
cs := s.chain.GetContractState(scriptHash)
if cs == nil {
Expand Down
45 changes: 43 additions & 2 deletions pkg/rpc/server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type rpcTestCase struct {
}

const testContractHash = "4546ec6fcdaa1c3ccdb048526b78624b457b60a4"
const testContractID = 0
const deploymentTxHash = "17be1bbb0fdecae18cd4c6a2db19311f47bd540371e2ea479a46b349a66aa0b3"

const verifyContractHash = "47ef649f9a77cad161ddaa28b39c7e450e5429e7"
Expand Down Expand Up @@ -94,7 +95,7 @@ var rpcTestCases = map[string][]rpcTestCase{
},
"getcontractstate": {
{
name: "positive",
name: "positive, by hash",
params: fmt.Sprintf(`["%s"]`, testContractHash),
result: func(e *executor) interface{} { return &state.Contract{} },
check: func(t *testing.T, e *executor, cs interface{}) {
Expand All @@ -104,10 +105,50 @@ var rpcTestCases = map[string][]rpcTestCase{
},
},
{
name: "negative",
name: "positive, by id",
params: `[0]`,
result: func(e *executor) interface{} { return &state.Contract{} },
check: func(t *testing.T, e *executor, cs interface{}) {
res, ok := cs.(*state.Contract)
require.True(t, ok)
assert.Equal(t, int32(0), res.ID)
},
},
{
name: "positive, native by id",
params: `[-3]`,
result: func(e *executor) interface{} { return &state.Contract{} },
check: func(t *testing.T, e *executor, cs interface{}) {
res, ok := cs.(*state.Contract)
require.True(t, ok)
assert.Equal(t, int32(-3), res.ID)
},
},
{
name: "positive, native by name",
params: `["Policy"]`,
result: func(e *executor) interface{} { return &state.Contract{} },
check: func(t *testing.T, e *executor, cs interface{}) {
res, ok := cs.(*state.Contract)
require.True(t, ok)
assert.Equal(t, int32(-3), res.ID)
},
},
{
name: "negative, bad hash",
params: `["6d1eeca891ee93de2b7a77eb91c26f3b3c04d6c3"]`,
fail: true,
},
{
name: "negative, bad ID",
params: `[-8]`,
fail: true,
},
{
name: "negative, bad native name",
params: `["unknown_native"]`,
fail: true,
},
{
name: "no params",
params: `[]`,
Expand Down

0 comments on commit 86d5a92

Please sign in to comment.