forked from TrueCloudLab/neoneo-go
parent
7d46404e2d
commit
ff4384d7ff
11 changed files with 344 additions and 2 deletions
|
@ -36,7 +36,7 @@ which would yield the response:
|
||||||
| Method | Implemented |
|
| Method | Implemented |
|
||||||
| ------- | ------------|
|
| ------- | ------------|
|
||||||
| `getaccountstate` | Yes |
|
| `getaccountstate` | Yes |
|
||||||
| `getapplicationlog` | No (#500) |
|
| `getapplicationlog` | Yes |
|
||||||
| `getassetstate` | Yes |
|
| `getassetstate` | Yes |
|
||||||
| `getbestblockhash` | Yes |
|
| `getbestblockhash` | Yes |
|
||||||
| `getblock` | Yes |
|
| `getblock` | Yes |
|
||||||
|
|
|
@ -839,6 +839,12 @@ func (bc *Blockchain) GetTransaction(hash util.Uint256) (*transaction.Transactio
|
||||||
return bc.dao.GetTransaction(hash)
|
return bc.dao.GetTransaction(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAppExecResult returns application execution result by the given
|
||||||
|
// tx hash.
|
||||||
|
func (bc *Blockchain) GetAppExecResult(hash util.Uint256) (*state.AppExecResult, error) {
|
||||||
|
return bc.dao.GetAppExecResult(hash)
|
||||||
|
}
|
||||||
|
|
||||||
// GetStorageItem returns an item from storage.
|
// GetStorageItem returns an item from storage.
|
||||||
func (bc *Blockchain) GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem {
|
func (bc *Blockchain) GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem {
|
||||||
return bc.dao.GetStorageItem(scripthash, key)
|
return bc.dao.GetStorageItem(scripthash, key)
|
||||||
|
|
|
@ -32,6 +32,7 @@ type Blockchainer interface {
|
||||||
HasTransaction(util.Uint256) bool
|
HasTransaction(util.Uint256) bool
|
||||||
GetAssetState(util.Uint256) *state.Asset
|
GetAssetState(util.Uint256) *state.Asset
|
||||||
GetAccountState(util.Uint160) *state.Account
|
GetAccountState(util.Uint160) *state.Account
|
||||||
|
GetAppExecResult(util.Uint256) (*state.AppExecResult, error)
|
||||||
GetValidators(txes ...*transaction.Transaction) ([]*keys.PublicKey, error)
|
GetValidators(txes ...*transaction.Transaction) ([]*keys.PublicKey, error)
|
||||||
GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error)
|
GetScriptHashesForVerifying(*transaction.Transaction) ([]util.Uint160, error)
|
||||||
GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem
|
GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem
|
||||||
|
|
|
@ -67,6 +67,9 @@ func (chain *testChain) Close() {
|
||||||
func (chain testChain) HeaderHeight() uint32 {
|
func (chain testChain) HeaderHeight() uint32 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
func (chain testChain) GetAppExecResult(hash util.Uint256) (*state.AppExecResult, error) {
|
||||||
|
panic("TODO")
|
||||||
|
}
|
||||||
func (chain testChain) GetBlock(hash util.Uint256) (*block.Block, error) {
|
func (chain testChain) GetBlock(hash util.Uint256) (*block.Block, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
60
pkg/rpc/response/result/application_log.go
Normal file
60
pkg/rpc/response/result/application_log.go
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package result
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/core/state"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/smartcontract"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ApplicationLog wrapper used for the representation of the
|
||||||
|
// state.AppExecResult based on the specific tx on the RPC Server.
|
||||||
|
type ApplicationLog struct {
|
||||||
|
TxHash util.Uint256 `json:"txid"`
|
||||||
|
Executions []Execution `json:"executions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execution response wrapper
|
||||||
|
type Execution struct {
|
||||||
|
Trigger string `json:"trigger"`
|
||||||
|
ScriptHash util.Uint160 `json:"contract"`
|
||||||
|
VMState string `json:"vmstate"`
|
||||||
|
GasConsumed util.Fixed8 `json:"gas_consumed"`
|
||||||
|
Stack json.RawMessage `json:"stack"`
|
||||||
|
Events []NotificationEvent `json:"notifications"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//NotificationEvent response wrapper
|
||||||
|
type NotificationEvent struct {
|
||||||
|
Contract util.Uint160 `json:"contract"`
|
||||||
|
Item smartcontract.Parameter `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewApplicationLog creates a new ApplicationLog wrapper.
|
||||||
|
func NewApplicationLog(appExecRes *state.AppExecResult, scriptHash util.Uint160) ApplicationLog {
|
||||||
|
events := make([]NotificationEvent, 0, len(appExecRes.Events))
|
||||||
|
for _, e := range appExecRes.Events {
|
||||||
|
item := e.Item.ToContractParameter()
|
||||||
|
events = append(events, NotificationEvent{
|
||||||
|
Contract: e.ScriptHash,
|
||||||
|
Item: item,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerString := appExecRes.Trigger.String()
|
||||||
|
|
||||||
|
executions := []Execution{{
|
||||||
|
Trigger: triggerString,
|
||||||
|
ScriptHash: scriptHash,
|
||||||
|
VMState: appExecRes.VMState,
|
||||||
|
GasConsumed: appExecRes.GasConsumed,
|
||||||
|
Stack: json.RawMessage(appExecRes.Stack),
|
||||||
|
Events: events,
|
||||||
|
}}
|
||||||
|
|
||||||
|
return ApplicationLog{
|
||||||
|
TxHash: appExecRes.TxHash,
|
||||||
|
Executions: executions,
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,13 @@ import "github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
// Metrics used in monitoring service.
|
// Metrics used in monitoring service.
|
||||||
var (
|
var (
|
||||||
|
getapplicationlogCalled = prometheus.NewCounter(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Help: "Number of calls to getapplicationlog rpc endpoint",
|
||||||
|
Name: "getapplicationlog_called",
|
||||||
|
Namespace: "neogo",
|
||||||
|
},
|
||||||
|
)
|
||||||
getbestblockhashCalled = prometheus.NewCounter(
|
getbestblockhashCalled = prometheus.NewCounter(
|
||||||
prometheus.CounterOpts{
|
prometheus.CounterOpts{
|
||||||
Help: "Number of calls to getbestblockhash rpc endpoint",
|
Help: "Number of calls to getbestblockhash rpc endpoint",
|
||||||
|
@ -143,6 +150,7 @@ var (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
prometheus.MustRegister(
|
prometheus.MustRegister(
|
||||||
|
getapplicationlogCalled,
|
||||||
getbestblockhashCalled,
|
getbestblockhashCalled,
|
||||||
getbestblockCalled,
|
getbestblockCalled,
|
||||||
getblockcountCalled,
|
getblockcountCalled,
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/CityOfZion/neo-go/pkg/core"
|
"github.com/CityOfZion/neo-go/pkg/core"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/state"
|
"github.com/CityOfZion/neo-go/pkg/core/state"
|
||||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
||||||
"github.com/CityOfZion/neo-go/pkg/encoding/address"
|
"github.com/CityOfZion/neo-go/pkg/encoding/address"
|
||||||
"github.com/CityOfZion/neo-go/pkg/io"
|
"github.com/CityOfZion/neo-go/pkg/io"
|
||||||
"github.com/CityOfZion/neo-go/pkg/network"
|
"github.com/CityOfZion/neo-go/pkg/network"
|
||||||
|
@ -114,6 +115,10 @@ func (s *Server) methodHandler(w http.ResponseWriter, req *request.In, reqParams
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
switch req.Method {
|
switch req.Method {
|
||||||
|
case "getapplicationlog":
|
||||||
|
getapplicationlogCalled.Inc()
|
||||||
|
results, resultsErr = s.getApplicationLog(reqParams)
|
||||||
|
|
||||||
case "getbestblockhash":
|
case "getbestblockhash":
|
||||||
getbestblockhashCalled.Inc()
|
getbestblockhashCalled.Inc()
|
||||||
results = "0x" + s.chain.CurrentBlockHash().StringLE()
|
results = "0x" + s.chain.CurrentBlockHash().StringLE()
|
||||||
|
@ -284,6 +289,39 @@ Methods:
|
||||||
s.WriteResponse(req, w, results)
|
s.WriteResponse(req, w, results)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getApplicationLog returns the contract log based on the specified txid.
|
||||||
|
func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, error) {
|
||||||
|
param, ok := reqParams.Value(0)
|
||||||
|
if !ok {
|
||||||
|
return nil, response.ErrInvalidParams
|
||||||
|
}
|
||||||
|
|
||||||
|
txHash, err := param.GetUint256()
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.ErrInvalidParams
|
||||||
|
}
|
||||||
|
|
||||||
|
appExecResult, err := s.chain.GetAppExecResult(txHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.NewRPCError("Unknown transaction", "", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, _, err := s.chain.GetTransaction(txHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.NewRPCError("Error while getting transaction", "", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var scriptHash util.Uint160
|
||||||
|
switch t := tx.Data.(type) {
|
||||||
|
case *transaction.InvocationTX:
|
||||||
|
scriptHash = hash.Hash160(t.Script)
|
||||||
|
default:
|
||||||
|
return nil, response.NewRPCError("Invalid transaction type", "", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.NewApplicationLog(appExecResult, scriptHash), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) getStorage(ps request.Params) (interface{}, error) {
|
func (s *Server) getStorage(ps request.Params) (interface{}, error) {
|
||||||
param, ok := ps.Value(0)
|
param, ok := ps.Value(0)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -40,6 +40,44 @@ type rpcTestCase struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var rpcTestCases = map[string][]rpcTestCase{
|
var rpcTestCases = map[string][]rpcTestCase{
|
||||||
|
"getapplicationlog": {
|
||||||
|
{
|
||||||
|
name: "positive",
|
||||||
|
params: `["d5cf936296de912aa4d051531bd8d25c7a58fb68fc7f87c8d3e6e85475187c08"]`,
|
||||||
|
result: func(e *executor) interface{} { return &result.ApplicationLog{} },
|
||||||
|
check: func(t *testing.T, e *executor, acc interface{}) {
|
||||||
|
res, ok := acc.(*result.ApplicationLog)
|
||||||
|
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
expectedTxHash := util.Uint256{0x8, 0x7c, 0x18, 0x75, 0x54, 0xe8, 0xe6, 0xd3, 0xc8, 0x87, 0x7f, 0xfc, 0x68, 0xfb, 0x58, 0x7a, 0x5c, 0xd2, 0xd8, 0x1b, 0x53, 0x51, 0xd0, 0xa4, 0x2a, 0x91, 0xde, 0x96, 0x62, 0x93, 0xcf, 0xd5}
|
||||||
|
assert.Equal(t, expectedTxHash, res.TxHash)
|
||||||
|
assert.Equal(t, 1, len(res.Executions))
|
||||||
|
assert.Equal(t, "Application", res.Executions[0].Trigger)
|
||||||
|
assert.Equal(t, "HALT", res.Executions[0].VMState)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no params",
|
||||||
|
params: `[]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid address",
|
||||||
|
params: `["notahash"]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid tx hash",
|
||||||
|
params: `["d24cc1d52b5c0216cbf3835bb5bac8ccf32639fa1ab6627ec4e2b9f33f7ec02f"]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid tx type",
|
||||||
|
params: `["f9adfde059810f37b3d0686d67f6b29034e0c669537df7e59b40c14a0508b9ed"]`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
"getaccountstate": {
|
"getaccountstate": {
|
||||||
{
|
{
|
||||||
name: "positive",
|
name: "positive",
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/smartcontract"
|
||||||
"github.com/CityOfZion/neo-go/pkg/util"
|
"github.com/CityOfZion/neo-go/pkg/util"
|
||||||
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
|
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
|
||||||
)
|
)
|
||||||
|
@ -169,6 +170,11 @@ func (c *Context) Dup() StackItem {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToContractParameter implements StackItem interface.
|
||||||
|
func (c *Context) ToContractParameter() smartcontract.Parameter {
|
||||||
|
panic("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Context) atBreakPoint() bool {
|
func (c *Context) atBreakPoint() bool {
|
||||||
for _, n := range c.breakPoints {
|
for _, n := range c.breakPoints {
|
||||||
if n == c.ip {
|
if n == c.ip {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/smartcontract"
|
||||||
"github.com/CityOfZion/neo-go/pkg/vm/emit"
|
"github.com/CityOfZion/neo-go/pkg/vm/emit"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,6 +18,8 @@ type StackItem interface {
|
||||||
Value() interface{}
|
Value() interface{}
|
||||||
// Dup duplicates current StackItem.
|
// Dup duplicates current StackItem.
|
||||||
Dup() StackItem
|
Dup() StackItem
|
||||||
|
// ToContractParameter converts StackItem to smartcontract.Parameter
|
||||||
|
ToContractParameter() smartcontract.Parameter
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeStackItem(v interface{}) StackItem {
|
func makeStackItem(v interface{}) StackItem {
|
||||||
|
@ -115,6 +118,19 @@ func (i *StructItem) Dup() StackItem {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToContractParameter implements StackItem interface.
|
||||||
|
func (i *StructItem) ToContractParameter() smartcontract.Parameter {
|
||||||
|
var value []smartcontract.Parameter
|
||||||
|
for _, stackItem := range i.value {
|
||||||
|
parameter := stackItem.ToContractParameter()
|
||||||
|
value = append(value, parameter)
|
||||||
|
}
|
||||||
|
return smartcontract.Parameter{
|
||||||
|
Type: smartcontract.ArrayType,
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clone returns a Struct with all Struct fields copied by value.
|
// Clone returns a Struct with all Struct fields copied by value.
|
||||||
// Array fields are still copied by reference.
|
// Array fields are still copied by reference.
|
||||||
func (i *StructItem) Clone() *StructItem {
|
func (i *StructItem) Clone() *StructItem {
|
||||||
|
@ -162,6 +178,14 @@ func (i *BigIntegerItem) Dup() StackItem {
|
||||||
return &BigIntegerItem{n.Set(i.value)}
|
return &BigIntegerItem{n.Set(i.value)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToContractParameter implements StackItem interface.
|
||||||
|
func (i *BigIntegerItem) ToContractParameter() smartcontract.Parameter {
|
||||||
|
return smartcontract.Parameter{
|
||||||
|
Type: smartcontract.IntegerType,
|
||||||
|
Value: i.value.Int64(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
func (i *BigIntegerItem) MarshalJSON() ([]byte, error) {
|
func (i *BigIntegerItem) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(i.value)
|
return json.Marshal(i.value)
|
||||||
|
@ -198,6 +222,14 @@ func (i *BoolItem) Dup() StackItem {
|
||||||
return &BoolItem{i.value}
|
return &BoolItem{i.value}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToContractParameter implements StackItem interface.
|
||||||
|
func (i *BoolItem) ToContractParameter() smartcontract.Parameter {
|
||||||
|
return smartcontract.Parameter{
|
||||||
|
Type: smartcontract.BoolType,
|
||||||
|
Value: i.value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ByteArrayItem represents a byte array on the stack.
|
// ByteArrayItem represents a byte array on the stack.
|
||||||
type ByteArrayItem struct {
|
type ByteArrayItem struct {
|
||||||
value []byte
|
value []byte
|
||||||
|
@ -231,6 +263,14 @@ func (i *ByteArrayItem) Dup() StackItem {
|
||||||
return &ByteArrayItem{a}
|
return &ByteArrayItem{a}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToContractParameter implements StackItem interface.
|
||||||
|
func (i *ByteArrayItem) ToContractParameter() smartcontract.Parameter {
|
||||||
|
return smartcontract.Parameter{
|
||||||
|
Type: smartcontract.ByteArrayType,
|
||||||
|
Value: i.value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ArrayItem represents a new ArrayItem object.
|
// ArrayItem represents a new ArrayItem object.
|
||||||
type ArrayItem struct {
|
type ArrayItem struct {
|
||||||
value []StackItem
|
value []StackItem
|
||||||
|
@ -263,6 +303,19 @@ func (i *ArrayItem) Dup() StackItem {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToContractParameter implements StackItem interface.
|
||||||
|
func (i *ArrayItem) ToContractParameter() smartcontract.Parameter {
|
||||||
|
var value []smartcontract.Parameter
|
||||||
|
for _, stackItem := range i.value {
|
||||||
|
parameter := stackItem.ToContractParameter()
|
||||||
|
value = append(value, parameter)
|
||||||
|
}
|
||||||
|
return smartcontract.Parameter{
|
||||||
|
Type: smartcontract.ArrayType,
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MapItem represents Map object.
|
// MapItem represents Map object.
|
||||||
type MapItem struct {
|
type MapItem struct {
|
||||||
value map[interface{}]StackItem
|
value map[interface{}]StackItem
|
||||||
|
@ -280,7 +333,6 @@ func (i *MapItem) Value() interface{} {
|
||||||
return i.value
|
return i.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
|
||||||
func (i *MapItem) String() string {
|
func (i *MapItem) String() string {
|
||||||
return "Map"
|
return "Map"
|
||||||
}
|
}
|
||||||
|
@ -297,6 +349,23 @@ func (i *MapItem) Dup() StackItem {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToContractParameter implements StackItem interface.
|
||||||
|
func (i *MapItem) ToContractParameter() smartcontract.Parameter {
|
||||||
|
value := make(map[smartcontract.Parameter]smartcontract.Parameter)
|
||||||
|
for key, val := range i.value {
|
||||||
|
pValue := val.ToContractParameter()
|
||||||
|
pKey := fromMapKey(key).ToContractParameter()
|
||||||
|
if pKey.Type == smartcontract.ByteArrayType {
|
||||||
|
pKey.Value = string(pKey.Value.([]byte))
|
||||||
|
}
|
||||||
|
value[pKey] = pValue
|
||||||
|
}
|
||||||
|
return smartcontract.Parameter{
|
||||||
|
Type: smartcontract.MapType,
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add adds key-value pair to the map.
|
// Add adds key-value pair to the map.
|
||||||
func (i *MapItem) Add(key, value StackItem) {
|
func (i *MapItem) Add(key, value StackItem) {
|
||||||
i.value[toMapKey(key)] = value
|
i.value[toMapKey(key)] = value
|
||||||
|
@ -316,6 +385,20 @@ func toMapKey(key StackItem) interface{} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fromMapKey converts map key to StackItem
|
||||||
|
func fromMapKey(key interface{}) StackItem {
|
||||||
|
switch t := key.(type) {
|
||||||
|
case bool:
|
||||||
|
return &BoolItem{value: t}
|
||||||
|
case int64:
|
||||||
|
return &BigIntegerItem{value: big.NewInt(t)}
|
||||||
|
case string:
|
||||||
|
return &ByteArrayItem{value: []byte(t)}
|
||||||
|
default:
|
||||||
|
panic("wrong key type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// InteropItem represents interop data on the stack.
|
// InteropItem represents interop data on the stack.
|
||||||
type InteropItem struct {
|
type InteropItem struct {
|
||||||
value interface{}
|
value interface{}
|
||||||
|
@ -344,6 +427,14 @@ func (i *InteropItem) Dup() StackItem {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToContractParameter implements StackItem interface.
|
||||||
|
func (i *InteropItem) ToContractParameter() smartcontract.Parameter {
|
||||||
|
return smartcontract.Parameter{
|
||||||
|
Type: smartcontract.InteropInterfaceType,
|
||||||
|
Value: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
func (i *InteropItem) MarshalJSON() ([]byte, error) {
|
func (i *InteropItem) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(i.value)
|
return json.Marshal(i.value)
|
||||||
|
|
91
pkg/vm/stack_item_test.go
Normal file
91
pkg/vm/stack_item_test.go
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/CityOfZion/neo-go/pkg/smartcontract"
|
||||||
|
)
|
||||||
|
|
||||||
|
var toContractParameterTestCases = []struct {
|
||||||
|
input StackItem
|
||||||
|
result smartcontract.Parameter
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
input: NewStructItem([]StackItem{
|
||||||
|
NewBigIntegerItem(1),
|
||||||
|
NewBoolItem(true),
|
||||||
|
}),
|
||||||
|
result: smartcontract.Parameter{Type: smartcontract.ArrayType, Value: []smartcontract.Parameter{
|
||||||
|
{Type: smartcontract.IntegerType, Value: int64(1)},
|
||||||
|
{Type: smartcontract.BoolType, Value: true},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: NewBoolItem(false),
|
||||||
|
result: smartcontract.Parameter{Type: smartcontract.BoolType, Value: false},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: NewByteArrayItem([]byte{0x01, 0x02, 0x03}),
|
||||||
|
result: smartcontract.Parameter{Type: smartcontract.ByteArrayType, Value: []byte{0x01, 0x02, 0x03}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: NewArrayItem([]StackItem{NewBigIntegerItem(2), NewBoolItem(true)}),
|
||||||
|
result: smartcontract.Parameter{Type: smartcontract.ArrayType, Value: []smartcontract.Parameter{
|
||||||
|
{Type: smartcontract.IntegerType, Value: int64(2)},
|
||||||
|
{Type: smartcontract.BoolType, Value: true},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: NewInteropItem(nil),
|
||||||
|
result: smartcontract.Parameter{Type: smartcontract.InteropInterfaceType, Value: nil},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: &MapItem{value: map[interface{}]StackItem{
|
||||||
|
toMapKey(NewBigIntegerItem(1)): NewBoolItem(true),
|
||||||
|
toMapKey(NewByteArrayItem([]byte("qwerty"))): NewBigIntegerItem(3),
|
||||||
|
toMapKey(NewBoolItem(true)): NewBoolItem(false),
|
||||||
|
}},
|
||||||
|
result: smartcontract.Parameter{
|
||||||
|
Type: smartcontract.MapType,
|
||||||
|
Value: map[smartcontract.Parameter]smartcontract.Parameter{
|
||||||
|
{Type: smartcontract.IntegerType, Value: int64(1)}: {Type: smartcontract.BoolType, Value: true},
|
||||||
|
{Type: smartcontract.ByteArrayType, Value: "qwerty"}: {Type: smartcontract.IntegerType, Value: int64(3)},
|
||||||
|
{Type: smartcontract.BoolType, Value: true}: {Type: smartcontract.BoolType, Value: false},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToContractParameter(t *testing.T) {
|
||||||
|
for _, tc := range toContractParameterTestCases {
|
||||||
|
res := tc.input.ToContractParameter()
|
||||||
|
assert.Equal(t, res, tc.result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fromMapKeyTestCases = []struct {
|
||||||
|
input interface{}
|
||||||
|
result StackItem
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
input: true,
|
||||||
|
result: NewBoolItem(true),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: int64(4),
|
||||||
|
result: NewBigIntegerItem(4),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "qwerty",
|
||||||
|
result: NewByteArrayItem([]byte("qwerty")),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromMapKey(t *testing.T) {
|
||||||
|
for _, tc := range fromMapKeyTestCases {
|
||||||
|
res := fromMapKey(tc.input)
|
||||||
|
assert.Equal(t, res, tc.result)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue