mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-29 23:33:37 +00:00
Merge pull request #2090 from nspcc-dev/new-query-commands
New query commands
This commit is contained in:
commit
6e2eddbeb9
11 changed files with 330 additions and 85 deletions
|
@ -15,6 +15,8 @@ import (
|
|||
func TestRegisterCandidate(t *testing.T) {
|
||||
e := newExecutor(t, true)
|
||||
|
||||
validatorHex := hex.EncodeToString(validatorPriv.PublicKey().Bytes())
|
||||
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
|
@ -24,6 +26,15 @@ func TestRegisterCandidate(t *testing.T) {
|
|||
"GAS:"+validatorPriv.Address()+":10000")
|
||||
e.checkTxPersisted(t)
|
||||
|
||||
e.Run(t, "neo-go", "query", "committee",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr)
|
||||
e.checkNextLine(t, "^\\s*"+validatorHex)
|
||||
|
||||
e.Run(t, "neo-go", "query", "candidates",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr)
|
||||
e.checkNextLine(t, "^\\s*Key.+$") // Header.
|
||||
e.checkEOF(t)
|
||||
|
||||
// missing address
|
||||
e.RunWithError(t, "neo-go", "wallet", "candidate", "register",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
|
@ -48,7 +59,7 @@ func TestRegisterCandidate(t *testing.T) {
|
|||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--wallet", validatorWallet,
|
||||
"--address", validatorPriv.Address(),
|
||||
"--candidate", hex.EncodeToString(validatorPriv.PublicKey().Bytes()))
|
||||
"--candidate", validatorHex)
|
||||
_, index := e.checkTxPersisted(t)
|
||||
|
||||
vs, err = e.Chain.GetEnrollments()
|
||||
|
@ -57,11 +68,21 @@ func TestRegisterCandidate(t *testing.T) {
|
|||
b, _ := e.Chain.GetGoverningTokenBalance(validatorPriv.GetScriptHash())
|
||||
require.Equal(t, b, vs[0].Votes)
|
||||
|
||||
e.Run(t, "neo-go", "query", "committee",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr)
|
||||
e.checkNextLine(t, "^\\s*"+validatorHex)
|
||||
|
||||
e.Run(t, "neo-go", "query", "candidates",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr)
|
||||
e.checkNextLine(t, "^\\s*Key.+$") // Header.
|
||||
e.checkNextLine(t, "^\\s*"+validatorHex+"\\s*"+b.String()+"\\s*true\\s*true$")
|
||||
e.checkEOF(t)
|
||||
|
||||
// check state
|
||||
e.Run(t, "neo-go", "wallet", "candidate", "getstate",
|
||||
e.Run(t, "neo-go", "query", "voter",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--address", validatorPriv.Address())
|
||||
e.checkNextLine(t, "^\\s*Voted:\\s+"+validatorPriv.Address())
|
||||
validatorPriv.Address())
|
||||
e.checkNextLine(t, "^\\s*Voted:\\s+"+validatorHex+"\\s+\\("+validatorPriv.Address()+"\\)$")
|
||||
e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$")
|
||||
e.checkNextLine(t, "^\\s*Block\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
|
||||
e.checkEOF(t)
|
||||
|
@ -80,9 +101,9 @@ func TestRegisterCandidate(t *testing.T) {
|
|||
require.Equal(t, big.NewInt(0), vs[0].Votes)
|
||||
|
||||
// check state
|
||||
e.Run(t, "neo-go", "wallet", "candidate", "getstate",
|
||||
e.Run(t, "neo-go", "query", "voter",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--address", validatorPriv.Address())
|
||||
validatorPriv.Address())
|
||||
e.checkNextLine(t, "^\\s*Voted:\\s+"+"null") // no vote.
|
||||
e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$")
|
||||
e.checkNextLine(t, "^\\s*Block\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
|
||||
|
@ -104,6 +125,6 @@ func TestRegisterCandidate(t *testing.T) {
|
|||
vs, err = e.Chain.GetEnrollments()
|
||||
require.Equal(t, 0, len(vs))
|
||||
|
||||
// getstate: missing address
|
||||
e.RunWithError(t, "neo-go", "wallet", "candidate", "getstate")
|
||||
// query voter: missing address
|
||||
e.RunWithError(t, "neo-go", "query", "voter")
|
||||
}
|
||||
|
|
|
@ -3,17 +3,24 @@ package query
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||
"github.com/nspcc-dev/neo-go/cli/options"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
|
@ -29,12 +36,36 @@ func NewCommands() []cli.Command {
|
|||
Name: "query",
|
||||
Usage: "Query data from RPC node",
|
||||
Subcommands: []cli.Command{
|
||||
{
|
||||
Name: "candidates",
|
||||
Usage: "Get candidates and votes",
|
||||
Action: queryCandidates,
|
||||
Flags: options.RPC,
|
||||
},
|
||||
{
|
||||
Name: "committee",
|
||||
Usage: "Get committee list",
|
||||
Action: queryCommittee,
|
||||
Flags: options.RPC,
|
||||
},
|
||||
{
|
||||
Name: "height",
|
||||
Usage: "Get node height",
|
||||
Action: queryHeight,
|
||||
Flags: options.RPC,
|
||||
},
|
||||
{
|
||||
Name: "tx",
|
||||
Usage: "Query transaction status",
|
||||
Action: queryTx,
|
||||
Flags: queryTxFlags,
|
||||
},
|
||||
{
|
||||
Name: "voter",
|
||||
Usage: "Print NEO holder account state",
|
||||
Action: queryVoter,
|
||||
Flags: options.RPC,
|
||||
},
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
@ -113,3 +144,150 @@ func dumpApplicationLog(ctx *cli.Context, res *result.ApplicationLog, tx *result
|
|||
_ = tw.Flush()
|
||||
fmt.Fprint(ctx.App.Writer, buf.String())
|
||||
}
|
||||
|
||||
func queryCandidates(ctx *cli.Context) error {
|
||||
var err error
|
||||
|
||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
vals, err := c.GetNextBlockValidators()
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
comm, err := c.GetCommittee()
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
sort.Slice(vals, func(i, j int) bool {
|
||||
if vals[i].Active != vals[j].Active {
|
||||
return vals[i].Active
|
||||
}
|
||||
if vals[i].Votes != vals[j].Votes {
|
||||
return vals[i].Votes > vals[j].Votes
|
||||
}
|
||||
return vals[i].PublicKey.Cmp(&vals[j].PublicKey) == -1
|
||||
})
|
||||
buf := bytes.NewBuffer(nil)
|
||||
tw := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0)
|
||||
_, _ = tw.Write([]byte("Key\tVotes\tCommittee\tConsensus\n"))
|
||||
for _, val := range vals {
|
||||
_, _ = tw.Write([]byte(fmt.Sprintf("%s\t%d\t%t\t%t\n", hex.EncodeToString(val.PublicKey.Bytes()), val.Votes, comm.Contains(&val.PublicKey), val.Active)))
|
||||
}
|
||||
_ = tw.Flush()
|
||||
fmt.Fprint(ctx.App.Writer, buf.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func queryCommittee(ctx *cli.Context) error {
|
||||
var err error
|
||||
|
||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
comm, err := c.GetCommittee()
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
for _, k := range comm {
|
||||
fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(k.Bytes()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func queryHeight(ctx *cli.Context) error {
|
||||
var err error
|
||||
|
||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
blockCount, err := c.GetBlockCount()
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
blockHeight := blockCount - 1 // GetBlockCount returns block count (including 0), not the highest block index.
|
||||
|
||||
fmt.Fprintf(ctx.App.Writer, "Latest block: %d\n", blockHeight)
|
||||
|
||||
stateHeight, err := c.GetStateHeight()
|
||||
if err == nil { // We can be talking to a node without getstateheight request support.
|
||||
fmt.Fprintf(ctx.App.Writer, "Validated state: %d\n", stateHeight.Validated)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func queryVoter(ctx *cli.Context) error {
|
||||
args := ctx.Args()
|
||||
if len(args) == 0 {
|
||||
return cli.NewExitError("No address specified", 1)
|
||||
}
|
||||
|
||||
addr, err := flags.ParseAddress(args[0])
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Sprintf("wrong address: %s", args[0]), 1)
|
||||
}
|
||||
|
||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
c, exitErr := options.GetRPCClient(gctx, ctx)
|
||||
if exitErr != nil {
|
||||
return exitErr
|
||||
}
|
||||
|
||||
neoHash, err := c.GetNativeContractHash(nativenames.Neo)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to get NEO contract hash: %w", err), 1)
|
||||
}
|
||||
res, err := c.InvokeFunction(neoHash, "getAccountState", []smartcontract.Parameter{
|
||||
{
|
||||
Type: smartcontract.Hash160Type,
|
||||
Value: addr,
|
||||
},
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
if res.State != "HALT" {
|
||||
return cli.NewExitError(fmt.Errorf("invocation failed: %s", res.FaultException), 1)
|
||||
}
|
||||
if len(res.Stack) == 0 {
|
||||
return cli.NewExitError("result stack is empty", 1)
|
||||
}
|
||||
st := new(state.NEOBalance)
|
||||
if _, ok := res.Stack[0].(stackitem.Null); !ok {
|
||||
err = st.FromStackItem(res.Stack[0])
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to convert account state from stackitem: %w", err), 1)
|
||||
}
|
||||
}
|
||||
dec, err := c.NEP17Decimals(neoHash)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to get decimals: %w", err), 1)
|
||||
}
|
||||
voted := "null"
|
||||
if st.VoteTo != nil {
|
||||
voted = fmt.Sprintf("%s (%s)", hex.EncodeToString(st.VoteTo.Bytes()), address.Uint160ToString(st.VoteTo.GetScriptHash()))
|
||||
}
|
||||
fmt.Fprintf(ctx.App.Writer, "\tVoted: %s\n", voted)
|
||||
fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", fixedn.ToString(&st.Balance, int(dec)))
|
||||
fmt.Fprintf(ctx.App.Writer, "\tBlock: %d\n", st.BalanceHeight)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -130,3 +130,12 @@ func (e *executor) compareQueryTxVerbose(t *testing.T, tx *transaction.Transacti
|
|||
}
|
||||
e.checkEOF(t)
|
||||
}
|
||||
|
||||
func TestQueryHeight(t *testing.T) {
|
||||
e := newExecutor(t, true)
|
||||
|
||||
e.Run(t, "neo-go", "query", "height", "--rpc-endpoint", "http://"+e.RPC.Addr)
|
||||
e.checkNextLine(t, `^Latest block: [0-9]+$`)
|
||||
e.checkNextLine(t, `^Validated state: [0-9]+$`)
|
||||
e.checkEOF(t)
|
||||
}
|
||||
|
|
|
@ -7,14 +7,11 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/cli/input"
|
||||
"github.com/nspcc-dev/neo-go/cli/options"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpc/client"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
|
@ -74,18 +71,6 @@ func newValidatorCommands() []cli.Command {
|
|||
},
|
||||
}, options.RPC...),
|
||||
},
|
||||
{
|
||||
Name: "getstate",
|
||||
Usage: "print NEO holder account state",
|
||||
UsageText: "getstate -a <addr>",
|
||||
Action: getAccountState,
|
||||
Flags: append([]cli.Flag{
|
||||
flags.AddressFlag{
|
||||
Name: "address, a",
|
||||
Usage: "Address to get state of",
|
||||
},
|
||||
}, options.RPC...),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,54 +212,3 @@ func getDecryptedAccount(ctx *cli.Context, wall *wallet.Wallet, addr util.Uint16
|
|||
}
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
func getAccountState(ctx *cli.Context) error {
|
||||
addrFlag := ctx.Generic("address").(*flags.Address)
|
||||
if !addrFlag.IsSet {
|
||||
return cli.NewExitError("address was not provided", 1)
|
||||
}
|
||||
|
||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
c, exitErr := options.GetRPCClient(gctx, ctx)
|
||||
if exitErr != nil {
|
||||
return exitErr
|
||||
}
|
||||
|
||||
neoHash, err := c.GetNativeContractHash(nativenames.Neo)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to get NEO contract hash: %w", err), 1)
|
||||
}
|
||||
res, err := c.InvokeFunction(neoHash, "getAccountState", []smartcontract.Parameter{
|
||||
{
|
||||
Type: smartcontract.Hash160Type,
|
||||
Value: addrFlag.Uint160(),
|
||||
},
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
if res.State != "HALT" {
|
||||
return cli.NewExitError(fmt.Errorf("invocation failed: %s", res.FaultException), 1)
|
||||
}
|
||||
if len(res.Stack) == 0 {
|
||||
return cli.NewExitError("result stack is empty", 1)
|
||||
}
|
||||
st := new(state.NEOBalance)
|
||||
err = st.FromStackItem(res.Stack[0])
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to convert account state from stackitem: %w", err), 1)
|
||||
}
|
||||
dec, err := c.NEP17Decimals(neoHash)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to get decimals: %w", err), 1)
|
||||
}
|
||||
voted := "null"
|
||||
if st.VoteTo != nil {
|
||||
voted = address.Uint160ToString(st.VoteTo.GetScriptHash())
|
||||
}
|
||||
fmt.Fprintf(ctx.App.Writer, "\tVoted: %s\n", voted)
|
||||
fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", fixedn.ToString(&st.Balance, int(dec)))
|
||||
fmt.Fprintf(ctx.App.Writer, "\tBlock: %d\n", st.BalanceHeight)
|
||||
return nil
|
||||
}
|
||||
|
|
78
docs/cli.md
78
docs/cli.md
|
@ -464,7 +464,17 @@ You can also vote for candidates if you own NEO:
|
|||
./bin/neo-go wallet candidate vote -a NMe64G6j6nkPZby26JAgpaCNrn1Ee4wW6E -w wallet.json -r http://localhost:20332 -c 03cecd63d7d8120c3b194c3b2880dd4aafe1475c57e40c852872d7305615258140
|
||||
```
|
||||
|
||||
### Querying transaction status
|
||||
### Getting data from chain
|
||||
|
||||
#### Node height/validated height
|
||||
`query height` returns the latest block and validated state height:
|
||||
```
|
||||
$ ./bin/neo-go query height -r http://localhost:20332
|
||||
Latest block: 11926
|
||||
Validated state: 11926
|
||||
```
|
||||
|
||||
#### Transaction status
|
||||
`query tx` provides convenient wrapper over RPC calls to query transaction status.
|
||||
```
|
||||
./bin/neo-go query tx --rpc-endpoint http://localhost:20332 aaf87628851e0c03ee086ff88596bc24de87082e9e5c73d75bb1c740d1d68088
|
||||
|
@ -476,6 +486,72 @@ Success: true
|
|||
`OnChain` is true if transaction was included in block and `Success` is true
|
||||
if it was executed successfully.
|
||||
|
||||
#### Committee members
|
||||
`query commitee` returns a list of current committee members:
|
||||
```
|
||||
$ ./bin/neo-go query committee -r http://localhost:20332
|
||||
03009b7540e10f2562e5fd8fac9eaec25166a58b26e412348ff5a86927bfac22a2
|
||||
030205e9cefaea5a1dfc580af20c8d5aa2468bb0148f1a5e4605fc622c80e604ba
|
||||
0207da870cedb777fceff948641021714ec815110ca111ccc7a54c168e065bda70
|
||||
02147c1b1d5728e1954958daff2f88ee2fa50a06890a8a9db3fa9e972b66ae559f
|
||||
0214baf0ceea3a66f17e7e1e839ea25fd8bed6cd82e6bb6e68250189065f44ff01
|
||||
03184b018d6b2bc093e535519732b3fd3f7551c8cffaf4621dd5a0b89482ca66c9
|
||||
0231edee3978d46c335e851c76059166eb8878516f459e085c0dd092f0f1d51c21
|
||||
023e9b32ea89b94d066e649b124fd50e396ee91369e8e2a6ae1b11c170d022256d
|
||||
03408dcd416396f64783ac587ea1e1593c57d9fea880c8a6a1920e92a259477806
|
||||
035056669864feea401d8c31e447fb82dd29f342a9476cfd449584ce2a6165e4d7
|
||||
025831cee3708e87d78211bec0d1bfee9f4c85ae784762f042e7f31c0d40c329b8
|
||||
026328aae34f149853430f526ecaa9cf9c8d78a4ea82d08bdf63dd03c4d0693be6
|
||||
0370c75c54445565df62cfe2e76fbec4ba00d1298867972213530cae6d418da636
|
||||
03840415b0a0fcf066bcc3dc92d8349ebd33a6ab1402ef649bae00e5d9f5840828
|
||||
03957af9e77282ae3263544b7b2458903624adc3f5dee303957cb6570524a5f254
|
||||
02a7834be9b32e2981d157cb5bbd3acb42cfd11ea5c3b10224d7a44e98c5910f1b
|
||||
02ba2c70f5996f357a43198705859fae2cfea13e1172962800772b3d588a9d4abd
|
||||
03c609bea5a4825908027e4ab217e7efc06e311f19ecad9d417089f14927a173d5
|
||||
02c69a8d084ee7319cfecf5161ff257aa2d1f53e79bf6c6f164cff5d94675c38b3
|
||||
02cf9dc6e85d581480d91e88e8cbeaa0c153a046e89ded08b4cefd851e1d7325b5
|
||||
03d84d22b8753cf225d263a3a782a4e16ca72ef323cfde04977c74f14873ab1e4c
|
||||
```
|
||||
|
||||
#### Candidate/voting data
|
||||
`query candidates` returns all current candidates, number of votes for them
|
||||
and their committee/consensus status:
|
||||
```
|
||||
$ ./bin/neo-go query candidates -r http://localhost:20332
|
||||
Key Votes Committee Consensus
|
||||
03009b7540e10f2562e5fd8fac9eaec25166a58b26e412348ff5a86927bfac22a2 2000000 true true
|
||||
030205e9cefaea5a1dfc580af20c8d5aa2468bb0148f1a5e4605fc622c80e604ba 2000000 true true
|
||||
0214baf0ceea3a66f17e7e1e839ea25fd8bed6cd82e6bb6e68250189065f44ff01 2000000 true true
|
||||
023e9b32ea89b94d066e649b124fd50e396ee91369e8e2a6ae1b11c170d022256d 2000000 true true
|
||||
03408dcd416396f64783ac587ea1e1593c57d9fea880c8a6a1920e92a259477806 2000000 true true
|
||||
02a7834be9b32e2981d157cb5bbd3acb42cfd11ea5c3b10224d7a44e98c5910f1b 2000000 true true
|
||||
02ba2c70f5996f357a43198705859fae2cfea13e1172962800772b3d588a9d4abd 2000000 true true
|
||||
025664cef0abcba7787ad5fb12f3af31c5cdc7a479068aa2ad8ee78804768bffe9 1000000 false false
|
||||
03650a684461a64bf46bee561d9981a4c57adc6ccbd3a9512b83701480b30218ab 1000000 false false
|
||||
026a10aa2b4d7639c5deafa4ff081467db10b5d00432749a2a5ee1d2bfed23e1c0 1000000 false false
|
||||
02d5786a9214a8a3f1757d7596fd10f5241205e2c0d68362f4766579bac6189249 1000000 false false
|
||||
033d8e35f8cd9a33852280b6d93093c7292ed5ce90d90f149fa2da50ba6168dfce 100000 false false
|
||||
0349c7ef0b4aaf181f0a3e1350c527b136cc5b42498cb83ab8880c05ed95167e1c 100000 false false
|
||||
035b4f9be2b853e06eb5a09c167e038b96b4804235961510423252f2ee3dbba583 100000 false false
|
||||
027e459b264b6f7e325ab4b0bb0fa641081fb68517fd613ebd7a94cb79d3081e4f 100000 false false
|
||||
0288cad442a877960c76b4f688f4be30f768256d9a3da2492b0180b91243918b4f 100000 false false
|
||||
02a40c552798f79636095817ec88924fc6cb7094e5a3cb059a9b3bc91ea3bf0d3d 100000 false false
|
||||
02db79e69c518ae9254e314b6f5f4b63e914cdd4b2574dc2f9236c01c1fc1d8973 100000 false false
|
||||
02ec143f00b88524caf36a0121c2de09eef0519ddbe1c710a00f0e2663201ee4c0 100000 false false
|
||||
03d8d58d2257ca6cb14522b76513d4783f7d481801695893794c2186515c6de76f 0 false false
|
||||
```
|
||||
|
||||
#### Voter data
|
||||
`query voter` returns additional data about NEO holder: amount of NEO he has,
|
||||
candidate he voted for (if any) and block number of the last transactions
|
||||
involving NEO on this account:
|
||||
```
|
||||
$ ./bin/neo-go query voter -r http://localhost:20332 Nj91C8TxQSxW1jCE1ytFre6mg5qxTypg1Y
|
||||
Voted: 0214baf0ceea3a66f17e7e1e839ea25fd8bed6cd82e6bb6e68250189065f44ff01 (Nj91C8TxQSxW1jCE1ytFre6mg5qxTypg1Y)
|
||||
Amount : 2000000
|
||||
Block: 3970
|
||||
```
|
||||
|
||||
### NEP-17 token functions
|
||||
|
||||
`wallet nep17` contains a set of commands to use for NEP-17 tokens.
|
||||
|
|
|
@ -92,16 +92,16 @@ use.
|
|||
This command will create and send appropriate transaction to the network and
|
||||
you should then wait for it to settle in a block. If all goes well it'll end
|
||||
with "HALT" state and your registration will be completed. You can use
|
||||
`query tx` command to see transaction status or
|
||||
`getnextblockvalidators` to see if your candidate was added.
|
||||
`query tx` command to see transaction status or `query candidates` to see if
|
||||
your candidate was added.
|
||||
|
||||
### Voting
|
||||
|
||||
After registration completion if you own some NEO you can also vote for your
|
||||
candidate to help it become CN and receive additional voter GAS. To do that
|
||||
you need to know the public key of your candidate, which can either be seen in
|
||||
`getnextblockvalidators` RPC call output or extracted from wallet `wallet
|
||||
dump-keys` command:
|
||||
`query candidates` command output or extracted from wallet `wallet dump-keys`
|
||||
command:
|
||||
|
||||
```
|
||||
$ neo-go wallet dump-keys -w wallet.json
|
||||
|
|
|
@ -374,6 +374,18 @@ func (c *Client) GetRawTransactionVerbose(hash util.Uint256) (*result.Transactio
|
|||
return resp, nil
|
||||
}
|
||||
|
||||
// GetStateHeight returns current validated and local node state height.
|
||||
func (c *Client) GetStateHeight() (*result.StateHeight, error) {
|
||||
var (
|
||||
params = request.NewRawParams()
|
||||
resp = new(result.StateHeight)
|
||||
)
|
||||
if err := c.performRequest("getstateheight", params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetStorageByID returns the stored value, according to the contract ID and the stored key.
|
||||
func (c *Client) GetStorageByID(id int32, key []byte) ([]byte, error) {
|
||||
return c.getStorage(request.NewRawParams(id, base64.StdEncoding.EncodeToString(key)))
|
||||
|
|
|
@ -680,6 +680,21 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
},
|
||||
},
|
||||
},
|
||||
"getstateheight": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
return c.GetStateHeight()
|
||||
},
|
||||
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"localrootindex":11646,"validatedrootindex":11645}}`,
|
||||
result: func(c *Client) interface{} {
|
||||
return &result.StateHeight{
|
||||
Local: 11646,
|
||||
Validated: 11645,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
"getstorage": {
|
||||
{
|
||||
name: "by hash, positive",
|
||||
|
|
|
@ -10,8 +10,8 @@ import (
|
|||
|
||||
// StateHeight is a result of getstateheight RPC.
|
||||
type StateHeight struct {
|
||||
BlockHeight uint32 `json:"blockHeight"`
|
||||
StateHeight uint32 `json:"stateHeight"`
|
||||
Local uint32 `json:"localrootindex"`
|
||||
Validated uint32 `json:"validatedrootindex"`
|
||||
}
|
||||
|
||||
// ProofWithKey represens key-proof pair.
|
||||
|
|
|
@ -969,8 +969,8 @@ func (s *Server) getStateHeight(_ request.Params) (interface{}, *response.Error)
|
|||
stateHeight = height - 1
|
||||
}
|
||||
return &result.StateHeight{
|
||||
BlockHeight: height,
|
||||
StateHeight: stateHeight,
|
||||
Local: height,
|
||||
Validated: stateHeight,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -324,8 +324,8 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
sh, ok := res.(*result.StateHeight)
|
||||
require.True(t, ok)
|
||||
|
||||
require.Equal(t, e.chain.BlockHeight(), sh.BlockHeight)
|
||||
require.Equal(t, uint32(0), sh.StateHeight)
|
||||
require.Equal(t, e.chain.BlockHeight(), sh.Local)
|
||||
require.Equal(t, uint32(0), sh.Validated)
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue