core: add System.Blockchain.GetTransactionFromBlock interop
This commit is contained in:
parent
1e63ae4b3f
commit
d692de5ea4
6 changed files with 103 additions and 9 deletions
|
@ -35,14 +35,15 @@ var syscalls = map[string]map[string]string{
|
|||
"Deserialize": "Neo.Runtime.Deserialize",
|
||||
},
|
||||
"blockchain": {
|
||||
"GetAccount": "Neo.Blockchain.GetAccount",
|
||||
"GetBlock": "Neo.Blockchain.GetBlock",
|
||||
"GetContract": "Neo.Blockchain.GetContract",
|
||||
"GetHeader": "Neo.Blockchain.GetHeader",
|
||||
"GetHeight": "Neo.Blockchain.GetHeight",
|
||||
"GetTransaction": "System.Blockchain.GetTransaction",
|
||||
"GetTransactionHeight": "System.Blockchain.GetTransactionHeight",
|
||||
"GetValidators": "Neo.Blockchain.GetValidators",
|
||||
"GetAccount": "Neo.Blockchain.GetAccount",
|
||||
"GetBlock": "Neo.Blockchain.GetBlock",
|
||||
"GetContract": "Neo.Blockchain.GetContract",
|
||||
"GetHeader": "Neo.Blockchain.GetHeader",
|
||||
"GetHeight": "Neo.Blockchain.GetHeight",
|
||||
"GetTransaction": "System.Blockchain.GetTransaction",
|
||||
"GetTransactionFromBlock": "System.Blockchain.GetTransactionFromBlock",
|
||||
"GetTransactionHeight": "System.Blockchain.GetTransactionHeight",
|
||||
"GetValidators": "Neo.Blockchain.GetValidators",
|
||||
},
|
||||
"header": {
|
||||
"GetIndex": "Neo.Header.GetIndex",
|
||||
|
|
|
@ -306,11 +306,16 @@ func TestContractIsPayable(t *testing.T) {
|
|||
// Helper functions to create VM, InteropContext, TX, Account, Contract.
|
||||
|
||||
func createVMAndPushBlock(t *testing.T) (*vm.VM, *block.Block, *interop.Context, *Blockchain) {
|
||||
v, block, context, chain := createVMAndBlock(t)
|
||||
v.Estack().PushVal(stackitem.NewInterop(block))
|
||||
return v, block, context, chain
|
||||
}
|
||||
|
||||
func createVMAndBlock(t *testing.T) (*vm.VM, *block.Block, *interop.Context, *Blockchain) {
|
||||
v := vm.New()
|
||||
block := newDumbBlock()
|
||||
chain := newTestChain(t)
|
||||
context := chain.newInteropContext(trigger.Application, dao.NewSimple(storage.NewMemoryStore()), block, nil)
|
||||
v.Estack().PushVal(stackitem.NewInterop(block))
|
||||
return v, block, context, chain
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,27 @@ func bcGetTransaction(ic *interop.Context, v *vm.VM) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// bcGetTransactionFromBlock returns transaction with the given index from the
|
||||
// block with height or hash specified.
|
||||
func bcGetTransactionFromBlock(ic *interop.Context, v *vm.VM) error {
|
||||
hash, err := getBlockHashFromElement(ic.Chain, v.Estack().Pop())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
block, err := ic.DAO.GetBlock(hash)
|
||||
if err != nil || !isTraceableBlock(ic, block.Index) {
|
||||
v.Estack().PushVal(stackitem.Null{})
|
||||
return nil
|
||||
}
|
||||
index := v.Estack().Pop().BigInt().Int64()
|
||||
if index < 0 || index >= int64(len(block.Transactions)) {
|
||||
return errors.New("wrong transaction index")
|
||||
}
|
||||
tx := block.Transactions[index]
|
||||
v.Estack().PushVal(tx.Hash().BytesBE())
|
||||
return nil
|
||||
}
|
||||
|
||||
// bcGetTransactionHeight returns transaction height.
|
||||
func bcGetTransactionHeight(ic *interop.Context, v *vm.VM) error {
|
||||
_, h, err := getTransactionAndHeight(ic.DAO, v)
|
||||
|
|
|
@ -52,3 +52,61 @@ func TestBCGetTransaction(t *testing.T) {
|
|||
require.True(t, ok)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBCGetTransactionFromBlock(t *testing.T) {
|
||||
v, block, context, chain := createVMAndBlock(t)
|
||||
defer chain.Close()
|
||||
require.NoError(t, chain.AddBlock(chain.newBlock()))
|
||||
require.NoError(t, context.DAO.StoreAsBlock(block))
|
||||
|
||||
t.Run("success", func(t *testing.T) {
|
||||
v.Estack().PushVal(0)
|
||||
v.Estack().PushVal(block.Hash().BytesBE())
|
||||
err := bcGetTransactionFromBlock(context, v)
|
||||
require.NoError(t, err)
|
||||
|
||||
value := v.Estack().Pop().Value()
|
||||
actual, ok := value.([]byte)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, block.Transactions[0].Hash().BytesBE(), actual)
|
||||
})
|
||||
|
||||
t.Run("invalid block hash", func(t *testing.T) {
|
||||
v.Estack().PushVal(0)
|
||||
v.Estack().PushVal(block.Hash().BytesBE()[:10])
|
||||
err := bcGetTransactionFromBlock(context, v)
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("isn't traceable", func(t *testing.T) {
|
||||
block.Index = 2
|
||||
require.NoError(t, context.DAO.StoreAsBlock(block))
|
||||
v.Estack().PushVal(0)
|
||||
v.Estack().PushVal(block.Hash().BytesBE())
|
||||
err := bcGetTransactionFromBlock(context, v)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, ok := v.Estack().Pop().Item().(stackitem.Null)
|
||||
require.True(t, ok)
|
||||
})
|
||||
|
||||
t.Run("bad block hash", func(t *testing.T) {
|
||||
block.Index = 1
|
||||
require.NoError(t, context.DAO.StoreAsBlock(block))
|
||||
v.Estack().PushVal(0)
|
||||
v.Estack().PushVal(block.Hash().BytesLE())
|
||||
err := bcGetTransactionFromBlock(context, v)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, ok := v.Estack().Pop().Item().(stackitem.Null)
|
||||
require.True(t, ok)
|
||||
})
|
||||
|
||||
t.Run("bad transaction index", func(t *testing.T) {
|
||||
require.NoError(t, context.DAO.StoreAsBlock(block))
|
||||
v.Estack().PushVal(1)
|
||||
v.Estack().PushVal(block.Hash().BytesBE())
|
||||
err := bcGetTransactionFromBlock(context, v)
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -70,6 +70,7 @@ var systemInterops = []interop.Function{
|
|||
{Name: "System.Blockchain.GetHeader", Func: bcGetHeader, Price: 100},
|
||||
{Name: "System.Blockchain.GetHeight", Func: bcGetHeight, Price: 1},
|
||||
{Name: "System.Blockchain.GetTransaction", Func: bcGetTransaction, Price: 100},
|
||||
{Name: "System.Blockchain.GetTransactionFromBlock", Func: bcGetTransactionFromBlock, Price: 100},
|
||||
{Name: "System.Blockchain.GetTransactionHeight", Func: bcGetTransactionHeight, Price: 100},
|
||||
{Name: "System.Contract.Call", Func: contractCall, Price: 1},
|
||||
{Name: "System.Contract.CallEx", Func: contractCallEx, Price: 1},
|
||||
|
|
|
@ -65,6 +65,14 @@ func GetTransaction(hash []byte) Transaction {
|
|||
return Transaction{}
|
||||
}
|
||||
|
||||
// GetTransactionFromBlock returns transaction hash (256 bit in BE format
|
||||
// represented as a slice of 32 bytes) from the block found by the given hash or
|
||||
// index (with the same encoding as for GetHeader) by its index. This
|
||||
// function uses `System.Blockchain.GetTransactionFromBlock` syscall.
|
||||
func GetTransactionFromBlock(heightOrHash interface{}, index int) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTransactionHeight returns transaction's height (index of the block that
|
||||
// includes it) by the given ID (256 bit in BE format represented as a slice of
|
||||
// 32 bytes). This function uses `System.Blockchain.GetTransactionHeight` syscall.
|
||||
|
|
Loading…
Reference in a new issue