forked from TrueCloudLab/neoneo-go
rpc: add getstate
RPC handler
This commit is contained in:
parent
c8120a139d
commit
01143da621
11 changed files with 182 additions and 21 deletions
|
@ -54,6 +54,7 @@ which would yield the response:
|
||||||
| `getproof` |
|
| `getproof` |
|
||||||
| `getrawmempool` |
|
| `getrawmempool` |
|
||||||
| `getrawtransaction` |
|
| `getrawtransaction` |
|
||||||
|
| `getstate` |
|
||||||
| `getstateheight` |
|
| `getstateheight` |
|
||||||
| `getstateroot` |
|
| `getstateroot` |
|
||||||
| `getstorage` |
|
| `getstorage` |
|
||||||
|
|
|
@ -13,6 +13,7 @@ type StateRoot interface {
|
||||||
CurrentLocalHeight() uint32
|
CurrentLocalHeight() uint32
|
||||||
CurrentLocalStateRoot() util.Uint256
|
CurrentLocalStateRoot() util.Uint256
|
||||||
CurrentValidatedHeight() uint32
|
CurrentValidatedHeight() uint32
|
||||||
|
GetState(root util.Uint256, key []byte) ([]byte, error)
|
||||||
GetStateProof(root util.Uint256, key []byte) ([][]byte, error)
|
GetStateProof(root util.Uint256, key []byte) ([][]byte, error)
|
||||||
GetStateRoot(height uint32) (*state.MPTRoot, error)
|
GetStateRoot(height uint32) (*state.MPTRoot, error)
|
||||||
GetStateValidators(height uint32) keys.PublicKeys
|
GetStateValidators(height uint32) keys.PublicKeys
|
||||||
|
|
|
@ -501,6 +501,20 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
checkResult(t, res, stackitem.Null{})
|
checkResult(t, res, stackitem.Null{})
|
||||||
|
|
||||||
|
// Invoke `test_contract.go`: put new value with the same key to check `getstate` RPC call
|
||||||
|
script.Reset()
|
||||||
|
emit.AppCall(script.BinWriter, cHash, "putValue", callflag.All, "testkey", "newtestvalue")
|
||||||
|
|
||||||
|
txInv = transaction.New(script.Bytes(), 1*native.GASFactor)
|
||||||
|
txInv.Nonce = getNextNonce()
|
||||||
|
txInv.ValidUntilBlock = validUntilBlock
|
||||||
|
txInv.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
|
||||||
|
require.NoError(t, addNetworkFee(bc, txInv, acc0))
|
||||||
|
require.NoError(t, acc0.SignTx(testchain.Network(), txInv))
|
||||||
|
b = bc.newBlock(txInv)
|
||||||
|
require.NoError(t, bc.AddBlock(b))
|
||||||
|
checkTxHalt(t, bc, txInv.Hash())
|
||||||
|
|
||||||
// Compile contract to test `invokescript` RPC call
|
// Compile contract to test `invokescript` RPC call
|
||||||
_, _ = newDeployTx(t, bc, priv0ScriptHash, prefix+"invokescript_contract.go", "ContractForInvokescriptTest", nil)
|
_, _ = newDeployTx(t, bc, priv0ScriptHash, prefix+"invokescript_contract.go", "ContractForInvokescriptTest", nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ type Management struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
managementContractID = -1
|
ManagementContractID = -1
|
||||||
|
|
||||||
prefixContract = 8
|
prefixContract = 8
|
||||||
|
|
||||||
|
@ -55,15 +55,15 @@ var (
|
||||||
keyMinimumDeploymentFee = []byte{20}
|
keyMinimumDeploymentFee = []byte{20}
|
||||||
)
|
)
|
||||||
|
|
||||||
// makeContractKey creates a key from account script hash.
|
// MakeContractKey creates a key from account script hash.
|
||||||
func makeContractKey(h util.Uint160) []byte {
|
func MakeContractKey(h util.Uint160) []byte {
|
||||||
return makeUint160Key(prefixContract, h)
|
return makeUint160Key(prefixContract, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newManagement creates new Management native contract.
|
// newManagement creates new Management native contract.
|
||||||
func newManagement() *Management {
|
func newManagement() *Management {
|
||||||
var m = &Management{
|
var m = &Management{
|
||||||
ContractMD: *interop.NewContractMD(nativenames.Management, managementContractID),
|
ContractMD: *interop.NewContractMD(nativenames.Management, ManagementContractID),
|
||||||
contracts: make(map[util.Uint160]*state.Contract),
|
contracts: make(map[util.Uint160]*state.Contract),
|
||||||
nep17: make(map[util.Uint160]struct{}),
|
nep17: make(map[util.Uint160]struct{}),
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ func (m *Management) GetContract(d dao.DAO, hash util.Uint160) (*state.Contract,
|
||||||
|
|
||||||
func (m *Management) getContractFromDAO(d dao.DAO, hash util.Uint160) (*state.Contract, error) {
|
func (m *Management) getContractFromDAO(d dao.DAO, hash util.Uint160) (*state.Contract, error) {
|
||||||
contract := new(state.Contract)
|
contract := new(state.Contract)
|
||||||
key := makeContractKey(hash)
|
key := MakeContractKey(hash)
|
||||||
err := getConvertibleFromDAO(m.ID, d, key, contract)
|
err := getConvertibleFromDAO(m.ID, d, key, contract)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -268,7 +268,7 @@ func (m *Management) markUpdated(h util.Uint160) {
|
||||||
// It doesn't run _deploy method and doesn't emit notification.
|
// It doesn't run _deploy method and doesn't emit notification.
|
||||||
func (m *Management) Deploy(d dao.DAO, sender util.Uint160, neff *nef.File, manif *manifest.Manifest) (*state.Contract, error) {
|
func (m *Management) Deploy(d dao.DAO, sender util.Uint160, neff *nef.File, manif *manifest.Manifest) (*state.Contract, error) {
|
||||||
h := state.CreateContractHash(sender, neff.Checksum, manif.Name)
|
h := state.CreateContractHash(sender, neff.Checksum, manif.Name)
|
||||||
key := makeContractKey(h)
|
key := MakeContractKey(h)
|
||||||
si := d.GetStorageItem(m.ID, key)
|
si := d.GetStorageItem(m.ID, key)
|
||||||
if si != nil {
|
if si != nil {
|
||||||
return nil, errors.New("contract already exists")
|
return nil, errors.New("contract already exists")
|
||||||
|
@ -382,7 +382,7 @@ func (m *Management) Destroy(d dao.DAO, hash util.Uint160) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
key := makeContractKey(hash)
|
key := MakeContractKey(hash)
|
||||||
err = d.DeleteStorageItem(m.ID, key)
|
err = d.DeleteStorageItem(m.ID, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -553,7 +553,7 @@ func (m *Management) Initialize(ic *interop.Context) error {
|
||||||
|
|
||||||
// PutContractState saves given contract state into given DAO.
|
// PutContractState saves given contract state into given DAO.
|
||||||
func (m *Management) PutContractState(d dao.DAO, cs *state.Contract) error {
|
func (m *Management) PutContractState(d dao.DAO, cs *state.Contract) error {
|
||||||
key := makeContractKey(cs.Hash)
|
key := MakeContractKey(cs.Hash)
|
||||||
if err := putConvertibleToDAO(m.ID, d, key, cs); err != nil {
|
if err := putConvertibleToDAO(m.ID, d, key, cs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,12 @@ func NewModule(bc blockchainer.Blockchainer, log *zap.Logger, s *storage.MemCach
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetState returns value at the specified key fom the MPT with the specified root.
|
||||||
|
func (s *Module) GetState(root util.Uint256, key []byte) ([]byte, error) {
|
||||||
|
tr := mpt.NewTrie(mpt.NewHashNode(root), false, storage.NewMemCachedStore(s.Store))
|
||||||
|
return tr.Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
// GetStateProof returns proof of having key in the MPT with the specified root.
|
// GetStateProof returns proof of having key in the MPT with the specified root.
|
||||||
func (s *Module) GetStateProof(root util.Uint256, key []byte) ([][]byte, error) {
|
func (s *Module) GetStateProof(root util.Uint256, key []byte) ([][]byte, error) {
|
||||||
tr := mpt.NewTrie(mpt.NewHashNode(root), false, storage.NewMemCachedStore(s.Store))
|
tr := mpt.NewTrie(mpt.NewHashNode(root), false, storage.NewMemCachedStore(s.Store))
|
||||||
|
|
|
@ -285,7 +285,6 @@ func TestStateSyncModule_RestoreBasicChain(t *testing.T) {
|
||||||
// make spout chain higher that latest state sync point
|
// make spout chain higher that latest state sync point
|
||||||
require.NoError(t, bcSpout.AddBlock(bcSpout.newBlock()))
|
require.NoError(t, bcSpout.AddBlock(bcSpout.newBlock()))
|
||||||
require.NoError(t, bcSpout.AddBlock(bcSpout.newBlock()))
|
require.NoError(t, bcSpout.AddBlock(bcSpout.newBlock()))
|
||||||
require.NoError(t, bcSpout.AddBlock(bcSpout.newBlock()))
|
|
||||||
require.Equal(t, uint32(stateSyncPoint+2), bcSpout.BlockHeight())
|
require.Equal(t, uint32(stateSyncPoint+2), bcSpout.BlockHeight())
|
||||||
|
|
||||||
boltCfg := func(c *config.Config) {
|
boltCfg := func(c *config.Config) {
|
||||||
|
|
|
@ -374,6 +374,19 @@ func (c *Client) GetRawTransactionVerbose(hash util.Uint256) (*result.Transactio
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetState returns historical contract storage item state by the given stateroot,
|
||||||
|
// historical contract hash and historical item key.
|
||||||
|
func (c *Client) GetState(stateroot util.Uint256, historicalContractHash util.Uint160, historicalKey []byte) ([]byte, error) {
|
||||||
|
var (
|
||||||
|
params = request.NewRawParams(stateroot.StringLE(), historicalContractHash.StringLE(), historicalKey)
|
||||||
|
resp []byte
|
||||||
|
)
|
||||||
|
if err := c.performRequest("getstate", params, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetStateHeight returns current validated and local node state height.
|
// GetStateHeight returns current validated and local node state height.
|
||||||
func (c *Client) GetStateHeight() (*result.StateHeight, error) {
|
func (c *Client) GetStateHeight() (*result.StateHeight, error) {
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -675,6 +675,20 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"getstate": {
|
||||||
|
{
|
||||||
|
name: "positive",
|
||||||
|
invoke: func(c *Client) (interface{}, error) {
|
||||||
|
root, _ := util.Uint256DecodeStringLE("252e9d73d49c95c7618d40650da504e05183a1b2eed0685e42c360413c329170")
|
||||||
|
cHash, _ := util.Uint160DecodeStringLE("5c9e40a12055c6b9e3f72271c9779958c842135d")
|
||||||
|
return c.GetState(root, cHash, []byte("testkey"))
|
||||||
|
},
|
||||||
|
serverResponse: `{"id":1,"jsonrpc":"2.0","result":"dGVzdHZhbHVl"}`,
|
||||||
|
result: func(c *Client) interface{} {
|
||||||
|
return []byte("testvalue")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"getstateheight": {
|
"getstateheight": {
|
||||||
{
|
{
|
||||||
name: "positive",
|
name: "positive",
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/mpt"
|
"github.com/nspcc-dev/neo-go/pkg/core/mpt"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"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/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||||
|
@ -44,6 +45,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -118,6 +120,7 @@ var rpcHandlers = map[string]func(*Server, request.Params) (interface{}, *respon
|
||||||
"getproof": (*Server).getProof,
|
"getproof": (*Server).getProof,
|
||||||
"getrawmempool": (*Server).getRawMempool,
|
"getrawmempool": (*Server).getRawMempool,
|
||||||
"getrawtransaction": (*Server).getrawtransaction,
|
"getrawtransaction": (*Server).getrawtransaction,
|
||||||
|
"getstate": (*Server).getState,
|
||||||
"getstateheight": (*Server).getStateHeight,
|
"getstateheight": (*Server).getStateHeight,
|
||||||
"getstateroot": (*Server).getStateRoot,
|
"getstateroot": (*Server).getStateRoot,
|
||||||
"getstorage": (*Server).getStorage,
|
"getstorage": (*Server).getStorage,
|
||||||
|
@ -1026,6 +1029,46 @@ func (s *Server) verifyProof(ps request.Params) (interface{}, *response.Error) {
|
||||||
return vp, nil
|
return vp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) getState(ps request.Params) (interface{}, *response.Error) {
|
||||||
|
root, err := ps.Value(0).GetUint256()
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.WrapErrorWithData(response.ErrInvalidParams, errors.New("invalid stateroot"))
|
||||||
|
}
|
||||||
|
if s.chain.GetConfig().KeepOnlyLatestState {
|
||||||
|
curr, err := s.chain.GetStateModule().GetStateRoot(s.chain.BlockHeight())
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.NewInternalServerError("failed to get current stateroot", err)
|
||||||
|
}
|
||||||
|
if !curr.Root.Equals(root) {
|
||||||
|
return nil, response.NewInvalidRequestError("'getstate' is not supported for old states", errKeepOnlyLatestState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
csHash, err := ps.Value(1).GetUint160FromHex()
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.WrapErrorWithData(response.ErrInvalidParams, errors.New("invalid contract hash"))
|
||||||
|
}
|
||||||
|
key, err := ps.Value(2).GetBytesBase64()
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.WrapErrorWithData(response.ErrInvalidParams, errors.New("invalid key"))
|
||||||
|
}
|
||||||
|
csKey := makeStorageKey(native.ManagementContractID, native.MakeContractKey(csHash))
|
||||||
|
csBytes, err := s.chain.GetStateModule().GetState(root, csKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.NewInternalServerError("failed to get historical contract state", err)
|
||||||
|
}
|
||||||
|
contract := new(state.Contract)
|
||||||
|
err = stackitem.DeserializeConvertible(csBytes, contract)
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.NewInternalServerError("failed to deserialize historical contract state", err)
|
||||||
|
}
|
||||||
|
sKey := makeStorageKey(contract.ID, key)
|
||||||
|
res, err := s.chain.GetStateModule().GetState(root, sKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.NewInternalServerError("failed to get historical item state", err)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) getStateHeight(_ request.Params) (interface{}, *response.Error) {
|
func (s *Server) getStateHeight(_ request.Params) (interface{}, *response.Error) {
|
||||||
var height = s.chain.BlockHeight()
|
var height = s.chain.BlockHeight()
|
||||||
var stateHeight = s.chain.GetStateModule().CurrentValidatedHeight()
|
var stateHeight = s.chain.GetStateModule().CurrentValidatedHeight()
|
||||||
|
|
|
@ -55,7 +55,7 @@ type rpcTestCase struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const testContractHash = "5c9e40a12055c6b9e3f72271c9779958c842135d"
|
const testContractHash = "5c9e40a12055c6b9e3f72271c9779958c842135d"
|
||||||
const deploymentTxHash = "fefc10d2f7e323282cb50838174b68979b1794c1e5131f2b4737acbc5dde5932"
|
const deploymentTxHash = "cb17eac9594d7ffa318545ab36e3227eedf30b4d13d76d3b49c94243fb3b2bde"
|
||||||
const genesisBlockHash = "0f8fb4e17d2ab9f3097af75ca7fd16064160fb8043db94909e00dd4e257b9dc4"
|
const genesisBlockHash = "0f8fb4e17d2ab9f3097af75ca7fd16064160fb8043db94909e00dd4e257b9dc4"
|
||||||
|
|
||||||
const verifyContractHash = "f68822e4ecd93de334bdf1f7c409eda3431bcbd0"
|
const verifyContractHash = "f68822e4ecd93de334bdf1f7c409eda3431bcbd0"
|
||||||
|
@ -316,6 +316,38 @@ var rpcTestCases = map[string][]rpcTestCase{
|
||||||
fail: true,
|
fail: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"getstate": {
|
||||||
|
{
|
||||||
|
name: "no params",
|
||||||
|
params: `[]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid root",
|
||||||
|
params: `["0xabcdef"]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid contract",
|
||||||
|
params: `["0000000000000000000000000000000000000000000000000000000000000000", "0xabcdef"]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid key",
|
||||||
|
params: `["0000000000000000000000000000000000000000000000000000000000000000", "` + testContractHash + `", "notabase64%"]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unknown contract",
|
||||||
|
params: `["0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000", "QQ=="]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unknown root/item",
|
||||||
|
params: `["0000000000000000000000000000000000000000000000000000000000000000", "` + testContractHash + `", "QQ=="]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
"getstateheight": {
|
"getstateheight": {
|
||||||
{
|
{
|
||||||
name: "positive",
|
name: "positive",
|
||||||
|
@ -347,7 +379,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
||||||
name: "positive",
|
name: "positive",
|
||||||
params: fmt.Sprintf(`["%s", "dGVzdGtleQ=="]`, testContractHash),
|
params: fmt.Sprintf(`["%s", "dGVzdGtleQ=="]`, testContractHash),
|
||||||
result: func(e *executor) interface{} {
|
result: func(e *executor) interface{} {
|
||||||
v := base64.StdEncoding.EncodeToString([]byte("testvalue"))
|
v := base64.StdEncoding.EncodeToString([]byte("newtestvalue"))
|
||||||
return &v
|
return &v
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -650,7 +682,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
expected := result.UnclaimedGas{
|
expected := result.UnclaimedGas{
|
||||||
Address: testchain.MultisigScriptHash(),
|
Address: testchain.MultisigScriptHash(),
|
||||||
Unclaimed: *big.NewInt(7500),
|
Unclaimed: *big.NewInt(8000),
|
||||||
}
|
}
|
||||||
assert.Equal(t, expected, *actual)
|
assert.Equal(t, expected, *actual)
|
||||||
},
|
},
|
||||||
|
@ -1387,6 +1419,31 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
|
||||||
t.Run("ByHeight", func(t *testing.T) { testRoot(t, strconv.FormatInt(5, 10)) })
|
t.Run("ByHeight", func(t *testing.T) { testRoot(t, strconv.FormatInt(5, 10)) })
|
||||||
t.Run("ByHash", func(t *testing.T) { testRoot(t, `"`+chain.GetHeaderHash(5).StringLE()+`"`) })
|
t.Run("ByHash", func(t *testing.T) { testRoot(t, `"`+chain.GetHeaderHash(5).StringLE()+`"`) })
|
||||||
})
|
})
|
||||||
|
t.Run("getstate", func(t *testing.T) {
|
||||||
|
testGetState := func(t *testing.T, p string, expected string) {
|
||||||
|
rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "getstate", "params": [%s]}`, p)
|
||||||
|
body := doRPCCall(rpc, httpSrv.URL, t)
|
||||||
|
rawRes := checkErrGetResult(t, body, false)
|
||||||
|
|
||||||
|
var actual string
|
||||||
|
require.NoError(t, json.Unmarshal(rawRes, &actual))
|
||||||
|
require.Equal(t, expected, actual)
|
||||||
|
}
|
||||||
|
t.Run("good: historical state", func(t *testing.T) {
|
||||||
|
root, err := e.chain.GetStateModule().GetStateRoot(4)
|
||||||
|
require.NoError(t, err)
|
||||||
|
// `testkey`-`testvalue` pair was put to the contract storage at block #3
|
||||||
|
params := fmt.Sprintf(`"%s", "%s", "%s"`, root.Root.StringLE(), testContractHash, base64.StdEncoding.EncodeToString([]byte("testkey")))
|
||||||
|
testGetState(t, params, base64.StdEncoding.EncodeToString([]byte("testvalue")))
|
||||||
|
})
|
||||||
|
t.Run("good: fresh state", func(t *testing.T) {
|
||||||
|
root, err := e.chain.GetStateModule().GetStateRoot(16)
|
||||||
|
require.NoError(t, err)
|
||||||
|
// `testkey`-`newtestvalue` pair was put to the contract storage at block #16
|
||||||
|
params := fmt.Sprintf(`"%s", "%s", "%s"`, root.Root.StringLE(), testContractHash, base64.StdEncoding.EncodeToString([]byte("testkey")))
|
||||||
|
testGetState(t, params, base64.StdEncoding.EncodeToString([]byte("newtestvalue")))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("getrawtransaction", func(t *testing.T) {
|
t.Run("getrawtransaction", func(t *testing.T) {
|
||||||
block, _ := chain.GetBlock(chain.GetHeaderHash(1))
|
block, _ := chain.GetBlock(chain.GetHeaderHash(1))
|
||||||
|
@ -1430,7 +1487,7 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
|
||||||
require.NoErrorf(t, err, "could not parse response: %s", txOut)
|
require.NoErrorf(t, err, "could not parse response: %s", txOut)
|
||||||
|
|
||||||
assert.Equal(t, *block.Transactions[0], actual.Transaction)
|
assert.Equal(t, *block.Transactions[0], actual.Transaction)
|
||||||
assert.Equal(t, 16, actual.Confirmations)
|
assert.Equal(t, 17, actual.Confirmations)
|
||||||
assert.Equal(t, TXHash, actual.Transaction.Hash())
|
assert.Equal(t, TXHash, actual.Transaction.Hash())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1543,12 +1600,12 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
|
||||||
require.NoError(t, json.Unmarshal(res, actual))
|
require.NoError(t, json.Unmarshal(res, actual))
|
||||||
checkNep17TransfersAux(t, e, actual, sent, rcvd)
|
checkNep17TransfersAux(t, e, actual, sent, rcvd)
|
||||||
}
|
}
|
||||||
t.Run("time frame only", func(t *testing.T) { testNEP17T(t, 4, 5, 0, 0, []int{9, 10, 11, 12}, []int{2, 3}) })
|
t.Run("time frame only", func(t *testing.T) { testNEP17T(t, 4, 5, 0, 0, []int{10, 11, 12, 13}, []int{2, 3}) })
|
||||||
t.Run("no res", func(t *testing.T) { testNEP17T(t, 100, 100, 0, 0, []int{}, []int{}) })
|
t.Run("no res", func(t *testing.T) { testNEP17T(t, 100, 100, 0, 0, []int{}, []int{}) })
|
||||||
t.Run("limit", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 0, []int{6, 7}, []int{1}) })
|
t.Run("limit", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 0, []int{7, 8}, []int{1}) })
|
||||||
t.Run("limit 2", func(t *testing.T) { testNEP17T(t, 4, 5, 2, 0, []int{9}, []int{2}) })
|
t.Run("limit 2", func(t *testing.T) { testNEP17T(t, 4, 5, 2, 0, []int{10}, []int{2}) })
|
||||||
t.Run("limit with page", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 1, []int{8, 9}, []int{2}) })
|
t.Run("limit with page", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 1, []int{9, 10}, []int{2}) })
|
||||||
t.Run("limit with page 2", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 2, []int{10, 11}, []int{3}) })
|
t.Run("limit with page 2", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 2, []int{11, 12}, []int{3}) })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1651,8 +1708,8 @@ func checkNep17Balances(t *testing.T, e *executor, acc interface{}) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Asset: e.chain.UtilityTokenHash(),
|
Asset: e.chain.UtilityTokenHash(),
|
||||||
Amount: "57898138260",
|
Amount: "57796933740",
|
||||||
LastUpdated: 15,
|
LastUpdated: 16,
|
||||||
}},
|
}},
|
||||||
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
|
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
|
||||||
}
|
}
|
||||||
|
@ -1661,7 +1718,7 @@ func checkNep17Balances(t *testing.T, e *executor, acc interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkNep17Transfers(t *testing.T, e *executor, acc interface{}) {
|
func checkNep17Transfers(t *testing.T, e *executor, acc interface{}) {
|
||||||
checkNep17TransfersAux(t, e, acc, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, []int{0, 1, 2, 3, 4, 5, 6, 7})
|
checkNep17TransfersAux(t, e, acc, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, []int{0, 1, 2, 3, 4, 5, 6, 7})
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkNep17TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcvd []int) {
|
func checkNep17TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcvd []int) {
|
||||||
|
@ -1670,6 +1727,11 @@ func checkNep17TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rc
|
||||||
rublesHash, err := util.Uint160DecodeStringLE(testContractHash)
|
rublesHash, err := util.Uint160DecodeStringLE(testContractHash)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
blockPutNewTestValue, err := e.chain.GetBlock(e.chain.GetHeaderHash(16)) // invoke `put` method of `test_contract.go` with `testkey`, `newtestvalue` args
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(blockPutNewTestValue.Transactions))
|
||||||
|
txPutNewTestValue := blockPutNewTestValue.Transactions[0]
|
||||||
|
|
||||||
blockSetRecord, err := e.chain.GetBlock(e.chain.GetHeaderHash(15)) // add type A record to `neo.com` domain via NNS
|
blockSetRecord, err := e.chain.GetBlock(e.chain.GetHeaderHash(15)) // add type A record to `neo.com` domain via NNS
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 1, len(blockSetRecord.Transactions))
|
require.Equal(t, 1, len(blockSetRecord.Transactions))
|
||||||
|
@ -1746,6 +1808,14 @@ func checkNep17TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rc
|
||||||
// duplicate the Server method.
|
// duplicate the Server method.
|
||||||
expected := result.NEP17Transfers{
|
expected := result.NEP17Transfers{
|
||||||
Sent: []result.NEP17Transfer{
|
Sent: []result.NEP17Transfer{
|
||||||
|
{
|
||||||
|
Timestamp: blockPutNewTestValue.Timestamp,
|
||||||
|
Asset: e.chain.UtilityTokenHash(),
|
||||||
|
Address: "", // burn
|
||||||
|
Amount: big.NewInt(txPutNewTestValue.SystemFee + txPutNewTestValue.NetworkFee).String(),
|
||||||
|
Index: 16,
|
||||||
|
TxHash: blockPutNewTestValue.Hash(),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Timestamp: blockSetRecord.Timestamp,
|
Timestamp: blockSetRecord.Timestamp,
|
||||||
Asset: e.chain.UtilityTokenHash(),
|
Asset: e.chain.UtilityTokenHash(),
|
||||||
|
|
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
Loading…
Reference in a new issue