Merge pull request #2165 from nspcc-dev/rpc/audit

rpc: request handlers audit
This commit is contained in:
Roman Khimov 2021-09-10 13:16:40 +03:00 committed by GitHub
commit c4637514d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 84 additions and 49 deletions

View file

@ -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 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`
This method doesn't work for the Ledger contract, you can get data via regular

View file

@ -157,7 +157,7 @@ func (b Header) MarshalJSON() ([]byte, error) {
PrevHash: b.PrevHash,
MerkleRoot: b.MerkleRoot,
Timestamp: b.Timestamp,
Nonce: fmt.Sprintf("%016x", b.Nonce),
Nonce: fmt.Sprintf("%016X", b.Nonce),
Index: b.Index,
PrimaryIndex: b.PrimaryIndex,
NextConsensus: address.Uint160ToString(b.NextConsensus),

View file

@ -140,6 +140,7 @@ func NewContractMD(name string, id int32) *ContractMD {
// Therefore values are taken from C# node.
c.NEF.Header.Compiler = "neo-core-v3.0"
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.Manifest = *manifest.DefaultManifest(name)

View file

@ -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 {
if len(ps) == 0 {
ps = []manifest.Parameter{}
}
return &manifest.Method{
Name: name,
Parameters: ps,

View file

@ -264,17 +264,12 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
result: func(c *Client) interface{} {
b := getResultBlock1()
return &result.Header{
Hash: b.Hash(),
Size: 457,
Version: b.Version,
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,
Header: b.Header,
BlockMetadata: result.BlockMetadata{
Size: 457,
NextBlockHash: b.NextBlockHash,
Confirmations: b.Confirmations,
},
}
},
},

View file

@ -1,10 +1,11 @@
package result
import (
"encoding/json"
"errors"
"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/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/util"
)
@ -13,33 +14,19 @@ 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 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"`
block.Header
BlockMetadata
}
)
// NewHeader creates a new Header wrapper.
func NewHeader(h *block.Header, chain blockchainer.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,
NextConsensus: address.Uint160ToString(h.NextConsensus),
Witnesses: []transaction.Witness{h.Script},
Confirmations: chain.BlockHeight() - h.Index + 1,
Header: *h,
BlockMetadata: BlockMetadata{
Size: io.GetVarSize(h),
Confirmations: chain.BlockHeight() - 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
}
// 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
}

View file

@ -548,8 +548,9 @@ func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response
return hashList, nil
}
return result.RawMempool{
Height: s.chain.BlockHeight(),
Verified: hashList,
Height: s.chain.BlockHeight(),
Verified: hashList,
Unverified: []util.Uint256{}, // avoid `null` result
}, nil
}
@ -1280,11 +1281,12 @@ func (s *Server) invokescript(reqParams request.Params) (interface{}, *response.
tx := &transaction.Transaction{}
if len(reqParams) > 1 {
signers, _, err := reqParams[1].GetSignersWithWitnesses()
signers, witnesses, err := reqParams[1].GetSignersWithWitnesses()
if err != nil {
return nil, response.ErrInvalidParams
}
tx.Signers = signers
tx.Scripts = witnesses
}
if len(tx.Signers) == 0 {
tx.Signers = []transaction.Signer{{Account: util.Uint160{}, Scopes: transaction.None}}

View file

@ -1455,17 +1455,12 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
t.Run("verbose != 0", func(t *testing.T) {
nextHash := chain.GetHeaderHash(int(hdr.Index) + 1)
expected := &result.Header{
Hash: hdr.Hash(),
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,
Header: *hdr,
BlockMetadata: result.BlockMetadata{
Size: io.GetVarSize(hdr),
NextBlockHash: &nextHash,
Confirmations: e.chain.BlockHeight() - hdr.Index + 1,
},
}
rpc := fmt.Sprintf(rpc, `["`+testHeaderHash+`", 2]`)

View file

@ -69,6 +69,14 @@ func TestEncodeDecodeBinary(t *testing.T) {
expected.Header.Magic = Magic
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) {
expected.Script = script
expected.Tokens = expected.Tokens[:0]