Merge pull request #2165 from nspcc-dev/rpc/audit
rpc: request handlers audit
This commit is contained in:
commit
c4637514d4
9 changed files with 84 additions and 49 deletions
|
@ -88,6 +88,11 @@ feature is not supported by the C# node.
|
||||||
It's possible to get non-native contract state by its ID, unlike with C# node where
|
It's possible to get non-native contract state by its ID, unlike with C# node where
|
||||||
it only works for native contracts.
|
it only works for native contracts.
|
||||||
|
|
||||||
|
##### `getrawtransaction`
|
||||||
|
|
||||||
|
VM state is included to verbose response along with other transaction fields if
|
||||||
|
the transaction is already on chain.
|
||||||
|
|
||||||
##### `getstorage`
|
##### `getstorage`
|
||||||
|
|
||||||
This method doesn't work for the Ledger contract, you can get data via regular
|
This method doesn't work for the Ledger contract, you can get data via regular
|
||||||
|
|
|
@ -157,7 +157,7 @@ func (b Header) MarshalJSON() ([]byte, error) {
|
||||||
PrevHash: b.PrevHash,
|
PrevHash: b.PrevHash,
|
||||||
MerkleRoot: b.MerkleRoot,
|
MerkleRoot: b.MerkleRoot,
|
||||||
Timestamp: b.Timestamp,
|
Timestamp: b.Timestamp,
|
||||||
Nonce: fmt.Sprintf("%016x", b.Nonce),
|
Nonce: fmt.Sprintf("%016X", b.Nonce),
|
||||||
Index: b.Index,
|
Index: b.Index,
|
||||||
PrimaryIndex: b.PrimaryIndex,
|
PrimaryIndex: b.PrimaryIndex,
|
||||||
NextConsensus: address.Uint160ToString(b.NextConsensus),
|
NextConsensus: address.Uint160ToString(b.NextConsensus),
|
||||||
|
|
|
@ -140,6 +140,7 @@ func NewContractMD(name string, id int32) *ContractMD {
|
||||||
// Therefore values are taken from C# node.
|
// Therefore values are taken from C# node.
|
||||||
c.NEF.Header.Compiler = "neo-core-v3.0"
|
c.NEF.Header.Compiler = "neo-core-v3.0"
|
||||||
c.NEF.Header.Magic = nef.Magic
|
c.NEF.Header.Magic = nef.Magic
|
||||||
|
c.NEF.Tokens = []nef.MethodToken{} // avoid `nil` result during JSON marshalling
|
||||||
c.Hash = state.CreateContractHash(util.Uint160{}, 0, c.Name)
|
c.Hash = state.CreateContractHash(util.Uint160{}, 0, c.Name)
|
||||||
c.Manifest = *manifest.DefaultManifest(name)
|
c.Manifest = *manifest.DefaultManifest(name)
|
||||||
|
|
||||||
|
|
|
@ -294,6 +294,9 @@ func (c *nep17TokenNative) addTokens(ic *interop.Context, h util.Uint160, amount
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDescriptor(name string, ret smartcontract.ParamType, ps ...manifest.Parameter) *manifest.Method {
|
func newDescriptor(name string, ret smartcontract.ParamType, ps ...manifest.Parameter) *manifest.Method {
|
||||||
|
if len(ps) == 0 {
|
||||||
|
ps = []manifest.Parameter{}
|
||||||
|
}
|
||||||
return &manifest.Method{
|
return &manifest.Method{
|
||||||
Name: name,
|
Name: name,
|
||||||
Parameters: ps,
|
Parameters: ps,
|
||||||
|
|
|
@ -264,17 +264,12 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
||||||
result: func(c *Client) interface{} {
|
result: func(c *Client) interface{} {
|
||||||
b := getResultBlock1()
|
b := getResultBlock1()
|
||||||
return &result.Header{
|
return &result.Header{
|
||||||
Hash: b.Hash(),
|
Header: b.Header,
|
||||||
|
BlockMetadata: result.BlockMetadata{
|
||||||
Size: 457,
|
Size: 457,
|
||||||
Version: b.Version,
|
|
||||||
NextBlockHash: b.NextBlockHash,
|
NextBlockHash: b.NextBlockHash,
|
||||||
PrevBlockHash: b.PrevHash,
|
|
||||||
MerkleRoot: b.MerkleRoot,
|
|
||||||
Timestamp: b.Timestamp,
|
|
||||||
Index: b.Index,
|
|
||||||
NextConsensus: address.Uint160ToString(b.NextConsensus),
|
|
||||||
Witnesses: []transaction.Witness{b.Script},
|
|
||||||
Confirmations: b.Confirmations,
|
Confirmations: b.Confirmations,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package result
|
package result
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
@ -13,33 +14,19 @@ type (
|
||||||
// Header wrapper used for the representation of
|
// Header wrapper used for the representation of
|
||||||
// block header on the RPC Server.
|
// block header on the RPC Server.
|
||||||
Header struct {
|
Header struct {
|
||||||
Hash util.Uint256 `json:"hash"`
|
block.Header
|
||||||
Size int `json:"size"`
|
BlockMetadata
|
||||||
Version uint32 `json:"version"`
|
|
||||||
PrevBlockHash util.Uint256 `json:"previousblockhash"`
|
|
||||||
MerkleRoot util.Uint256 `json:"merkleroot"`
|
|
||||||
Timestamp uint64 `json:"time"`
|
|
||||||
Index uint32 `json:"index"`
|
|
||||||
NextConsensus string `json:"nextconsensus"`
|
|
||||||
Witnesses []transaction.Witness `json:"witnesses"`
|
|
||||||
Confirmations uint32 `json:"confirmations"`
|
|
||||||
NextBlockHash *util.Uint256 `json:"nextblockhash,omitempty"`
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewHeader creates a new Header wrapper.
|
// NewHeader creates a new Header wrapper.
|
||||||
func NewHeader(h *block.Header, chain blockchainer.Blockchainer) Header {
|
func NewHeader(h *block.Header, chain blockchainer.Blockchainer) Header {
|
||||||
res := Header{
|
res := Header{
|
||||||
Hash: h.Hash(),
|
Header: *h,
|
||||||
|
BlockMetadata: BlockMetadata{
|
||||||
Size: io.GetVarSize(h),
|
Size: io.GetVarSize(h),
|
||||||
Version: h.Version,
|
|
||||||
PrevBlockHash: h.PrevHash,
|
|
||||||
MerkleRoot: h.MerkleRoot,
|
|
||||||
Timestamp: h.Timestamp,
|
|
||||||
Index: h.Index,
|
|
||||||
NextConsensus: address.Uint160ToString(h.NextConsensus),
|
|
||||||
Witnesses: []transaction.Witness{h.Script},
|
|
||||||
Confirmations: chain.BlockHeight() - h.Index + 1,
|
Confirmations: chain.BlockHeight() - h.Index + 1,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
hash := chain.GetHeaderHash(int(h.Index) + 1)
|
hash := chain.GetHeaderHash(int(h.Index) + 1)
|
||||||
|
@ -48,3 +35,42 @@ func NewHeader(h *block.Header, chain blockchainer.Blockchainer) Header {
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler interface.
|
||||||
|
func (h Header) MarshalJSON() ([]byte, error) {
|
||||||
|
output, err := json.Marshal(h.BlockMetadata)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
baseBytes, err := json.Marshal(h.Header)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have to keep both "fields" at the same level in json in order to
|
||||||
|
// match C# API, so there's no way to marshall Block correctly with
|
||||||
|
// standard json.Marshaller tool.
|
||||||
|
if output[len(output)-1] != '}' || baseBytes[0] != '{' {
|
||||||
|
return nil, errors.New("can't merge internal jsons")
|
||||||
|
}
|
||||||
|
output[len(output)-1] = ','
|
||||||
|
output = append(output, baseBytes[1:]...)
|
||||||
|
return output, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler interface.
|
||||||
|
func (h *Header) UnmarshalJSON(data []byte) error {
|
||||||
|
// As block.Block and BlockMetadata are at the same level in json,
|
||||||
|
// do unmarshalling separately for both structs.
|
||||||
|
meta := new(BlockMetadata)
|
||||||
|
err := json.Unmarshal(data, meta)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(data, &h.Header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.BlockMetadata = *meta
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -550,6 +550,7 @@ func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response
|
||||||
return result.RawMempool{
|
return result.RawMempool{
|
||||||
Height: s.chain.BlockHeight(),
|
Height: s.chain.BlockHeight(),
|
||||||
Verified: hashList,
|
Verified: hashList,
|
||||||
|
Unverified: []util.Uint256{}, // avoid `null` result
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1280,11 +1281,12 @@ func (s *Server) invokescript(reqParams request.Params) (interface{}, *response.
|
||||||
|
|
||||||
tx := &transaction.Transaction{}
|
tx := &transaction.Transaction{}
|
||||||
if len(reqParams) > 1 {
|
if len(reqParams) > 1 {
|
||||||
signers, _, err := reqParams[1].GetSignersWithWitnesses()
|
signers, witnesses, err := reqParams[1].GetSignersWithWitnesses()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.ErrInvalidParams
|
return nil, response.ErrInvalidParams
|
||||||
}
|
}
|
||||||
tx.Signers = signers
|
tx.Signers = signers
|
||||||
|
tx.Scripts = witnesses
|
||||||
}
|
}
|
||||||
if len(tx.Signers) == 0 {
|
if len(tx.Signers) == 0 {
|
||||||
tx.Signers = []transaction.Signer{{Account: util.Uint160{}, Scopes: transaction.None}}
|
tx.Signers = []transaction.Signer{{Account: util.Uint160{}, Scopes: transaction.None}}
|
||||||
|
|
|
@ -1455,17 +1455,12 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
|
||||||
t.Run("verbose != 0", func(t *testing.T) {
|
t.Run("verbose != 0", func(t *testing.T) {
|
||||||
nextHash := chain.GetHeaderHash(int(hdr.Index) + 1)
|
nextHash := chain.GetHeaderHash(int(hdr.Index) + 1)
|
||||||
expected := &result.Header{
|
expected := &result.Header{
|
||||||
Hash: hdr.Hash(),
|
Header: *hdr,
|
||||||
|
BlockMetadata: result.BlockMetadata{
|
||||||
Size: io.GetVarSize(hdr),
|
Size: io.GetVarSize(hdr),
|
||||||
Version: hdr.Version,
|
|
||||||
PrevBlockHash: hdr.PrevHash,
|
|
||||||
MerkleRoot: hdr.MerkleRoot,
|
|
||||||
Timestamp: hdr.Timestamp,
|
|
||||||
Index: hdr.Index,
|
|
||||||
NextConsensus: address.Uint160ToString(hdr.NextConsensus),
|
|
||||||
Witnesses: []transaction.Witness{hdr.Script},
|
|
||||||
Confirmations: e.chain.BlockHeight() - hdr.Index + 1,
|
|
||||||
NextBlockHash: &nextHash,
|
NextBlockHash: &nextHash,
|
||||||
|
Confirmations: e.chain.BlockHeight() - hdr.Index + 1,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc := fmt.Sprintf(rpc, `["`+testHeaderHash+`", 2]`)
|
rpc := fmt.Sprintf(rpc, `["`+testHeaderHash+`", 2]`)
|
||||||
|
|
|
@ -69,6 +69,14 @@ func TestEncodeDecodeBinary(t *testing.T) {
|
||||||
expected.Header.Magic = Magic
|
expected.Header.Magic = Magic
|
||||||
testserdes.EncodeDecodeBinary(t, expected, &File{})
|
testserdes.EncodeDecodeBinary(t, expected, &File{})
|
||||||
})
|
})
|
||||||
|
t.Run("positive with empty tokens", func(t *testing.T) {
|
||||||
|
expected.Script = script
|
||||||
|
// Check `Tokens` won't be deserialized to `nil`. We expect them to be non-nil slice in the related code.
|
||||||
|
expected.Tokens = []MethodToken{}
|
||||||
|
expected.Checksum = expected.CalculateChecksum()
|
||||||
|
expected.Header.Magic = Magic
|
||||||
|
testserdes.EncodeDecodeBinary(t, expected, &File{})
|
||||||
|
})
|
||||||
t.Run("invalid reserved bytes", func(t *testing.T) {
|
t.Run("invalid reserved bytes", func(t *testing.T) {
|
||||||
expected.Script = script
|
expected.Script = script
|
||||||
expected.Tokens = expected.Tokens[:0]
|
expected.Tokens = expected.Tokens[:0]
|
||||||
|
|
Loading…
Reference in a new issue