rpc: use raw stack items in invoke*
RPC
Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
7b4acd5a7f
commit
9cba25616d
6 changed files with 103 additions and 80 deletions
|
@ -6,12 +6,12 @@ import (
|
|||
|
||||
"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/encoding/bigint"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"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/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
)
|
||||
|
||||
|
@ -192,46 +192,20 @@ func (c *Client) MultiTransferNEP5(acc *wallet.Account, token util.Uint160, gas
|
|||
return c.SendRawTransaction(tx)
|
||||
}
|
||||
|
||||
func topIntFromStack(st []smartcontract.Parameter) (int64, error) {
|
||||
func topIntFromStack(st []stackitem.Item) (int64, error) {
|
||||
index := len(st) - 1 // top stack element is last in the array
|
||||
var decimals int64
|
||||
switch typ := st[index].Type; typ {
|
||||
case smartcontract.IntegerType:
|
||||
var ok bool
|
||||
decimals, ok = st[index].Value.(int64)
|
||||
if !ok {
|
||||
return 0, errors.New("invalid Integer item")
|
||||
}
|
||||
case smartcontract.ByteArrayType:
|
||||
data, ok := st[index].Value.([]byte)
|
||||
if !ok {
|
||||
return 0, errors.New("invalid ByteArray item")
|
||||
}
|
||||
decimals = bigint.FromBytes(data).Int64()
|
||||
default:
|
||||
return 0, fmt.Errorf("invalid stack item type: %s", typ)
|
||||
bi, err := st[index].TryInteger()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return decimals, nil
|
||||
return bi.Int64(), nil
|
||||
}
|
||||
|
||||
func topStringFromStack(st []smartcontract.Parameter) (string, error) {
|
||||
func topStringFromStack(st []stackitem.Item) (string, error) {
|
||||
index := len(st) - 1 // top stack element is last in the array
|
||||
var s string
|
||||
switch typ := st[index].Type; typ {
|
||||
case smartcontract.StringType:
|
||||
var ok bool
|
||||
s, ok = st[index].Value.(string)
|
||||
if !ok {
|
||||
return "", errors.New("invalid String item")
|
||||
}
|
||||
case smartcontract.ByteArrayType:
|
||||
data, ok := st[index].Value.([]byte)
|
||||
if !ok {
|
||||
return "", errors.New("invalid ByteArray item")
|
||||
}
|
||||
s = string(data)
|
||||
default:
|
||||
return "", fmt.Errorf("invalid stack item type: %s", typ)
|
||||
bs, err := st[index].TryBytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return s, nil
|
||||
return string(bs), nil
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -51,27 +52,26 @@ func (c *Client) GetBlockedAccounts() (native.BlockedAccounts, error) {
|
|||
return topBlockedAccountsFromStack(result.Stack)
|
||||
}
|
||||
|
||||
func topBlockedAccountsFromStack(st []smartcontract.Parameter) (native.BlockedAccounts, error) {
|
||||
func topBlockedAccountsFromStack(st []stackitem.Item) (native.BlockedAccounts, error) {
|
||||
index := len(st) - 1 // top stack element is last in the array
|
||||
var (
|
||||
ba native.BlockedAccounts
|
||||
err error
|
||||
)
|
||||
switch typ := st[index].Type; typ {
|
||||
case smartcontract.ArrayType:
|
||||
data, ok := st[index].Value.([]smartcontract.Parameter)
|
||||
items, ok := st[index].Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid stack item type: %s", st[index].Type())
|
||||
}
|
||||
ba = make(native.BlockedAccounts, len(items))
|
||||
for i, account := range items {
|
||||
val, ok := account.Value().([]byte)
|
||||
if !ok {
|
||||
return nil, errors.New("invalid Array item")
|
||||
return nil, fmt.Errorf("invalid array element: %s", account.Type())
|
||||
}
|
||||
ba = make(native.BlockedAccounts, len(data))
|
||||
for i, account := range data {
|
||||
ba[i], err = util.Uint160DecodeBytesLE(account.Value.([]byte))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ba[i], err = util.Uint160DecodeBytesLE(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid stack item type: %s", typ)
|
||||
}
|
||||
return ba, nil
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -648,12 +649,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
State: "HALT",
|
||||
GasConsumed: 31100000,
|
||||
Script: "1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf",
|
||||
Stack: []smartcontract.Parameter{
|
||||
{
|
||||
Type: smartcontract.ByteArrayType,
|
||||
Value: bytes,
|
||||
},
|
||||
},
|
||||
Stack: []stackitem.Item{stackitem.NewByteArray(bytes)},
|
||||
}
|
||||
},
|
||||
},
|
||||
|
@ -680,12 +676,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
State: "HALT",
|
||||
GasConsumed: 16100000,
|
||||
Script: "00046e616d656724058e5e1b6008847cd662728549088a9ee82191",
|
||||
Stack: []smartcontract.Parameter{
|
||||
{
|
||||
Type: smartcontract.ByteArrayType,
|
||||
Value: bytes,
|
||||
},
|
||||
},
|
||||
Stack: []stackitem.Item{stackitem.NewByteArray(bytes)},
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,14 +1,76 @@
|
|||
package result
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// Invoke represents code invocation result and is used by several RPC calls
|
||||
// that invoke functions, scripts and generic bytecode.
|
||||
type Invoke struct {
|
||||
State string `json:"state"`
|
||||
GasConsumed int64 `json:"gasconsumed,string"`
|
||||
Script string `json:"script"`
|
||||
Stack []smartcontract.Parameter `json:"stack"`
|
||||
State string `json:"state"`
|
||||
GasConsumed int64 `json:"gasconsumed,string"`
|
||||
Script string `json:"script"`
|
||||
Stack []stackitem.Item `json:"stack"`
|
||||
}
|
||||
|
||||
type invokeAux struct {
|
||||
State string `json:"state"`
|
||||
GasConsumed int64 `json:"gasconsumed,string"`
|
||||
Script string `json:"script"`
|
||||
Stack json.RawMessage `json:"stack"`
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (r Invoke) MarshalJSON() ([]byte, error) {
|
||||
var st json.RawMessage
|
||||
arr := make([]json.RawMessage, len(r.Stack))
|
||||
for i := range arr {
|
||||
data, err := stackitem.ToJSONWithTypes(r.Stack[i])
|
||||
if err != nil {
|
||||
st = []byte("error: recursive reference")
|
||||
break
|
||||
}
|
||||
arr[i] = data
|
||||
}
|
||||
|
||||
var err error
|
||||
if st == nil {
|
||||
st, err = json.Marshal(arr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return json.Marshal(&invokeAux{
|
||||
GasConsumed: r.GasConsumed,
|
||||
Script: r.Script,
|
||||
State: r.State,
|
||||
Stack: st,
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
func (r *Invoke) UnmarshalJSON(data []byte) error {
|
||||
aux := new(invokeAux)
|
||||
if err := json.Unmarshal(data, aux); err != nil {
|
||||
return err
|
||||
}
|
||||
var arr []json.RawMessage
|
||||
if err := json.Unmarshal(aux.Stack, &arr); err == nil {
|
||||
st := make([]stackitem.Item, len(arr))
|
||||
for i := range arr {
|
||||
st[i], err = stackitem.FromJSONWithTypes(arr[i])
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
r.Stack = st
|
||||
}
|
||||
}
|
||||
r.GasConsumed = aux.GasConsumed
|
||||
r.Script = aux.Script
|
||||
r.State = aux.State
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"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/network"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpc"
|
||||
|
@ -623,14 +622,11 @@ func (s *Server) getDecimals(contractID int32, cache map[int32]decimals) (decima
|
|||
}
|
||||
|
||||
d := decimals{Hash: h}
|
||||
switch item := res.Stack[len(res.Stack)-1]; item.Type {
|
||||
case smartcontract.IntegerType:
|
||||
d.Value = item.Value.(int64)
|
||||
case smartcontract.ByteArrayType:
|
||||
d.Value = bigint.FromBytes(item.Value.([]byte)).Int64()
|
||||
default:
|
||||
return d, errors.New("invalid result: not an integer")
|
||||
bi, err := res.Stack[len(res.Stack)-1].TryInteger()
|
||||
if err != nil {
|
||||
return decimals{}, err
|
||||
}
|
||||
d.Value = bi.Int64()
|
||||
if d.Value < 0 {
|
||||
return d, errors.New("incorrect result: negative result")
|
||||
}
|
||||
|
@ -896,7 +892,7 @@ func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) *resu
|
|||
State: vm.State().String(),
|
||||
GasConsumed: vm.GasConsumed(),
|
||||
Script: hex.EncodeToString(script),
|
||||
Stack: vm.Estack().ToContractParameters(),
|
||||
Stack: vm.Estack().ToArray(),
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -531,7 +531,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
require.True(t, ok)
|
||||
assert.Equal(t, "HALT", res.State)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
require.Equal(t, int64(3), res.Stack[0].Value)
|
||||
require.Equal(t, big.NewInt(3), res.Stack[0].Value())
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -543,7 +543,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
require.True(t, ok)
|
||||
assert.Equal(t, "HALT", res.State)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
require.Equal(t, int64(2), res.Stack[0].Value)
|
||||
require.Equal(t, big.NewInt(2), res.Stack[0].Value())
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -555,7 +555,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
require.True(t, ok)
|
||||
assert.Equal(t, "HALT", res.State)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
require.Equal(t, int64(1), res.Stack[0].Value)
|
||||
require.Equal(t, big.NewInt(1), res.Stack[0].Value())
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -567,7 +567,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
require.True(t, ok)
|
||||
assert.Equal(t, "HALT", res.State)
|
||||
assert.Equal(t, 1, len(res.Stack))
|
||||
assert.Equal(t, int64(1), res.Stack[0].Value)
|
||||
assert.Equal(t, big.NewInt(1), res.Stack[0].Value())
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue