vm: move State type into a package of its own
It's used a lot in other places that need it, but don't need whole VM at the same time.
This commit is contained in:
parent
4333ad4949
commit
fab8dfb9f8
24 changed files with 234 additions and 220 deletions
|
@ -23,8 +23,8 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
@ -354,7 +354,7 @@ func TestContractDeployWithData(t *testing.T) {
|
|||
|
||||
res := new(result.Invoke)
|
||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||
require.Equal(t, vm.HaltState.String(), res.State, res.FaultException)
|
||||
require.Equal(t, vmstate.Halt.String(), res.State, res.FaultException)
|
||||
require.Len(t, res.Stack, 1)
|
||||
require.Equal(t, []byte{12}, res.Stack[0].Value())
|
||||
|
||||
|
@ -366,7 +366,7 @@ func TestContractDeployWithData(t *testing.T) {
|
|||
|
||||
res = new(result.Invoke)
|
||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||
require.Equal(t, vm.HaltState.String(), res.State, res.FaultException)
|
||||
require.Equal(t, vmstate.Halt.String(), res.State, res.FaultException)
|
||||
require.Len(t, res.Stack, 1)
|
||||
require.Equal(t, []byte("take_me_to_church"), res.Stack[0].Value())
|
||||
}
|
||||
|
@ -672,7 +672,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
|||
|
||||
res := new(result.Invoke)
|
||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||
require.Equal(t, vm.HaltState.String(), res.State, res.FaultException)
|
||||
require.Equal(t, vmstate.Halt.String(), res.State, res.FaultException)
|
||||
require.Len(t, res.Stack, 1)
|
||||
require.Equal(t, []byte("on create|sub create"), res.Stack[0].Value())
|
||||
|
||||
|
@ -821,7 +821,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
|||
e.Run(t, append(cmd, strconv.FormatInt(storage.FindKeysOnly, 10))...)
|
||||
res := new(result.Invoke)
|
||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||
require.Equal(t, vm.HaltState.String(), res.State)
|
||||
require.Equal(t, vmstate.Halt.String(), res.State)
|
||||
require.Len(t, res.Stack, 1)
|
||||
require.Equal(t, []stackitem.Item{
|
||||
stackitem.Make("findkey1"),
|
||||
|
@ -832,7 +832,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
|||
e.Run(t, append(cmd, strconv.FormatInt(storage.FindDefault, 10))...)
|
||||
res := new(result.Invoke)
|
||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||
require.Equal(t, vm.HaltState.String(), res.State)
|
||||
require.Equal(t, vmstate.Halt.String(), res.State)
|
||||
require.Len(t, res.Stack, 1)
|
||||
|
||||
arr, ok := res.Stack[0].Value().([]stackitem.Item)
|
||||
|
@ -883,7 +883,7 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
|||
|
||||
res := new(result.Invoke)
|
||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||
require.Equal(t, vm.HaltState.String(), res.State)
|
||||
require.Equal(t, vmstate.Halt.String(), res.State)
|
||||
require.Len(t, res.Stack, 1)
|
||||
require.Equal(t, []byte("on update|sub update"), res.Stack[0].Value())
|
||||
})
|
||||
|
|
|
@ -23,7 +23,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/rpc/server"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/urfave/cli"
|
||||
"go.uber.org/zap"
|
||||
|
@ -293,7 +293,7 @@ func (e *executor) checkTxPersisted(t *testing.T, prefix ...string) (*transactio
|
|||
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(aer))
|
||||
require.Equal(t, vm.HaltState, aer[0].VMState)
|
||||
require.Equal(t, vmstate.Halt, aer[0].VMState)
|
||||
return tx, height
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -154,7 +154,7 @@ func TestSignMultisigTx(t *testing.T) {
|
|||
e.checkTxTestInvokeOutput(t, 11)
|
||||
res := new(result.Invoke)
|
||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||
require.Equal(t, vm.HaltState.String(), res.State, res.FaultException)
|
||||
require.Equal(t, vmstate.Halt.String(), res.State, res.FaultException)
|
||||
})
|
||||
|
||||
e.In.WriteString("pass\r")
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
|
@ -129,7 +130,7 @@ func DumpApplicationLog(
|
|||
if len(res.Executions) != 1 {
|
||||
_, _ = tw.Write([]byte("Success:\tunknown (no execution data)\n"))
|
||||
} else {
|
||||
_, _ = tw.Write([]byte(fmt.Sprintf("Success:\t%t\n", res.Executions[0].VMState == vm.HaltState)))
|
||||
_, _ = tw.Write([]byte(fmt.Sprintf("Success:\t%t\n", res.Executions[0].VMState == vmstate.Halt)))
|
||||
}
|
||||
}
|
||||
if verbose {
|
||||
|
@ -146,7 +147,7 @@ func DumpApplicationLog(
|
|||
v.PrintOps(tw)
|
||||
if res != nil {
|
||||
for _, e := range res.Executions {
|
||||
if e.VMState != vm.HaltState {
|
||||
if e.VMState != vmstate.Halt {
|
||||
_, _ = tw.Write([]byte("Exception:\t" + e.FaultException + "\n"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -117,7 +118,7 @@ func (e *executor) compareQueryTxVerbose(t *testing.T, tx *transaction.Transacti
|
|||
e.checkNextLine(t, `BlockHash:\s+`+e.Chain.GetHeaderHash(int(height)).StringLE())
|
||||
|
||||
res, _ := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
||||
e.checkNextLine(t, fmt.Sprintf(`Success:\s+%t`, res[0].Execution.VMState == vm.HaltState))
|
||||
e.checkNextLine(t, fmt.Sprintf(`Success:\s+%t`, res[0].Execution.VMState == vmstate.Halt))
|
||||
for _, s := range tx.Signers {
|
||||
e.checkNextLine(t, fmt.Sprintf(`Signer:\s+%s\s*\(%s\)`, address.Uint160ToString(s.Account), s.Scopes.String()))
|
||||
}
|
||||
|
@ -132,7 +133,7 @@ func (e *executor) compareQueryTxVerbose(t *testing.T, tx *transaction.Transacti
|
|||
}
|
||||
e.checkScriptDump(t, n)
|
||||
|
||||
if res[0].Execution.VMState != vm.HaltState {
|
||||
if res[0].Execution.VMState != vmstate.Halt {
|
||||
e.checkNextLine(t, `Exception:\s+`+regexp.QuoteMeta(res[0].Execution.FaultException))
|
||||
}
|
||||
e.checkEOF(t)
|
||||
|
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -116,10 +117,10 @@ func TestLedgerTransactionWitnessCondition(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLedgerVMStates(t *testing.T) {
|
||||
require.EqualValues(t, ledger.NoneState, vm.NoneState)
|
||||
require.EqualValues(t, ledger.HaltState, vm.HaltState)
|
||||
require.EqualValues(t, ledger.FaultState, vm.FaultState)
|
||||
require.EqualValues(t, ledger.BreakState, vm.BreakState)
|
||||
require.EqualValues(t, ledger.NoneState, vmstate.None)
|
||||
require.EqualValues(t, ledger.HaltState, vmstate.Halt)
|
||||
require.EqualValues(t, ledger.FaultState, vmstate.Fault)
|
||||
require.EqualValues(t, ledger.BreakState, vmstate.Break)
|
||||
}
|
||||
|
||||
type nativeTestCase struct {
|
||||
|
|
|
@ -40,6 +40,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
@ -816,7 +817,7 @@ func (bc *Blockchain) notificationDispatcher() {
|
|||
for ch := range executionFeed {
|
||||
ch <- aer
|
||||
}
|
||||
if aer.VMState == vm.HaltState {
|
||||
if aer.VMState == vmstate.Halt {
|
||||
for i := range aer.Events {
|
||||
for ch := range notificationFeed {
|
||||
ch <- &subscriptions.NotificationEvent{
|
||||
|
@ -1065,7 +1066,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
|
|||
err = fmt.Errorf("failed to store exec result: %w", err)
|
||||
break
|
||||
}
|
||||
if aer.Execution.VMState == vm.HaltState {
|
||||
if aer.Execution.VMState == vmstate.Halt {
|
||||
for j := range aer.Execution.Events {
|
||||
bc.handleNotification(&aer.Execution.Events[j], kvcache, transCache, block, aer.Container)
|
||||
}
|
||||
|
|
|
@ -39,10 +39,10 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -826,7 +826,7 @@ func TestBlockchain_Subscriptions(t *testing.T) {
|
|||
|
||||
exec := <-executionCh
|
||||
require.Equal(t, b.Hash(), exec.Container)
|
||||
require.Equal(t, exec.VMState, vm.HaltState)
|
||||
require.Equal(t, exec.VMState, vmstate.Halt)
|
||||
|
||||
// 3 burn events for every tx and 1 mint for primary node
|
||||
require.True(t, len(notificationCh) >= 4)
|
||||
|
@ -841,7 +841,7 @@ func TestBlockchain_Subscriptions(t *testing.T) {
|
|||
require.Equal(t, txExpected, tx)
|
||||
exec := <-executionCh
|
||||
require.Equal(t, tx.Hash(), exec.Container)
|
||||
if exec.VMState == vm.HaltState {
|
||||
if exec.VMState == vmstate.Halt {
|
||||
notif := <-notificationCh
|
||||
require.Equal(t, hash.Hash160(tx.Script), notif.ScriptHash)
|
||||
}
|
||||
|
@ -855,7 +855,7 @@ func TestBlockchain_Subscriptions(t *testing.T) {
|
|||
|
||||
exec = <-executionCh
|
||||
require.Equal(t, b.Hash(), exec.Container)
|
||||
require.Equal(t, exec.VMState, vm.HaltState)
|
||||
require.Equal(t, exec.VMState, vmstate.Halt)
|
||||
|
||||
bc.UnsubscribeFromBlocks(blockCh)
|
||||
bc.UnsubscribeFromTransactions(txCh)
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
|
@ -168,7 +167,7 @@ func CallFromNative(ic *interop.Context, caller util.Uint160, cs *state.Contract
|
|||
return fmt.Errorf("%w: %v", ErrNativeCall, err)
|
||||
}
|
||||
}
|
||||
if ic.VM.State() == vm.FaultState {
|
||||
if ic.VM.HasFailed() {
|
||||
return ErrNativeCall
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -13,8 +13,8 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
)
|
||||
|
||||
// Ledger provides an interface to blocks/transactions storage for smart
|
||||
|
@ -169,7 +169,7 @@ func (l *Ledger) getTransactionVMState(ic *interop.Context, params []stackitem.I
|
|||
}
|
||||
h, _, aer, err := ic.DAO.GetTxExecResult(hash)
|
||||
if err != nil || !isTraceableBlock(ic, h) {
|
||||
return stackitem.Make(vm.NoneState)
|
||||
return stackitem.Make(vmstate.None)
|
||||
}
|
||||
return stackitem.Make(aer.VMState)
|
||||
}
|
||||
|
|
|
@ -13,9 +13,9 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/neotest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -56,22 +56,22 @@ func TestLedger_GetTransactionState(t *testing.T) {
|
|||
hash := e.InvokeScript(t, []byte{byte(opcode.RET)}, []neotest.Signer{c.Committee})
|
||||
|
||||
t.Run("unknown transaction", func(t *testing.T) {
|
||||
ledgerInvoker.Invoke(t, vm.NoneState, "getTransactionVMState", util.Uint256{1, 2, 3})
|
||||
ledgerInvoker.Invoke(t, vmstate.None, "getTransactionVMState", util.Uint256{1, 2, 3})
|
||||
})
|
||||
t.Run("not a hash", func(t *testing.T) {
|
||||
ledgerInvoker.InvokeFail(t, "expected []byte of size 32", "getTransactionVMState", []byte{1, 2, 3})
|
||||
})
|
||||
t.Run("good: HALT", func(t *testing.T) {
|
||||
ledgerInvoker.Invoke(t, vm.HaltState, "getTransactionVMState", hash)
|
||||
ledgerInvoker.Invoke(t, vmstate.Halt, "getTransactionVMState", hash)
|
||||
})
|
||||
t.Run("isn't traceable", func(t *testing.T) {
|
||||
// Add more blocks so that tx becomes untraceable.
|
||||
e.GenerateNewBlocks(t, int(e.Chain.GetConfig().MaxTraceableBlocks))
|
||||
ledgerInvoker.Invoke(t, vm.NoneState, "getTransactionVMState", hash)
|
||||
ledgerInvoker.Invoke(t, vmstate.None, "getTransactionVMState", hash)
|
||||
})
|
||||
t.Run("good: FAULT", func(t *testing.T) {
|
||||
faultedH := e.InvokeScript(t, []byte{byte(opcode.ABORT)}, []neotest.Signer{c.Committee})
|
||||
ledgerInvoker.Invoke(t, vm.FaultState, "getTransactionVMState", faultedH)
|
||||
ledgerInvoker.Invoke(t, vmstate.Fault, "getTransactionVMState", faultedH)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,10 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -69,7 +69,7 @@ func TestManagement_ContractCache(t *testing.T) {
|
|||
managementInvoker.CheckHalt(t, tx1.Hash())
|
||||
aer, err := managementInvoker.Chain.GetAppExecResults(tx2.Hash(), trigger.Application)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vm.HaltState, aer[0].VMState, aer[0].FaultException)
|
||||
require.Equal(t, vmstate.Halt, aer[0].VMState, aer[0].FaultException)
|
||||
require.NotEqual(t, stackitem.Null{}, aer[0].Stack)
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
)
|
||||
|
||||
// NotificationEvent is a tuple of the scripthash that has emitted the Item as a
|
||||
|
@ -94,7 +94,7 @@ func (aer *AppExecResult) EncodeBinaryWithContext(w *io.BinWriter, sc *stackitem
|
|||
func (aer *AppExecResult) DecodeBinary(r *io.BinReader) {
|
||||
r.ReadBytes(aer.Container[:])
|
||||
aer.Trigger = trigger.Type(r.ReadB())
|
||||
aer.VMState = vm.State(r.ReadB())
|
||||
aer.VMState = vmstate.State(r.ReadB())
|
||||
aer.GasConsumed = int64(r.ReadU64LE())
|
||||
sz := r.ReadVarUint()
|
||||
if stackitem.MaxDeserialized < sz && r.Err == nil {
|
||||
|
@ -197,7 +197,7 @@ func (aer *AppExecResult) UnmarshalJSON(data []byte) error {
|
|||
// all resulting notifications, state, stack and other metadata.
|
||||
type Execution struct {
|
||||
Trigger trigger.Type
|
||||
VMState vm.State
|
||||
VMState vmstate.State
|
||||
GasConsumed int64
|
||||
Stack []stackitem.Item
|
||||
Events []NotificationEvent
|
||||
|
@ -266,7 +266,7 @@ func (e *Execution) UnmarshalJSON(data []byte) error {
|
|||
return err
|
||||
}
|
||||
e.Trigger = trigger
|
||||
state, err := vm.StateFromString(aux.VMState)
|
||||
state, err := vmstate.FromString(aux.VMState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -18,7 +18,7 @@ func BenchmarkAppExecResult_EncodeBinary(b *testing.B) {
|
|||
Container: random.Uint256(),
|
||||
Execution: Execution{
|
||||
Trigger: trigger.Application,
|
||||
VMState: vm.HaltState,
|
||||
VMState: vmstate.Halt,
|
||||
GasConsumed: 12345,
|
||||
Stack: []stackitem.Item{},
|
||||
Events: []NotificationEvent{{
|
||||
|
@ -54,7 +54,7 @@ func TestEncodeDecodeAppExecResult(t *testing.T) {
|
|||
Container: random.Uint256(),
|
||||
Execution: Execution{
|
||||
Trigger: 1,
|
||||
VMState: vm.HaltState,
|
||||
VMState: vmstate.Halt,
|
||||
GasConsumed: 10,
|
||||
Stack: []stackitem.Item{stackitem.NewBool(true)},
|
||||
Events: []NotificationEvent{},
|
||||
|
@ -63,12 +63,12 @@ func TestEncodeDecodeAppExecResult(t *testing.T) {
|
|||
}
|
||||
t.Run("halt", func(t *testing.T) {
|
||||
appExecResult := newAer()
|
||||
appExecResult.VMState = vm.HaltState
|
||||
appExecResult.VMState = vmstate.Halt
|
||||
testserdes.EncodeDecodeBinary(t, appExecResult, new(AppExecResult))
|
||||
})
|
||||
t.Run("fault", func(t *testing.T) {
|
||||
appExecResult := newAer()
|
||||
appExecResult.VMState = vm.FaultState
|
||||
appExecResult.VMState = vmstate.Fault
|
||||
testserdes.EncodeDecodeBinary(t, appExecResult, new(AppExecResult))
|
||||
})
|
||||
t.Run("with interop", func(t *testing.T) {
|
||||
|
@ -150,7 +150,7 @@ func TestMarshalUnmarshalJSONAppExecResult(t *testing.T) {
|
|||
Container: random.Uint256(),
|
||||
Execution: Execution{
|
||||
Trigger: trigger.Application,
|
||||
VMState: vm.HaltState,
|
||||
VMState: vmstate.Halt,
|
||||
GasConsumed: 10,
|
||||
Stack: []stackitem.Item{},
|
||||
Events: []NotificationEvent{},
|
||||
|
@ -164,7 +164,7 @@ func TestMarshalUnmarshalJSONAppExecResult(t *testing.T) {
|
|||
Container: random.Uint256(),
|
||||
Execution: Execution{
|
||||
Trigger: trigger.Application,
|
||||
VMState: vm.FaultState,
|
||||
VMState: vmstate.Fault,
|
||||
GasConsumed: 10,
|
||||
Stack: []stackitem.Item{stackitem.NewBool(true)},
|
||||
Events: []NotificationEvent{},
|
||||
|
@ -178,7 +178,7 @@ func TestMarshalUnmarshalJSONAppExecResult(t *testing.T) {
|
|||
Container: random.Uint256(),
|
||||
Execution: Execution{
|
||||
Trigger: trigger.OnPersist,
|
||||
VMState: vm.HaltState,
|
||||
VMState: vmstate.Halt,
|
||||
GasConsumed: 10,
|
||||
Stack: []stackitem.Item{},
|
||||
Events: []NotificationEvent{},
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -210,7 +211,7 @@ func (e *Executor) InvokeScriptCheckFAULT(t testing.TB, script []byte, signers [
|
|||
func (e *Executor) CheckHalt(t testing.TB, h util.Uint256, stack ...stackitem.Item) *state.AppExecResult {
|
||||
aer, err := e.Chain.GetAppExecResults(h, trigger.Application)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vm.HaltState, aer[0].VMState, aer[0].FaultException)
|
||||
require.Equal(t, vmstate.Halt, aer[0].VMState, aer[0].FaultException)
|
||||
if len(stack) != 0 {
|
||||
require.Equal(t, stack, aer[0].Stack)
|
||||
}
|
||||
|
@ -222,7 +223,7 @@ func (e *Executor) CheckHalt(t testing.TB, h util.Uint256, stack ...stackitem.It
|
|||
func (e *Executor) CheckFault(t testing.TB, h util.Uint256, s string) {
|
||||
aer, err := e.Chain.GetAppExecResults(h, trigger.Application)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vm.FaultState, aer[0].VMState)
|
||||
require.Equal(t, vmstate.Fault, aer[0].VMState)
|
||||
require.True(t, strings.Contains(aer[0].FaultException, s),
|
||||
"expected: %s, got: %s", s, aer[0].FaultException)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -91,7 +92,7 @@ func (c *ContractInvoker) InvokeAndCheck(t testing.TB, checkResult func(t testin
|
|||
c.AddNewBlock(t, tx)
|
||||
aer, err := c.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vm.HaltState, aer[0].VMState, aer[0].FaultException)
|
||||
require.Equal(t, vmstate.Halt, aer[0].VMState, aer[0].FaultException)
|
||||
if checkResult != nil {
|
||||
checkResult(t, aer[0].Stack)
|
||||
}
|
||||
|
|
|
@ -34,9 +34,9 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -129,7 +129,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
Executions: []state.Execution{
|
||||
{
|
||||
Trigger: trigger.Application,
|
||||
VMState: vm.HaltState,
|
||||
VMState: vmstate.Halt,
|
||||
GasConsumed: 1,
|
||||
Stack: []stackitem.Item{stackitem.NewBigInteger(big.NewInt(1))},
|
||||
Events: []state.NotificationEvent{},
|
||||
|
|
|
@ -35,10 +35,10 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -648,7 +648,7 @@ func TestSignAndPushP2PNotaryRequest(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(appLogs))
|
||||
appLog := appLogs[0]
|
||||
require.Equal(t, vm.HaltState, appLog.VMState)
|
||||
require.Equal(t, vmstate.Halt, appLog.VMState)
|
||||
require.Equal(t, appLog.GasConsumed, req.FallbackTransaction.SystemFee)
|
||||
})
|
||||
}
|
||||
|
@ -1282,7 +1282,7 @@ func TestClient_InvokeAndPackIteratorResults(t *testing.T) {
|
|||
t.Run("default max items constraint", func(t *testing.T) {
|
||||
res, err := c.InvokeAndPackIteratorResults(storageHash, "iterateOverValues", []smartcontract.Parameter{}, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vm.HaltState.String(), res.State)
|
||||
require.Equal(t, vmstate.Halt.String(), res.State)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
require.Equal(t, stackitem.ArrayT, res.Stack[0].Type())
|
||||
arr, ok := res.Stack[0].Value().([]stackitem.Item)
|
||||
|
@ -1298,7 +1298,7 @@ func TestClient_InvokeAndPackIteratorResults(t *testing.T) {
|
|||
max := 123
|
||||
res, err := c.InvokeAndPackIteratorResults(storageHash, "iterateOverValues", []smartcontract.Parameter{}, nil, max)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vm.HaltState.String(), res.State)
|
||||
require.Equal(t, vmstate.Halt.String(), res.State)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
require.Equal(t, stackitem.ArrayT, res.Stack[0].Type())
|
||||
arr, ok := res.Stack[0].Value().([]stackitem.Item)
|
||||
|
|
|
@ -45,6 +45,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -102,7 +103,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
assert.Equal(t, 1, len(res.Executions))
|
||||
assert.Equal(t, expectedTxHash, res.Container)
|
||||
assert.Equal(t, trigger.Application, res.Executions[0].Trigger)
|
||||
assert.Equal(t, vm.HaltState, res.Executions[0].VMState)
|
||||
assert.Equal(t, vmstate.Halt, res.Executions[0].VMState)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -116,7 +117,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
assert.Equal(t, 2, len(res.Executions))
|
||||
assert.Equal(t, trigger.OnPersist, res.Executions[0].Trigger)
|
||||
assert.Equal(t, trigger.PostPersist, res.Executions[1].Trigger)
|
||||
assert.Equal(t, vm.HaltState, res.Executions[0].VMState)
|
||||
assert.Equal(t, vmstate.Halt, res.Executions[0].VMState)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -129,7 +130,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
assert.Equal(t, genesisBlockHash, res.Container.StringLE())
|
||||
assert.Equal(t, 1, len(res.Executions))
|
||||
assert.Equal(t, trigger.PostPersist, res.Executions[0].Trigger)
|
||||
assert.Equal(t, vm.HaltState, res.Executions[0].VMState)
|
||||
assert.Equal(t, vmstate.Halt, res.Executions[0].VMState)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -142,7 +143,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
|||
assert.Equal(t, genesisBlockHash, res.Container.StringLE())
|
||||
assert.Equal(t, 1, len(res.Executions))
|
||||
assert.Equal(t, trigger.OnPersist, res.Executions[0].Trigger)
|
||||
assert.Equal(t, vm.HaltState, res.Executions[0].VMState)
|
||||
assert.Equal(t, vmstate.Halt, res.Executions[0].VMState)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1966,9 +1967,9 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
|
|||
require.NoError(t, json.Unmarshal(data, &res))
|
||||
require.Equal(t, 2, len(res.Executions))
|
||||
require.Equal(t, trigger.OnPersist, res.Executions[0].Trigger)
|
||||
require.Equal(t, vm.HaltState, res.Executions[0].VMState)
|
||||
require.Equal(t, vmstate.Halt, res.Executions[0].VMState)
|
||||
require.Equal(t, trigger.PostPersist, res.Executions[1].Trigger)
|
||||
require.Equal(t, vm.HaltState, res.Executions[1].VMState)
|
||||
require.Equal(t, vmstate.Halt, res.Executions[1].VMState)
|
||||
})
|
||||
|
||||
t.Run("submit", func(t *testing.T) {
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -44,7 +45,7 @@ type (
|
|||
}
|
||||
|
||||
vmUTExecutionEngineState struct {
|
||||
State State `json:"state"`
|
||||
State vmstate.State `json:"state"`
|
||||
ResultStack []vmUTStackItem `json:"resultStack"`
|
||||
InvocationStack []vmUTExecutionContextState `json:"invocationStack"`
|
||||
}
|
||||
|
@ -152,14 +153,14 @@ func testFile(t *testing.T, filename string) {
|
|||
t.Run(ut.Tests[i].Name, func(t *testing.T) {
|
||||
prog := []byte(test.Script)
|
||||
vm := load(prog)
|
||||
vm.state = BreakState
|
||||
vm.state = vmstate.Break
|
||||
vm.SyscallHandler = testSyscallHandler
|
||||
|
||||
for i := range test.Steps {
|
||||
execStep(t, vm, test.Steps[i])
|
||||
result := test.Steps[i].Result
|
||||
require.Equal(t, result.State, vm.state)
|
||||
if result.State == FaultState { // do not compare stacks on fault
|
||||
if result.State == vmstate.Fault { // do not compare stacks on fault
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStateFromString(t *testing.T) {
|
||||
var (
|
||||
s State
|
||||
err error
|
||||
)
|
||||
|
||||
s, err = StateFromString("HALT")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, HaltState, s)
|
||||
|
||||
s, err = StateFromString("BREAK")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, BreakState, s)
|
||||
|
||||
s, err = StateFromString("FAULT")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, FaultState, s)
|
||||
|
||||
s, err = StateFromString("NONE")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, NoneState, s)
|
||||
|
||||
s, err = StateFromString("HALT, BREAK")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, HaltState|BreakState, s)
|
||||
|
||||
s, err = StateFromString("FAULT, BREAK")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, FaultState|BreakState, s)
|
||||
|
||||
_, err = StateFromString("HALT, KEK")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestState_HasFlag(t *testing.T) {
|
||||
assert.True(t, HaltState.HasFlag(HaltState))
|
||||
assert.True(t, BreakState.HasFlag(BreakState))
|
||||
assert.True(t, FaultState.HasFlag(FaultState))
|
||||
assert.True(t, (HaltState | BreakState).HasFlag(HaltState))
|
||||
assert.True(t, (HaltState | BreakState).HasFlag(BreakState))
|
||||
|
||||
assert.False(t, HaltState.HasFlag(BreakState))
|
||||
assert.False(t, NoneState.HasFlag(HaltState))
|
||||
assert.False(t, (FaultState | BreakState).HasFlag(HaltState))
|
||||
}
|
||||
|
||||
func TestState_MarshalJSON(t *testing.T) {
|
||||
var (
|
||||
data []byte
|
||||
err error
|
||||
)
|
||||
|
||||
data, err = json.Marshal(HaltState | BreakState)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, data, []byte(`"HALT, BREAK"`))
|
||||
|
||||
data, err = json.Marshal(FaultState)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, data, []byte(`"FAULT"`))
|
||||
}
|
||||
|
||||
func TestState_UnmarshalJSON(t *testing.T) {
|
||||
var (
|
||||
s State
|
||||
err error
|
||||
)
|
||||
|
||||
err = json.Unmarshal([]byte(`"HALT, BREAK"`), &s)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, HaltState|BreakState, s)
|
||||
|
||||
err = json.Unmarshal([]byte(`"FAULT, BREAK"`), &s)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, FaultState|BreakState, s)
|
||||
|
||||
err = json.Unmarshal([]byte(`"NONE"`), &s)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, NoneState, s)
|
||||
}
|
||||
|
||||
// TestState_EnumCompat tests that byte value of State matches the C#'s one got from
|
||||
// https://github.com/neo-project/neo-vm/blob/0028d862e253bda3c12eb8bb007a2d95822d3922/src/neo-vm/VMState.cs#L16.
|
||||
func TestState_EnumCompat(t *testing.T) {
|
||||
assert.Equal(t, byte(0), byte(NoneState))
|
||||
assert.Equal(t, byte(1<<0), byte(HaltState))
|
||||
assert.Equal(t, byte(1<<1), byte(FaultState))
|
||||
assert.Equal(t, byte(1<<2), byte(BreakState))
|
||||
}
|
71
pkg/vm/vm.go
71
pkg/vm/vm.go
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/util/slice"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
)
|
||||
|
||||
type errorAtInstruct struct {
|
||||
|
@ -62,7 +63,7 @@ type SyscallHandler = func(*VM, uint32) error
|
|||
|
||||
// VM represents the virtual machine.
|
||||
type VM struct {
|
||||
state State
|
||||
state vmstate.State
|
||||
|
||||
// callback to get interop price
|
||||
getPrice func(opcode.Opcode, []byte) int64
|
||||
|
@ -104,7 +105,7 @@ func New() *VM {
|
|||
// NewWithTrigger returns a new VM for executions triggered by t.
|
||||
func NewWithTrigger(t trigger.Type) *VM {
|
||||
vm := &VM{
|
||||
state: NoneState,
|
||||
state: vmstate.None,
|
||||
trigger: t,
|
||||
|
||||
SyscallHandler: defaultSyscallHandler,
|
||||
|
@ -126,7 +127,7 @@ func (v *VM) SetPriceGetter(f func(opcode.Opcode, []byte) int64) {
|
|||
// more efficient. It reuses invocation and evaluation stacks as well as VM structure
|
||||
// itself.
|
||||
func (v *VM) Reset(t trigger.Type) {
|
||||
v.state = NoneState
|
||||
v.state = vmstate.None
|
||||
v.getPrice = nil
|
||||
v.istack.elems = v.istack.elems[:0]
|
||||
v.estack.elems = v.estack.elems[:0]
|
||||
|
@ -288,7 +289,7 @@ func (v *VM) LoadWithFlags(prog []byte, f callflag.CallFlag) {
|
|||
// Clear all stacks and state, it could be a reload.
|
||||
v.istack.Clear()
|
||||
v.estack.Clear()
|
||||
v.state = NoneState
|
||||
v.state = vmstate.None
|
||||
v.gasConsumed = 0
|
||||
v.invTree = nil
|
||||
v.LoadScriptWithFlags(prog, f)
|
||||
|
@ -398,7 +399,7 @@ func dumpStack(s *Stack) string {
|
|||
}
|
||||
|
||||
// State returns the state for the VM.
|
||||
func (v *VM) State() State {
|
||||
func (v *VM) State() vmstate.State {
|
||||
return v.state
|
||||
}
|
||||
|
||||
|
@ -413,39 +414,39 @@ func (v *VM) Run() error {
|
|||
var ctx *Context
|
||||
|
||||
if !v.Ready() {
|
||||
v.state = FaultState
|
||||
v.state = vmstate.Fault
|
||||
return errors.New("no program loaded")
|
||||
}
|
||||
|
||||
if v.state.HasFlag(FaultState) {
|
||||
if v.state.HasFlag(vmstate.Fault) {
|
||||
// VM already ran something and failed, in general its state is
|
||||
// undefined in this case so we can't run anything.
|
||||
return errors.New("VM has failed")
|
||||
}
|
||||
// HaltState (the default) or BreakState are safe to continue.
|
||||
v.state = NoneState
|
||||
// vmstate.Halt (the default) or vmstate.Break are safe to continue.
|
||||
v.state = vmstate.None
|
||||
ctx = v.Context()
|
||||
for {
|
||||
switch {
|
||||
case v.state.HasFlag(FaultState):
|
||||
case v.state.HasFlag(vmstate.Fault):
|
||||
// Should be caught and reported already by the v.Step(),
|
||||
// but we're checking here anyway just in case.
|
||||
return errors.New("VM has failed")
|
||||
case v.state.HasFlag(HaltState), v.state.HasFlag(BreakState):
|
||||
case v.state.HasFlag(vmstate.Halt), v.state.HasFlag(vmstate.Break):
|
||||
// Normal exit from this loop.
|
||||
return nil
|
||||
case v.state == NoneState:
|
||||
case v.state == vmstate.None:
|
||||
if err := v.step(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
v.state = FaultState
|
||||
v.state = vmstate.Fault
|
||||
return errors.New("unknown state")
|
||||
}
|
||||
// check for breakpoint before executing the next instruction
|
||||
ctx = v.Context()
|
||||
if ctx != nil && ctx.atBreakPoint() {
|
||||
v.state = BreakState
|
||||
v.state = vmstate.Break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -460,7 +461,7 @@ func (v *VM) Step() error {
|
|||
func (v *VM) step(ctx *Context) error {
|
||||
op, param, err := ctx.Next()
|
||||
if err != nil {
|
||||
v.state = FaultState
|
||||
v.state = vmstate.Fault
|
||||
return newError(ctx.ip, op, err)
|
||||
}
|
||||
return v.execute(ctx, op, param)
|
||||
|
@ -472,7 +473,7 @@ func (v *VM) StepInto() error {
|
|||
ctx := v.Context()
|
||||
|
||||
if ctx == nil {
|
||||
v.state = HaltState
|
||||
v.state = vmstate.Halt
|
||||
}
|
||||
|
||||
if v.HasStopped() {
|
||||
|
@ -482,7 +483,7 @@ func (v *VM) StepInto() error {
|
|||
if ctx != nil && ctx.prog != nil {
|
||||
op, param, err := ctx.Next()
|
||||
if err != nil {
|
||||
v.state = FaultState
|
||||
v.state = vmstate.Fault
|
||||
return newError(ctx.ip, op, err)
|
||||
}
|
||||
vErr := v.execute(ctx, op, param)
|
||||
|
@ -493,7 +494,7 @@ func (v *VM) StepInto() error {
|
|||
|
||||
cctx := v.Context()
|
||||
if cctx != nil && cctx.atBreakPoint() {
|
||||
v.state = BreakState
|
||||
v.state = vmstate.Break
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -501,16 +502,16 @@ func (v *VM) StepInto() error {
|
|||
// StepOut takes the debugger to the line where the current function was called.
|
||||
func (v *VM) StepOut() error {
|
||||
var err error
|
||||
if v.state == BreakState {
|
||||
v.state = NoneState
|
||||
if v.state == vmstate.Break {
|
||||
v.state = vmstate.None
|
||||
}
|
||||
|
||||
expSize := v.istack.Len()
|
||||
for v.state == NoneState && v.istack.Len() >= expSize {
|
||||
for v.state == vmstate.None && v.istack.Len() >= expSize {
|
||||
err = v.StepInto()
|
||||
}
|
||||
if v.state == NoneState {
|
||||
v.state = BreakState
|
||||
if v.state == vmstate.None {
|
||||
v.state = vmstate.Break
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -523,20 +524,20 @@ func (v *VM) StepOver() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if v.state == BreakState {
|
||||
v.state = NoneState
|
||||
if v.state == vmstate.Break {
|
||||
v.state = vmstate.None
|
||||
}
|
||||
|
||||
expSize := v.istack.Len()
|
||||
for {
|
||||
err = v.StepInto()
|
||||
if !(v.state == NoneState && v.istack.Len() > expSize) {
|
||||
if !(v.state == vmstate.None && v.istack.Len() > expSize) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if v.state == NoneState {
|
||||
v.state = BreakState
|
||||
if v.state == vmstate.None {
|
||||
v.state = vmstate.Break
|
||||
}
|
||||
|
||||
return err
|
||||
|
@ -545,22 +546,22 @@ func (v *VM) StepOver() error {
|
|||
// HasFailed returns whether the VM is in the failed state now. Usually, it's used to
|
||||
// check status after Run.
|
||||
func (v *VM) HasFailed() bool {
|
||||
return v.state.HasFlag(FaultState)
|
||||
return v.state.HasFlag(vmstate.Fault)
|
||||
}
|
||||
|
||||
// HasStopped returns whether the VM is in the Halt or Failed state.
|
||||
func (v *VM) HasStopped() bool {
|
||||
return v.state.HasFlag(HaltState) || v.state.HasFlag(FaultState)
|
||||
return v.state.HasFlag(vmstate.Halt) || v.state.HasFlag(vmstate.Fault)
|
||||
}
|
||||
|
||||
// HasHalted returns whether the VM is in the Halt state.
|
||||
func (v *VM) HasHalted() bool {
|
||||
return v.state.HasFlag(HaltState)
|
||||
return v.state.HasFlag(vmstate.Halt)
|
||||
}
|
||||
|
||||
// AtBreakpoint returns whether the VM is at breakpoint.
|
||||
func (v *VM) AtBreakpoint() bool {
|
||||
return v.state.HasFlag(BreakState)
|
||||
return v.state.HasFlag(vmstate.Break)
|
||||
}
|
||||
|
||||
// GetInteropID converts instruction parameter to an interop ID.
|
||||
|
@ -574,10 +575,10 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
// each panic at a central point, putting the VM in a fault state and setting error.
|
||||
defer func() {
|
||||
if errRecover := recover(); errRecover != nil {
|
||||
v.state = FaultState
|
||||
v.state = vmstate.Fault
|
||||
err = newError(ctx.ip, op, errRecover)
|
||||
} else if v.refs > MaxStackSize {
|
||||
v.state = FaultState
|
||||
v.state = vmstate.Fault
|
||||
err = newError(ctx.ip, op, "stack is too big")
|
||||
}
|
||||
}()
|
||||
|
@ -1469,7 +1470,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
|||
|
||||
v.unloadContext(oldCtx)
|
||||
if v.istack.Len() == 0 {
|
||||
v.state = HaltState
|
||||
v.state = vmstate.Halt
|
||||
break
|
||||
}
|
||||
|
||||
|
|
|
@ -1,23 +1,29 @@
|
|||
package vm
|
||||
/*
|
||||
Package vmstate contains a set of VM state flags along with appropriate type.
|
||||
It provides a set of conversion/marshaling functions/methods for this type as
|
||||
well. This package is made to make VM state reusable across all of the other
|
||||
components that need it without importing whole VM package.
|
||||
*/
|
||||
package vmstate
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// State of the VM.
|
||||
// State of the VM. It's a set of flags stored in the integer number.
|
||||
type State uint8
|
||||
|
||||
// Available States.
|
||||
const (
|
||||
// HaltState represents HALT VM state.
|
||||
HaltState State = 1 << iota
|
||||
// FaultState represents FAULT VM state.
|
||||
FaultState
|
||||
// BreakState represents BREAK VM state.
|
||||
BreakState
|
||||
// NoneState represents NONE VM state.
|
||||
NoneState State = 0
|
||||
// Halt represents HALT VM state (finished normally).
|
||||
Halt State = 1 << iota
|
||||
// Fault represents FAULT VM state (finished with an error).
|
||||
Fault
|
||||
// Break represents BREAK VM state (running, debug mode).
|
||||
Break
|
||||
// None represents NONE VM state (not started yet).
|
||||
None State = 0
|
||||
)
|
||||
|
||||
// HasFlag checks for State flag presence.
|
||||
|
@ -25,40 +31,40 @@ func (s State) HasFlag(f State) bool {
|
|||
return s&f != 0
|
||||
}
|
||||
|
||||
// String implements the stringer interface.
|
||||
// String implements the fmt.Stringer interface.
|
||||
func (s State) String() string {
|
||||
if s == NoneState {
|
||||
if s == None {
|
||||
return "NONE"
|
||||
}
|
||||
|
||||
ss := make([]string, 0, 3)
|
||||
if s.HasFlag(HaltState) {
|
||||
if s.HasFlag(Halt) {
|
||||
ss = append(ss, "HALT")
|
||||
}
|
||||
if s.HasFlag(FaultState) {
|
||||
if s.HasFlag(Fault) {
|
||||
ss = append(ss, "FAULT")
|
||||
}
|
||||
if s.HasFlag(BreakState) {
|
||||
if s.HasFlag(Break) {
|
||||
ss = append(ss, "BREAK")
|
||||
}
|
||||
return strings.Join(ss, ", ")
|
||||
}
|
||||
|
||||
// StateFromString converts a string into the VM State.
|
||||
func StateFromString(s string) (st State, err error) {
|
||||
// FromString converts a string into the State.
|
||||
func FromString(s string) (st State, err error) {
|
||||
if s = strings.TrimSpace(s); s == "NONE" {
|
||||
return NoneState, nil
|
||||
return None, nil
|
||||
}
|
||||
|
||||
ss := strings.Split(s, ",")
|
||||
for _, state := range ss {
|
||||
switch state = strings.TrimSpace(state); state {
|
||||
case "HALT":
|
||||
st |= HaltState
|
||||
st |= Halt
|
||||
case "FAULT":
|
||||
st |= FaultState
|
||||
st |= Fault
|
||||
case "BREAK":
|
||||
st |= BreakState
|
||||
st |= Break
|
||||
default:
|
||||
return 0, errors.New("unknown state")
|
||||
}
|
||||
|
@ -78,6 +84,6 @@ func (s *State) UnmarshalJSON(data []byte) (err error) {
|
|||
return errors.New("wrong format")
|
||||
}
|
||||
|
||||
*s, err = StateFromString(string(data[1 : l-1]))
|
||||
*s, err = FromString(string(data[1 : l-1]))
|
||||
return
|
||||
}
|
97
pkg/vm/vmstate/state_test.go
Normal file
97
pkg/vm/vmstate/state_test.go
Normal file
|
@ -0,0 +1,97 @@
|
|||
package vmstate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFromString(t *testing.T) {
|
||||
var (
|
||||
s State
|
||||
err error
|
||||
)
|
||||
|
||||
s, err = FromString("HALT")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, Halt, s)
|
||||
|
||||
s, err = FromString("BREAK")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, Break, s)
|
||||
|
||||
s, err = FromString("FAULT")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, Fault, s)
|
||||
|
||||
s, err = FromString("NONE")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, None, s)
|
||||
|
||||
s, err = FromString("HALT, BREAK")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, Halt|Break, s)
|
||||
|
||||
s, err = FromString("FAULT, BREAK")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, Fault|Break, s)
|
||||
|
||||
_, err = FromString("HALT, KEK")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestState_HasFlag(t *testing.T) {
|
||||
assert.True(t, Halt.HasFlag(Halt))
|
||||
assert.True(t, Break.HasFlag(Break))
|
||||
assert.True(t, Fault.HasFlag(Fault))
|
||||
assert.True(t, (Halt | Break).HasFlag(Halt))
|
||||
assert.True(t, (Halt | Break).HasFlag(Break))
|
||||
|
||||
assert.False(t, Halt.HasFlag(Break))
|
||||
assert.False(t, None.HasFlag(Halt))
|
||||
assert.False(t, (Fault | Break).HasFlag(Halt))
|
||||
}
|
||||
|
||||
func TestState_MarshalJSON(t *testing.T) {
|
||||
var (
|
||||
data []byte
|
||||
err error
|
||||
)
|
||||
|
||||
data, err = json.Marshal(Halt | Break)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, data, []byte(`"HALT, BREAK"`))
|
||||
|
||||
data, err = json.Marshal(Fault)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, data, []byte(`"FAULT"`))
|
||||
}
|
||||
|
||||
func TestState_UnmarshalJSON(t *testing.T) {
|
||||
var (
|
||||
s State
|
||||
err error
|
||||
)
|
||||
|
||||
err = json.Unmarshal([]byte(`"HALT, BREAK"`), &s)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, Halt|Break, s)
|
||||
|
||||
err = json.Unmarshal([]byte(`"FAULT, BREAK"`), &s)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, Fault|Break, s)
|
||||
|
||||
err = json.Unmarshal([]byte(`"NONE"`), &s)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, None, s)
|
||||
}
|
||||
|
||||
// TestState_EnumCompat tests that byte value of State matches the C#'s one got from
|
||||
// https://github.com/neo-project/neo-vm/blob/0028d862e253bda3c12eb8bb007a2d95822d3922/src/neo-vm/VMState.cs#L16.
|
||||
func TestState_EnumCompat(t *testing.T) {
|
||||
assert.Equal(t, byte(0), byte(None))
|
||||
assert.Equal(t, byte(1<<0), byte(Halt))
|
||||
assert.Equal(t, byte(1<<1), byte(Fault))
|
||||
assert.Equal(t, byte(1<<2), byte(Break))
|
||||
}
|
Loading…
Reference in a new issue