rpcclient: add GetProof and VerifyProof (fix #2942)
This commit is contained in:
parent
7306beca4d
commit
f21e618be5
3 changed files with 116 additions and 0 deletions
|
@ -447,6 +447,31 @@ func (c *Client) GetRawTransactionVerbose(hash util.Uint256) (*result.Transactio
|
|||
return resp, nil
|
||||
}
|
||||
|
||||
// GetProof returns existence proof of storage item state by the given stateroot
|
||||
// historical contract hash and historical item key.
|
||||
func (c *Client) GetProof(stateroot util.Uint256, historicalContractHash util.Uint160, historicalKey []byte) (*result.ProofWithKey, error) {
|
||||
var (
|
||||
params = []interface{}{stateroot.StringLE(), historicalContractHash.StringLE(), historicalKey}
|
||||
resp = &result.ProofWithKey{}
|
||||
)
|
||||
if err := c.performRequest("getproof", params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// VerifyProof returns value by the given stateroot and proof.
|
||||
func (c *Client) VerifyProof(stateroot util.Uint256, proof *result.ProofWithKey) ([]byte, error) {
|
||||
var (
|
||||
params = []interface{}{stateroot.StringLE(), proof.String()}
|
||||
resp []byte
|
||||
)
|
||||
if err := c.performRequest("verifyproof", params, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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) {
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"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/bigint"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
|
@ -831,6 +832,66 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
},
|
||||
},
|
||||
},
|
||||
"getproof": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
root, _ := util.Uint256DecodeStringLE("272002b11a6a39035c719defec3e4e6a8d1f4ae37a995b44734911413fcc2ba5")
|
||||
cHash, _ := util.Uint160DecodeStringLE("cc5e4edd9f5f8dba8bb65734541df7a1c081c67b")
|
||||
key := []byte{10}
|
||||
return c.GetProof(root, cHash, key)
|
||||
},
|
||||
serverResponse: `{"jsonrpc":"2.0","id":1,"result":"Bfn///8KBiQBAQ8DogBnMdiiPTEW05A6bJPmQ2TNVpuca/nB1rJRdQX7R4SyAAQEBAQEBAQDHvo5Rc9v\u002BWSpfsnMXM75ku\u002BZjvbLJhWXn/lh6L\u002B1yB0EA4k\u002Bsx4f7IgmdHNm3wRMpj5kTU4l0gChSGppo5p5wZyWA2\u002BKSFn16W6tRrGSfJob\u002BgqJukLcNDk0DBFYW2wIS2/NAzkugdLfZRXHOLqq5XJr89ElzlqyXU1o9D87l9YOcXjGBAQEA7oDTOxuU4iMAKPuhn5eJjzsM56bQrx3uORa8LKm42oDBCkBBg8PDw8PDwN96s39UOSCwMJmMQZzNjfNAPCbRRyke1B4VRKqOZ0NHlIAA2woQ13XO4Ug2aQ/cW4WBricVcUVqobFUU0dnRPtfIHeAxuYERXsV6HwdGjW\u002BhtpM0FEkw/mllbH5pyhn\u002BBx4r8wBAQEBAQEBAQEBAQEBAQEJAEBCgPXvpMqBogTeGhXjtFY4Rsn9bY/PgNX0l4iYOHMzUBQQgQCAugD"}`,
|
||||
result: func(c *Client) interface{} {
|
||||
b, _ := base64.StdEncoding.DecodeString("Bfn///8KBiQBAQ8DogBnMdiiPTEW05A6bJPmQ2TNVpuca/nB1rJRdQX7R4SyAAQEBAQEBAQDHvo5Rc9v\u002BWSpfsnMXM75ku\u002BZjvbLJhWXn/lh6L\u002B1yB0EA4k\u002Bsx4f7IgmdHNm3wRMpj5kTU4l0gChSGppo5p5wZyWA2\u002BKSFn16W6tRrGSfJob\u002BgqJukLcNDk0DBFYW2wIS2/NAzkugdLfZRXHOLqq5XJr89ElzlqyXU1o9D87l9YOcXjGBAQEA7oDTOxuU4iMAKPuhn5eJjzsM56bQrx3uORa8LKm42oDBCkBBg8PDw8PDwN96s39UOSCwMJmMQZzNjfNAPCbRRyke1B4VRKqOZ0NHlIAA2woQ13XO4Ug2aQ/cW4WBricVcUVqobFUU0dnRPtfIHeAxuYERXsV6HwdGjW\u002BhtpM0FEkw/mllbH5pyhn\u002BBx4r8wBAQEBAQEBAQEBAQEBAQEJAEBCgPXvpMqBogTeGhXjtFY4Rsn9bY/PgNX0l4iYOHMzUBQQgQCAugD")
|
||||
proof := &result.ProofWithKey{}
|
||||
r := io.NewBinReaderFromBuf(b)
|
||||
proof.DecodeBinary(r)
|
||||
return proof
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
root, _ := util.Uint256DecodeStringLE("272002b11a6a39035c719defec3e4e6a8d1f4ae37a995b44734911413fcc2ba5")
|
||||
cHash, _ := util.Uint160DecodeStringLE("cc5e4edd9f5f8dba8bb65734541df7a1c081c67b")
|
||||
key := []byte{01}
|
||||
return c.GetProof(root, cHash, key)
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error","data":"failed to get proof: item not found"}}`,
|
||||
fails: true,
|
||||
},
|
||||
},
|
||||
"verifyproof": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
root, _ := util.Uint256DecodeStringLE("272002b11a6a39035c719defec3e4e6a8d1f4ae37a995b44734911413fcc2ba5")
|
||||
b, _ := base64.StdEncoding.DecodeString("Bfn///8KBiQBAQ8DogBnMdiiPTEW05A6bJPmQ2TNVpuca/nB1rJRdQX7R4SyAAQEBAQEBAQDHvo5Rc9v\u002BWSpfsnMXM75ku\u002BZjvbLJhWXn/lh6L\u002B1yB0EA4k\u002Bsx4f7IgmdHNm3wRMpj5kTU4l0gChSGppo5p5wZyWA2\u002BKSFn16W6tRrGSfJob\u002BgqJukLcNDk0DBFYW2wIS2/NAzkugdLfZRXHOLqq5XJr89ElzlqyXU1o9D87l9YOcXjGBAQEA7oDTOxuU4iMAKPuhn5eJjzsM56bQrx3uORa8LKm42oDBCkBBg8PDw8PDwN96s39UOSCwMJmMQZzNjfNAPCbRRyke1B4VRKqOZ0NHlIAA2woQ13XO4Ug2aQ/cW4WBricVcUVqobFUU0dnRPtfIHeAxuYERXsV6HwdGjW\u002BhtpM0FEkw/mllbH5pyhn\u002BBx4r8wBAQEBAQEBAQEBAQEBAQEJAEBCgPXvpMqBogTeGhXjtFY4Rsn9bY/PgNX0l4iYOHMzUBQQgQCAugD")
|
||||
proof := &result.ProofWithKey{}
|
||||
r := io.NewBinReaderFromBuf(b)
|
||||
proof.DecodeBinary(r)
|
||||
return c.VerifyProof(root, proof)
|
||||
},
|
||||
serverResponse: `{"jsonrpc":"2.0","id":1,"result":"6AM="}`,
|
||||
result: func(c *Client) interface{} {
|
||||
return bigint.ToPreallocatedBytes(big.NewInt(1000), nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fail",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
root, _ := util.Uint256DecodeStringLE("272002b11a6a39035c719defec3e4e6a8d1f4ae37a995b44734911413fcc2ba5")
|
||||
b, _ := base64.StdEncoding.DecodeString("Bfn///8KBiQBAQ8DogBnMdiiPTEW05A6bJPmQ2TNVpuca/nB1rJRdQX7R4SyAAQEBAQEBAQDHvo5Rc9v\u002BWSpfsnMXM75ku\u002BZjvbLJhWXn/lh6L\u002B1yB0EA4k\u002Bsx4f7IgmdHNm3wRMpj5kTU4l0gChSGppo5p5wZyWA2\u002BKSFn16W6tRrGSfJob\u002BgqJukLcNDk0DBFYW2wIS2/NAzkugdLfZRXHOLqq5XJr89ElzlqyXU1o9D87l9YOcXjGBAQEA7oDTOxuU4iMAKPuhn5eJjzsM56bQrx3uORa8LKm42oDBCkBBg8PDw8PDwN96s39UOSCwMJmMQZzNjfNAPCbRRyke1B4VRKqOZ0NHlIAA2woQ13XO4Ug2aQ/cW4WBricVcUVqobFUU0dnRPtfIHeAxuYERXsV6HwdGjW\u002BhtpM0FEkw/mllbH5pyhn\u002BBx4r8wBAQEBAQEBAQEBAQEBAQEJAEBCgPXvpMqBogTeGhXjtFY4Rsn9bY/PgNX0l4iYOHMzUBQQgQCAugD")
|
||||
proof := &result.ProofWithKey{}
|
||||
r := io.NewBinReaderFromBuf(b)
|
||||
proof.DecodeBinary(r)
|
||||
return c.VerifyProof(root, proof)
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":"invalid"}`,
|
||||
fails: true,
|
||||
},
|
||||
},
|
||||
"findstates": {
|
||||
{
|
||||
name: "positive",
|
||||
|
|
|
@ -23,12 +23,15 @@ import (
|
|||
"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/fee"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
||||
"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/hash"
|
||||
"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/bigint"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
|
@ -1764,6 +1767,33 @@ func TestClient_GetNotaryServiceFeePerKey(t *testing.T) {
|
|||
require.Equal(t, defaultNotaryServiceFeePerKey, actual)
|
||||
}
|
||||
|
||||
func TestClient_States(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
stateheight, err := c.GetStateHeight()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, chain.BlockHeight(), stateheight.Local)
|
||||
|
||||
stateroot, err := c.GetStateRootByHeight(stateheight.Local)
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Run("proof", func(t *testing.T) {
|
||||
policy, err := chain.GetNativeContractScriptHash(nativenames.Policy)
|
||||
assert.NoError(t, err)
|
||||
proof, err := c.GetProof(stateroot.Root, policy, []byte{19}) // storagePrice key in policy contract
|
||||
assert.NoError(t, err)
|
||||
value, err := c.VerifyProof(stateroot.Root, proof)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, big.NewInt(native.DefaultStoragePrice), bigint.FromBytes(value))
|
||||
})
|
||||
}
|
||||
|
||||
func TestClientOracle(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
|
|
Loading…
Reference in a new issue