forked from TrueCloudLab/neoneo-go
core: update System.Blockchain.GetBlock interop
closes #1025 Now we put on stack stackitem.Array instead of Interop, so we're able to use all available block properties without extra interop getters. Removed Neo.Blockchain.GetBlock interop as we don't need it anymore.
This commit is contained in:
parent
e2187c0a96
commit
7a2d37cf7e
7 changed files with 93 additions and 12 deletions
|
@ -1054,7 +1054,7 @@ func (c *codegen) convertSyscall(expr *ast.CallExpr, api, name string) {
|
||||||
}
|
}
|
||||||
emit.Syscall(c.prog.BinWriter, api)
|
emit.Syscall(c.prog.BinWriter, api)
|
||||||
switch name {
|
switch name {
|
||||||
case "GetTransaction":
|
case "GetTransaction", "GetBlock":
|
||||||
c.emitConvert(stackitem.StructT)
|
c.emitConvert(stackitem.StructT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ var syscalls = map[string]map[string]string{
|
||||||
},
|
},
|
||||||
"blockchain": {
|
"blockchain": {
|
||||||
"GetAccount": "Neo.Blockchain.GetAccount",
|
"GetAccount": "Neo.Blockchain.GetAccount",
|
||||||
"GetBlock": "Neo.Blockchain.GetBlock",
|
"GetBlock": "System.Blockchain.GetBlock",
|
||||||
"GetContract": "Neo.Blockchain.GetContract",
|
"GetContract": "Neo.Blockchain.GetContract",
|
||||||
"GetHeader": "Neo.Blockchain.GetHeader",
|
"GetHeader": "Neo.Blockchain.GetHeader",
|
||||||
"GetHeight": "Neo.Blockchain.GetHeight",
|
"GetHeight": "Neo.Blockchain.GetHeight",
|
||||||
|
|
|
@ -305,6 +305,14 @@ func TestContractIsPayable(t *testing.T) {
|
||||||
|
|
||||||
// Helper functions to create VM, InteropContext, TX, Account, Contract.
|
// 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) {
|
func createVMAndPushBlock(t *testing.T) (*vm.VM, *block.Block, *interop.Context, *Blockchain) {
|
||||||
v, block, context, chain := createVMAndBlock(t)
|
v, block, context, chain := createVMAndBlock(t)
|
||||||
v.Estack().PushVal(stackitem.NewInterop(block))
|
v.Estack().PushVal(stackitem.NewInterop(block))
|
||||||
|
|
|
@ -53,6 +53,20 @@ func getBlockHashFromElement(bc blockchainer.Blockchainer, element *vm.Element)
|
||||||
return hash, nil
|
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.
|
// bcGetBlock returns current block.
|
||||||
func bcGetBlock(ic *interop.Context, v *vm.VM) error {
|
func bcGetBlock(ic *interop.Context, v *vm.VM) error {
|
||||||
hash, err := getBlockHashFromElement(ic.Chain, v.Estack().Pop())
|
hash, err := getBlockHashFromElement(ic.Chain, v.Estack().Pop())
|
||||||
|
@ -60,10 +74,10 @@ func bcGetBlock(ic *interop.Context, v *vm.VM) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
block, err := ic.Chain.GetBlock(hash)
|
block, err := ic.Chain.GetBlock(hash)
|
||||||
if err != nil {
|
if err != nil || !isTraceableBlock(ic, block.Index) {
|
||||||
v.Estack().PushVal([]byte{})
|
v.Estack().PushVal(stackitem.Null{})
|
||||||
} else {
|
} else {
|
||||||
v.Estack().PushVal(stackitem.NewInterop(block))
|
v.Estack().PushVal(blockToStackItem(block))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,3 +110,38 @@ func TestBCGetTransactionFromBlock(t *testing.T) {
|
||||||
require.Error(t, err)
|
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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ func getInteropFromSlice(ic *interop.Context, slice []interop.Function) func(uin
|
||||||
var systemInterops = []interop.Function{
|
var systemInterops = []interop.Function{
|
||||||
{Name: "System.Block.GetTransactionCount", Func: blockGetTransactionCount, Price: 1},
|
{Name: "System.Block.GetTransactionCount", Func: blockGetTransactionCount, Price: 1},
|
||||||
{Name: "System.Block.GetTransactions", Func: blockGetTransactions, 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.GetContract", Func: bcGetContract, Price: 100},
|
||||||
{Name: "System.Blockchain.GetHeader", Func: bcGetHeader, Price: 100},
|
{Name: "System.Blockchain.GetHeader", Func: bcGetHeader, Price: 100},
|
||||||
{Name: "System.Blockchain.GetHeight", Func: bcGetHeight, Price: 1},
|
{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.GetTransactionCount", Func: blockGetTransactionCount, Price: 1},
|
||||||
{Name: "Neo.Block.GetTransactions", Func: blockGetTransactions, Price: 1},
|
{Name: "Neo.Block.GetTransactions", Func: blockGetTransactions, Price: 1},
|
||||||
{Name: "Neo.Blockchain.GetAccount", Func: bcGetAccount, Price: 100},
|
{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.GetContract", Func: bcGetContract, Price: 100},
|
||||||
{Name: "Neo.Blockchain.GetHeader", Func: bcGetHeader, Price: 100},
|
{Name: "Neo.Blockchain.GetHeader", Func: bcGetHeader, Price: 100},
|
||||||
{Name: "Neo.Blockchain.GetHeight", Func: bcGetHeight, Price: 1},
|
{Name: "Neo.Blockchain.GetHeight", Func: bcGetHeight, Price: 1},
|
||||||
|
|
|
@ -5,7 +5,6 @@ package blockchain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/account"
|
"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/contract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/header"
|
"github.com/nspcc-dev/neo-go/pkg/interop/header"
|
||||||
)
|
)
|
||||||
|
@ -34,6 +33,32 @@ type Transaction struct {
|
||||||
Script []byte
|
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).
|
// 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
|
// 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
|
// 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
|
// 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
|
// encoding as for GetHeader). This function uses `System.Blockchain.GetBlock`
|
||||||
// of returned structure. This function uses `Neo.Blockchain.GetBlock` syscall.
|
// syscall.
|
||||||
func GetBlock(heightOrHash interface{}) block.Block {
|
func GetBlock(heightOrHash interface{}) Block {
|
||||||
return block.Block{}
|
return Block{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransaction returns transaction found by the given hash (256 bit in BE
|
// GetTransaction returns transaction found by the given hash (256 bit in BE
|
||||||
|
|
Loading…
Reference in a new issue