From d2ec0fed3d57d6b4fc7a82282472d0f5a9b9ecc0 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Wed, 15 Jul 2020 12:53:09 +0300 Subject: [PATCH] core: adjust System.Blockchain.GetContract interop Part of #1055. It should put on stack an array instead of interop interface. --- pkg/compiler/syscall.go | 2 +- pkg/core/interop_system.go | 22 ++++++++++++++++++++-- pkg/core/interop_system_test.go | 28 ++++++++++++++++++++++++++++ pkg/interop/blockchain/blockchain.go | 16 ++++++++++------ 4 files changed, 59 insertions(+), 9 deletions(-) diff --git a/pkg/compiler/syscall.go b/pkg/compiler/syscall.go index 88926e5fd..6f96c5f79 100644 --- a/pkg/compiler/syscall.go +++ b/pkg/compiler/syscall.go @@ -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}, diff --git a/pkg/core/interop_system.go b/pkg/core/interop_system.go index de84623aa..65f99db65 100644 --- a/pkg/core/interop_system.go +++ b/pkg/core/interop_system.go @@ -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 } diff --git a/pkg/core/interop_system_test.go b/pkg/core/interop_system_test.go index e17b3ffe2..e5ecf893e 100644 --- a/pkg/core/interop_system_test.go +++ b/pkg/core/interop_system_test.go @@ -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) + }) +} diff --git a/pkg/interop/blockchain/blockchain.go b/pkg/interop/blockchain/blockchain.go index 417cd9d76..c8e582a80 100644 --- a/pkg/interop/blockchain/blockchain.go +++ b/pkg/interop/blockchain/blockchain.go @@ -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{} }