commit
4afdb9fd89
8 changed files with 134 additions and 5 deletions
|
@ -167,7 +167,7 @@ func queryCandidates(ctx *cli.Context) error {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
vals, err := c.GetNextBlockValidators()
|
vals, err := c.GetCandidates()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ which would yield the response:
|
||||||
| `getblockhash` |
|
| `getblockhash` |
|
||||||
| `getblockheader` |
|
| `getblockheader` |
|
||||||
| `getblockheadercount` |
|
| `getblockheadercount` |
|
||||||
|
| `getcandidates` |
|
||||||
| `getcommittee` |
|
| `getcommittee` |
|
||||||
| `getconnectioncount` |
|
| `getconnectioncount` |
|
||||||
| `getcontractstate` |
|
| `getcontractstate` |
|
||||||
|
|
|
@ -557,7 +557,20 @@ func (c *Client) GetUnclaimedGas(address string) (result.UnclaimedGas, error) {
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNextBlockValidators returns the current NEO consensus nodes information and voting status.
|
// GetCandidates returns the current list of NEO candidate node with voting data and
|
||||||
|
// validator status.
|
||||||
|
func (c *Client) GetCandidates() ([]result.Candidate, error) {
|
||||||
|
var (
|
||||||
|
params = request.NewRawParams()
|
||||||
|
resp = new([]result.Candidate)
|
||||||
|
)
|
||||||
|
if err := c.performRequest("getcandidates", params, resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return *resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNextBlockValidators returns the current NEO consensus nodes information and voting data.
|
||||||
func (c *Client) GetNextBlockValidators() ([]result.Validator, error) {
|
func (c *Client) GetNextBlockValidators() ([]result.Validator, error) {
|
||||||
var (
|
var (
|
||||||
params = request.NewRawParams()
|
params = request.NewRawParams()
|
||||||
|
|
|
@ -940,6 +940,21 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"getcandidates": {
|
||||||
|
{
|
||||||
|
name: "positive",
|
||||||
|
invoke: func(c *Client) (interface{}, error) {
|
||||||
|
return c.GetCandidates()
|
||||||
|
},
|
||||||
|
serverResponse: `{"id":1,"jsonrpc":"2.0","result":[{"publickey":"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2","votes":"0","active":true},{"publickey":"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e","votes":"0","active":true},{"publickey":"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699","votes":"0","active":true},{"publickey":"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62","votes":"0","active":true}]}`,
|
||||||
|
result: func(c *Client) interface{} { return []result.Candidate{} },
|
||||||
|
check: func(t *testing.T, c *Client, uns interface{}) {
|
||||||
|
res, ok := uns.([]result.Candidate)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.Equal(t, 4, len(res))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"getvalidators": {
|
"getvalidators": {
|
||||||
{
|
{
|
||||||
name: "positive",
|
name: "positive",
|
||||||
|
@ -1657,6 +1672,12 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
|
||||||
return c.GetUnclaimedGas("")
|
return c.GetUnclaimedGas("")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "getcandidates_unmarshalling_error",
|
||||||
|
invoke: func(c *Client) (interface{}, error) {
|
||||||
|
return c.GetCandidates()
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "getvalidators_unmarshalling_error",
|
name: "getvalidators_unmarshalling_error",
|
||||||
invoke: func(c *Client) (interface{}, error) {
|
invoke: func(c *Client) (interface{}, error) {
|
||||||
|
|
|
@ -1,13 +1,51 @@
|
||||||
package result
|
package result
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Validator used for the representation of
|
// Validator is used for the representation of consensus node data in the JSON-RPC
|
||||||
// state.Validator on the RPC Server.
|
// protocol.
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
|
PublicKey keys.PublicKey `json:"publickey"`
|
||||||
|
Votes int64 `json:"votes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Candidate represents a node participating in the governance elections, it's
|
||||||
|
// active when it's a validator (consensus node).
|
||||||
|
type Candidate struct {
|
||||||
PublicKey keys.PublicKey `json:"publickey"`
|
PublicKey keys.PublicKey `json:"publickey"`
|
||||||
Votes int64 `json:"votes,string"`
|
Votes int64 `json:"votes,string"`
|
||||||
Active bool `json:"active"`
|
Active bool `json:"active"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type newValidator struct {
|
||||||
|
PublicKey keys.PublicKey `json:"publickey"`
|
||||||
|
Votes int64 `json:"votes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type oldValidator struct {
|
||||||
|
PublicKey keys.PublicKey `json:"publickey"`
|
||||||
|
Votes int64 `json:"votes,string"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
|
func (v *Validator) UnmarshalJSON(data []byte) error {
|
||||||
|
var nv = new(newValidator)
|
||||||
|
err := json.Unmarshal(data, nv)
|
||||||
|
if err != nil {
|
||||||
|
var ov = new(oldValidator)
|
||||||
|
err := json.Unmarshal(data, ov)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.PublicKey = ov.PublicKey
|
||||||
|
v.Votes = ov.Votes
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
v.PublicKey = nv.PublicKey
|
||||||
|
v.Votes = nv.Votes
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
22
pkg/rpc/response/result/validator_test.go
Normal file
22
pkg/rpc/response/result/validator_test.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package result
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidatorUnmarshal(t *testing.T) {
|
||||||
|
old := []byte(`{"publickey":"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62","votes":"100500","active":true}`)
|
||||||
|
v := new(Validator)
|
||||||
|
require.NoError(t, json.Unmarshal(old, v))
|
||||||
|
require.Equal(t, int64(100500), v.Votes)
|
||||||
|
|
||||||
|
new := []byte(`{"publickey":"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62","votes":42}`)
|
||||||
|
require.NoError(t, json.Unmarshal(new, v))
|
||||||
|
require.Equal(t, int64(42), v.Votes)
|
||||||
|
|
||||||
|
bad := []byte(`{"publickey":"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62","votes":"notanumber"}`)
|
||||||
|
require.Error(t, json.Unmarshal(bad, v))
|
||||||
|
}
|
|
@ -118,6 +118,7 @@ var rpcHandlers = map[string]func(*Server, request.Params) (interface{}, *respon
|
||||||
"getblockheader": (*Server).getBlockHeader,
|
"getblockheader": (*Server).getBlockHeader,
|
||||||
"getblockheadercount": (*Server).getBlockHeaderCount,
|
"getblockheadercount": (*Server).getBlockHeaderCount,
|
||||||
"getblocksysfee": (*Server).getBlockSysFee,
|
"getblocksysfee": (*Server).getBlockSysFee,
|
||||||
|
"getcandidates": (*Server).getCandidates,
|
||||||
"getcommittee": (*Server).getCommittee,
|
"getcommittee": (*Server).getCommittee,
|
||||||
"getconnectioncount": (*Server).getConnectionCount,
|
"getconnectioncount": (*Server).getConnectionCount,
|
||||||
"getcontractstate": (*Server).getContractState,
|
"getcontractstate": (*Server).getContractState,
|
||||||
|
@ -1538,6 +1539,29 @@ func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Erro
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getCandidates returns the current list of candidates with their active/inactive voting status.
|
||||||
|
func (s *Server) getCandidates(_ request.Params) (interface{}, *response.Error) {
|
||||||
|
var validators keys.PublicKeys
|
||||||
|
|
||||||
|
validators, err := s.chain.GetNextBlockValidators()
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.NewRPCError("Can't get next block validators", err.Error())
|
||||||
|
}
|
||||||
|
enrollments, err := s.chain.GetEnrollments()
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.NewRPCError("Can't get enrollments", err.Error())
|
||||||
|
}
|
||||||
|
var res = make([]result.Candidate, 0)
|
||||||
|
for _, v := range enrollments {
|
||||||
|
res = append(res, result.Candidate{
|
||||||
|
PublicKey: *v.Key,
|
||||||
|
Votes: v.Votes.Int64(),
|
||||||
|
Active: validators.Contains(v.Key),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
// getNextBlockValidators returns validators for the next block with voting status.
|
// getNextBlockValidators returns validators for the next block with voting status.
|
||||||
func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *response.Error) {
|
func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *response.Error) {
|
||||||
var validators keys.PublicKeys
|
var validators keys.PublicKeys
|
||||||
|
@ -1552,10 +1576,12 @@ func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *respons
|
||||||
}
|
}
|
||||||
var res = make([]result.Validator, 0)
|
var res = make([]result.Validator, 0)
|
||||||
for _, v := range enrollments {
|
for _, v := range enrollments {
|
||||||
|
if !validators.Contains(v.Key) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
res = append(res, result.Validator{
|
res = append(res, result.Validator{
|
||||||
PublicKey: *v.Key,
|
PublicKey: *v.Key,
|
||||||
Votes: v.Votes.Int64(),
|
Votes: v.Votes.Int64(),
|
||||||
Active: validators.Contains(v.Key),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
|
@ -818,6 +818,14 @@ var rpcTestCases = map[string][]rpcTestCase{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"getcandidates": {
|
||||||
|
{
|
||||||
|
params: "[]",
|
||||||
|
result: func(*executor) interface{} {
|
||||||
|
return &[]result.Candidate{}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"getnextblockvalidators": {
|
"getnextblockvalidators": {
|
||||||
{
|
{
|
||||||
params: "[]",
|
params: "[]",
|
||||||
|
|
Loading…
Reference in a new issue