mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-26 19:42:23 +00:00
Merge pull request #1236 from nspcc-dev/rpc/getrawmempool
rpc: update `getrawmempool` and `getrawtransaction` RPC-calls
This commit is contained in:
commit
b187dfe3ce
14 changed files with 120 additions and 86 deletions
|
@ -378,7 +378,7 @@ func (bc *Blockchain) notificationDispatcher() {
|
|||
for ch := range executionFeed {
|
||||
ch <- aer
|
||||
}
|
||||
if aer.VMState == "HALT" {
|
||||
if aer.VMState == vm.HaltState {
|
||||
for i := range aer.Events {
|
||||
for ch := range notificationFeed {
|
||||
ch <- &aer.Events[i]
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"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/stretchr/testify/assert"
|
||||
|
@ -316,7 +317,7 @@ func TestSubscriptions(t *testing.T) {
|
|||
|
||||
exec := <-executionCh
|
||||
require.Equal(t, b.Hash(), exec.TxHash)
|
||||
require.Equal(t, exec.VMState, "HALT")
|
||||
require.Equal(t, exec.VMState, vm.HaltState)
|
||||
|
||||
// 3 burn events for every tx and 1 mint for primary node
|
||||
require.True(t, len(notificationCh) >= 4)
|
||||
|
@ -331,7 +332,7 @@ func TestSubscriptions(t *testing.T) {
|
|||
require.Equal(t, txExpected, tx)
|
||||
exec := <-executionCh
|
||||
require.Equal(t, tx.Hash(), exec.TxHash)
|
||||
if exec.VMState == "HALT" {
|
||||
if exec.VMState == vm.HaltState {
|
||||
notif := <-notificationCh
|
||||
require.Equal(t, hash.Hash160(tx.Script), notif.ScriptHash)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"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/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -122,14 +123,14 @@ func TestNativeContract_Invoke(t *testing.T) {
|
|||
|
||||
res, err := chain.GetAppExecResult(tx.Hash())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "HALT", res.VMState)
|
||||
require.Equal(t, vm.HaltState, res.VMState)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
require.Equal(t, smartcontract.IntegerType, res.Stack[0].Type)
|
||||
require.EqualValues(t, 42, res.Stack[0].Value)
|
||||
|
||||
res, err = chain.GetAppExecResult(tx2.Hash())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "FAULT", res.VMState)
|
||||
require.Equal(t, vm.FaultState, res.VMState)
|
||||
|
||||
require.NoError(t, chain.persist())
|
||||
select {
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"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/emit"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -253,7 +254,7 @@ func invokeNativePolicyMethod(chain *Blockchain, method string, args ...interfac
|
|||
}
|
||||
|
||||
func checkResult(t *testing.T, result *state.AppExecResult, expected smartcontract.Parameter) {
|
||||
require.Equal(t, "HALT", result.VMState)
|
||||
require.Equal(t, vm.HaltState, result.VMState)
|
||||
require.Equal(t, 1, len(result.Stack))
|
||||
require.Equal(t, expected.Type, result.Stack[0].Type)
|
||||
require.EqualValues(t, expected.Value, result.Stack[0].Value)
|
||||
|
|
|
@ -7,6 +7,7 @@ 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/stackitem"
|
||||
)
|
||||
|
||||
|
@ -23,7 +24,7 @@ type NotificationEvent struct {
|
|||
type AppExecResult struct {
|
||||
TxHash util.Uint256
|
||||
Trigger trigger.Type
|
||||
VMState string
|
||||
VMState vm.State
|
||||
GasConsumed int64
|
||||
Stack []smartcontract.Parameter
|
||||
Events []NotificationEvent
|
||||
|
@ -56,7 +57,7 @@ func (ne *NotificationEvent) DecodeBinary(r *io.BinReader) {
|
|||
func (aer *AppExecResult) EncodeBinary(w *io.BinWriter) {
|
||||
w.WriteBytes(aer.TxHash[:])
|
||||
w.WriteB(byte(aer.Trigger))
|
||||
w.WriteString(aer.VMState)
|
||||
w.WriteB(byte(aer.VMState))
|
||||
w.WriteU64LE(uint64(aer.GasConsumed))
|
||||
w.WriteArray(aer.Stack)
|
||||
w.WriteArray(aer.Events)
|
||||
|
@ -66,7 +67,7 @@ func (aer *AppExecResult) EncodeBinary(w *io.BinWriter) {
|
|||
func (aer *AppExecResult) DecodeBinary(r *io.BinReader) {
|
||||
r.ReadBytes(aer.TxHash[:])
|
||||
aer.Trigger = trigger.Type(r.ReadB())
|
||||
aer.VMState = r.ReadString()
|
||||
aer.VMState = vm.State(r.ReadB())
|
||||
aer.GasConsumed = int64(r.ReadU64LE())
|
||||
r.ReadArray(&aer.Stack)
|
||||
r.ReadArray(&aer.Events)
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/internal/random"
|
||||
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
|
@ -23,7 +24,7 @@ func TestEncodeDecodeAppExecResult(t *testing.T) {
|
|||
appExecResult := &AppExecResult{
|
||||
TxHash: random.Uint256(),
|
||||
Trigger: 1,
|
||||
VMState: "Hault",
|
||||
VMState: vm.HaltState,
|
||||
GasConsumed: 10,
|
||||
Stack: []smartcontract.Parameter{},
|
||||
Events: []NotificationEvent{},
|
||||
|
|
|
@ -49,7 +49,7 @@ func NewApplicationLog(appExecRes *state.AppExecResult) ApplicationLog {
|
|||
return ApplicationLog{
|
||||
TxHash: appExecRes.TxHash,
|
||||
Trigger: appExecRes.Trigger.String(),
|
||||
VMState: appExecRes.VMState,
|
||||
VMState: appExecRes.VMState.String(),
|
||||
GasConsumed: appExecRes.GasConsumed,
|
||||
Stack: appExecRes.Stack,
|
||||
Events: events,
|
||||
|
|
10
pkg/rpc/response/result/raw_mempool.go
Normal file
10
pkg/rpc/response/result/raw_mempool.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
package result
|
||||
|
||||
import "github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
||||
// RawMempool represents a result of getrawmempool RPC call.
|
||||
type RawMempool struct {
|
||||
Height uint32 `json:"height"`
|
||||
Verified []util.Uint256 `json:"verified"`
|
||||
Unverified []util.Uint256 `json:"unverified"`
|
||||
}
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
@ -22,10 +23,11 @@ type TransactionMetadata struct {
|
|||
Blockhash util.Uint256 `json:"blockhash,omitempty"`
|
||||
Confirmations int `json:"confirmations,omitempty"`
|
||||
Timestamp uint64 `json:"blocktime,omitempty"`
|
||||
VMState string `json:"vmstate"`
|
||||
}
|
||||
|
||||
// NewTransactionOutputRaw returns a new ransactionOutputRaw object.
|
||||
func NewTransactionOutputRaw(tx *transaction.Transaction, header *block.Header, chain blockchainer.Blockchainer) TransactionOutputRaw {
|
||||
func NewTransactionOutputRaw(tx *transaction.Transaction, header *block.Header, appExecResult *state.AppExecResult, chain blockchainer.Blockchainer) TransactionOutputRaw {
|
||||
// confirmations formula
|
||||
confirmations := int(chain.BlockHeight() - header.Base.Index + 1)
|
||||
return TransactionOutputRaw{
|
||||
|
@ -34,6 +36,7 @@ func NewTransactionOutputRaw(tx *transaction.Transaction, header *block.Header,
|
|||
Blockhash: header.Hash(),
|
||||
Confirmations: confirmations,
|
||||
Timestamp: header.Timestamp,
|
||||
VMState: appExecResult.VMState.String(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +47,7 @@ func (t TransactionOutputRaw) MarshalJSON() ([]byte, error) {
|
|||
Blockhash: t.Blockhash,
|
||||
Confirmations: t.Confirmations,
|
||||
Timestamp: t.Timestamp,
|
||||
VMState: t.VMState,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -75,6 +79,7 @@ func (t *TransactionOutputRaw) UnmarshalJSON(data []byte) error {
|
|||
t.Blockhash = output.Blockhash
|
||||
t.Confirmations = output.Confirmations
|
||||
t.Timestamp = output.Timestamp
|
||||
t.VMState = output.VMState
|
||||
|
||||
return json.Unmarshal(data, &t.Transaction)
|
||||
}
|
||||
|
|
|
@ -463,13 +463,20 @@ func (s *Server) getPeers(_ request.Params) (interface{}, *response.Error) {
|
|||
return peers, nil
|
||||
}
|
||||
|
||||
func (s *Server) getRawMempool(_ request.Params) (interface{}, *response.Error) {
|
||||
func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response.Error) {
|
||||
verbose := reqParams.Value(0).GetBoolean()
|
||||
mp := s.chain.GetMemPool()
|
||||
hashList := make([]util.Uint256, 0)
|
||||
for _, item := range mp.GetVerifiedTransactions() {
|
||||
hashList = append(hashList, item.Hash())
|
||||
}
|
||||
return hashList, nil
|
||||
if !verbose {
|
||||
return hashList, nil
|
||||
}
|
||||
return result.RawMempool{
|
||||
Height: s.chain.BlockHeight(),
|
||||
Verified: hashList,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) validateAddress(reqParams request.Params) (interface{}, *response.Error) {
|
||||
|
@ -685,10 +692,13 @@ func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *resp
|
|||
_header := s.chain.GetHeaderHash(int(height))
|
||||
header, err := s.chain.GetHeader(_header)
|
||||
if err != nil {
|
||||
resultsErr = response.NewInvalidParamsError(err.Error(), err)
|
||||
} else {
|
||||
results = result.NewTransactionOutputRaw(tx, header, s.chain)
|
||||
return nil, response.NewInvalidParamsError(err.Error(), err)
|
||||
}
|
||||
st, err := s.chain.GetAppExecResult(txHash)
|
||||
if err != nil {
|
||||
return nil, response.NewRPCError("Unknown transaction", err.Error(), err)
|
||||
}
|
||||
results = result.NewTransactionOutputRaw(tx, header, st, s.chain)
|
||||
} else {
|
||||
results = hex.EncodeToString(tx.Bytes())
|
||||
}
|
||||
|
@ -873,7 +883,7 @@ func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) *resu
|
|||
vm.LoadScriptWithFlags(script, smartcontract.All)
|
||||
_ = vm.Run()
|
||||
result := &result.Invoke{
|
||||
State: vm.State(),
|
||||
State: vm.State().String(),
|
||||
GasConsumed: vm.GasConsumed(),
|
||||
Script: hex.EncodeToString(script),
|
||||
Stack: vm.Estack().ToContractParameters(),
|
||||
|
|
|
@ -162,14 +162,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 = BreakState
|
||||
vm.RegisterInteropGetter(getTestingInterop)
|
||||
|
||||
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 == FaultState { // do not compare stacks on fault
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -11,10 +11,14 @@ type State uint8
|
|||
|
||||
// Available States.
|
||||
const (
|
||||
noneState State = 0
|
||||
haltState State = 1 << iota
|
||||
faultState
|
||||
breakState
|
||||
// NoneState represents NONE VM state.
|
||||
NoneState State = 0
|
||||
// HaltState represents HALT VM state.
|
||||
HaltState State = 1 << iota
|
||||
// FaultState represents FAULT VM state.
|
||||
FaultState
|
||||
// BreakState represents BREAK VM state.
|
||||
BreakState
|
||||
)
|
||||
|
||||
// HasFlag checks for State flag presence.
|
||||
|
@ -24,18 +28,18 @@ func (s State) HasFlag(f State) bool {
|
|||
|
||||
// String implements the stringer interface.
|
||||
func (s State) String() string {
|
||||
if s == noneState {
|
||||
if s == NoneState {
|
||||
return "NONE"
|
||||
}
|
||||
|
||||
ss := make([]string, 0, 3)
|
||||
if s.HasFlag(haltState) {
|
||||
if s.HasFlag(HaltState) {
|
||||
ss = append(ss, "HALT")
|
||||
}
|
||||
if s.HasFlag(faultState) {
|
||||
if s.HasFlag(FaultState) {
|
||||
ss = append(ss, "FAULT")
|
||||
}
|
||||
if s.HasFlag(breakState) {
|
||||
if s.HasFlag(BreakState) {
|
||||
ss = append(ss, "BREAK")
|
||||
}
|
||||
return strings.Join(ss, ", ")
|
||||
|
@ -44,18 +48,18 @@ func (s State) String() string {
|
|||
// StateFromString converts string into the VM State.
|
||||
func StateFromString(s string) (st State, err error) {
|
||||
if s = strings.TrimSpace(s); s == "NONE" {
|
||||
return noneState, nil
|
||||
return NoneState, nil
|
||||
}
|
||||
|
||||
ss := strings.Split(s, ",")
|
||||
for _, state := range ss {
|
||||
switch state = strings.TrimSpace(state); state {
|
||||
case "HALT":
|
||||
st |= haltState
|
||||
st |= HaltState
|
||||
case "FAULT":
|
||||
st |= faultState
|
||||
st |= FaultState
|
||||
case "BREAK":
|
||||
st |= breakState
|
||||
st |= BreakState
|
||||
default:
|
||||
return 0, errors.New("unknown state")
|
||||
}
|
||||
|
|
|
@ -15,42 +15,42 @@ func TestStateFromString(t *testing.T) {
|
|||
|
||||
s, err = StateFromString("HALT")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, haltState, s)
|
||||
assert.Equal(t, HaltState, s)
|
||||
|
||||
s, err = StateFromString("BREAK")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, breakState, s)
|
||||
assert.Equal(t, BreakState, s)
|
||||
|
||||
s, err = StateFromString("FAULT")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, faultState, s)
|
||||
assert.Equal(t, FaultState, s)
|
||||
|
||||
s, err = StateFromString("NONE")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, noneState, s)
|
||||
assert.Equal(t, NoneState, s)
|
||||
|
||||
s, err = StateFromString("HALT, BREAK")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, haltState|breakState, s)
|
||||
assert.Equal(t, HaltState|BreakState, s)
|
||||
|
||||
s, err = StateFromString("FAULT, BREAK")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, faultState|breakState, s)
|
||||
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.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))
|
||||
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) {
|
||||
|
@ -59,11 +59,11 @@ func TestState_MarshalJSON(t *testing.T) {
|
|||
err error
|
||||
)
|
||||
|
||||
data, err = json.Marshal(haltState | breakState)
|
||||
data, err = json.Marshal(HaltState | BreakState)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, data, []byte(`"HALT, BREAK"`))
|
||||
|
||||
data, err = json.Marshal(faultState)
|
||||
data, err = json.Marshal(FaultState)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, data, []byte(`"FAULT"`))
|
||||
}
|
||||
|
@ -76,13 +76,13 @@ func TestState_UnmarshalJSON(t *testing.T) {
|
|||
|
||||
err = json.Unmarshal([]byte(`"HALT, BREAK"`), &s)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, haltState|breakState, s)
|
||||
assert.Equal(t, HaltState|BreakState, s)
|
||||
|
||||
err = json.Unmarshal([]byte(`"FAULT, BREAK"`), &s)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, faultState|breakState, s)
|
||||
assert.Equal(t, FaultState|BreakState, s)
|
||||
|
||||
err = json.Unmarshal([]byte(`"NONE"`), &s)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, noneState, s)
|
||||
assert.Equal(t, NoneState, s)
|
||||
}
|
||||
|
|
70
pkg/vm/vm.go
70
pkg/vm/vm.go
|
@ -93,7 +93,7 @@ func New() *VM {
|
|||
func NewWithTrigger(t trigger.Type) *VM {
|
||||
vm := &VM{
|
||||
getInterop: make([]InteropGetterFunc, 0, 3), // 3 functions is typical for our default usage.
|
||||
state: haltState,
|
||||
state: HaltState,
|
||||
istack: NewStack("invocation"),
|
||||
refs: newRefCounter(),
|
||||
keys: make(map[string]*keys.PublicKey),
|
||||
|
@ -264,7 +264,7 @@ func (v *VM) Load(prog []byte) {
|
|||
// Clear all stacks and state, it could be a reload.
|
||||
v.istack.Clear()
|
||||
v.estack.Clear()
|
||||
v.state = noneState
|
||||
v.state = NoneState
|
||||
v.gasConsumed = 0
|
||||
v.LoadScript(prog)
|
||||
}
|
||||
|
@ -330,9 +330,9 @@ func (v *VM) Stack(n string) string {
|
|||
return string(b)
|
||||
}
|
||||
|
||||
// State returns string representation of the state for the VM.
|
||||
func (v *VM) State() string {
|
||||
return v.state.String()
|
||||
// State returns the state for the VM.
|
||||
func (v *VM) State() State {
|
||||
return v.state
|
||||
}
|
||||
|
||||
// Ready returns true if the VM ready to execute the loaded program.
|
||||
|
@ -344,37 +344,37 @@ func (v *VM) Ready() bool {
|
|||
// Run starts the execution of the loaded program.
|
||||
func (v *VM) Run() error {
|
||||
if !v.Ready() {
|
||||
v.state = faultState
|
||||
v.state = FaultState
|
||||
return errors.New("no program loaded")
|
||||
}
|
||||
|
||||
if v.state.HasFlag(faultState) {
|
||||
if v.state.HasFlag(FaultState) {
|
||||
// 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
|
||||
// HaltState (the default) or BreakState are safe to continue.
|
||||
v.state = NoneState
|
||||
for {
|
||||
// check for breakpoint before executing the next instruction
|
||||
ctx := v.Context()
|
||||
if ctx != nil && ctx.atBreakPoint() {
|
||||
v.state = breakState
|
||||
v.state = BreakState
|
||||
}
|
||||
switch {
|
||||
case v.state.HasFlag(faultState):
|
||||
case v.state.HasFlag(FaultState):
|
||||
// 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(HaltState), v.state.HasFlag(BreakState):
|
||||
// Normal exit from this loop.
|
||||
return nil
|
||||
case v.state == noneState:
|
||||
case v.state == NoneState:
|
||||
if err := v.Step(); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
v.state = faultState
|
||||
v.state = FaultState
|
||||
return errors.New("unknown state")
|
||||
}
|
||||
}
|
||||
|
@ -385,7 +385,7 @@ func (v *VM) Step() error {
|
|||
ctx := v.Context()
|
||||
op, param, err := ctx.Next()
|
||||
if err != nil {
|
||||
v.state = faultState
|
||||
v.state = FaultState
|
||||
return newError(ctx.ip, op, err)
|
||||
}
|
||||
return v.execute(ctx, op, param)
|
||||
|
@ -397,7 +397,7 @@ func (v *VM) StepInto() error {
|
|||
ctx := v.Context()
|
||||
|
||||
if ctx == nil {
|
||||
v.state = haltState
|
||||
v.state = HaltState
|
||||
}
|
||||
|
||||
if v.HasStopped() {
|
||||
|
@ -407,7 +407,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 = FaultState
|
||||
return newError(ctx.ip, op, err)
|
||||
}
|
||||
vErr := v.execute(ctx, op, param)
|
||||
|
@ -418,7 +418,7 @@ func (v *VM) StepInto() error {
|
|||
|
||||
cctx := v.Context()
|
||||
if cctx != nil && cctx.atBreakPoint() {
|
||||
v.state = breakState
|
||||
v.state = BreakState
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -426,14 +426,14 @@ 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 == BreakState {
|
||||
v.state = NoneState
|
||||
} else {
|
||||
v.state = breakState
|
||||
v.state = BreakState
|
||||
}
|
||||
|
||||
expSize := v.istack.len
|
||||
for v.state == noneState && v.istack.len >= expSize {
|
||||
for v.state == NoneState && v.istack.len >= expSize {
|
||||
err = v.StepInto()
|
||||
}
|
||||
return err
|
||||
|
@ -447,22 +447,22 @@ func (v *VM) StepOver() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if v.state == breakState {
|
||||
v.state = noneState
|
||||
if v.state == BreakState {
|
||||
v.state = NoneState
|
||||
} else {
|
||||
v.state = breakState
|
||||
v.state = BreakState
|
||||
}
|
||||
|
||||
expSize := v.istack.len
|
||||
for {
|
||||
err = v.StepInto()
|
||||
if !(v.state == noneState && v.istack.len > expSize) {
|
||||
if !(v.state == NoneState && v.istack.len > expSize) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if v.state == noneState {
|
||||
v.state = breakState
|
||||
if v.state == NoneState {
|
||||
v.state = BreakState
|
||||
}
|
||||
|
||||
return err
|
||||
|
@ -471,22 +471,22 @@ func (v *VM) StepOver() error {
|
|||
// HasFailed returns whether VM is in the failed state now. Usually used to
|
||||
// check status after Run.
|
||||
func (v *VM) HasFailed() bool {
|
||||
return v.state.HasFlag(faultState)
|
||||
return v.state.HasFlag(FaultState)
|
||||
}
|
||||
|
||||
// HasStopped returns whether VM is in Halt or Failed state.
|
||||
func (v *VM) HasStopped() bool {
|
||||
return v.state.HasFlag(haltState) || v.state.HasFlag(faultState)
|
||||
return v.state.HasFlag(HaltState) || v.state.HasFlag(FaultState)
|
||||
}
|
||||
|
||||
// HasHalted returns whether VM is in Halt state.
|
||||
func (v *VM) HasHalted() bool {
|
||||
return v.state.HasFlag(haltState)
|
||||
return v.state.HasFlag(HaltState)
|
||||
}
|
||||
|
||||
// AtBreakpoint returns whether VM is at breakpoint.
|
||||
func (v *VM) AtBreakpoint() bool {
|
||||
return v.state.HasFlag(breakState)
|
||||
return v.state.HasFlag(BreakState)
|
||||
}
|
||||
|
||||
// GetInteropID converts instruction parameter to an interop ID.
|
||||
|
@ -512,10 +512,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 = FaultState
|
||||
err = newError(ctx.ip, op, errRecover)
|
||||
} else if v.refs.size > MaxStackSize {
|
||||
v.state = faultState
|
||||
v.state = FaultState
|
||||
err = newError(ctx.ip, op, "stack is too big")
|
||||
}
|
||||
}()
|
||||
|
@ -1268,7 +1268,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 = HaltState
|
||||
break
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue