neoneo-go/pkg/core/interop_neo_test.go
Roman Khimov 7e371588a7 core/tx: remove one layer of indirection for scripts and inouts
It reduces heap pressure a little for these elements as we don't have to
allocate/free them individually. And they're directly tied to transactions or
block, not being shared or anything like that, so it makes little sense for
them to be pointer-based. It only makes building transactions a little easier,
but that's obviously a minor usecase.
2019-12-09 17:14:10 +03:00

422 lines
12 KiB
Go

package core
import (
"math/big"
"testing"
"github.com/CityOfZion/neo-go/pkg/core/storage"
"github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/smartcontract"
"github.com/CityOfZion/neo-go/pkg/smartcontract/trigger"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/CityOfZion/neo-go/pkg/vm"
"github.com/stretchr/testify/require"
)
/* Missing tests:
* TestTxGetReferences
* TestTxGetUnspentCoins
* TestTxGetWitnesses
* TestBcGetAccount
* TestBcGetAsset
* TestAccountGetBalance
* TestAccountIsStandard
* TestCreateContractStateFromVM
* TestContractCreate
* TestContractMigrate
* TestAssetCreate
* TestAssetRenew
* TestRuntimeSerialize
* TestRuntimeDeserialize
*/
func TestHeaderGetVersion(t *testing.T) {
v, block, context := createVMAndPushBlock(t)
err := context.headerGetVersion(v)
require.NoError(t, err)
value := v.Estack().Pop().Value().(*big.Int)
require.Equal(t, uint64(block.Version), value.Uint64())
}
func TestHeaderGetVersion_Negative(t *testing.T) {
v := vm.New()
block := newDumbBlock()
context := newInteropContext(trigger.Application, newTestChain(t), storage.NewMemoryStore(), block, nil)
v.Estack().PushVal(vm.NewBoolItem(false))
err := context.headerGetVersion(v)
require.Errorf(t, err, "value is not a header or block")
}
func TestHeaderGetConsensusData(t *testing.T) {
v, block, context := createVMAndPushBlock(t)
err := context.headerGetConsensusData(v)
require.NoError(t, err)
value := v.Estack().Pop().Value().(*big.Int)
require.Equal(t, block.ConsensusData, value.Uint64())
}
func TestHeaderGetMerkleRoot(t *testing.T) {
v, block, context := createVMAndPushBlock(t)
err := context.headerGetMerkleRoot(v)
require.NoError(t, err)
value := v.Estack().Pop().Value()
require.Equal(t, block.MerkleRoot.BytesLE(), value)
}
func TestHeaderGetNextConsensus(t *testing.T) {
v, block, context := createVMAndPushBlock(t)
err := context.headerGetNextConsensus(v)
require.NoError(t, err)
value := v.Estack().Pop().Value()
require.Equal(t, block.NextConsensus.BytesLE(), value)
}
func TestTxGetAttributes(t *testing.T) {
v, tx, context := createVMAndPushTX(t)
err := context.txGetAttributes(v)
require.NoError(t, err)
value := v.Estack().Pop().Value().([]vm.StackItem)
require.Equal(t, tx.Attributes[0].Usage, value[0].Value().(*transaction.Attribute).Usage)
}
func TestTxGetInputs(t *testing.T) {
v, tx, context := createVMAndPushTX(t)
err := context.txGetInputs(v)
require.NoError(t, err)
value := v.Estack().Pop().Value().([]vm.StackItem)
require.Equal(t, tx.Inputs[0], *value[0].Value().(*transaction.Input))
}
func TestTxGetOutputs(t *testing.T) {
v, tx, context := createVMAndPushTX(t)
err := context.txGetOutputs(v)
require.NoError(t, err)
value := v.Estack().Pop().Value().([]vm.StackItem)
require.Equal(t, tx.Outputs[0], *value[0].Value().(*transaction.Output))
}
func TestTxGetType(t *testing.T) {
v, tx, context := createVMAndPushTX(t)
err := context.txGetType(v)
require.NoError(t, err)
value := v.Estack().Pop().Value().(*big.Int)
require.Equal(t, big.NewInt(int64(tx.Type)), value)
}
func TestPopInputFromVM(t *testing.T) {
v, tx, _ := createVMAndTX(t)
v.Estack().PushVal(vm.NewInteropItem(&tx.Inputs[0]))
input, err := popInputFromVM(v)
require.NoError(t, err)
require.Equal(t, tx.Inputs[0], *input)
}
func TestInputGetHash(t *testing.T) {
v, tx, context := createVMAndTX(t)
v.Estack().PushVal(vm.NewInteropItem(&tx.Inputs[0]))
err := context.inputGetHash(v)
require.NoError(t, err)
hash := v.Estack().Pop().Value()
require.Equal(t, tx.Inputs[0].PrevHash.BytesBE(), hash)
}
func TestInputGetIndex(t *testing.T) {
v, tx, context := createVMAndTX(t)
v.Estack().PushVal(vm.NewInteropItem(&tx.Inputs[0]))
err := context.inputGetIndex(v)
require.NoError(t, err)
index := v.Estack().Pop().Value()
require.Equal(t, big.NewInt(int64(tx.Inputs[0].PrevIndex)), index)
}
func TestPopOutputFromVM(t *testing.T) {
v, tx, _ := createVMAndTX(t)
v.Estack().PushVal(vm.NewInteropItem(&tx.Outputs[0]))
output, err := popOutputFromVM(v)
require.NoError(t, err)
require.Equal(t, tx.Outputs[0], *output)
}
func TestOutputGetAssetID(t *testing.T) {
v, tx, context := createVMAndTX(t)
v.Estack().PushVal(vm.NewInteropItem(&tx.Outputs[0]))
err := context.outputGetAssetID(v)
require.NoError(t, err)
assetID := v.Estack().Pop().Value()
require.Equal(t, tx.Outputs[0].AssetID.BytesBE(), assetID)
}
func TestOutputGetScriptHash(t *testing.T) {
v, tx, context := createVMAndTX(t)
v.Estack().PushVal(vm.NewInteropItem(&tx.Outputs[0]))
err := context.outputGetScriptHash(v)
require.NoError(t, err)
scriptHash := v.Estack().Pop().Value()
require.Equal(t, tx.Outputs[0].ScriptHash.BytesBE(), scriptHash)
}
func TestOutputGetValue(t *testing.T) {
v, tx, context := createVMAndTX(t)
v.Estack().PushVal(vm.NewInteropItem(&tx.Outputs[0]))
err := context.outputGetValue(v)
require.NoError(t, err)
amount := v.Estack().Pop().Value()
require.Equal(t, big.NewInt(int64(tx.Outputs[0].Amount)), amount)
}
func TestAttrGetData(t *testing.T) {
v, tx, context := createVMAndTX(t)
v.Estack().PushVal(vm.NewInteropItem(&tx.Attributes[0]))
err := context.attrGetData(v)
require.NoError(t, err)
data := v.Estack().Pop().Value()
require.Equal(t, tx.Attributes[0].Data, data)
}
func TestAttrGetUsage(t *testing.T) {
v, tx, context := createVMAndTX(t)
v.Estack().PushVal(vm.NewInteropItem(&tx.Attributes[0]))
err := context.attrGetUsage(v)
require.NoError(t, err)
usage := v.Estack().Pop().Value()
require.Equal(t, big.NewInt(int64(tx.Attributes[0].Usage)), usage)
}
func TestAccountGetScriptHash(t *testing.T) {
v, accState, context := createVMAndAccState(t)
v.Estack().PushVal(vm.NewInteropItem(accState))
err := context.accountGetScriptHash(v)
require.NoError(t, err)
hash := v.Estack().Pop().Value()
require.Equal(t, accState.ScriptHash.BytesBE(), hash)
}
func TestAccountGetVotes(t *testing.T) {
v, accState, context := createVMAndAccState(t)
v.Estack().PushVal(vm.NewInteropItem(accState))
err := context.accountGetVotes(v)
require.NoError(t, err)
votes := v.Estack().Pop().Value().([]vm.StackItem)
require.Equal(t, vm.NewByteArrayItem(accState.Votes[0].Bytes()), votes[0])
}
func TestContractGetScript(t *testing.T) {
v, contractState, context := createVMAndContractState(t)
v.Estack().PushVal(vm.NewInteropItem(contractState))
err := context.contractGetScript(v)
require.NoError(t, err)
script := v.Estack().Pop().Value()
require.Equal(t, contractState.Script, script)
}
func TestContractIsPayable(t *testing.T) {
v, contractState, context := createVMAndContractState(t)
v.Estack().PushVal(vm.NewInteropItem(contractState))
err := context.contractIsPayable(v)
require.NoError(t, err)
isPayable := v.Estack().Pop().Value()
require.Equal(t, contractState.IsPayable(), isPayable)
}
func TestAssetGetAdmin(t *testing.T) {
v, assetState, context := createVMAndAssetState(t)
v.Estack().PushVal(vm.NewInteropItem(assetState))
err := context.assetGetAdmin(v)
require.NoError(t, err)
admin := v.Estack().Pop().Value()
require.Equal(t, assetState.Admin.BytesBE(), admin)
}
func TestAssetGetAmount(t *testing.T) {
v, assetState, context := createVMAndAssetState(t)
v.Estack().PushVal(vm.NewInteropItem(assetState))
err := context.assetGetAmount(v)
require.NoError(t, err)
amount := v.Estack().Pop().Value()
require.Equal(t, big.NewInt(int64(assetState.Amount)), amount)
}
func TestAssetGetAssetID(t *testing.T) {
v, assetState, context := createVMAndAssetState(t)
v.Estack().PushVal(vm.NewInteropItem(assetState))
err := context.assetGetAssetID(v)
require.NoError(t, err)
assetID := v.Estack().Pop().Value()
require.Equal(t, assetState.ID.BytesBE(), assetID)
}
func TestAssetGetAssetType(t *testing.T) {
v, assetState, context := createVMAndAssetState(t)
v.Estack().PushVal(vm.NewInteropItem(assetState))
err := context.assetGetAssetType(v)
require.NoError(t, err)
assetType := v.Estack().Pop().Value()
require.Equal(t, big.NewInt(int64(assetState.AssetType)), assetType)
}
func TestAssetGetAvailable(t *testing.T) {
v, assetState, context := createVMAndAssetState(t)
v.Estack().PushVal(vm.NewInteropItem(assetState))
err := context.assetGetAvailable(v)
require.NoError(t, err)
available := v.Estack().Pop().Value()
require.Equal(t, big.NewInt(int64(assetState.Available)), available)
}
func TestAssetGetIssuer(t *testing.T) {
v, assetState, context := createVMAndAssetState(t)
v.Estack().PushVal(vm.NewInteropItem(assetState))
err := context.assetGetIssuer(v)
require.NoError(t, err)
issuer := v.Estack().Pop().Value()
require.Equal(t, assetState.Issuer.BytesBE(), issuer)
}
func TestAssetGetOwner(t *testing.T) {
v, assetState, context := createVMAndAssetState(t)
v.Estack().PushVal(vm.NewInteropItem(assetState))
err := context.assetGetOwner(v)
require.NoError(t, err)
owner := v.Estack().Pop().Value()
require.Equal(t, assetState.Owner.Bytes(), owner)
}
func TestAssetGetPrecision(t *testing.T) {
v, assetState, context := createVMAndAssetState(t)
v.Estack().PushVal(vm.NewInteropItem(assetState))
err := context.assetGetPrecision(v)
require.NoError(t, err)
precision := v.Estack().Pop().Value()
require.Equal(t, big.NewInt(int64(assetState.Precision)), precision)
}
// Helper functions to create VM, InteropContext, TX, AccountState, ContractState, AssetState.
func createVMAndPushBlock(t *testing.T) (*vm.VM, *Block, *interopContext) {
v := vm.New()
block := newDumbBlock()
context := newInteropContext(trigger.Application, newTestChain(t), storage.NewMemoryStore(), block, nil)
v.Estack().PushVal(vm.NewInteropItem(block))
return v, block, context
}
func createVMAndPushTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interopContext) {
v, tx, context := createVMAndTX(t)
v.Estack().PushVal(vm.NewInteropItem(tx))
return v, tx, context
}
func createVMAndAssetState(t *testing.T) (*vm.VM, *AssetState, *interopContext) {
v := vm.New()
assetState := &AssetState{
ID: util.Uint256{},
AssetType: transaction.GoverningToken,
Name: "TestAsset",
Amount: 1,
Available: 2,
Precision: 1,
FeeMode: 1,
FeeAddress: randomUint160(),
Owner: &keys.PublicKey{X: big.NewInt(1), Y: big.NewInt(1)},
Admin: randomUint160(),
Issuer: randomUint160(),
Expiration: 10,
IsFrozen: false,
}
context := newInteropContext(trigger.Application, newTestChain(t), storage.NewMemoryStore(), nil, nil)
return v, assetState, context
}
func createVMAndContractState(t *testing.T) (*vm.VM, *ContractState, *interopContext) {
v := vm.New()
contractState := &ContractState{
Script: []byte("testscript"),
ParamList: []smartcontract.ParamType{smartcontract.StringType, smartcontract.IntegerType, smartcontract.Hash160Type},
ReturnType: smartcontract.ArrayType,
Properties: smartcontract.HasStorage,
Name: randomString(10),
CodeVersion: randomString(10),
Author: randomString(10),
Email: randomString(10),
Description: randomString(10),
scriptHash: randomUint160(),
}
context := newInteropContext(trigger.Application, newTestChain(t), storage.NewMemoryStore(), nil, nil)
return v, contractState, context
}
func createVMAndAccState(t *testing.T) (*vm.VM, *AccountState, *interopContext) {
v := vm.New()
rawHash := "4d3b96ae1bcc5a585e075e3b81920210dec16302"
hash, err := util.Uint160DecodeStringBE(rawHash)
accountState := NewAccountState(hash)
key := &keys.PublicKey{X: big.NewInt(1), Y: big.NewInt(1)}
accountState.Votes = []*keys.PublicKey{key}
require.NoError(t, err)
context := newInteropContext(trigger.Application, newTestChain(t), storage.NewMemoryStore(), nil, nil)
return v, accountState, context
}
func createVMAndTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interopContext) {
v := vm.New()
tx := newMinerTX()
bytes := make([]byte, 1)
attributes := append(tx.Attributes, transaction.Attribute{
Usage: transaction.Description,
Data: bytes,
})
inputs := append(tx.Inputs, transaction.Input{
PrevHash: randomUint256(),
PrevIndex: 1,
})
outputs := append(tx.Outputs, transaction.Output{
AssetID: randomUint256(),
Amount: 10,
ScriptHash: randomUint160(),
Position: 1,
})
tx.Attributes = attributes
tx.Inputs = inputs
tx.Outputs = outputs
context := newInteropContext(trigger.Application, newTestChain(t), storage.NewMemoryStore(), nil, tx)
return v, tx, context
}