core: adjust System.Blockchain.GetContract interop

Part of #1055.

It should put on stack an array instead of interop interface.
This commit is contained in:
Anna Shaleva 2020-07-15 12:53:09 +03:00
parent 1a5fb01e61
commit d2ec0fed3d
4 changed files with 59 additions and 9 deletions

View file

@ -14,7 +14,7 @@ var syscalls = map[string]map[string]Syscall{
},
"blockchain": {
"GetBlock": {"System.Blockchain.GetBlock", true},
"GetContract": {"System.Blockchain.GetContract", false},
"GetContract": {"System.Blockchain.GetContract", true},
"GetHeight": {"System.Blockchain.GetHeight", false},
"GetTransaction": {"System.Blockchain.GetTransaction", true},
"GetTransactionFromBlock": {"System.Blockchain.GetTransactionFromBlock", false},

View file

@ -83,6 +83,20 @@ func bcGetBlock(ic *interop.Context, v *vm.VM) error {
return nil
}
// contractToStackItem converts state.Contract to stackitem.Item
func contractToStackItem(cs *state.Contract) (stackitem.Item, error) {
manifest, err := cs.Manifest.MarshalJSON()
if err != nil {
return nil, err
}
return stackitem.NewArray([]stackitem.Item{
stackitem.NewByteArray(cs.Script),
stackitem.NewByteArray(manifest),
stackitem.NewBool(cs.HasStorage()),
stackitem.NewBool(cs.IsPayable()),
}), nil
}
// bcGetContract returns contract.
func bcGetContract(ic *interop.Context, v *vm.VM) error {
hashbytes := v.Estack().Pop().Bytes()
@ -92,9 +106,13 @@ func bcGetContract(ic *interop.Context, v *vm.VM) error {
}
cs, err := ic.DAO.GetContractState(hash)
if err != nil {
v.Estack().PushVal([]byte{})
v.Estack().PushVal(stackitem.Null{})
} else {
v.Estack().PushVal(stackitem.NewInterop(cs))
item, err := contractToStackItem(cs)
if err != nil {
return err
}
v.Estack().PushVal(item)
}
return nil
}

View file

@ -292,3 +292,31 @@ func TestRuntimeGetInvocationCounter(t *testing.T) {
require.EqualValues(t, 42, v.Estack().Pop().BigInt().Int64())
})
}
func TestBlockchainGetContractState(t *testing.T) {
v, cs, ic, bc := createVMAndContractState(t)
defer bc.Close()
require.NoError(t, ic.DAO.PutContractState(cs))
t.Run("positive", func(t *testing.T) {
v.Estack().PushVal(cs.ScriptHash().BytesBE())
require.NoError(t, bcGetContract(ic, v))
expectedManifest, err := cs.Manifest.MarshalJSON()
require.NoError(t, err)
actual := v.Estack().Pop().Array()
require.Equal(t, 4, len(actual))
require.Equal(t, cs.Script, actual[0].Value().([]byte))
require.Equal(t, expectedManifest, actual[1].Value().([]byte))
require.Equal(t, cs.HasStorage(), actual[2].Bool())
require.Equal(t, cs.IsPayable(), actual[3].Bool())
})
t.Run("uncknown contract state", func(t *testing.T) {
v.Estack().PushVal(util.Uint160{1, 2, 3}.BytesBE())
require.NoError(t, bcGetContract(ic, v))
actual := v.Estack().Pop().Item()
require.Equal(t, stackitem.Null{}, actual)
})
}

View file

@ -3,10 +3,6 @@ Package blockchain provides functions to access various blockchain data.
*/
package blockchain
import (
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
)
// Transaction represents a NEO transaction. It's similar to Transaction class
// in Neo .net framework.
type Transaction struct {
@ -57,6 +53,14 @@ type Block struct {
TransactionsLength int
}
// Contract represents a Neo contract and is used in interop functions.
type Contract struct {
Script []byte
Manifest []byte
HasStorage bool
IsPayable bool
}
// GetHeight returns current block height (index of the last accepted block).
// Note that when transaction is being run as a part of new block this block is
// considered as not yet accepted (persisted) and thus you'll get an index of
@ -99,6 +103,6 @@ func GetTransactionHeight(hash []byte) int {
// format represented as a slice of 20 bytes). Refer to the `contract` package
// for details on how to use the returned structure. This function uses
// `System.Blockchain.GetContract` syscall.
func GetContract(scriptHash []byte) contract.Contract {
return contract.Contract{}
func GetContract(scriptHash []byte) Contract {
return Contract{}
}