mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-22 19:29:39 +00:00
parent
8141d49e5a
commit
42e2aff381
5 changed files with 174 additions and 1 deletions
|
@ -42,7 +42,7 @@ which would yield the response:
|
||||||
| `getblock` | Yes |
|
| `getblock` | Yes |
|
||||||
| `getblockcount` | Yes |
|
| `getblockcount` | Yes |
|
||||||
| `getblockhash` | Yes |
|
| `getblockhash` | Yes |
|
||||||
| `getblockheader` | No (#711) |
|
| `getblockheader` | Yes |
|
||||||
| `getblocksysfee` | Yes |
|
| `getblocksysfee` | Yes |
|
||||||
| `getclaimable` | Yes |
|
| `getclaimable` | Yes |
|
||||||
| `getconnectioncount` | Yes |
|
| `getconnectioncount` | Yes |
|
||||||
|
|
53
pkg/rpc/response/result/block_header.go
Normal file
53
pkg/rpc/response/result/block_header.go
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package result
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Header wrapper used for the representation of
|
||||||
|
// block header on the RPC Server.
|
||||||
|
Header struct {
|
||||||
|
Hash util.Uint256 `json:"hash"`
|
||||||
|
Size int `json:"size"`
|
||||||
|
Version uint32 `json:"version"`
|
||||||
|
PrevBlockHash util.Uint256 `json:"previousblockhash"`
|
||||||
|
MerkleRoot util.Uint256 `json:"merkleroot"`
|
||||||
|
Timestamp uint32 `json:"time"`
|
||||||
|
Index uint32 `json:"index"`
|
||||||
|
Nonce string `json:"nonce"`
|
||||||
|
NextConsensus util.Uint160 `json:"nextconsensus"`
|
||||||
|
Script transaction.Witness `json:"script"`
|
||||||
|
Confirmations uint32 `json:"confirmations"`
|
||||||
|
NextBlockHash *util.Uint256 `json:"nextblockhash,omitempty"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewHeader creates a new Header wrapper.
|
||||||
|
func NewHeader(h *block.Header, chain core.Blockchainer) Header {
|
||||||
|
res := Header{
|
||||||
|
Hash: h.Hash(),
|
||||||
|
Size: io.GetVarSize(h),
|
||||||
|
Version: h.Version,
|
||||||
|
PrevBlockHash: h.PrevHash,
|
||||||
|
MerkleRoot: h.MerkleRoot,
|
||||||
|
Timestamp: h.Timestamp,
|
||||||
|
Index: h.Index,
|
||||||
|
Nonce: strconv.FormatUint(h.ConsensusData, 16),
|
||||||
|
NextConsensus: h.NextConsensus,
|
||||||
|
Script: h.Script,
|
||||||
|
Confirmations: chain.BlockHeight() - h.Index + 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
hash := chain.GetHeaderHash(int(h.Index) + 1)
|
||||||
|
if !hash.Equals(util.Uint256{}) {
|
||||||
|
res.NextBlockHash = &hash
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
|
@ -43,6 +43,14 @@ var (
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
getblockheaderCalled = prometheus.NewCounter(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Help: "Number of calls to getblockheader rpc endpoint",
|
||||||
|
Name: "getblockheader_called",
|
||||||
|
Namespace: "neogo",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
getblocksysfeeCalled = prometheus.NewCounter(
|
getblocksysfeeCalled = prometheus.NewCounter(
|
||||||
prometheus.CounterOpts{
|
prometheus.CounterOpts{
|
||||||
Help: "Number of calls to getblocksysfee rpc endpoint",
|
Help: "Number of calls to getblocksysfee rpc endpoint",
|
||||||
|
@ -171,6 +179,7 @@ func init() {
|
||||||
getbestblockCalled,
|
getbestblockCalled,
|
||||||
getblockcountCalled,
|
getblockcountCalled,
|
||||||
getblockHashCalled,
|
getblockHashCalled,
|
||||||
|
getblockheaderCalled,
|
||||||
getblocksysfeeCalled,
|
getblocksysfeeCalled,
|
||||||
getconnectioncountCalled,
|
getconnectioncountCalled,
|
||||||
getcontractstateCalled,
|
getcontractstateCalled,
|
||||||
|
|
|
@ -186,6 +186,10 @@ Methods:
|
||||||
|
|
||||||
results = s.chain.GetHeaderHash(num)
|
results = s.chain.GetHeaderHash(num)
|
||||||
|
|
||||||
|
case "getblockheader":
|
||||||
|
getblockheaderCalled.Inc()
|
||||||
|
results, resultsErr = s.getBlockHeader(reqParams)
|
||||||
|
|
||||||
case "getblocksysfee":
|
case "getblocksysfee":
|
||||||
getblocksysfeeCalled.Inc()
|
getblocksysfeeCalled.Inc()
|
||||||
results, resultsErr = s.getBlockSysFee(reqParams)
|
results, resultsErr = s.getBlockSysFee(reqParams)
|
||||||
|
@ -557,6 +561,45 @@ func (s *Server) getBlockSysFee(reqParams request.Params) (util.Fixed8, error) {
|
||||||
return blockSysFee, nil
|
return blockSysFee, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getBlockHeader returns the corresponding block header information according to the specified script hash.
|
||||||
|
func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, error) {
|
||||||
|
var verbose bool
|
||||||
|
|
||||||
|
param, ok := reqParams.ValueWithType(0, request.StringT)
|
||||||
|
if !ok {
|
||||||
|
return nil, response.ErrInvalidParams
|
||||||
|
}
|
||||||
|
hash, err := param.GetUint256()
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.ErrInvalidParams
|
||||||
|
}
|
||||||
|
|
||||||
|
param, ok = reqParams.ValueWithType(1, request.NumberT)
|
||||||
|
if ok {
|
||||||
|
v, err := param.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.ErrInvalidParams
|
||||||
|
}
|
||||||
|
verbose = v != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
h, err := s.chain.GetHeader(hash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.NewRPCError("unknown block", "", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
return result.NewHeader(h, s.chain), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := io.NewBufBinWriter()
|
||||||
|
h.EncodeBinary(buf.BinWriter)
|
||||||
|
if buf.Err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return hex.EncodeToString(buf.Bytes()), nil
|
||||||
|
}
|
||||||
|
|
||||||
// invoke implements the `invoke` RPC call.
|
// invoke implements the `invoke` RPC call.
|
||||||
func (s *Server) invoke(reqParams request.Params) (interface{}, error) {
|
func (s *Server) invoke(reqParams request.Params) (interface{}, error) {
|
||||||
scriptHashHex, ok := reqParams.ValueWithType(0, request.StringT)
|
scriptHashHex, ok := reqParams.ValueWithType(0, request.StringT)
|
||||||
|
|
|
@ -9,12 +9,14 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core"
|
"github.com/nspcc-dev/neo-go/pkg/core"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/internal/random"
|
"github.com/nspcc-dev/neo-go/pkg/internal/random"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc/response"
|
"github.com/nspcc-dev/neo-go/pkg/rpc/response"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
|
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
@ -334,6 +336,72 @@ var rpcTestCases = map[string][]rpcTestCase{
|
||||||
fail: true,
|
fail: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"getblockheader": {
|
||||||
|
{
|
||||||
|
name: "positive, no verbose",
|
||||||
|
params: `["a6e526375a780335112299f2262501e5e9574c3ba61b16bbc1e282b344f6c14d"]`,
|
||||||
|
result: func(e *executor) interface{} {
|
||||||
|
expected := "00000000b32b4a122730deb7f862bdc99b45cc8ef12ae55a8096a344429968702091bf3a8e9f458e580420a99a67f0d4137266f76523ea618d1db7ec314b106eb6e67c1721bd575e340000005704000000000000be48d3a3f5d10013ab9ffee489706078714f1ea201fd04014092cb08b7fbef9b8fe47e7d7ec0557e32aeb2e61bdf5c1c6cac203ed12ad32d50629af1783436e585acc8581f46b2b29247f04102d66e9e7e112ae5444c46487340896a200e806f4597df05a12f91f0fbc5c256522687547e7e057b88ec14082213ce98a88f6fd312d3e3fad4b77db1fcc95af69282d887d56f461280df557e4820402903ff86e02559a58376da45d27eb24e5362f6fd922b79a55c9927e33a81265b5ccfef9db83a48b3597e9b576999fc5c0f02df982dbf871a1ef60b089ffb4dae40405d746c546d0ac3d7e36f61d71996f104884db93cca7499f687eb8b8e444327f97bfb05e49ee388d36e0dc73132a3a9ec24a6d8c8b27ae92223dbb7b06af1ec8b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae00"
|
||||||
|
return &expected
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "positive, verbose 0",
|
||||||
|
params: `["a6e526375a780335112299f2262501e5e9574c3ba61b16bbc1e282b344f6c14d", 0]`,
|
||||||
|
result: func(e *executor) interface{} {
|
||||||
|
expected := "00000000b32b4a122730deb7f862bdc99b45cc8ef12ae55a8096a344429968702091bf3a8e9f458e580420a99a67f0d4137266f76523ea618d1db7ec314b106eb6e67c1721bd575e340000005704000000000000be48d3a3f5d10013ab9ffee489706078714f1ea201fd04014092cb08b7fbef9b8fe47e7d7ec0557e32aeb2e61bdf5c1c6cac203ed12ad32d50629af1783436e585acc8581f46b2b29247f04102d66e9e7e112ae5444c46487340896a200e806f4597df05a12f91f0fbc5c256522687547e7e057b88ec14082213ce98a88f6fd312d3e3fad4b77db1fcc95af69282d887d56f461280df557e4820402903ff86e02559a58376da45d27eb24e5362f6fd922b79a55c9927e33a81265b5ccfef9db83a48b3597e9b576999fc5c0f02df982dbf871a1ef60b089ffb4dae40405d746c546d0ac3d7e36f61d71996f104884db93cca7499f687eb8b8e444327f97bfb05e49ee388d36e0dc73132a3a9ec24a6d8c8b27ae92223dbb7b06af1ec8b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae00"
|
||||||
|
return &expected
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "positive, verbose !=0",
|
||||||
|
params: `["a6e526375a780335112299f2262501e5e9574c3ba61b16bbc1e282b344f6c14d", 2]`,
|
||||||
|
result: func(e *executor) interface{} {
|
||||||
|
hash, _ := util.Uint256DecodeStringLE("a6e526375a780335112299f2262501e5e9574c3ba61b16bbc1e282b344f6c14d")
|
||||||
|
block, _ := e.chain.GetBlock(hash)
|
||||||
|
header := block.Header()
|
||||||
|
expected := result.Header{
|
||||||
|
Hash: header.Hash(),
|
||||||
|
Size: io.GetVarSize(header),
|
||||||
|
Version: header.Version,
|
||||||
|
PrevBlockHash: header.PrevHash,
|
||||||
|
MerkleRoot: header.MerkleRoot,
|
||||||
|
Timestamp: header.Timestamp,
|
||||||
|
Index: header.Index,
|
||||||
|
Nonce: strconv.FormatUint(header.ConsensusData, 16),
|
||||||
|
NextConsensus: header.NextConsensus,
|
||||||
|
Script: header.Script,
|
||||||
|
Confirmations: e.chain.BlockHeight() - header.Index + 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
nextHash := e.chain.GetHeaderHash(int(header.Index) + 1)
|
||||||
|
if !hash.Equals(util.Uint256{}) {
|
||||||
|
expected.NextBlockHash = &nextHash
|
||||||
|
}
|
||||||
|
return &expected
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid verbose type",
|
||||||
|
params: `["a6e526375a780335112299f2262501e5e9574c3ba61b16bbc1e282b344f6c14d", true]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid block hash",
|
||||||
|
params: `["notahash"]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unknown block",
|
||||||
|
params: `["a6e526375a780335112299f2262501e5e9574c3ba61b16bbc1e282b344f6c141"]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no params",
|
||||||
|
params: `[]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
"getblocksysfee": {
|
"getblocksysfee": {
|
||||||
{
|
{
|
||||||
name: "positive",
|
name: "positive",
|
||||||
|
|
Loading…
Reference in a new issue