diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go
index 247ced9d2..39b005081 100644
--- a/pkg/compiler/codegen.go
+++ b/pkg/compiler/codegen.go
@@ -1054,7 +1054,7 @@ func (c *codegen) convertSyscall(expr *ast.CallExpr, api, name string) {
 	}
 	emit.Syscall(c.prog.BinWriter, api)
 	switch name {
-	case "GetTransaction":
+	case "GetTransaction", "GetBlock":
 		c.emitConvert(stackitem.StructT)
 	}
 
diff --git a/pkg/compiler/syscall.go b/pkg/compiler/syscall.go
index 0c4135b59..0ea6e1158 100644
--- a/pkg/compiler/syscall.go
+++ b/pkg/compiler/syscall.go
@@ -36,7 +36,7 @@ var syscalls = map[string]map[string]string{
 	},
 	"blockchain": {
 		"GetAccount":              "Neo.Blockchain.GetAccount",
-		"GetBlock":                "Neo.Blockchain.GetBlock",
+		"GetBlock":                "System.Blockchain.GetBlock",
 		"GetContract":             "Neo.Blockchain.GetContract",
 		"GetHeader":               "Neo.Blockchain.GetHeader",
 		"GetHeight":               "Neo.Blockchain.GetHeight",
diff --git a/pkg/core/interop_neo_test.go b/pkg/core/interop_neo_test.go
index 3796ca8da..626e0c5cd 100644
--- a/pkg/core/interop_neo_test.go
+++ b/pkg/core/interop_neo_test.go
@@ -305,6 +305,14 @@ func TestContractIsPayable(t *testing.T) {
 
 // Helper functions to create VM, InteropContext, TX, Account, Contract.
 
+func createVM(t *testing.T) (*vm.VM, *interop.Context, *Blockchain) {
+	v := vm.New()
+	chain := newTestChain(t)
+	context := chain.newInteropContext(trigger.Application,
+		dao.NewSimple(storage.NewMemoryStore()), nil, nil)
+	return v, context, chain
+}
+
 func createVMAndPushBlock(t *testing.T) (*vm.VM, *block.Block, *interop.Context, *Blockchain) {
 	v, block, context, chain := createVMAndBlock(t)
 	v.Estack().PushVal(stackitem.NewInterop(block))
diff --git a/pkg/core/interop_system.go b/pkg/core/interop_system.go
index de1503a21..a571a09cf 100644
--- a/pkg/core/interop_system.go
+++ b/pkg/core/interop_system.go
@@ -53,6 +53,20 @@ func getBlockHashFromElement(bc blockchainer.Blockchainer, element *vm.Element)
 	return hash, nil
 }
 
+// blockToStackItem converts block.Block to stackitem.Item
+func blockToStackItem(b *block.Block) stackitem.Item {
+	return stackitem.NewArray([]stackitem.Item{
+		stackitem.NewByteArray(b.Hash().BytesBE()),
+		stackitem.NewBigInteger(big.NewInt(int64(b.Version))),
+		stackitem.NewByteArray(b.PrevHash.BytesBE()),
+		stackitem.NewByteArray(b.MerkleRoot.BytesBE()),
+		stackitem.NewBigInteger(big.NewInt(int64(b.Timestamp))),
+		stackitem.NewBigInteger(big.NewInt(int64(b.Index))),
+		stackitem.NewByteArray(b.NextConsensus.BytesBE()),
+		stackitem.NewBigInteger(big.NewInt(int64(len(b.Transactions)))),
+	})
+}
+
 // bcGetBlock returns current block.
 func bcGetBlock(ic *interop.Context, v *vm.VM) error {
 	hash, err := getBlockHashFromElement(ic.Chain, v.Estack().Pop())
@@ -60,10 +74,10 @@ func bcGetBlock(ic *interop.Context, v *vm.VM) error {
 		return err
 	}
 	block, err := ic.Chain.GetBlock(hash)
-	if err != nil {
-		v.Estack().PushVal([]byte{})
+	if err != nil || !isTraceableBlock(ic, block.Index) {
+		v.Estack().PushVal(stackitem.Null{})
 	} else {
-		v.Estack().PushVal(stackitem.NewInterop(block))
+		v.Estack().PushVal(blockToStackItem(block))
 	}
 	return nil
 }
diff --git a/pkg/core/interop_system_test.go b/pkg/core/interop_system_test.go
index caed6569c..3a06fcb4a 100644
--- a/pkg/core/interop_system_test.go
+++ b/pkg/core/interop_system_test.go
@@ -110,3 +110,38 @@ func TestBCGetTransactionFromBlock(t *testing.T) {
 		require.Error(t, err)
 	})
 }
+
+func TestBCGetBlock(t *testing.T) {
+	v, context, chain := createVM(t)
+	defer chain.Close()
+	block := chain.newBlock()
+	require.NoError(t, chain.AddBlock(block))
+
+	t.Run("success", func(t *testing.T) {
+		v.Estack().PushVal(block.Hash().BytesBE())
+		err := bcGetBlock(context, v)
+		require.NoError(t, err)
+
+		value := v.Estack().Pop().Value()
+		actual, ok := value.([]stackitem.Item)
+		require.True(t, ok)
+		require.Equal(t, 8, len(actual))
+		require.Equal(t, block.Hash().BytesBE(), actual[0].Value().([]byte))
+		require.Equal(t, int64(block.Version), actual[1].Value().(*big.Int).Int64())
+		require.Equal(t, block.PrevHash.BytesBE(), actual[2].Value().([]byte))
+		require.Equal(t, block.MerkleRoot.BytesBE(), actual[3].Value().([]byte))
+		require.Equal(t, int64(block.Timestamp), actual[4].Value().(*big.Int).Int64())
+		require.Equal(t, int64(block.Index), actual[5].Value().(*big.Int).Int64())
+		require.Equal(t, block.NextConsensus.BytesBE(), actual[6].Value().([]byte))
+		require.Equal(t, int64(len(block.Transactions)), actual[7].Value().(*big.Int).Int64())
+	})
+
+	t.Run("bad hash", func(t *testing.T) {
+		v.Estack().PushVal(block.Hash().BytesLE())
+		err := bcGetTransaction(context, v)
+		require.NoError(t, err)
+
+		_, ok := v.Estack().Pop().Item().(stackitem.Null)
+		require.True(t, ok)
+	})
+}
diff --git a/pkg/core/interops.go b/pkg/core/interops.go
index 068534d19..97bc2a6af 100644
--- a/pkg/core/interops.go
+++ b/pkg/core/interops.go
@@ -64,7 +64,7 @@ func getInteropFromSlice(ic *interop.Context, slice []interop.Function) func(uin
 var systemInterops = []interop.Function{
 	{Name: "System.Block.GetTransactionCount", Func: blockGetTransactionCount, Price: 1},
 	{Name: "System.Block.GetTransactions", Func: blockGetTransactions, Price: 1},
-	{Name: "System.Blockchain.GetBlock", Func: bcGetBlock, Price: 200},
+	{Name: "System.Blockchain.GetBlock", Func: bcGetBlock, Price: 250},
 	{Name: "System.Blockchain.GetContract", Func: bcGetContract, Price: 100},
 	{Name: "System.Blockchain.GetHeader", Func: bcGetHeader, Price: 100},
 	{Name: "System.Blockchain.GetHeight", Func: bcGetHeight, Price: 1},
@@ -107,7 +107,6 @@ var neoInterops = []interop.Function{
 	{Name: "Neo.Block.GetTransactionCount", Func: blockGetTransactionCount, Price: 1},
 	{Name: "Neo.Block.GetTransactions", Func: blockGetTransactions, Price: 1},
 	{Name: "Neo.Blockchain.GetAccount", Func: bcGetAccount, Price: 100},
-	{Name: "Neo.Blockchain.GetBlock", Func: bcGetBlock, Price: 200},
 	{Name: "Neo.Blockchain.GetContract", Func: bcGetContract, Price: 100},
 	{Name: "Neo.Blockchain.GetHeader", Func: bcGetHeader, Price: 100},
 	{Name: "Neo.Blockchain.GetHeight", Func: bcGetHeight, Price: 1},
diff --git a/pkg/interop/blockchain/blockchain.go b/pkg/interop/blockchain/blockchain.go
index db7b5c7db..5afb272a5 100644
--- a/pkg/interop/blockchain/blockchain.go
+++ b/pkg/interop/blockchain/blockchain.go
@@ -5,7 +5,6 @@ package blockchain
 
 import (
 	"github.com/nspcc-dev/neo-go/pkg/interop/account"
-	"github.com/nspcc-dev/neo-go/pkg/interop/block"
 	"github.com/nspcc-dev/neo-go/pkg/interop/contract"
 	"github.com/nspcc-dev/neo-go/pkg/interop/header"
 )
@@ -34,6 +33,32 @@ type Transaction struct {
 	Script []byte
 }
 
+// Block represents a NEO block, it's a data structure that you can get
+// block-related data from. It's similar to the Block class in the Neo .net
+// framework. To use it you need to get it via GetBlock function call.
+type Block struct {
+	// Hash represents the hash (256 bit BE value in a 32 byte slice) of the
+	// given block.
+	Hash []byte
+	// Version of the block.
+	Version int
+	// PrevHash represents the hash (256 bit BE value in a 32 byte slice) of the
+	// previous block.
+	PrevHash []byte
+	// MerkleRoot represents the root hash (256 bit BE value in a 32 byte slice)
+	// of a transaction list.
+	MerkleRoot []byte
+	// Timestamp represents millisecond-precision block timestamp.
+	Timestamp int
+	// Index represents the height of the block.
+	Index int
+	// NextConsensus representes contract address of the next miner (160 bit BE
+	// value in a 20 byte slice).
+	NextConsensus []byte
+	// TransactionsLength represents the length of block's transactions array.
+	TransactionsLength int
+}
+
 // 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
@@ -52,10 +77,10 @@ func GetHeader(heightOrHash interface{}) header.Header {
 }
 
 // GetBlock returns block found by the given hash or index (with the same
-// encoding as for GetHeader). Refer to the `block` package for possible uses
-// of returned structure. This function uses `Neo.Blockchain.GetBlock` syscall.
-func GetBlock(heightOrHash interface{}) block.Block {
-	return block.Block{}
+// encoding as for GetHeader). This function uses `System.Blockchain.GetBlock`
+// syscall.
+func GetBlock(heightOrHash interface{}) Block {
+	return Block{}
 }
 
 // GetTransaction returns transaction found by the given hash (256 bit in BE