vm: move opcodes into their own package

This allows easier reuse of opcodes and in some cases allows to eliminate
dependencies on the whole vm package, like in compiler that only needs opcodes
and doesn't care about VM for any other purpose.

And yes, they're opcodes because an instruction is a whole thing with
operands, that's what context.Next() returns.
This commit is contained in:
Roman Khimov 2019-12-03 17:05:06 +03:00
parent f48228ef7d
commit 8d4dd2d2e1
21 changed files with 1285 additions and 1248 deletions

View file

@ -12,7 +12,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/smartcontract"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/CityOfZion/neo-go/pkg/vm"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
"github.com/CityOfZion/neo-go/pkg/wallet"
"github.com/nspcc-dev/dbft"
"github.com/nspcc-dev/dbft/block"
@ -283,7 +283,7 @@ func (s *service) getBlockWitness(b *core.Block) *transaction.Witness {
var invoc []byte
for i, j := 0, 0; i < len(pubs) && j < m; i++ {
if sig, ok := sigs[pubs[i]]; ok {
invoc = append(invoc, byte(vm.PUSHBYTES64))
invoc = append(invoc, byte(opcode.PUSHBYTES64))
invoc = append(invoc, sig...)
j++
}

View file

@ -10,6 +10,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/smartcontract"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/CityOfZion/neo-go/pkg/vm"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/dbft/payload"
"github.com/pkg/errors"
)
@ -193,7 +194,7 @@ func (p *Payload) Sign(key *privateKey) error {
return err
}
p.Witness.InvocationScript = append([]byte{byte(vm.PUSHBYTES64)}, sig...)
p.Witness.InvocationScript = append([]byte{byte(opcode.PUSHBYTES64)}, sig...)
p.Witness.VerificationScript = verif
return nil

View file

@ -9,7 +9,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/smartcontract"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/CityOfZion/neo-go/pkg/vm"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
)
// createGenesisBlock creates a genesis block based on the given configuration.
@ -33,7 +33,7 @@ func createGenesisBlock(cfg config.ProtocolConfiguration) (*Block, error) {
NextConsensus: nextConsensus,
Script: &transaction.Witness{
InvocationScript: []byte{},
VerificationScript: []byte{byte(vm.PUSHT)},
VerificationScript: []byte{byte(opcode.PUSHT)},
},
}
@ -77,7 +77,7 @@ func createGenesisBlock(cfg config.ProtocolConfiguration) (*Block, error) {
Scripts: []*transaction.Witness{
{
InvocationScript: []byte{},
VerificationScript: []byte{byte(vm.PUSHT)},
VerificationScript: []byte{byte(opcode.PUSHT)},
},
},
},
@ -92,7 +92,7 @@ func createGenesisBlock(cfg config.ProtocolConfiguration) (*Block, error) {
}
func governingTokenTX() *transaction.Transaction {
admin := hash.Hash160([]byte{byte(vm.PUSHT)})
admin := hash.Hash160([]byte{byte(opcode.PUSHT)})
registerTX := &transaction.RegisterTX{
AssetType: transaction.GoverningToken,
Name: "[{\"lang\":\"zh-CN\",\"name\":\"小蚁股\"},{\"lang\":\"en\",\"name\":\"AntShare\"}]",
@ -115,7 +115,7 @@ func governingTokenTX() *transaction.Transaction {
}
func utilityTokenTX() *transaction.Transaction {
admin := hash.Hash160([]byte{byte(vm.PUSHF)})
admin := hash.Hash160([]byte{byte(opcode.PUSHF)})
registerTX := &transaction.RegisterTX{
AssetType: transaction.UtilityToken,
Name: "[{\"lang\":\"zh-CN\",\"name\":\"小蚁币\"},{\"lang\":\"en\",\"name\":\"AntCoin\"}]",

View file

@ -13,6 +13,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/smartcontract"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/CityOfZion/neo-go/pkg/vm"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
errs "github.com/pkg/errors"
)
@ -281,7 +282,7 @@ func CreateFunctionInvocationScript(contract util.Uint160, params Params) ([]byt
if err != nil {
return nil, err
}
err = vm.EmitOpcode(script, vm.PACK)
err = vm.EmitOpcode(script, opcode.PACK)
if err != nil {
return nil, err
}

View file

@ -7,6 +7,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/vm"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
)
// CreateSignatureRedeemScript creates a check signature script runnable by VM.
@ -16,7 +17,7 @@ func CreateSignatureRedeemScript(key *keys.PublicKey) ([]byte, error) {
if err != nil {
return nil, err
}
err = vm.EmitOpcode(buf, vm.CHECKSIG)
err = vm.EmitOpcode(buf, opcode.CHECKSIG)
if err != nil {
return nil, err
}
@ -49,7 +50,7 @@ func CreateMultiSigRedeemScript(m int, publicKeys keys.PublicKeys) ([]byte, erro
if err := vm.EmitInt(buf, int64(len(publicKeys))); err != nil {
return nil, err
}
if err := vm.EmitOpcode(buf, vm.CHECKMULTISIG); err != nil {
if err := vm.EmitOpcode(buf, opcode.CHECKMULTISIG); err != nil {
return nil, err
}

View file

@ -5,7 +5,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/vm"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
"github.com/stretchr/testify/assert"
)
@ -24,7 +24,7 @@ func TestCreateMultiSigRedeemScript(t *testing.T) {
br := io.NewBinReaderFromBuf(out)
var b uint8
br.ReadLE(&b)
assert.Equal(t, vm.PUSH3, vm.Instruction(b))
assert.Equal(t, opcode.PUSH3, opcode.Opcode(b))
for i := 0; i < len(validators); i++ {
bb := br.ReadBytes()
@ -35,7 +35,7 @@ func TestCreateMultiSigRedeemScript(t *testing.T) {
}
br.ReadLE(&b)
assert.Equal(t, vm.PUSH3, vm.Instruction(b))
assert.Equal(t, opcode.PUSH3, opcode.Opcode(b))
br.ReadLE(&b)
assert.Equal(t, vm.CHECKMULTISIG, vm.Instruction(b))
assert.Equal(t, opcode.CHECKMULTISIG, opcode.Opcode(b))
}

View file

@ -13,7 +13,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/crypto"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/vm"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
)
// The identifier of the entry function. Default set to Main.
@ -95,13 +95,13 @@ func (c *codegen) emitLoadLocal(name string) {
}
func (c *codegen) emitLoadLocalPos(pos int) {
emitOpcode(c.prog.BinWriter, vm.DUPFROMALTSTACK)
emitOpcode(c.prog.BinWriter, opcode.DUPFROMALTSTACK)
emitInt(c.prog.BinWriter, int64(pos))
emitOpcode(c.prog.BinWriter, vm.PICKITEM)
emitOpcode(c.prog.BinWriter, opcode.PICKITEM)
}
func (c *codegen) emitStoreLocal(pos int) {
emitOpcode(c.prog.BinWriter, vm.DUPFROMALTSTACK)
emitOpcode(c.prog.BinWriter, opcode.DUPFROMALTSTACK)
if pos < 0 {
c.prog.Err = fmt.Errorf("invalid position to store local: %d", pos)
@ -110,19 +110,19 @@ func (c *codegen) emitStoreLocal(pos int) {
emitInt(c.prog.BinWriter, int64(pos))
emitInt(c.prog.BinWriter, 2)
emitOpcode(c.prog.BinWriter, vm.ROLL)
emitOpcode(c.prog.BinWriter, vm.SETITEM)
emitOpcode(c.prog.BinWriter, opcode.ROLL)
emitOpcode(c.prog.BinWriter, opcode.SETITEM)
}
func (c *codegen) emitLoadField(i int) {
emitInt(c.prog.BinWriter, int64(i))
emitOpcode(c.prog.BinWriter, vm.PICKITEM)
emitOpcode(c.prog.BinWriter, opcode.PICKITEM)
}
func (c *codegen) emitStoreStructField(i int) {
emitInt(c.prog.BinWriter, int64(i))
emitOpcode(c.prog.BinWriter, vm.ROT)
emitOpcode(c.prog.BinWriter, vm.SETITEM)
emitOpcode(c.prog.BinWriter, opcode.ROT)
emitOpcode(c.prog.BinWriter, opcode.SETITEM)
}
// convertGlobals traverses the AST and only converts global declarations.
@ -163,8 +163,8 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl) {
// All globals copied into the scope of the function need to be added
// to the stack size of the function.
emitInt(c.prog.BinWriter, f.stackSize()+countGlobals(file))
emitOpcode(c.prog.BinWriter, vm.NEWARRAY)
emitOpcode(c.prog.BinWriter, vm.TOALTSTACK)
emitOpcode(c.prog.BinWriter, opcode.NEWARRAY)
emitOpcode(c.prog.BinWriter, opcode.TOALTSTACK)
// We need to handle methods, which in Go, is just syntactic sugar.
// The method receiver will be passed in as first argument.
@ -202,9 +202,9 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl) {
// If this function returns the void (no return stmt) we will cleanup its junk on the stack.
if !hasReturnStmt(decl) {
emitOpcode(c.prog.BinWriter, vm.FROMALTSTACK)
emitOpcode(c.prog.BinWriter, vm.DROP)
emitOpcode(c.prog.BinWriter, vm.RET)
emitOpcode(c.prog.BinWriter, opcode.FROMALTSTACK)
emitOpcode(c.prog.BinWriter, opcode.DROP)
emitOpcode(c.prog.BinWriter, opcode.RET)
}
}
@ -295,9 +295,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
ast.Walk(c, n.Results[0])
}
emitOpcode(c.prog.BinWriter, vm.FROMALTSTACK)
emitOpcode(c.prog.BinWriter, vm.DROP) // Cleanup the stack.
emitOpcode(c.prog.BinWriter, vm.RET)
emitOpcode(c.prog.BinWriter, opcode.FROMALTSTACK)
emitOpcode(c.prog.BinWriter, opcode.DROP) // Cleanup the stack.
emitOpcode(c.prog.BinWriter, opcode.RET)
return nil
case *ast.IfStmt:
@ -307,13 +307,13 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
if n.Cond != nil {
ast.Walk(c, n.Cond)
emitJmp(c.prog.BinWriter, vm.JMPIFNOT, int16(lElse))
emitJmp(c.prog.BinWriter, opcode.JMPIFNOT, int16(lElse))
}
c.setLabel(lIf)
ast.Walk(c, n.Body)
if n.Else != nil {
emitJmp(c.prog.BinWriter, vm.JMP, int16(lElseEnd))
emitJmp(c.prog.BinWriter, opcode.JMP, int16(lElseEnd))
}
c.setLabel(lElse)
@ -359,7 +359,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
c.emitLoadConst(c.typeInfo.Types[n.Elts[i]])
}
emitInt(c.prog.BinWriter, int64(ln))
emitOpcode(c.prog.BinWriter, vm.PACK)
emitOpcode(c.prog.BinWriter, opcode.PACK)
return nil
}
@ -374,13 +374,13 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
switch n.Op {
case token.LAND:
ast.Walk(c, n.X)
emitJmp(c.prog.BinWriter, vm.JMPIFNOT, int16(len(c.l)-1))
emitJmp(c.prog.BinWriter, opcode.JMPIFNOT, int16(len(c.l)-1))
ast.Walk(c, n.Y)
return nil
case token.LOR:
ast.Walk(c, n.X)
emitJmp(c.prog.BinWriter, vm.JMPIF, int16(len(c.l)-3))
emitJmp(c.prog.BinWriter, opcode.JMPIF, int16(len(c.l)-3))
ast.Walk(c, n.Y)
return nil
@ -405,24 +405,24 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
case n.Op == token.ADD:
// VM has separate opcodes for number and string concatenation
if isStringType(tinfo.Type) {
emitOpcode(c.prog.BinWriter, vm.CAT)
emitOpcode(c.prog.BinWriter, opcode.CAT)
} else {
emitOpcode(c.prog.BinWriter, vm.ADD)
emitOpcode(c.prog.BinWriter, opcode.ADD)
}
case n.Op == token.EQL:
// VM has separate opcodes for number and string equality
if isStringType(c.typeInfo.Types[n.X].Type) {
emitOpcode(c.prog.BinWriter, vm.EQUAL)
emitOpcode(c.prog.BinWriter, opcode.EQUAL)
} else {
emitOpcode(c.prog.BinWriter, vm.NUMEQUAL)
emitOpcode(c.prog.BinWriter, opcode.NUMEQUAL)
}
case n.Op == token.NEQ:
// VM has separate opcodes for number and string equality
if isStringType(c.typeInfo.Types[n.X].Type) {
emitOpcode(c.prog.BinWriter, vm.EQUAL)
emitOpcode(c.prog.BinWriter, vm.NOT)
emitOpcode(c.prog.BinWriter, opcode.EQUAL)
emitOpcode(c.prog.BinWriter, opcode.NOT)
} else {
emitOpcode(c.prog.BinWriter, vm.NUMNOTEQUAL)
emitOpcode(c.prog.BinWriter, opcode.NUMNOTEQUAL)
}
default:
c.convertToken(n.Op)
@ -478,14 +478,14 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
// Do not swap for builtin functions.
if !isBuiltin {
if numArgs == 2 {
emitOpcode(c.prog.BinWriter, vm.SWAP)
emitOpcode(c.prog.BinWriter, opcode.SWAP)
} else if numArgs == 3 {
emitInt(c.prog.BinWriter, 2)
emitOpcode(c.prog.BinWriter, vm.XSWAP)
emitOpcode(c.prog.BinWriter, opcode.XSWAP)
} else {
for i := 1; i < numArgs; i++ {
emitInt(c.prog.BinWriter, int64(i))
emitOpcode(c.prog.BinWriter, vm.ROLL)
emitOpcode(c.prog.BinWriter, opcode.ROLL)
}
}
}
@ -499,7 +499,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
case isSyscall(f):
c.convertSyscall(f.selector.Name, f.name)
default:
emitCall(c.prog.BinWriter, vm.CALL, int16(f.label))
emitCall(c.prog.BinWriter, opcode.CALL, int16(f.label))
}
return nil
@ -529,11 +529,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
case token.ADD:
// +10 == 10, no need to do anything in this case
case token.SUB:
emitOpcode(c.prog.BinWriter, vm.NEGATE)
emitOpcode(c.prog.BinWriter, opcode.NEGATE)
case token.NOT:
emitOpcode(c.prog.BinWriter, vm.NOT)
emitOpcode(c.prog.BinWriter, opcode.NOT)
case token.XOR:
emitOpcode(c.prog.BinWriter, vm.INVERT)
emitOpcode(c.prog.BinWriter, opcode.INVERT)
default:
c.prog.Err = fmt.Errorf("invalid unary operator: %s", n.Op)
return nil
@ -565,7 +565,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
c.emitLoadField(int(val))
default:
ast.Walk(c, n.Index)
emitOpcode(c.prog.BinWriter, vm.PICKITEM) // just pickitem here
emitOpcode(c.prog.BinWriter, opcode.PICKITEM) // just pickitem here
}
return nil
@ -583,14 +583,14 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
ast.Walk(c, n.Cond)
// Jump if the condition is false
emitJmp(c.prog.BinWriter, vm.JMPIFNOT, int16(fend))
emitJmp(c.prog.BinWriter, opcode.JMPIFNOT, int16(fend))
// Walk body followed by the iterator (post stmt).
ast.Walk(c, n.Body)
ast.Walk(c, n.Post)
// Jump back to condition.
emitJmp(c.prog.BinWriter, vm.JMP, int16(fstart))
emitJmp(c.prog.BinWriter, opcode.JMP, int16(fstart))
c.setLabel(fend)
return nil
@ -616,7 +616,7 @@ func (c *codegen) convertSyscall(api, name string) {
// This NOP instruction is basically not needed, but if we do, we have a
// one to one matching avm file with neo-python which is very nice for debugging.
emitOpcode(c.prog.BinWriter, vm.NOP)
emitOpcode(c.prog.BinWriter, opcode.NOP)
}
func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
@ -633,32 +633,32 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
arg := expr.Args[0]
typ := c.typeInfo.Types[arg].Type
if isStringType(typ) {
emitOpcode(c.prog.BinWriter, vm.SIZE)
emitOpcode(c.prog.BinWriter, opcode.SIZE)
} else {
emitOpcode(c.prog.BinWriter, vm.ARRAYSIZE)
emitOpcode(c.prog.BinWriter, opcode.ARRAYSIZE)
}
case "append":
arg := expr.Args[0]
typ := c.typeInfo.Types[arg].Type
if isByteArrayType(typ) {
emitOpcode(c.prog.BinWriter, vm.CAT)
emitOpcode(c.prog.BinWriter, opcode.CAT)
} else {
emitOpcode(c.prog.BinWriter, vm.SWAP)
emitOpcode(c.prog.BinWriter, vm.DUP)
emitOpcode(c.prog.BinWriter, vm.PUSH2)
emitOpcode(c.prog.BinWriter, vm.XSWAP)
emitOpcode(c.prog.BinWriter, vm.APPEND)
emitOpcode(c.prog.BinWriter, opcode.SWAP)
emitOpcode(c.prog.BinWriter, opcode.DUP)
emitOpcode(c.prog.BinWriter, opcode.PUSH2)
emitOpcode(c.prog.BinWriter, opcode.XSWAP)
emitOpcode(c.prog.BinWriter, opcode.APPEND)
}
case "SHA256":
emitOpcode(c.prog.BinWriter, vm.SHA256)
emitOpcode(c.prog.BinWriter, opcode.SHA256)
case "SHA1":
emitOpcode(c.prog.BinWriter, vm.SHA1)
emitOpcode(c.prog.BinWriter, opcode.SHA1)
case "Hash256":
emitOpcode(c.prog.BinWriter, vm.HASH256)
emitOpcode(c.prog.BinWriter, opcode.HASH256)
case "Hash160":
emitOpcode(c.prog.BinWriter, vm.HASH160)
emitOpcode(c.prog.BinWriter, opcode.HASH160)
case "Equals":
emitOpcode(c.prog.BinWriter, vm.EQUAL)
emitOpcode(c.prog.BinWriter, opcode.EQUAL)
case "FromAddress":
// We can be sure that this is a ast.BasicLit just containing a simple
// address string. Note that the string returned from calling Value will
@ -694,10 +694,10 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) {
return
}
emitOpcode(c.prog.BinWriter, vm.NOP)
emitOpcode(c.prog.BinWriter, opcode.NOP)
emitInt(c.prog.BinWriter, int64(strct.NumFields()))
emitOpcode(c.prog.BinWriter, vm.NEWSTRUCT)
emitOpcode(c.prog.BinWriter, vm.TOALTSTACK)
emitOpcode(c.prog.BinWriter, opcode.NEWSTRUCT)
emitOpcode(c.prog.BinWriter, opcode.TOALTSTACK)
// We need to locally store all the fields, even if they are not initialized.
// We will initialize all fields to their "zero" value.
@ -730,55 +730,55 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) {
c.emitLoadConst(typeAndVal)
c.emitStoreLocal(i)
}
emitOpcode(c.prog.BinWriter, vm.FROMALTSTACK)
emitOpcode(c.prog.BinWriter, opcode.FROMALTSTACK)
}
func (c *codegen) convertToken(tok token.Token) {
switch tok {
case token.ADD_ASSIGN:
emitOpcode(c.prog.BinWriter, vm.ADD)
emitOpcode(c.prog.BinWriter, opcode.ADD)
case token.SUB_ASSIGN:
emitOpcode(c.prog.BinWriter, vm.SUB)
emitOpcode(c.prog.BinWriter, opcode.SUB)
case token.MUL_ASSIGN:
emitOpcode(c.prog.BinWriter, vm.MUL)
emitOpcode(c.prog.BinWriter, opcode.MUL)
case token.QUO_ASSIGN:
emitOpcode(c.prog.BinWriter, vm.DIV)
emitOpcode(c.prog.BinWriter, opcode.DIV)
case token.ADD:
emitOpcode(c.prog.BinWriter, vm.ADD)
emitOpcode(c.prog.BinWriter, opcode.ADD)
case token.SUB:
emitOpcode(c.prog.BinWriter, vm.SUB)
emitOpcode(c.prog.BinWriter, opcode.SUB)
case token.MUL:
emitOpcode(c.prog.BinWriter, vm.MUL)
emitOpcode(c.prog.BinWriter, opcode.MUL)
case token.QUO:
emitOpcode(c.prog.BinWriter, vm.DIV)
emitOpcode(c.prog.BinWriter, opcode.DIV)
case token.LSS:
emitOpcode(c.prog.BinWriter, vm.LT)
emitOpcode(c.prog.BinWriter, opcode.LT)
case token.LEQ:
emitOpcode(c.prog.BinWriter, vm.LTE)
emitOpcode(c.prog.BinWriter, opcode.LTE)
case token.GTR:
emitOpcode(c.prog.BinWriter, vm.GT)
emitOpcode(c.prog.BinWriter, opcode.GT)
case token.GEQ:
emitOpcode(c.prog.BinWriter, vm.GTE)
emitOpcode(c.prog.BinWriter, opcode.GTE)
case token.EQL:
emitOpcode(c.prog.BinWriter, vm.NUMEQUAL)
emitOpcode(c.prog.BinWriter, opcode.NUMEQUAL)
case token.NEQ:
emitOpcode(c.prog.BinWriter, vm.NUMNOTEQUAL)
emitOpcode(c.prog.BinWriter, opcode.NUMNOTEQUAL)
case token.DEC:
emitOpcode(c.prog.BinWriter, vm.DEC)
emitOpcode(c.prog.BinWriter, opcode.DEC)
case token.INC:
emitOpcode(c.prog.BinWriter, vm.INC)
emitOpcode(c.prog.BinWriter, opcode.INC)
case token.NOT:
emitOpcode(c.prog.BinWriter, vm.NOT)
emitOpcode(c.prog.BinWriter, opcode.NOT)
case token.AND:
emitOpcode(c.prog.BinWriter, vm.AND)
emitOpcode(c.prog.BinWriter, opcode.AND)
case token.OR:
emitOpcode(c.prog.BinWriter, vm.OR)
emitOpcode(c.prog.BinWriter, opcode.OR)
case token.SHL:
emitOpcode(c.prog.BinWriter, vm.SHL)
emitOpcode(c.prog.BinWriter, opcode.SHL)
case token.SHR:
emitOpcode(c.prog.BinWriter, vm.SHR)
emitOpcode(c.prog.BinWriter, opcode.SHR)
case token.XOR:
emitOpcode(c.prog.BinWriter, vm.XOR)
emitOpcode(c.prog.BinWriter, opcode.XOR)
default:
c.prog.Err = fmt.Errorf("compiler could not convert token: %s", tok)
return
@ -869,8 +869,8 @@ func (c *codegen) resolveFuncDecls(f *ast.File) {
func (c *codegen) writeJumps(b []byte) {
for i, op := range b {
j := i + 1
switch vm.Instruction(op) {
case vm.JMP, vm.JMPIFNOT, vm.JMPIF, vm.CALL:
switch opcode.Opcode(op) {
case opcode.JMP, opcode.JMPIFNOT, opcode.JMPIF, opcode.CALL:
index := int16(binary.LittleEndian.Uint16(b[j : j+2]))
if int(index) > len(c.l) || int(index) < 0 {
continue

View file

@ -8,40 +8,40 @@ import (
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/CityOfZion/neo-go/pkg/vm"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
)
// emit a VM Instruction with data to the given buffer.
func emit(w *io.BinWriter, instr vm.Instruction, b []byte) {
func emit(w *io.BinWriter, instr opcode.Opcode, b []byte) {
emitOpcode(w, instr)
w.WriteBytes(b)
}
// emitOpcode emits a single VM Instruction the given buffer.
func emitOpcode(w *io.BinWriter, instr vm.Instruction) {
func emitOpcode(w *io.BinWriter, instr opcode.Opcode) {
w.WriteLE(byte(instr))
}
// emitBool emits a bool type the given buffer.
func emitBool(w *io.BinWriter, ok bool) {
if ok {
emitOpcode(w, vm.PUSHT)
emitOpcode(w, opcode.PUSHT)
return
}
emitOpcode(w, vm.PUSHF)
emitOpcode(w, opcode.PUSHF)
}
// emitInt emits a int type to the given buffer.
func emitInt(w *io.BinWriter, i int64) {
switch {
case i == -1:
emitOpcode(w, vm.PUSHM1)
emitOpcode(w, opcode.PUSHM1)
return
case i == 0:
emitOpcode(w, vm.PUSHF)
emitOpcode(w, opcode.PUSHF)
return
case i > 0 && i < 16:
val := vm.Instruction(int(vm.PUSH1) - 1 + int(i))
val := opcode.Opcode(int(opcode.PUSH1) - 1 + int(i))
emitOpcode(w, val)
return
}
@ -61,19 +61,19 @@ func emitBytes(w *io.BinWriter, b []byte) {
n := len(b)
switch {
case n <= int(vm.PUSHBYTES75):
emit(w, vm.Instruction(n), b)
case n <= int(opcode.PUSHBYTES75):
emit(w, opcode.Opcode(n), b)
return
case n < 0x100:
emit(w, vm.PUSHDATA1, []byte{byte(n)})
emit(w, opcode.PUSHDATA1, []byte{byte(n)})
case n < 0x10000:
buf := make([]byte, 2)
binary.LittleEndian.PutUint16(buf, uint16(n))
emit(w, vm.PUSHDATA2, buf)
emit(w, opcode.PUSHDATA2, buf)
default:
buf := make([]byte, 4)
binary.LittleEndian.PutUint32(buf, uint32(n))
emit(w, vm.PUSHDATA4, buf)
emit(w, opcode.PUSHDATA4, buf)
if w.Err != nil {
return
}
@ -92,16 +92,16 @@ func emitSyscall(w *io.BinWriter, api string) {
buf := make([]byte, len(api)+1)
buf[0] = byte(len(api))
copy(buf[1:], api)
emit(w, vm.SYSCALL, buf)
emit(w, opcode.SYSCALL, buf)
}
// emitCall emits a call Instruction with label to the given buffer.
func emitCall(w *io.BinWriter, instr vm.Instruction, label int16) {
func emitCall(w *io.BinWriter, instr opcode.Opcode, label int16) {
emitJmp(w, instr, label)
}
// emitJmp emits a jump Instruction along with label to the given buffer.
func emitJmp(w *io.BinWriter, instr vm.Instruction, label int16) {
func emitJmp(w *io.BinWriter, instr opcode.Opcode, label int16) {
if !isInstrJmp(instr) {
w.Err = fmt.Errorf("opcode %s is not a jump or call type", instr)
return
@ -111,8 +111,8 @@ func emitJmp(w *io.BinWriter, instr vm.Instruction, label int16) {
emit(w, instr, buf)
}
func isInstrJmp(instr vm.Instruction) bool {
if instr == vm.JMP || instr == vm.JMPIFNOT || instr == vm.JMPIF || instr == vm.CALL {
func isInstrJmp(instr opcode.Opcode) bool {
if instr == opcode.JMP || instr == opcode.JMPIFNOT || instr == opcode.JMPIF || instr == opcode.CALL {
return true
}
return false

View file

@ -4,6 +4,7 @@ import (
"errors"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
)
// Context represents the current execution context of the VM.
@ -42,31 +43,31 @@ func NewContext(b []byte) *Context {
// Next returns the next instruction to execute with its parameter if any. After
// its invocation the instruction pointer points to the instruction being
// returned.
func (c *Context) Next() (Instruction, []byte, error) {
func (c *Context) Next() (opcode.Opcode, []byte, error) {
c.ip = c.nextip
if c.ip >= len(c.prog) {
return RET, nil, nil
return opcode.RET, nil, nil
}
r := io.NewBinReaderFromBuf(c.prog[c.ip:])
var instrbyte byte
r.ReadLE(&instrbyte)
instr := Instruction(instrbyte)
instr := opcode.Opcode(instrbyte)
c.nextip++
var numtoread int
switch instr {
case PUSHDATA1, SYSCALL:
case opcode.PUSHDATA1, opcode.SYSCALL:
var n byte
r.ReadLE(&n)
numtoread = int(n)
c.nextip++
case PUSHDATA2:
case opcode.PUSHDATA2:
var n uint16
r.ReadLE(&n)
numtoread = int(n)
c.nextip += 2
case PUSHDATA4:
case opcode.PUSHDATA4:
var n uint32
r.ReadLE(&n)
if n > MaxItemSize {
@ -74,16 +75,16 @@ func (c *Context) Next() (Instruction, []byte, error) {
}
numtoread = int(n)
c.nextip += 4
case JMP, JMPIF, JMPIFNOT, CALL, CALLED, CALLEDT:
case opcode.JMP, opcode.JMPIF, opcode.JMPIFNOT, opcode.CALL, opcode.CALLED, opcode.CALLEDT:
numtoread = 2
case CALLI:
case opcode.CALLI:
numtoread = 4
case APPCALL, TAILCALL:
case opcode.APPCALL, opcode.TAILCALL:
numtoread = 20
case CALLE, CALLET:
case opcode.CALLE, opcode.CALLET:
numtoread = 22
default:
if instr >= PUSHBYTES1 && instr <= PUSHBYTES75 {
if instr >= opcode.PUSHBYTES1 && instr <= opcode.PUSHBYTES75 {
numtoread = int(instr)
} else {
// No parameters, can just return.
@ -112,8 +113,8 @@ func (c *Context) LenInstr() int {
}
// CurrInstr returns the current instruction and opcode.
func (c *Context) CurrInstr() (int, Instruction) {
return c.ip, Instruction(c.prog[c.ip])
func (c *Context) CurrInstr() (int, opcode.Opcode) {
return c.ip, opcode.Opcode(c.prog[c.ip])
}
// Copy returns an new exact copy of c.

View file

@ -2,18 +2,22 @@ package vm
import (
"encoding/binary"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
)
func getNumOfThingsFromInstr(instr Instruction, param []byte) (int, bool) {
func getNumOfThingsFromInstr(instr opcode.Opcode, param []byte) (int, bool) {
var nthings int
switch instr {
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8,
PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16:
nthings = int(instr-PUSH1) + 1
case PUSHBYTES1:
case opcode.PUSH1, opcode.PUSH2, opcode.PUSH3, opcode.PUSH4,
opcode.PUSH5, opcode.PUSH6, opcode.PUSH7, opcode.PUSH8,
opcode.PUSH9, opcode.PUSH10, opcode.PUSH11, opcode.PUSH12,
opcode.PUSH13, opcode.PUSH14, opcode.PUSH15, opcode.PUSH16:
nthings = int(instr-opcode.PUSH1) + 1
case opcode.PUSHBYTES1:
nthings = int(param[0])
case PUSHBYTES2:
case opcode.PUSHBYTES2:
nthings = int(binary.LittleEndian.Uint16(param))
default:
return 0, false
@ -43,7 +47,7 @@ func IsMultiSigContract(script []byte) bool {
if err != nil {
return false
}
if instr != PUSHBYTES33 {
if instr != opcode.PUSHBYTES33 {
break
}
nkeys++
@ -62,11 +66,11 @@ func IsMultiSigContract(script []byte) bool {
return false
}
instr, _, err = ctx.Next()
if err != nil || instr != CHECKMULTISIG {
if err != nil || instr != opcode.CHECKMULTISIG {
return false
}
instr, _, err = ctx.Next()
if err != nil || instr != RET || ctx.ip != len(script) {
if err != nil || instr != opcode.RET || ctx.ip != len(script) {
return false
}
return true
@ -77,15 +81,15 @@ func IsMultiSigContract(script []byte) bool {
func IsSignatureContract(script []byte) bool {
ctx := NewContext(script)
instr, _, err := ctx.Next()
if err != nil || instr != PUSHBYTES33 {
if err != nil || instr != opcode.PUSHBYTES33 {
return false
}
instr, _, err = ctx.Next()
if err != nil || instr != CHECKSIG {
if err != nil || instr != opcode.CHECKSIG {
return false
}
instr, _, err = ctx.Next()
if err != nil || instr != RET || ctx.ip != len(script) {
if err != nil || instr != opcode.RET || ctx.ip != len(script) {
return false
}
return true

View file

@ -3,225 +3,226 @@ package vm
import (
"testing"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
"github.com/stretchr/testify/assert"
)
func TestIsSignatureContractGood(t *testing.T) {
prog := make([]byte, 35)
prog[0] = byte(PUSHBYTES33)
prog[34] = byte(CHECKSIG)
prog[0] = byte(opcode.PUSHBYTES33)
prog[34] = byte(opcode.CHECKSIG)
assert.Equal(t, true, IsSignatureContract(prog))
assert.Equal(t, true, IsStandardContract(prog))
}
func TestIsSignatureContractBadNoCheckSig(t *testing.T) {
prog := make([]byte, 34)
prog[0] = byte(PUSHBYTES33)
prog[0] = byte(opcode.PUSHBYTES33)
assert.Equal(t, false, IsSignatureContract(prog))
assert.Equal(t, false, IsStandardContract(prog))
}
func TestIsSignatureContractBadNoCheckSig2(t *testing.T) {
prog := make([]byte, 35)
prog[0] = byte(PUSHBYTES33)
prog[34] = byte(CHECKMULTISIG)
prog[0] = byte(opcode.PUSHBYTES33)
prog[34] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, false, IsSignatureContract(prog))
}
func TestIsSignatureContractBadWrongPush(t *testing.T) {
prog := make([]byte, 35)
prog[0] = byte(PUSHBYTES32)
prog[33] = byte(NOP)
prog[34] = byte(CHECKSIG)
prog[0] = byte(opcode.PUSHBYTES32)
prog[33] = byte(opcode.NOP)
prog[34] = byte(opcode.CHECKSIG)
assert.Equal(t, false, IsSignatureContract(prog))
}
func TestIsSignatureContractBadWrongInstr(t *testing.T) {
prog := make([]byte, 30)
prog[0] = byte(PUSHBYTES33)
prog[0] = byte(opcode.PUSHBYTES33)
assert.Equal(t, false, IsSignatureContract(prog))
}
func TestIsSignatureContractBadExcessiveInstr(t *testing.T) {
prog := make([]byte, 36)
prog[0] = byte(PUSHBYTES33)
prog[34] = byte(CHECKSIG)
prog[35] = byte(RET)
prog[0] = byte(opcode.PUSHBYTES33)
prog[34] = byte(opcode.CHECKSIG)
prog[35] = byte(opcode.RET)
assert.Equal(t, false, IsSignatureContract(prog))
}
func TestIsMultiSigContractGood(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(CHECKMULTISIG)
prog[0] = byte(opcode.PUSH2)
prog[1] = byte(opcode.PUSHBYTES33)
prog[35] = byte(opcode.PUSHBYTES33)
prog[69] = byte(opcode.PUSH2)
prog[70] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, true, IsMultiSigContract(prog))
assert.Equal(t, true, IsStandardContract(prog))
}
func TestIsMultiSigContractGoodPushBytes1(t *testing.T) {
prog := make([]byte, 73)
prog[0] = byte(PUSHBYTES1)
prog[0] = byte(opcode.PUSHBYTES1)
prog[1] = 2
prog[2] = byte(PUSHBYTES33)
prog[36] = byte(PUSHBYTES33)
prog[70] = byte(PUSHBYTES1)
prog[2] = byte(opcode.PUSHBYTES33)
prog[36] = byte(opcode.PUSHBYTES33)
prog[70] = byte(opcode.PUSHBYTES1)
prog[71] = 2
prog[72] = byte(CHECKMULTISIG)
prog[72] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, true, IsMultiSigContract(prog))
}
func TestIsMultiSigContractGoodPushBytes2(t *testing.T) {
prog := make([]byte, 75)
prog[0] = byte(PUSHBYTES2)
prog[0] = byte(opcode.PUSHBYTES2)
prog[1] = 2
prog[3] = byte(PUSHBYTES33)
prog[37] = byte(PUSHBYTES33)
prog[71] = byte(PUSHBYTES2)
prog[3] = byte(opcode.PUSHBYTES33)
prog[37] = byte(opcode.PUSHBYTES33)
prog[71] = byte(opcode.PUSHBYTES2)
prog[72] = 2
prog[74] = byte(CHECKMULTISIG)
prog[74] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, true, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadNSigs1(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSH0)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(CHECKMULTISIG)
prog[0] = byte(opcode.PUSH0)
prog[1] = byte(opcode.PUSHBYTES33)
prog[35] = byte(opcode.PUSHBYTES33)
prog[69] = byte(opcode.PUSH2)
prog[70] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
assert.Equal(t, false, IsStandardContract(prog))
}
func TestIsMultiSigContractBadNSigs2(t *testing.T) {
prog := make([]byte, 73)
prog[0] = byte(PUSHBYTES2)
prog[0] = byte(opcode.PUSHBYTES2)
prog[1] = 0xff
prog[2] = 0xff
prog[3] = byte(PUSHBYTES33)
prog[37] = byte(PUSHBYTES33)
prog[71] = byte(PUSH2)
prog[72] = byte(CHECKMULTISIG)
prog[3] = byte(opcode.PUSHBYTES33)
prog[37] = byte(opcode.PUSHBYTES33)
prog[71] = byte(opcode.PUSH2)
prog[72] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadNSigs3(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSH5)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(CHECKMULTISIG)
prog[0] = byte(opcode.PUSH5)
prog[1] = byte(opcode.PUSHBYTES33)
prog[35] = byte(opcode.PUSHBYTES33)
prog[69] = byte(opcode.PUSH2)
prog[70] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadExcessiveNOP1(t *testing.T) {
prog := make([]byte, 72)
prog[0] = byte(PUSH2)
prog[1] = byte(NOP)
prog[2] = byte(PUSHBYTES33)
prog[36] = byte(PUSHBYTES33)
prog[70] = byte(PUSH2)
prog[71] = byte(CHECKMULTISIG)
prog[0] = byte(opcode.PUSH2)
prog[1] = byte(opcode.NOP)
prog[2] = byte(opcode.PUSHBYTES33)
prog[36] = byte(opcode.PUSHBYTES33)
prog[70] = byte(opcode.PUSH2)
prog[71] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadExcessiveNOP2(t *testing.T) {
prog := make([]byte, 72)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(NOP)
prog[36] = byte(PUSHBYTES33)
prog[70] = byte(PUSH2)
prog[71] = byte(CHECKMULTISIG)
prog[0] = byte(opcode.PUSH2)
prog[1] = byte(opcode.PUSHBYTES33)
prog[35] = byte(opcode.NOP)
prog[36] = byte(opcode.PUSHBYTES33)
prog[70] = byte(opcode.PUSH2)
prog[71] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadExcessiveNOP3(t *testing.T) {
prog := make([]byte, 72)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(NOP)
prog[70] = byte(PUSH2)
prog[71] = byte(CHECKMULTISIG)
prog[0] = byte(opcode.PUSH2)
prog[1] = byte(opcode.PUSHBYTES33)
prog[35] = byte(opcode.PUSHBYTES33)
prog[69] = byte(opcode.NOP)
prog[70] = byte(opcode.PUSH2)
prog[71] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadExcessiveNOP4(t *testing.T) {
prog := make([]byte, 72)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(NOP)
prog[71] = byte(CHECKMULTISIG)
prog[0] = byte(opcode.PUSH2)
prog[1] = byte(opcode.PUSHBYTES33)
prog[35] = byte(opcode.PUSHBYTES33)
prog[69] = byte(opcode.PUSH2)
prog[70] = byte(opcode.NOP)
prog[71] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadExcessiveNOP5(t *testing.T) {
prog := make([]byte, 72)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(CHECKMULTISIG)
prog[71] = byte(NOP)
prog[0] = byte(opcode.PUSH2)
prog[1] = byte(opcode.PUSHBYTES33)
prog[35] = byte(opcode.PUSHBYTES33)
prog[69] = byte(opcode.PUSH2)
prog[70] = byte(opcode.CHECKMULTISIG)
prog[71] = byte(opcode.NOP)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadNKeys1(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH3)
prog[70] = byte(CHECKMULTISIG)
prog[0] = byte(opcode.PUSH2)
prog[1] = byte(opcode.PUSHBYTES33)
prog[35] = byte(opcode.PUSHBYTES33)
prog[69] = byte(opcode.PUSH3)
prog[70] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadNKeys2(t *testing.T) {
prog := make([]byte, 1)
prog[0] = byte(PUSH10)
prog[0] = byte(opcode.PUSH10)
key := make([]byte, 33)
var asize = uint16(MaxArraySize + 1)
for i := 0; i < int(asize); i++ {
prog = append(prog, byte(PUSHBYTES33))
prog = append(prog, byte(opcode.PUSHBYTES33))
prog = append(prog, key...)
}
prog = append(prog, byte(PUSHBYTES2), byte(asize&0xff), byte((asize<<8)&0xff), byte(CHECKMULTISIG))
prog = append(prog, byte(opcode.PUSHBYTES2), byte(asize&0xff), byte((asize<<8)&0xff), byte(opcode.CHECKMULTISIG))
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadRead1(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSHBYTES75)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(CHECKMULTISIG)
prog[0] = byte(opcode.PUSHBYTES75)
prog[1] = byte(opcode.PUSHBYTES33)
prog[35] = byte(opcode.PUSHBYTES33)
prog[69] = byte(opcode.PUSH2)
prog[70] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadRead2(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES75)
prog[69] = byte(PUSH2)
prog[70] = byte(CHECKMULTISIG)
prog[0] = byte(opcode.PUSH2)
prog[1] = byte(opcode.PUSHBYTES33)
prog[35] = byte(opcode.PUSHBYTES75)
prog[69] = byte(opcode.PUSH2)
prog[70] = byte(opcode.CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadRead3(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(PUSHBYTES1)
prog[0] = byte(opcode.PUSH2)
prog[1] = byte(opcode.PUSHBYTES33)
prog[35] = byte(opcode.PUSHBYTES33)
prog[69] = byte(opcode.PUSH2)
prog[70] = byte(opcode.PUSHBYTES1)
assert.Equal(t, false, IsMultiSigContract(prog))
}

View file

@ -9,10 +9,11 @@ import (
"math/big"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
)
// Emit a VM Instruction with data to the given buffer.
func Emit(w *bytes.Buffer, op Instruction, b []byte) error {
func Emit(w *bytes.Buffer, op opcode.Opcode, b []byte) error {
if err := w.WriteByte(byte(op)); err != nil {
return err
}
@ -21,28 +22,28 @@ func Emit(w *bytes.Buffer, op Instruction, b []byte) error {
}
// EmitOpcode emits a single VM Instruction the given buffer.
func EmitOpcode(w io.ByteWriter, op Instruction) error {
func EmitOpcode(w io.ByteWriter, op opcode.Opcode) error {
return w.WriteByte(byte(op))
}
// EmitBool emits a bool type the given buffer.
func EmitBool(w io.ByteWriter, ok bool) error {
if ok {
return EmitOpcode(w, PUSHT)
return EmitOpcode(w, opcode.PUSHT)
}
return EmitOpcode(w, PUSHF)
return EmitOpcode(w, opcode.PUSHF)
}
// EmitInt emits a int type to the given buffer.
func EmitInt(w *bytes.Buffer, i int64) error {
if i == -1 {
return EmitOpcode(w, PUSHM1)
return EmitOpcode(w, opcode.PUSHM1)
}
if i == 0 {
return EmitOpcode(w, PUSHF)
return EmitOpcode(w, opcode.PUSHF)
}
if i > 0 && i < 16 {
val := Instruction(int(PUSH1) - 1 + int(i))
val := opcode.Opcode(int(opcode.PUSH1) - 1 + int(i))
return EmitOpcode(w, val)
}
@ -63,18 +64,18 @@ func EmitBytes(w *bytes.Buffer, b []byte) error {
n = len(b)
)
if n <= int(PUSHBYTES75) {
return Emit(w, Instruction(n), b)
if n <= int(opcode.PUSHBYTES75) {
return Emit(w, opcode.Opcode(n), b)
} else if n < 0x100 {
err = Emit(w, PUSHDATA1, []byte{byte(n)})
err = Emit(w, opcode.PUSHDATA1, []byte{byte(n)})
} else if n < 0x10000 {
buf := make([]byte, 2)
binary.LittleEndian.PutUint16(buf, uint16(n))
err = Emit(w, PUSHDATA2, buf)
err = Emit(w, opcode.PUSHDATA2, buf)
} else {
buf := make([]byte, 4)
binary.LittleEndian.PutUint32(buf, uint32(n))
err = Emit(w, PUSHDATA4, buf)
err = Emit(w, opcode.PUSHDATA4, buf)
}
if err != nil {
return err
@ -92,16 +93,16 @@ func EmitSyscall(w *bytes.Buffer, api string) error {
buf := make([]byte, len(api)+1)
buf[0] = byte(len(api))
copy(buf[1:], api)
return Emit(w, SYSCALL, buf)
return Emit(w, opcode.SYSCALL, buf)
}
// EmitCall emits a call Instruction with label to the given buffer.
func EmitCall(w *bytes.Buffer, op Instruction, label int16) error {
func EmitCall(w *bytes.Buffer, op opcode.Opcode, label int16) error {
return EmitJmp(w, op, label)
}
// EmitJmp emits a jump Instruction along with label to the given buffer.
func EmitJmp(w *bytes.Buffer, op Instruction, label int16) error {
func EmitJmp(w *bytes.Buffer, op opcode.Opcode, label int16) error {
if !isInstructionJmp(op) {
return fmt.Errorf("opcode %s is not a jump or call type", op.String())
}
@ -113,9 +114,9 @@ func EmitJmp(w *bytes.Buffer, op Instruction, label int16) error {
// EmitAppCall emits an appcall, if tailCall is true, tailCall opcode will be
// emitted instead.
func EmitAppCall(w *bytes.Buffer, scriptHash util.Uint160, tailCall bool) error {
op := APPCALL
op := opcode.APPCALL
if tailCall {
op = TAILCALL
op = opcode.TAILCALL
}
return Emit(w, op, scriptHash.Bytes())
}
@ -142,8 +143,8 @@ func EmitAppCallWithOperation(w *bytes.Buffer, scriptHash util.Uint160, operatio
return EmitAppCall(w, scriptHash, false)
}
func isInstructionJmp(op Instruction) bool {
if op == JMP || op == JMPIFNOT || op == JMPIF || op == CALL {
func isInstructionJmp(op opcode.Opcode) bool {
if op == opcode.JMP || op == opcode.JMPIFNOT || op == opcode.JMPIF || op == opcode.CALL {
return true
}
return false

View file

@ -5,13 +5,14 @@ import (
"encoding/binary"
"testing"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
"github.com/stretchr/testify/assert"
)
func TestEmitInt(t *testing.T) {
buf := new(bytes.Buffer)
EmitInt(buf, 10)
assert.Equal(t, Instruction(buf.Bytes()[0]), PUSH10)
assert.Equal(t, opcode.Opcode(buf.Bytes()[0]), opcode.PUSH10)
buf.Reset()
EmitInt(buf, 100)
assert.Equal(t, buf.Bytes()[0], uint8(1))
@ -26,8 +27,8 @@ func TestEmitBool(t *testing.T) {
buf := new(bytes.Buffer)
EmitBool(buf, true)
EmitBool(buf, false)
assert.Equal(t, Instruction(buf.Bytes()[0]), PUSH1)
assert.Equal(t, Instruction(buf.Bytes()[1]), PUSH0)
assert.Equal(t, opcode.Opcode(buf.Bytes()[0]), opcode.PUSH1)
assert.Equal(t, opcode.Opcode(buf.Bytes()[1]), opcode.PUSH0)
}
func TestEmitString(t *testing.T) {
@ -48,7 +49,7 @@ func TestEmitSyscall(t *testing.T) {
buf := new(bytes.Buffer)
for _, syscall := range syscalls {
EmitSyscall(buf, syscall)
assert.Equal(t, Instruction(buf.Bytes()[0]), SYSCALL)
assert.Equal(t, opcode.Opcode(buf.Bytes()[0]), opcode.SYSCALL)
assert.Equal(t, buf.Bytes()[1], uint8(len(syscall)))
assert.Equal(t, buf.Bytes()[2:], []byte(syscall))
buf.Reset()
@ -57,8 +58,8 @@ func TestEmitSyscall(t *testing.T) {
func TestEmitCall(t *testing.T) {
buf := new(bytes.Buffer)
EmitCall(buf, JMP, 100)
assert.Equal(t, Instruction(buf.Bytes()[0]), JMP)
EmitCall(buf, opcode.JMP, 100)
assert.Equal(t, opcode.Opcode(buf.Bytes()[0]), opcode.JMP)
label := binary.LittleEndian.Uint16(buf.Bytes()[1:3])
assert.Equal(t, label, uint16(100))
}

View file

@ -1,393 +0,0 @@
// Code generated by "stringer -type=Instruction"; DO NOT EDIT.
package vm
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[PUSH0-0]
_ = x[PUSHF-0]
_ = x[PUSHBYTES1-1]
_ = x[PUSHBYTES2-2]
_ = x[PUSHBYTES3-3]
_ = x[PUSHBYTES4-4]
_ = x[PUSHBYTES5-5]
_ = x[PUSHBYTES6-6]
_ = x[PUSHBYTES7-7]
_ = x[PUSHBYTES8-8]
_ = x[PUSHBYTES9-9]
_ = x[PUSHBYTES10-10]
_ = x[PUSHBYTES11-11]
_ = x[PUSHBYTES12-12]
_ = x[PUSHBYTES13-13]
_ = x[PUSHBYTES14-14]
_ = x[PUSHBYTES15-15]
_ = x[PUSHBYTES16-16]
_ = x[PUSHBYTES17-17]
_ = x[PUSHBYTES18-18]
_ = x[PUSHBYTES19-19]
_ = x[PUSHBYTES20-20]
_ = x[PUSHBYTES21-21]
_ = x[PUSHBYTES22-22]
_ = x[PUSHBYTES23-23]
_ = x[PUSHBYTES24-24]
_ = x[PUSHBYTES25-25]
_ = x[PUSHBYTES26-26]
_ = x[PUSHBYTES27-27]
_ = x[PUSHBYTES28-28]
_ = x[PUSHBYTES29-29]
_ = x[PUSHBYTES30-30]
_ = x[PUSHBYTES31-31]
_ = x[PUSHBYTES32-32]
_ = x[PUSHBYTES33-33]
_ = x[PUSHBYTES34-34]
_ = x[PUSHBYTES35-35]
_ = x[PUSHBYTES36-36]
_ = x[PUSHBYTES37-37]
_ = x[PUSHBYTES38-38]
_ = x[PUSHBYTES39-39]
_ = x[PUSHBYTES40-40]
_ = x[PUSHBYTES41-41]
_ = x[PUSHBYTES42-42]
_ = x[PUSHBYTES43-43]
_ = x[PUSHBYTES44-44]
_ = x[PUSHBYTES45-45]
_ = x[PUSHBYTES46-46]
_ = x[PUSHBYTES47-47]
_ = x[PUSHBYTES48-48]
_ = x[PUSHBYTES49-49]
_ = x[PUSHBYTES50-50]
_ = x[PUSHBYTES51-51]
_ = x[PUSHBYTES52-52]
_ = x[PUSHBYTES53-53]
_ = x[PUSHBYTES54-54]
_ = x[PUSHBYTES55-55]
_ = x[PUSHBYTES56-56]
_ = x[PUSHBYTES57-57]
_ = x[PUSHBYTES58-58]
_ = x[PUSHBYTES59-59]
_ = x[PUSHBYTES60-60]
_ = x[PUSHBYTES61-61]
_ = x[PUSHBYTES62-62]
_ = x[PUSHBYTES63-63]
_ = x[PUSHBYTES64-64]
_ = x[PUSHBYTES65-65]
_ = x[PUSHBYTES66-66]
_ = x[PUSHBYTES67-67]
_ = x[PUSHBYTES68-68]
_ = x[PUSHBYTES69-69]
_ = x[PUSHBYTES70-70]
_ = x[PUSHBYTES71-71]
_ = x[PUSHBYTES72-72]
_ = x[PUSHBYTES73-73]
_ = x[PUSHBYTES74-74]
_ = x[PUSHBYTES75-75]
_ = x[PUSHDATA1-76]
_ = x[PUSHDATA2-77]
_ = x[PUSHDATA4-78]
_ = x[PUSHM1-79]
_ = x[PUSH1-81]
_ = x[PUSHT-81]
_ = x[PUSH2-82]
_ = x[PUSH3-83]
_ = x[PUSH4-84]
_ = x[PUSH5-85]
_ = x[PUSH6-86]
_ = x[PUSH7-87]
_ = x[PUSH8-88]
_ = x[PUSH9-89]
_ = x[PUSH10-90]
_ = x[PUSH11-91]
_ = x[PUSH12-92]
_ = x[PUSH13-93]
_ = x[PUSH14-94]
_ = x[PUSH15-95]
_ = x[PUSH16-96]
_ = x[NOP-97]
_ = x[JMP-98]
_ = x[JMPIF-99]
_ = x[JMPIFNOT-100]
_ = x[CALL-101]
_ = x[RET-102]
_ = x[APPCALL-103]
_ = x[SYSCALL-104]
_ = x[TAILCALL-105]
_ = x[DUPFROMALTSTACK-106]
_ = x[TOALTSTACK-107]
_ = x[FROMALTSTACK-108]
_ = x[XDROP-109]
_ = x[XSWAP-114]
_ = x[XTUCK-115]
_ = x[DEPTH-116]
_ = x[DROP-117]
_ = x[DUP-118]
_ = x[NIP-119]
_ = x[OVER-120]
_ = x[PICK-121]
_ = x[ROLL-122]
_ = x[ROT-123]
_ = x[SWAP-124]
_ = x[TUCK-125]
_ = x[CAT-126]
_ = x[SUBSTR-127]
_ = x[LEFT-128]
_ = x[RIGHT-129]
_ = x[SIZE-130]
_ = x[INVERT-131]
_ = x[AND-132]
_ = x[OR-133]
_ = x[XOR-134]
_ = x[EQUAL-135]
_ = x[INC-139]
_ = x[DEC-140]
_ = x[SIGN-141]
_ = x[NEGATE-143]
_ = x[ABS-144]
_ = x[NOT-145]
_ = x[NZ-146]
_ = x[ADD-147]
_ = x[SUB-148]
_ = x[MUL-149]
_ = x[DIV-150]
_ = x[MOD-151]
_ = x[SHL-152]
_ = x[SHR-153]
_ = x[BOOLAND-154]
_ = x[BOOLOR-155]
_ = x[NUMEQUAL-156]
_ = x[NUMNOTEQUAL-158]
_ = x[LT-159]
_ = x[GT-160]
_ = x[LTE-161]
_ = x[GTE-162]
_ = x[MIN-163]
_ = x[MAX-164]
_ = x[WITHIN-165]
_ = x[SHA1-167]
_ = x[SHA256-168]
_ = x[HASH160-169]
_ = x[HASH256-170]
_ = x[CHECKSIG-172]
_ = x[VERIFY-173]
_ = x[CHECKMULTISIG-174]
_ = x[ARRAYSIZE-192]
_ = x[PACK-193]
_ = x[UNPACK-194]
_ = x[PICKITEM-195]
_ = x[SETITEM-196]
_ = x[NEWARRAY-197]
_ = x[NEWSTRUCT-198]
_ = x[NEWMAP-199]
_ = x[APPEND-200]
_ = x[REVERSE-201]
_ = x[REMOVE-202]
_ = x[HASKEY-203]
_ = x[KEYS-204]
_ = x[VALUES-205]
_ = x[CALLI-224]
_ = x[CALLE-225]
_ = x[CALLED-226]
_ = x[CALLET-227]
_ = x[CALLEDT-228]
_ = x[THROW-240]
_ = x[THROWIFNOT-241]
}
const _Instruction_name = "PUSH0PUSHBYTES1PUSHBYTES2PUSHBYTES3PUSHBYTES4PUSHBYTES5PUSHBYTES6PUSHBYTES7PUSHBYTES8PUSHBYTES9PUSHBYTES10PUSHBYTES11PUSHBYTES12PUSHBYTES13PUSHBYTES14PUSHBYTES15PUSHBYTES16PUSHBYTES17PUSHBYTES18PUSHBYTES19PUSHBYTES20PUSHBYTES21PUSHBYTES22PUSHBYTES23PUSHBYTES24PUSHBYTES25PUSHBYTES26PUSHBYTES27PUSHBYTES28PUSHBYTES29PUSHBYTES30PUSHBYTES31PUSHBYTES32PUSHBYTES33PUSHBYTES34PUSHBYTES35PUSHBYTES36PUSHBYTES37PUSHBYTES38PUSHBYTES39PUSHBYTES40PUSHBYTES41PUSHBYTES42PUSHBYTES43PUSHBYTES44PUSHBYTES45PUSHBYTES46PUSHBYTES47PUSHBYTES48PUSHBYTES49PUSHBYTES50PUSHBYTES51PUSHBYTES52PUSHBYTES53PUSHBYTES54PUSHBYTES55PUSHBYTES56PUSHBYTES57PUSHBYTES58PUSHBYTES59PUSHBYTES60PUSHBYTES61PUSHBYTES62PUSHBYTES63PUSHBYTES64PUSHBYTES65PUSHBYTES66PUSHBYTES67PUSHBYTES68PUSHBYTES69PUSHBYTES70PUSHBYTES71PUSHBYTES72PUSHBYTES73PUSHBYTES74PUSHBYTES75PUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPIFJMPIFNOTCALLRETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTSIZEINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINSHA1SHA256HASH160HASH256CHECKSIGVERIFYCHECKMULTISIGARRAYSIZEPACKUNPACKPICKITEMSETITEMNEWARRAYNEWSTRUCTNEWMAPAPPENDREVERSEREMOVEHASKEYKEYSVALUESCALLICALLECALLEDCALLETCALLEDTTHROWTHROWIFNOT"
var _Instruction_map = map[Instruction]string{
0: _Instruction_name[0:5],
1: _Instruction_name[5:15],
2: _Instruction_name[15:25],
3: _Instruction_name[25:35],
4: _Instruction_name[35:45],
5: _Instruction_name[45:55],
6: _Instruction_name[55:65],
7: _Instruction_name[65:75],
8: _Instruction_name[75:85],
9: _Instruction_name[85:95],
10: _Instruction_name[95:106],
11: _Instruction_name[106:117],
12: _Instruction_name[117:128],
13: _Instruction_name[128:139],
14: _Instruction_name[139:150],
15: _Instruction_name[150:161],
16: _Instruction_name[161:172],
17: _Instruction_name[172:183],
18: _Instruction_name[183:194],
19: _Instruction_name[194:205],
20: _Instruction_name[205:216],
21: _Instruction_name[216:227],
22: _Instruction_name[227:238],
23: _Instruction_name[238:249],
24: _Instruction_name[249:260],
25: _Instruction_name[260:271],
26: _Instruction_name[271:282],
27: _Instruction_name[282:293],
28: _Instruction_name[293:304],
29: _Instruction_name[304:315],
30: _Instruction_name[315:326],
31: _Instruction_name[326:337],
32: _Instruction_name[337:348],
33: _Instruction_name[348:359],
34: _Instruction_name[359:370],
35: _Instruction_name[370:381],
36: _Instruction_name[381:392],
37: _Instruction_name[392:403],
38: _Instruction_name[403:414],
39: _Instruction_name[414:425],
40: _Instruction_name[425:436],
41: _Instruction_name[436:447],
42: _Instruction_name[447:458],
43: _Instruction_name[458:469],
44: _Instruction_name[469:480],
45: _Instruction_name[480:491],
46: _Instruction_name[491:502],
47: _Instruction_name[502:513],
48: _Instruction_name[513:524],
49: _Instruction_name[524:535],
50: _Instruction_name[535:546],
51: _Instruction_name[546:557],
52: _Instruction_name[557:568],
53: _Instruction_name[568:579],
54: _Instruction_name[579:590],
55: _Instruction_name[590:601],
56: _Instruction_name[601:612],
57: _Instruction_name[612:623],
58: _Instruction_name[623:634],
59: _Instruction_name[634:645],
60: _Instruction_name[645:656],
61: _Instruction_name[656:667],
62: _Instruction_name[667:678],
63: _Instruction_name[678:689],
64: _Instruction_name[689:700],
65: _Instruction_name[700:711],
66: _Instruction_name[711:722],
67: _Instruction_name[722:733],
68: _Instruction_name[733:744],
69: _Instruction_name[744:755],
70: _Instruction_name[755:766],
71: _Instruction_name[766:777],
72: _Instruction_name[777:788],
73: _Instruction_name[788:799],
74: _Instruction_name[799:810],
75: _Instruction_name[810:821],
76: _Instruction_name[821:830],
77: _Instruction_name[830:839],
78: _Instruction_name[839:848],
79: _Instruction_name[848:854],
81: _Instruction_name[854:859],
82: _Instruction_name[859:864],
83: _Instruction_name[864:869],
84: _Instruction_name[869:874],
85: _Instruction_name[874:879],
86: _Instruction_name[879:884],
87: _Instruction_name[884:889],
88: _Instruction_name[889:894],
89: _Instruction_name[894:899],
90: _Instruction_name[899:905],
91: _Instruction_name[905:911],
92: _Instruction_name[911:917],
93: _Instruction_name[917:923],
94: _Instruction_name[923:929],
95: _Instruction_name[929:935],
96: _Instruction_name[935:941],
97: _Instruction_name[941:944],
98: _Instruction_name[944:947],
99: _Instruction_name[947:952],
100: _Instruction_name[952:960],
101: _Instruction_name[960:964],
102: _Instruction_name[964:967],
103: _Instruction_name[967:974],
104: _Instruction_name[974:981],
105: _Instruction_name[981:989],
106: _Instruction_name[989:1004],
107: _Instruction_name[1004:1014],
108: _Instruction_name[1014:1026],
109: _Instruction_name[1026:1031],
114: _Instruction_name[1031:1036],
115: _Instruction_name[1036:1041],
116: _Instruction_name[1041:1046],
117: _Instruction_name[1046:1050],
118: _Instruction_name[1050:1053],
119: _Instruction_name[1053:1056],
120: _Instruction_name[1056:1060],
121: _Instruction_name[1060:1064],
122: _Instruction_name[1064:1068],
123: _Instruction_name[1068:1071],
124: _Instruction_name[1071:1075],
125: _Instruction_name[1075:1079],
126: _Instruction_name[1079:1082],
127: _Instruction_name[1082:1088],
128: _Instruction_name[1088:1092],
129: _Instruction_name[1092:1097],
130: _Instruction_name[1097:1101],
131: _Instruction_name[1101:1107],
132: _Instruction_name[1107:1110],
133: _Instruction_name[1110:1112],
134: _Instruction_name[1112:1115],
135: _Instruction_name[1115:1120],
139: _Instruction_name[1120:1123],
140: _Instruction_name[1123:1126],
141: _Instruction_name[1126:1130],
143: _Instruction_name[1130:1136],
144: _Instruction_name[1136:1139],
145: _Instruction_name[1139:1142],
146: _Instruction_name[1142:1144],
147: _Instruction_name[1144:1147],
148: _Instruction_name[1147:1150],
149: _Instruction_name[1150:1153],
150: _Instruction_name[1153:1156],
151: _Instruction_name[1156:1159],
152: _Instruction_name[1159:1162],
153: _Instruction_name[1162:1165],
154: _Instruction_name[1165:1172],
155: _Instruction_name[1172:1178],
156: _Instruction_name[1178:1186],
158: _Instruction_name[1186:1197],
159: _Instruction_name[1197:1199],
160: _Instruction_name[1199:1201],
161: _Instruction_name[1201:1204],
162: _Instruction_name[1204:1207],
163: _Instruction_name[1207:1210],
164: _Instruction_name[1210:1213],
165: _Instruction_name[1213:1219],
167: _Instruction_name[1219:1223],
168: _Instruction_name[1223:1229],
169: _Instruction_name[1229:1236],
170: _Instruction_name[1236:1243],
172: _Instruction_name[1243:1251],
173: _Instruction_name[1251:1257],
174: _Instruction_name[1257:1270],
192: _Instruction_name[1270:1279],
193: _Instruction_name[1279:1283],
194: _Instruction_name[1283:1289],
195: _Instruction_name[1289:1297],
196: _Instruction_name[1297:1304],
197: _Instruction_name[1304:1312],
198: _Instruction_name[1312:1321],
199: _Instruction_name[1321:1327],
200: _Instruction_name[1327:1333],
201: _Instruction_name[1333:1340],
202: _Instruction_name[1340:1346],
203: _Instruction_name[1346:1352],
204: _Instruction_name[1352:1356],
205: _Instruction_name[1356:1362],
224: _Instruction_name[1362:1367],
225: _Instruction_name[1367:1372],
226: _Instruction_name[1372:1378],
227: _Instruction_name[1378:1384],
228: _Instruction_name[1384:1391],
240: _Instruction_name[1391:1396],
241: _Instruction_name[1396:1406],
}
func (i Instruction) String() string {
if str, ok := _Instruction_map[i]; ok {
return str
}
return "Instruction(" + strconv.FormatInt(int64(i), 10) + ")"
}

View file

@ -1,215 +0,0 @@
package vm
//go:generate stringer -type=Instruction
// Instruction represents an single operation for the NEO virtual machine.
type Instruction byte
// Viable list of supported instruction constants.
const (
// Constants
PUSH0 Instruction = 0x00
PUSHF Instruction = PUSH0
PUSHBYTES1 Instruction = 0x01
PUSHBYTES2 Instruction = 0x02
PUSHBYTES3 Instruction = 0x03
PUSHBYTES4 Instruction = 0x04
PUSHBYTES5 Instruction = 0x05
PUSHBYTES6 Instruction = 0x06
PUSHBYTES7 Instruction = 0x07
PUSHBYTES8 Instruction = 0x08
PUSHBYTES9 Instruction = 0x09
PUSHBYTES10 Instruction = 0x0A
PUSHBYTES11 Instruction = 0x0B
PUSHBYTES12 Instruction = 0x0C
PUSHBYTES13 Instruction = 0x0D
PUSHBYTES14 Instruction = 0x0E
PUSHBYTES15 Instruction = 0x0F
PUSHBYTES16 Instruction = 0x10
PUSHBYTES17 Instruction = 0x11
PUSHBYTES18 Instruction = 0x12
PUSHBYTES19 Instruction = 0x13
PUSHBYTES20 Instruction = 0x14
PUSHBYTES21 Instruction = 0x15
PUSHBYTES22 Instruction = 0x16
PUSHBYTES23 Instruction = 0x17
PUSHBYTES24 Instruction = 0x18
PUSHBYTES25 Instruction = 0x19
PUSHBYTES26 Instruction = 0x1A
PUSHBYTES27 Instruction = 0x1B
PUSHBYTES28 Instruction = 0x1C
PUSHBYTES29 Instruction = 0x1D
PUSHBYTES30 Instruction = 0x1E
PUSHBYTES31 Instruction = 0x1F
PUSHBYTES32 Instruction = 0x20
PUSHBYTES33 Instruction = 0x21
PUSHBYTES34 Instruction = 0x22
PUSHBYTES35 Instruction = 0x23
PUSHBYTES36 Instruction = 0x24
PUSHBYTES37 Instruction = 0x25
PUSHBYTES38 Instruction = 0x26
PUSHBYTES39 Instruction = 0x27
PUSHBYTES40 Instruction = 0x28
PUSHBYTES41 Instruction = 0x29
PUSHBYTES42 Instruction = 0x2A
PUSHBYTES43 Instruction = 0x2B
PUSHBYTES44 Instruction = 0x2C
PUSHBYTES45 Instruction = 0x2D
PUSHBYTES46 Instruction = 0x2E
PUSHBYTES47 Instruction = 0x2F
PUSHBYTES48 Instruction = 0x30
PUSHBYTES49 Instruction = 0x31
PUSHBYTES50 Instruction = 0x32
PUSHBYTES51 Instruction = 0x33
PUSHBYTES52 Instruction = 0x34
PUSHBYTES53 Instruction = 0x35
PUSHBYTES54 Instruction = 0x36
PUSHBYTES55 Instruction = 0x37
PUSHBYTES56 Instruction = 0x38
PUSHBYTES57 Instruction = 0x39
PUSHBYTES58 Instruction = 0x3A
PUSHBYTES59 Instruction = 0x3B
PUSHBYTES60 Instruction = 0x3C
PUSHBYTES61 Instruction = 0x3D
PUSHBYTES62 Instruction = 0x3E
PUSHBYTES63 Instruction = 0x3F
PUSHBYTES64 Instruction = 0x40
PUSHBYTES65 Instruction = 0x41
PUSHBYTES66 Instruction = 0x42
PUSHBYTES67 Instruction = 0x43
PUSHBYTES68 Instruction = 0x44
PUSHBYTES69 Instruction = 0x45
PUSHBYTES70 Instruction = 0x46
PUSHBYTES71 Instruction = 0x47
PUSHBYTES72 Instruction = 0x48
PUSHBYTES73 Instruction = 0x49
PUSHBYTES74 Instruction = 0x4A
PUSHBYTES75 Instruction = 0x4B
PUSHDATA1 Instruction = 0x4C
PUSHDATA2 Instruction = 0x4D
PUSHDATA4 Instruction = 0x4E
PUSHM1 Instruction = 0x4F
PUSH1 Instruction = 0x51
PUSHT Instruction = PUSH1
PUSH2 Instruction = 0x52
PUSH3 Instruction = 0x53
PUSH4 Instruction = 0x54
PUSH5 Instruction = 0x55
PUSH6 Instruction = 0x56
PUSH7 Instruction = 0x57
PUSH8 Instruction = 0x58
PUSH9 Instruction = 0x59
PUSH10 Instruction = 0x5A
PUSH11 Instruction = 0x5B
PUSH12 Instruction = 0x5C
PUSH13 Instruction = 0x5D
PUSH14 Instruction = 0x5E
PUSH15 Instruction = 0x5F
PUSH16 Instruction = 0x60
// Flow control
NOP Instruction = 0x61
JMP Instruction = 0x62
JMPIF Instruction = 0x63
JMPIFNOT Instruction = 0x64
CALL Instruction = 0x65
RET Instruction = 0x66
APPCALL Instruction = 0x67
SYSCALL Instruction = 0x68
TAILCALL Instruction = 0x69
// Stack
DUPFROMALTSTACK Instruction = 0x6A
TOALTSTACK Instruction = 0x6B
FROMALTSTACK Instruction = 0x6C
XDROP Instruction = 0x6D
XSWAP Instruction = 0x72
XTUCK Instruction = 0x73
DEPTH Instruction = 0x74
DROP Instruction = 0x75
DUP Instruction = 0x76
NIP Instruction = 0x77
OVER Instruction = 0x78
PICK Instruction = 0x79
ROLL Instruction = 0x7A
ROT Instruction = 0x7B
SWAP Instruction = 0x7C
TUCK Instruction = 0x7D
// Splice
CAT Instruction = 0x7E
SUBSTR Instruction = 0x7F
LEFT Instruction = 0x80
RIGHT Instruction = 0x81
SIZE Instruction = 0x82
// Bitwise logic
INVERT Instruction = 0x83
AND Instruction = 0x84
OR Instruction = 0x85
XOR Instruction = 0x86
EQUAL Instruction = 0x87
// Arithmetic
INC Instruction = 0x8B
DEC Instruction = 0x8C
SIGN Instruction = 0x8D
NEGATE Instruction = 0x8F
ABS Instruction = 0x90
NOT Instruction = 0x91
NZ Instruction = 0x92
ADD Instruction = 0x93
SUB Instruction = 0x94
MUL Instruction = 0x95
DIV Instruction = 0x96
MOD Instruction = 0x97
SHL Instruction = 0x98
SHR Instruction = 0x99
BOOLAND Instruction = 0x9A
BOOLOR Instruction = 0x9B
NUMEQUAL Instruction = 0x9C
NUMNOTEQUAL Instruction = 0x9E
LT Instruction = 0x9F
GT Instruction = 0xA0
LTE Instruction = 0xA1
GTE Instruction = 0xA2
MIN Instruction = 0xA3
MAX Instruction = 0xA4
WITHIN Instruction = 0xA5
// Crypto
SHA1 Instruction = 0xA7
SHA256 Instruction = 0xA8
HASH160 Instruction = 0xA9
HASH256 Instruction = 0xAA
CHECKSIG Instruction = 0xAC
VERIFY Instruction = 0xAD
CHECKMULTISIG Instruction = 0xAE
// Advanced data structures (arrays, structures, maps)
ARRAYSIZE Instruction = 0xC0
PACK Instruction = 0xC1
UNPACK Instruction = 0xC2
PICKITEM Instruction = 0xC3
SETITEM Instruction = 0xC4
NEWARRAY Instruction = 0xC5
NEWSTRUCT Instruction = 0xC6
NEWMAP Instruction = 0xC7
APPEND Instruction = 0xC8
REVERSE Instruction = 0xC9
REMOVE Instruction = 0xCA
HASKEY Instruction = 0xCB
KEYS Instruction = 0xCC
VALUES Instruction = 0xCD
// Stack isolation
CALLI Instruction = 0xE0
CALLE Instruction = 0xE1
CALLED Instruction = 0xE2
CALLET Instruction = 0xE3
CALLEDT Instruction = 0xE4
// Exceptions
THROW Instruction = 0xF0
THROWIFNOT Instruction = 0xF1
)

View file

@ -15,6 +15,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
"github.com/stretchr/testify/require"
)
@ -154,7 +155,7 @@ func testFile(t *testing.T, filename string) {
ctx := vm.istack.Peek(i).Value().(*Context)
if ctx.nextip < len(ctx.prog) {
require.Equal(t, s.InstructionPointer, ctx.nextip)
require.Equal(t, s.Instruction, Instruction(ctx.prog[ctx.nextip]).String())
require.Equal(t, s.Instruction, opcode.Opcode(ctx.prog[ctx.nextip]).String())
}
compareStacks(t, s.EStack, vm.estack)
compareStacks(t, s.AStack, vm.astack)

215
pkg/vm/opcode/opcode.go Normal file
View file

@ -0,0 +1,215 @@
package opcode
//go:generate stringer -type=Opcode
// Opcode represents a single operation code for the NEO virtual machine.
type Opcode byte
// Viable list of supported instruction constants.
const (
// Constants
PUSH0 Opcode = 0x00
PUSHF Opcode = PUSH0
PUSHBYTES1 Opcode = 0x01
PUSHBYTES2 Opcode = 0x02
PUSHBYTES3 Opcode = 0x03
PUSHBYTES4 Opcode = 0x04
PUSHBYTES5 Opcode = 0x05
PUSHBYTES6 Opcode = 0x06
PUSHBYTES7 Opcode = 0x07
PUSHBYTES8 Opcode = 0x08
PUSHBYTES9 Opcode = 0x09
PUSHBYTES10 Opcode = 0x0A
PUSHBYTES11 Opcode = 0x0B
PUSHBYTES12 Opcode = 0x0C
PUSHBYTES13 Opcode = 0x0D
PUSHBYTES14 Opcode = 0x0E
PUSHBYTES15 Opcode = 0x0F
PUSHBYTES16 Opcode = 0x10
PUSHBYTES17 Opcode = 0x11
PUSHBYTES18 Opcode = 0x12
PUSHBYTES19 Opcode = 0x13
PUSHBYTES20 Opcode = 0x14
PUSHBYTES21 Opcode = 0x15
PUSHBYTES22 Opcode = 0x16
PUSHBYTES23 Opcode = 0x17
PUSHBYTES24 Opcode = 0x18
PUSHBYTES25 Opcode = 0x19
PUSHBYTES26 Opcode = 0x1A
PUSHBYTES27 Opcode = 0x1B
PUSHBYTES28 Opcode = 0x1C
PUSHBYTES29 Opcode = 0x1D
PUSHBYTES30 Opcode = 0x1E
PUSHBYTES31 Opcode = 0x1F
PUSHBYTES32 Opcode = 0x20
PUSHBYTES33 Opcode = 0x21
PUSHBYTES34 Opcode = 0x22
PUSHBYTES35 Opcode = 0x23
PUSHBYTES36 Opcode = 0x24
PUSHBYTES37 Opcode = 0x25
PUSHBYTES38 Opcode = 0x26
PUSHBYTES39 Opcode = 0x27
PUSHBYTES40 Opcode = 0x28
PUSHBYTES41 Opcode = 0x29
PUSHBYTES42 Opcode = 0x2A
PUSHBYTES43 Opcode = 0x2B
PUSHBYTES44 Opcode = 0x2C
PUSHBYTES45 Opcode = 0x2D
PUSHBYTES46 Opcode = 0x2E
PUSHBYTES47 Opcode = 0x2F
PUSHBYTES48 Opcode = 0x30
PUSHBYTES49 Opcode = 0x31
PUSHBYTES50 Opcode = 0x32
PUSHBYTES51 Opcode = 0x33
PUSHBYTES52 Opcode = 0x34
PUSHBYTES53 Opcode = 0x35
PUSHBYTES54 Opcode = 0x36
PUSHBYTES55 Opcode = 0x37
PUSHBYTES56 Opcode = 0x38
PUSHBYTES57 Opcode = 0x39
PUSHBYTES58 Opcode = 0x3A
PUSHBYTES59 Opcode = 0x3B
PUSHBYTES60 Opcode = 0x3C
PUSHBYTES61 Opcode = 0x3D
PUSHBYTES62 Opcode = 0x3E
PUSHBYTES63 Opcode = 0x3F
PUSHBYTES64 Opcode = 0x40
PUSHBYTES65 Opcode = 0x41
PUSHBYTES66 Opcode = 0x42
PUSHBYTES67 Opcode = 0x43
PUSHBYTES68 Opcode = 0x44
PUSHBYTES69 Opcode = 0x45
PUSHBYTES70 Opcode = 0x46
PUSHBYTES71 Opcode = 0x47
PUSHBYTES72 Opcode = 0x48
PUSHBYTES73 Opcode = 0x49
PUSHBYTES74 Opcode = 0x4A
PUSHBYTES75 Opcode = 0x4B
PUSHDATA1 Opcode = 0x4C
PUSHDATA2 Opcode = 0x4D
PUSHDATA4 Opcode = 0x4E
PUSHM1 Opcode = 0x4F
PUSH1 Opcode = 0x51
PUSHT Opcode = PUSH1
PUSH2 Opcode = 0x52
PUSH3 Opcode = 0x53
PUSH4 Opcode = 0x54
PUSH5 Opcode = 0x55
PUSH6 Opcode = 0x56
PUSH7 Opcode = 0x57
PUSH8 Opcode = 0x58
PUSH9 Opcode = 0x59
PUSH10 Opcode = 0x5A
PUSH11 Opcode = 0x5B
PUSH12 Opcode = 0x5C
PUSH13 Opcode = 0x5D
PUSH14 Opcode = 0x5E
PUSH15 Opcode = 0x5F
PUSH16 Opcode = 0x60
// Flow control
NOP Opcode = 0x61
JMP Opcode = 0x62
JMPIF Opcode = 0x63
JMPIFNOT Opcode = 0x64
CALL Opcode = 0x65
RET Opcode = 0x66
APPCALL Opcode = 0x67
SYSCALL Opcode = 0x68
TAILCALL Opcode = 0x69
// Stack
DUPFROMALTSTACK Opcode = 0x6A
TOALTSTACK Opcode = 0x6B
FROMALTSTACK Opcode = 0x6C
XDROP Opcode = 0x6D
XSWAP Opcode = 0x72
XTUCK Opcode = 0x73
DEPTH Opcode = 0x74
DROP Opcode = 0x75
DUP Opcode = 0x76
NIP Opcode = 0x77
OVER Opcode = 0x78
PICK Opcode = 0x79
ROLL Opcode = 0x7A
ROT Opcode = 0x7B
SWAP Opcode = 0x7C
TUCK Opcode = 0x7D
// Splice
CAT Opcode = 0x7E
SUBSTR Opcode = 0x7F
LEFT Opcode = 0x80
RIGHT Opcode = 0x81
SIZE Opcode = 0x82
// Bitwise logic
INVERT Opcode = 0x83
AND Opcode = 0x84
OR Opcode = 0x85
XOR Opcode = 0x86
EQUAL Opcode = 0x87
// Arithmetic
INC Opcode = 0x8B
DEC Opcode = 0x8C
SIGN Opcode = 0x8D
NEGATE Opcode = 0x8F
ABS Opcode = 0x90
NOT Opcode = 0x91
NZ Opcode = 0x92
ADD Opcode = 0x93
SUB Opcode = 0x94
MUL Opcode = 0x95
DIV Opcode = 0x96
MOD Opcode = 0x97
SHL Opcode = 0x98
SHR Opcode = 0x99
BOOLAND Opcode = 0x9A
BOOLOR Opcode = 0x9B
NUMEQUAL Opcode = 0x9C
NUMNOTEQUAL Opcode = 0x9E
LT Opcode = 0x9F
GT Opcode = 0xA0
LTE Opcode = 0xA1
GTE Opcode = 0xA2
MIN Opcode = 0xA3
MAX Opcode = 0xA4
WITHIN Opcode = 0xA5
// Crypto
SHA1 Opcode = 0xA7
SHA256 Opcode = 0xA8
HASH160 Opcode = 0xA9
HASH256 Opcode = 0xAA
CHECKSIG Opcode = 0xAC
VERIFY Opcode = 0xAD
CHECKMULTISIG Opcode = 0xAE
// Advanced data structures (arrays, structures, maps)
ARRAYSIZE Opcode = 0xC0
PACK Opcode = 0xC1
UNPACK Opcode = 0xC2
PICKITEM Opcode = 0xC3
SETITEM Opcode = 0xC4
NEWARRAY Opcode = 0xC5
NEWSTRUCT Opcode = 0xC6
NEWMAP Opcode = 0xC7
APPEND Opcode = 0xC8
REVERSE Opcode = 0xC9
REMOVE Opcode = 0xCA
HASKEY Opcode = 0xCB
KEYS Opcode = 0xCC
VALUES Opcode = 0xCD
// Stack isolation
CALLI Opcode = 0xE0
CALLE Opcode = 0xE1
CALLED Opcode = 0xE2
CALLET Opcode = 0xE3
CALLEDT Opcode = 0xE4
// Exceptions
THROW Opcode = 0xF0
THROWIFNOT Opcode = 0xF1
)

View file

@ -0,0 +1,393 @@
// Code generated by "stringer -type=Opcode"; DO NOT EDIT.
package opcode
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[PUSH0-0]
_ = x[PUSHF-0]
_ = x[PUSHBYTES1-1]
_ = x[PUSHBYTES2-2]
_ = x[PUSHBYTES3-3]
_ = x[PUSHBYTES4-4]
_ = x[PUSHBYTES5-5]
_ = x[PUSHBYTES6-6]
_ = x[PUSHBYTES7-7]
_ = x[PUSHBYTES8-8]
_ = x[PUSHBYTES9-9]
_ = x[PUSHBYTES10-10]
_ = x[PUSHBYTES11-11]
_ = x[PUSHBYTES12-12]
_ = x[PUSHBYTES13-13]
_ = x[PUSHBYTES14-14]
_ = x[PUSHBYTES15-15]
_ = x[PUSHBYTES16-16]
_ = x[PUSHBYTES17-17]
_ = x[PUSHBYTES18-18]
_ = x[PUSHBYTES19-19]
_ = x[PUSHBYTES20-20]
_ = x[PUSHBYTES21-21]
_ = x[PUSHBYTES22-22]
_ = x[PUSHBYTES23-23]
_ = x[PUSHBYTES24-24]
_ = x[PUSHBYTES25-25]
_ = x[PUSHBYTES26-26]
_ = x[PUSHBYTES27-27]
_ = x[PUSHBYTES28-28]
_ = x[PUSHBYTES29-29]
_ = x[PUSHBYTES30-30]
_ = x[PUSHBYTES31-31]
_ = x[PUSHBYTES32-32]
_ = x[PUSHBYTES33-33]
_ = x[PUSHBYTES34-34]
_ = x[PUSHBYTES35-35]
_ = x[PUSHBYTES36-36]
_ = x[PUSHBYTES37-37]
_ = x[PUSHBYTES38-38]
_ = x[PUSHBYTES39-39]
_ = x[PUSHBYTES40-40]
_ = x[PUSHBYTES41-41]
_ = x[PUSHBYTES42-42]
_ = x[PUSHBYTES43-43]
_ = x[PUSHBYTES44-44]
_ = x[PUSHBYTES45-45]
_ = x[PUSHBYTES46-46]
_ = x[PUSHBYTES47-47]
_ = x[PUSHBYTES48-48]
_ = x[PUSHBYTES49-49]
_ = x[PUSHBYTES50-50]
_ = x[PUSHBYTES51-51]
_ = x[PUSHBYTES52-52]
_ = x[PUSHBYTES53-53]
_ = x[PUSHBYTES54-54]
_ = x[PUSHBYTES55-55]
_ = x[PUSHBYTES56-56]
_ = x[PUSHBYTES57-57]
_ = x[PUSHBYTES58-58]
_ = x[PUSHBYTES59-59]
_ = x[PUSHBYTES60-60]
_ = x[PUSHBYTES61-61]
_ = x[PUSHBYTES62-62]
_ = x[PUSHBYTES63-63]
_ = x[PUSHBYTES64-64]
_ = x[PUSHBYTES65-65]
_ = x[PUSHBYTES66-66]
_ = x[PUSHBYTES67-67]
_ = x[PUSHBYTES68-68]
_ = x[PUSHBYTES69-69]
_ = x[PUSHBYTES70-70]
_ = x[PUSHBYTES71-71]
_ = x[PUSHBYTES72-72]
_ = x[PUSHBYTES73-73]
_ = x[PUSHBYTES74-74]
_ = x[PUSHBYTES75-75]
_ = x[PUSHDATA1-76]
_ = x[PUSHDATA2-77]
_ = x[PUSHDATA4-78]
_ = x[PUSHM1-79]
_ = x[PUSH1-81]
_ = x[PUSHT-81]
_ = x[PUSH2-82]
_ = x[PUSH3-83]
_ = x[PUSH4-84]
_ = x[PUSH5-85]
_ = x[PUSH6-86]
_ = x[PUSH7-87]
_ = x[PUSH8-88]
_ = x[PUSH9-89]
_ = x[PUSH10-90]
_ = x[PUSH11-91]
_ = x[PUSH12-92]
_ = x[PUSH13-93]
_ = x[PUSH14-94]
_ = x[PUSH15-95]
_ = x[PUSH16-96]
_ = x[NOP-97]
_ = x[JMP-98]
_ = x[JMPIF-99]
_ = x[JMPIFNOT-100]
_ = x[CALL-101]
_ = x[RET-102]
_ = x[APPCALL-103]
_ = x[SYSCALL-104]
_ = x[TAILCALL-105]
_ = x[DUPFROMALTSTACK-106]
_ = x[TOALTSTACK-107]
_ = x[FROMALTSTACK-108]
_ = x[XDROP-109]
_ = x[XSWAP-114]
_ = x[XTUCK-115]
_ = x[DEPTH-116]
_ = x[DROP-117]
_ = x[DUP-118]
_ = x[NIP-119]
_ = x[OVER-120]
_ = x[PICK-121]
_ = x[ROLL-122]
_ = x[ROT-123]
_ = x[SWAP-124]
_ = x[TUCK-125]
_ = x[CAT-126]
_ = x[SUBSTR-127]
_ = x[LEFT-128]
_ = x[RIGHT-129]
_ = x[SIZE-130]
_ = x[INVERT-131]
_ = x[AND-132]
_ = x[OR-133]
_ = x[XOR-134]
_ = x[EQUAL-135]
_ = x[INC-139]
_ = x[DEC-140]
_ = x[SIGN-141]
_ = x[NEGATE-143]
_ = x[ABS-144]
_ = x[NOT-145]
_ = x[NZ-146]
_ = x[ADD-147]
_ = x[SUB-148]
_ = x[MUL-149]
_ = x[DIV-150]
_ = x[MOD-151]
_ = x[SHL-152]
_ = x[SHR-153]
_ = x[BOOLAND-154]
_ = x[BOOLOR-155]
_ = x[NUMEQUAL-156]
_ = x[NUMNOTEQUAL-158]
_ = x[LT-159]
_ = x[GT-160]
_ = x[LTE-161]
_ = x[GTE-162]
_ = x[MIN-163]
_ = x[MAX-164]
_ = x[WITHIN-165]
_ = x[SHA1-167]
_ = x[SHA256-168]
_ = x[HASH160-169]
_ = x[HASH256-170]
_ = x[CHECKSIG-172]
_ = x[VERIFY-173]
_ = x[CHECKMULTISIG-174]
_ = x[ARRAYSIZE-192]
_ = x[PACK-193]
_ = x[UNPACK-194]
_ = x[PICKITEM-195]
_ = x[SETITEM-196]
_ = x[NEWARRAY-197]
_ = x[NEWSTRUCT-198]
_ = x[NEWMAP-199]
_ = x[APPEND-200]
_ = x[REVERSE-201]
_ = x[REMOVE-202]
_ = x[HASKEY-203]
_ = x[KEYS-204]
_ = x[VALUES-205]
_ = x[CALLI-224]
_ = x[CALLE-225]
_ = x[CALLED-226]
_ = x[CALLET-227]
_ = x[CALLEDT-228]
_ = x[THROW-240]
_ = x[THROWIFNOT-241]
}
const _Opcode_name = "PUSH0PUSHBYTES1PUSHBYTES2PUSHBYTES3PUSHBYTES4PUSHBYTES5PUSHBYTES6PUSHBYTES7PUSHBYTES8PUSHBYTES9PUSHBYTES10PUSHBYTES11PUSHBYTES12PUSHBYTES13PUSHBYTES14PUSHBYTES15PUSHBYTES16PUSHBYTES17PUSHBYTES18PUSHBYTES19PUSHBYTES20PUSHBYTES21PUSHBYTES22PUSHBYTES23PUSHBYTES24PUSHBYTES25PUSHBYTES26PUSHBYTES27PUSHBYTES28PUSHBYTES29PUSHBYTES30PUSHBYTES31PUSHBYTES32PUSHBYTES33PUSHBYTES34PUSHBYTES35PUSHBYTES36PUSHBYTES37PUSHBYTES38PUSHBYTES39PUSHBYTES40PUSHBYTES41PUSHBYTES42PUSHBYTES43PUSHBYTES44PUSHBYTES45PUSHBYTES46PUSHBYTES47PUSHBYTES48PUSHBYTES49PUSHBYTES50PUSHBYTES51PUSHBYTES52PUSHBYTES53PUSHBYTES54PUSHBYTES55PUSHBYTES56PUSHBYTES57PUSHBYTES58PUSHBYTES59PUSHBYTES60PUSHBYTES61PUSHBYTES62PUSHBYTES63PUSHBYTES64PUSHBYTES65PUSHBYTES66PUSHBYTES67PUSHBYTES68PUSHBYTES69PUSHBYTES70PUSHBYTES71PUSHBYTES72PUSHBYTES73PUSHBYTES74PUSHBYTES75PUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPIFJMPIFNOTCALLRETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTSIZEINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINSHA1SHA256HASH160HASH256CHECKSIGVERIFYCHECKMULTISIGARRAYSIZEPACKUNPACKPICKITEMSETITEMNEWARRAYNEWSTRUCTNEWMAPAPPENDREVERSEREMOVEHASKEYKEYSVALUESCALLICALLECALLEDCALLETCALLEDTTHROWTHROWIFNOT"
var _Opcode_map = map[Opcode]string{
0: _Opcode_name[0:5],
1: _Opcode_name[5:15],
2: _Opcode_name[15:25],
3: _Opcode_name[25:35],
4: _Opcode_name[35:45],
5: _Opcode_name[45:55],
6: _Opcode_name[55:65],
7: _Opcode_name[65:75],
8: _Opcode_name[75:85],
9: _Opcode_name[85:95],
10: _Opcode_name[95:106],
11: _Opcode_name[106:117],
12: _Opcode_name[117:128],
13: _Opcode_name[128:139],
14: _Opcode_name[139:150],
15: _Opcode_name[150:161],
16: _Opcode_name[161:172],
17: _Opcode_name[172:183],
18: _Opcode_name[183:194],
19: _Opcode_name[194:205],
20: _Opcode_name[205:216],
21: _Opcode_name[216:227],
22: _Opcode_name[227:238],
23: _Opcode_name[238:249],
24: _Opcode_name[249:260],
25: _Opcode_name[260:271],
26: _Opcode_name[271:282],
27: _Opcode_name[282:293],
28: _Opcode_name[293:304],
29: _Opcode_name[304:315],
30: _Opcode_name[315:326],
31: _Opcode_name[326:337],
32: _Opcode_name[337:348],
33: _Opcode_name[348:359],
34: _Opcode_name[359:370],
35: _Opcode_name[370:381],
36: _Opcode_name[381:392],
37: _Opcode_name[392:403],
38: _Opcode_name[403:414],
39: _Opcode_name[414:425],
40: _Opcode_name[425:436],
41: _Opcode_name[436:447],
42: _Opcode_name[447:458],
43: _Opcode_name[458:469],
44: _Opcode_name[469:480],
45: _Opcode_name[480:491],
46: _Opcode_name[491:502],
47: _Opcode_name[502:513],
48: _Opcode_name[513:524],
49: _Opcode_name[524:535],
50: _Opcode_name[535:546],
51: _Opcode_name[546:557],
52: _Opcode_name[557:568],
53: _Opcode_name[568:579],
54: _Opcode_name[579:590],
55: _Opcode_name[590:601],
56: _Opcode_name[601:612],
57: _Opcode_name[612:623],
58: _Opcode_name[623:634],
59: _Opcode_name[634:645],
60: _Opcode_name[645:656],
61: _Opcode_name[656:667],
62: _Opcode_name[667:678],
63: _Opcode_name[678:689],
64: _Opcode_name[689:700],
65: _Opcode_name[700:711],
66: _Opcode_name[711:722],
67: _Opcode_name[722:733],
68: _Opcode_name[733:744],
69: _Opcode_name[744:755],
70: _Opcode_name[755:766],
71: _Opcode_name[766:777],
72: _Opcode_name[777:788],
73: _Opcode_name[788:799],
74: _Opcode_name[799:810],
75: _Opcode_name[810:821],
76: _Opcode_name[821:830],
77: _Opcode_name[830:839],
78: _Opcode_name[839:848],
79: _Opcode_name[848:854],
81: _Opcode_name[854:859],
82: _Opcode_name[859:864],
83: _Opcode_name[864:869],
84: _Opcode_name[869:874],
85: _Opcode_name[874:879],
86: _Opcode_name[879:884],
87: _Opcode_name[884:889],
88: _Opcode_name[889:894],
89: _Opcode_name[894:899],
90: _Opcode_name[899:905],
91: _Opcode_name[905:911],
92: _Opcode_name[911:917],
93: _Opcode_name[917:923],
94: _Opcode_name[923:929],
95: _Opcode_name[929:935],
96: _Opcode_name[935:941],
97: _Opcode_name[941:944],
98: _Opcode_name[944:947],
99: _Opcode_name[947:952],
100: _Opcode_name[952:960],
101: _Opcode_name[960:964],
102: _Opcode_name[964:967],
103: _Opcode_name[967:974],
104: _Opcode_name[974:981],
105: _Opcode_name[981:989],
106: _Opcode_name[989:1004],
107: _Opcode_name[1004:1014],
108: _Opcode_name[1014:1026],
109: _Opcode_name[1026:1031],
114: _Opcode_name[1031:1036],
115: _Opcode_name[1036:1041],
116: _Opcode_name[1041:1046],
117: _Opcode_name[1046:1050],
118: _Opcode_name[1050:1053],
119: _Opcode_name[1053:1056],
120: _Opcode_name[1056:1060],
121: _Opcode_name[1060:1064],
122: _Opcode_name[1064:1068],
123: _Opcode_name[1068:1071],
124: _Opcode_name[1071:1075],
125: _Opcode_name[1075:1079],
126: _Opcode_name[1079:1082],
127: _Opcode_name[1082:1088],
128: _Opcode_name[1088:1092],
129: _Opcode_name[1092:1097],
130: _Opcode_name[1097:1101],
131: _Opcode_name[1101:1107],
132: _Opcode_name[1107:1110],
133: _Opcode_name[1110:1112],
134: _Opcode_name[1112:1115],
135: _Opcode_name[1115:1120],
139: _Opcode_name[1120:1123],
140: _Opcode_name[1123:1126],
141: _Opcode_name[1126:1130],
143: _Opcode_name[1130:1136],
144: _Opcode_name[1136:1139],
145: _Opcode_name[1139:1142],
146: _Opcode_name[1142:1144],
147: _Opcode_name[1144:1147],
148: _Opcode_name[1147:1150],
149: _Opcode_name[1150:1153],
150: _Opcode_name[1153:1156],
151: _Opcode_name[1156:1159],
152: _Opcode_name[1159:1162],
153: _Opcode_name[1162:1165],
154: _Opcode_name[1165:1172],
155: _Opcode_name[1172:1178],
156: _Opcode_name[1178:1186],
158: _Opcode_name[1186:1197],
159: _Opcode_name[1197:1199],
160: _Opcode_name[1199:1201],
161: _Opcode_name[1201:1204],
162: _Opcode_name[1204:1207],
163: _Opcode_name[1207:1210],
164: _Opcode_name[1210:1213],
165: _Opcode_name[1213:1219],
167: _Opcode_name[1219:1223],
168: _Opcode_name[1223:1229],
169: _Opcode_name[1229:1236],
170: _Opcode_name[1236:1243],
172: _Opcode_name[1243:1251],
173: _Opcode_name[1251:1257],
174: _Opcode_name[1257:1270],
192: _Opcode_name[1270:1279],
193: _Opcode_name[1279:1283],
194: _Opcode_name[1283:1289],
195: _Opcode_name[1289:1297],
196: _Opcode_name[1297:1304],
197: _Opcode_name[1304:1312],
198: _Opcode_name[1312:1321],
199: _Opcode_name[1321:1327],
200: _Opcode_name[1327:1333],
201: _Opcode_name[1333:1340],
202: _Opcode_name[1340:1346],
203: _Opcode_name[1346:1352],
204: _Opcode_name[1352:1356],
205: _Opcode_name[1356:1362],
224: _Opcode_name[1362:1367],
225: _Opcode_name[1367:1372],
226: _Opcode_name[1372:1378],
227: _Opcode_name[1378:1384],
228: _Opcode_name[1384:1391],
240: _Opcode_name[1391:1396],
241: _Opcode_name[1396:1406],
}
func (i Opcode) String() string {
if str, ok := _Opcode_map[i]; ok {
return str
}
return "Opcode(" + strconv.FormatInt(int64(i), 10) + ")"
}

View file

@ -0,0 +1,20 @@
package opcode
import (
"testing"
"github.com/stretchr/testify/assert"
)
// Nothing more to test here, really.
func TestStringer(t *testing.T) {
tests := map[Opcode]string{
ADD: "ADD",
SUB: "SUB",
THROWIFNOT: "THROWIFNOT",
0xff: "Opcode(255)",
}
for o, s := range tests {
assert.Equal(t, s, o.String())
}
}

View file

@ -14,12 +14,13 @@ import (
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
"github.com/pkg/errors"
)
type errorAtInstruct struct {
ip int
op Instruction
op opcode.Opcode
err interface{}
}
@ -27,7 +28,7 @@ func (e *errorAtInstruct) Error() string {
return fmt.Sprintf("error encountered at instruction %d (%s): %s", e.ip, e.op, e.err)
}
func newError(ip int, op Instruction, err interface{}) *errorAtInstruct {
func newError(ip int, op opcode.Opcode, err interface{}) *errorAtInstruct {
return &errorAtInstruct{ip: ip, op: op, err: err}
}
@ -175,12 +176,12 @@ func (v *VM) PrintOps() {
var desc = ""
if parameter != nil {
switch instr {
case JMP, JMPIF, JMPIFNOT, CALL:
case opcode.JMP, opcode.JMPIF, opcode.JMPIFNOT, opcode.CALL:
offset := int16(binary.LittleEndian.Uint16(parameter))
desc = fmt.Sprintf("%d (%d/%x)", ctx.ip+int(offset), offset, parameter)
case SYSCALL:
case opcode.SYSCALL:
desc = fmt.Sprintf("%q", parameter)
case APPCALL, TAILCALL:
case opcode.APPCALL, opcode.TAILCALL:
desc = fmt.Sprintf("%x", parameter)
default:
if utf8.Valid(parameter) {
@ -447,7 +448,7 @@ func (v *VM) SetScriptGetter(gs func(util.Uint160) []byte) {
}
// execute performs an instruction cycle in the VM. Acting on the instruction (opcode).
func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error) {
func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err error) {
// Instead of polluting the whole VM logic with error handling, we will recover
// each panic at a central point, putting the VM in a fault state and setting error.
defer func() {
@ -460,44 +461,46 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
}
}()
if op >= PUSHBYTES1 && op <= PUSHBYTES75 {
if op >= opcode.PUSHBYTES1 && op <= opcode.PUSHBYTES75 {
v.estack.PushVal(parameter)
return
}
switch op {
case PUSHM1, PUSH1, PUSH2, PUSH3, PUSH4, PUSH5,
PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11,
PUSH12, PUSH13, PUSH14, PUSH15, PUSH16:
val := int(op) - int(PUSH1) + 1
case opcode.PUSHM1, opcode.PUSH1, opcode.PUSH2, opcode.PUSH3,
opcode.PUSH4, opcode.PUSH5, opcode.PUSH6, opcode.PUSH7,
opcode.PUSH8, opcode.PUSH9, opcode.PUSH10, opcode.PUSH11,
opcode.PUSH12, opcode.PUSH13, opcode.PUSH14, opcode.PUSH15,
opcode.PUSH16:
val := int(op) - int(opcode.PUSH1) + 1
v.estack.PushVal(val)
case PUSH0:
case opcode.PUSH0:
v.estack.PushVal([]byte{})
case PUSHDATA1, PUSHDATA2, PUSHDATA4:
case opcode.PUSHDATA1, opcode.PUSHDATA2, opcode.PUSHDATA4:
v.estack.PushVal(parameter)
// Stack operations.
case TOALTSTACK:
case opcode.TOALTSTACK:
v.astack.Push(v.estack.Pop())
case FROMALTSTACK:
case opcode.FROMALTSTACK:
v.estack.Push(v.astack.Pop())
case DUPFROMALTSTACK:
case opcode.DUPFROMALTSTACK:
v.estack.Push(v.astack.Dup(0))
case DUP:
case opcode.DUP:
v.estack.Push(v.estack.Dup(0))
case SWAP:
case opcode.SWAP:
a := v.estack.Pop()
b := v.estack.Pop()
v.estack.Push(a)
v.estack.Push(b)
case TUCK:
case opcode.TUCK:
a := v.estack.Dup(0)
if a == nil {
panic("no top-level element found")
@ -507,7 +510,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
}
v.estack.InsertAt(a, 2)
case CAT:
case opcode.CAT:
b := v.estack.Pop().Bytes()
a := v.estack.Pop().Bytes()
if l := len(a) + len(b); l > MaxItemSize {
@ -516,7 +519,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
ab := append(a, b...)
v.estack.PushVal(ab)
case SUBSTR:
case opcode.SUBSTR:
l := int(v.estack.Pop().BigInt().Int64())
if l < 0 {
panic("negative length")
@ -538,7 +541,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
}
v.estack.PushVal(s[o:last])
case LEFT:
case opcode.LEFT:
l := int(v.estack.Pop().BigInt().Int64())
if l < 0 {
panic("negative length")
@ -549,7 +552,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
}
v.estack.PushVal(s[:l])
case RIGHT:
case opcode.RIGHT:
l := int(v.estack.Pop().BigInt().Int64())
if l < 0 {
panic("negative length")
@ -557,7 +560,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
s := v.estack.Pop().Bytes()
v.estack.PushVal(s[len(s)-l:])
case XDROP:
case opcode.XDROP:
n := int(v.estack.Pop().BigInt().Int64())
if n < 0 {
panic("invalid length")
@ -567,7 +570,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
panic("bad index")
}
case XSWAP:
case opcode.XSWAP:
n := int(v.estack.Pop().BigInt().Int64())
if n < 0 {
panic("XSWAP: invalid length")
@ -583,7 +586,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
b.value = aval
}
case XTUCK:
case opcode.XTUCK:
n := int(v.estack.Pop().BigInt().Int64())
if n <= 0 {
panic("XTUCK: invalid length")
@ -597,30 +600,30 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
}
v.estack.InsertAt(a, n)
case ROT:
case opcode.ROT:
e := v.estack.RemoveAt(2)
if e == nil {
panic("no top-level element found")
}
v.estack.Push(e)
case DEPTH:
case opcode.DEPTH:
v.estack.PushVal(v.estack.Len())
case NIP:
case opcode.NIP:
elem := v.estack.RemoveAt(1)
if elem == nil {
panic("no second element found")
}
case OVER:
case opcode.OVER:
a := v.estack.Peek(1)
if a == nil {
panic("no second element found")
}
v.estack.Push(a)
case PICK:
case opcode.PICK:
n := int(v.estack.Pop().BigInt().Int64())
if n < 0 {
panic("negative stack item returned")
@ -631,7 +634,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
}
v.estack.Push(a)
case ROLL:
case opcode.ROLL:
n := int(v.estack.Pop().BigInt().Int64())
if n < 0 {
panic("negative stack item returned")
@ -644,13 +647,13 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.estack.Push(e)
}
case DROP:
case opcode.DROP:
if v.estack.Len() < 1 {
panic("stack is too small")
}
v.estack.Pop()
case EQUAL:
case opcode.EQUAL:
b := v.estack.Pop()
if b == nil {
panic("no top-level element found")
@ -673,28 +676,28 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.estack.PushVal(reflect.DeepEqual(a, b))
// Bit operations.
case INVERT:
case opcode.INVERT:
// inplace
a := v.estack.Peek(0).BigInt()
a.Not(a)
case AND:
case opcode.AND:
b := v.estack.Pop().BigInt()
a := v.estack.Pop().BigInt()
v.estack.PushVal(new(big.Int).And(b, a))
case OR:
case opcode.OR:
b := v.estack.Pop().BigInt()
a := v.estack.Pop().BigInt()
v.estack.PushVal(new(big.Int).Or(b, a))
case XOR:
case opcode.XOR:
b := v.estack.Pop().BigInt()
a := v.estack.Pop().BigInt()
v.estack.PushVal(new(big.Int).Xor(b, a))
// Numeric operations.
case ADD:
case opcode.ADD:
a := v.estack.Pop().BigInt()
v.checkBigIntSize(a)
b := v.estack.Pop().BigInt()
@ -704,7 +707,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.checkBigIntSize(c)
v.estack.PushVal(c)
case SUB:
case opcode.SUB:
b := v.estack.Pop().BigInt()
v.checkBigIntSize(b)
a := v.estack.Pop().BigInt()
@ -714,7 +717,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.checkBigIntSize(c)
v.estack.PushVal(c)
case DIV:
case opcode.DIV:
b := v.estack.Pop().BigInt()
v.checkBigIntSize(b)
a := v.estack.Pop().BigInt()
@ -722,7 +725,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.estack.PushVal(new(big.Int).Div(a, b))
case MUL:
case opcode.MUL:
a := v.estack.Pop().BigInt()
v.checkBigIntSize(a)
b := v.estack.Pop().BigInt()
@ -732,7 +735,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.checkBigIntSize(c)
v.estack.PushVal(c)
case MOD:
case opcode.MOD:
b := v.estack.Pop().BigInt()
v.checkBigIntSize(b)
a := v.estack.Pop().BigInt()
@ -740,7 +743,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.estack.PushVal(new(big.Int).Mod(a, b))
case SHL, SHR:
case opcode.SHL, opcode.SHR:
b := v.estack.Pop().BigInt().Int64()
if b == 0 {
return
@ -751,7 +754,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.checkBigIntSize(a)
var item big.Int
if op == SHL {
if op == opcode.SHL {
item.Lsh(a, uint(b))
} else {
item.Rsh(a, uint(b))
@ -760,47 +763,47 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.checkBigIntSize(&item)
v.estack.PushVal(&item)
case BOOLAND:
case opcode.BOOLAND:
b := v.estack.Pop().Bool()
a := v.estack.Pop().Bool()
v.estack.PushVal(a && b)
case BOOLOR:
case opcode.BOOLOR:
b := v.estack.Pop().Bool()
a := v.estack.Pop().Bool()
v.estack.PushVal(a || b)
case NUMEQUAL:
case opcode.NUMEQUAL:
b := v.estack.Pop().BigInt()
a := v.estack.Pop().BigInt()
v.estack.PushVal(a.Cmp(b) == 0)
case NUMNOTEQUAL:
case opcode.NUMNOTEQUAL:
b := v.estack.Pop().BigInt()
a := v.estack.Pop().BigInt()
v.estack.PushVal(a.Cmp(b) != 0)
case LT:
case opcode.LT:
b := v.estack.Pop().BigInt()
a := v.estack.Pop().BigInt()
v.estack.PushVal(a.Cmp(b) == -1)
case GT:
case opcode.GT:
b := v.estack.Pop().BigInt()
a := v.estack.Pop().BigInt()
v.estack.PushVal(a.Cmp(b) == 1)
case LTE:
case opcode.LTE:
b := v.estack.Pop().BigInt()
a := v.estack.Pop().BigInt()
v.estack.PushVal(a.Cmp(b) <= 0)
case GTE:
case opcode.GTE:
b := v.estack.Pop().BigInt()
a := v.estack.Pop().BigInt()
v.estack.PushVal(a.Cmp(b) >= 0)
case MIN:
case opcode.MIN:
b := v.estack.Pop().BigInt()
a := v.estack.Pop().BigInt()
val := a
@ -809,7 +812,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
}
v.estack.PushVal(val)
case MAX:
case opcode.MAX:
b := v.estack.Pop().BigInt()
a := v.estack.Pop().BigInt()
val := a
@ -818,46 +821,46 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
}
v.estack.PushVal(val)
case WITHIN:
case opcode.WITHIN:
b := v.estack.Pop().BigInt()
a := v.estack.Pop().BigInt()
x := v.estack.Pop().BigInt()
v.estack.PushVal(a.Cmp(x) <= 0 && x.Cmp(b) == -1)
case INC:
case opcode.INC:
x := v.estack.Pop().BigInt()
a := new(big.Int).Add(x, big.NewInt(1))
v.checkBigIntSize(a)
v.estack.PushVal(a)
case DEC:
case opcode.DEC:
x := v.estack.Pop().BigInt()
a := new(big.Int).Sub(x, big.NewInt(1))
v.checkBigIntSize(a)
v.estack.PushVal(a)
case SIGN:
case opcode.SIGN:
x := v.estack.Pop().BigInt()
v.estack.PushVal(x.Sign())
case NEGATE:
case opcode.NEGATE:
x := v.estack.Pop().BigInt()
v.estack.PushVal(x.Neg(x))
case ABS:
case opcode.ABS:
x := v.estack.Pop().BigInt()
v.estack.PushVal(x.Abs(x))
case NOT:
case opcode.NOT:
x := v.estack.Pop().Bool()
v.estack.PushVal(!x)
case NZ:
case opcode.NZ:
x := v.estack.Pop().BigInt()
v.estack.PushVal(x.Cmp(big.NewInt(0)) != 0)
// Object operations.
case NEWARRAY:
case opcode.NEWARRAY:
item := v.estack.Pop()
switch t := item.value.(type) {
case *StructItem:
@ -875,7 +878,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.estack.PushVal(&ArrayItem{items})
}
case NEWSTRUCT:
case opcode.NEWSTRUCT:
item := v.estack.Pop()
switch t := item.value.(type) {
case *ArrayItem:
@ -893,7 +896,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.estack.PushVal(&StructItem{items})
}
case APPEND:
case opcode.APPEND:
itemElem := v.estack.Pop()
arrElem := v.estack.Pop()
@ -920,7 +923,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.estack.updateSizeAdd(val)
case PACK:
case opcode.PACK:
n := int(v.estack.Pop().BigInt().Int64())
if n < 0 || n > v.estack.Len() || n > MaxArraySize {
panic("OPACK: invalid length")
@ -933,7 +936,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.estack.PushVal(items)
case UNPACK:
case opcode.UNPACK:
a := v.estack.Pop().Array()
l := len(a)
for i := l - 1; i >= 0; i-- {
@ -941,7 +944,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
}
v.estack.PushVal(l)
case PICKITEM:
case opcode.PICKITEM:
key := v.estack.Pop()
validateMapKey(key)
@ -972,7 +975,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.estack.PushVal(int(item))
}
case SETITEM:
case opcode.SETITEM:
item := v.estack.Pop().value
key := v.estack.Pop()
validateMapKey(key)
@ -1003,14 +1006,14 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
panic(fmt.Sprintf("SETITEM: invalid item type %s", t))
}
case REVERSE:
case opcode.REVERSE:
a := v.estack.Pop().Array()
if len(a) > 1 {
for i, j := 0, len(a)-1; i <= j; i, j = i+1, j-1 {
a[i], a[j] = a[j], a[i]
}
}
case REMOVE:
case opcode.REMOVE:
key := v.estack.Pop()
validateMapKey(key)
@ -1043,7 +1046,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
panic("REMOVE: invalid type")
}
case ARRAYSIZE:
case opcode.ARRAYSIZE:
elem := v.estack.Pop()
// Cause there is no native (byte) item type here, hence we need to check
// the type of the item for array size operations.
@ -1056,12 +1059,12 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.estack.PushVal(len(elem.Bytes()))
}
case SIZE:
case opcode.SIZE:
elem := v.estack.Pop()
arr := elem.Bytes()
v.estack.PushVal(len(arr))
case JMP, JMPIF, JMPIFNOT:
case opcode.JMP, opcode.JMPIF, opcode.JMPIFNOT:
var (
rOffset = int16(binary.LittleEndian.Uint16(parameter))
offset = ctx.ip + int(rOffset)
@ -1070,9 +1073,9 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
panic(fmt.Sprintf("JMP: invalid offset %d ip at %d", offset, ctx.ip))
}
cond := true
if op > JMP {
if op > opcode.JMP {
cond = v.estack.Pop().Bool()
if op == JMPIFNOT {
if op == opcode.JMPIFNOT {
cond = !cond
}
}
@ -1080,18 +1083,18 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
ctx.nextip = offset
}
case CALL:
case opcode.CALL:
v.checkInvocationStackSize()
newCtx := ctx.Copy()
newCtx.rvcount = -1
v.istack.PushVal(newCtx)
err = v.execute(v.Context(), JMP, parameter)
err = v.execute(v.Context(), opcode.JMP, parameter)
if err != nil {
return
}
case SYSCALL:
case opcode.SYSCALL:
ifunc, ok := v.interop[string(parameter)]
if !ok {
panic(fmt.Sprintf("interop hook (%q) not registered", parameter))
@ -1100,12 +1103,12 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
panic(fmt.Sprintf("failed to invoke syscall: %s", err))
}
case APPCALL, TAILCALL:
case opcode.APPCALL, opcode.TAILCALL:
if v.getScript == nil {
panic("no getScript callback is set up")
}
if op == APPCALL {
if op == opcode.APPCALL {
v.checkInvocationStackSize()
}
@ -1119,13 +1122,13 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
panic("could not find script")
}
if op == TAILCALL {
if op == opcode.TAILCALL {
_ = v.istack.Pop()
}
v.LoadScript(script)
case RET:
case opcode.RET:
oldCtx := v.istack.Pop().Value().(*Context)
rvcount := oldCtx.rvcount
oldEstack := v.estack
@ -1151,12 +1154,12 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.astack = v.Context().astack
}
case CHECKSIG, VERIFY:
case opcode.CHECKSIG, opcode.VERIFY:
var hashToCheck []byte
keyb := v.estack.Pop().Bytes()
signature := v.estack.Pop().Bytes()
if op == CHECKSIG {
if op == opcode.CHECKSIG {
if v.checkhash == nil {
panic("VM is not set up properly for signature checks")
}
@ -1173,7 +1176,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
res := pkey.Verify(signature, hashToCheck)
v.estack.PushVal(res)
case CHECKMULTISIG:
case opcode.CHECKMULTISIG:
pkeys, err := v.estack.popSigElements()
if err != nil {
panic(fmt.Sprintf("wrong parameters: %s", err.Error()))
@ -1214,10 +1217,10 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
}
v.estack.PushVal(sigok)
case NEWMAP:
case opcode.NEWMAP:
v.estack.Push(&Element{value: NewMapItem()})
case KEYS:
case opcode.KEYS:
item := v.estack.Pop()
if item == nil {
panic("no argument")
@ -1234,7 +1237,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
}
v.estack.PushVal(arr)
case VALUES:
case opcode.VALUES:
item := v.estack.Pop()
if item == nil {
panic("no argument")
@ -1259,7 +1262,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.estack.PushVal(arr)
case HASKEY:
case opcode.HASKEY:
key := v.estack.Pop()
validateMapKey(key)
@ -1281,31 +1284,31 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
}
// Cryptographic operations.
case SHA1:
case opcode.SHA1:
b := v.estack.Pop().Bytes()
sha := sha1.New()
sha.Write(b)
v.estack.PushVal(sha.Sum(nil))
case SHA256:
case opcode.SHA256:
b := v.estack.Pop().Bytes()
v.estack.PushVal(hash.Sha256(b).Bytes())
case HASH160:
case opcode.HASH160:
b := v.estack.Pop().Bytes()
v.estack.PushVal(hash.Hash160(b).Bytes())
case HASH256:
case opcode.HASH256:
b := v.estack.Pop().Bytes()
v.estack.PushVal(hash.DoubleSha256(b).Bytes())
case NOP:
case opcode.NOP:
// unlucky ^^
case CALLI, CALLE, CALLED, CALLET, CALLEDT:
case opcode.CALLI, opcode.CALLE, opcode.CALLED, opcode.CALLET, opcode.CALLEDT:
var (
tailCall = (op == CALLET || op == CALLEDT)
hashOnStack = (op == CALLED || op == CALLEDT)
tailCall = (op == opcode.CALLET || op == opcode.CALLEDT)
hashOnStack = (op == opcode.CALLED || op == opcode.CALLEDT)
addElement int
newCtx *Context
)
@ -1327,7 +1330,7 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.checkInvocationStackSize()
}
if op == CALLI {
if op == opcode.CALLI {
newCtx = ctx.Copy()
} else {
var hashBytes []byte
@ -1362,17 +1365,17 @@ func (v *VM) execute(ctx *Context, op Instruction, parameter []byte) (err error)
v.istack.PushVal(newCtx)
v.estack = newCtx.estack
v.astack = newCtx.astack
if op == CALLI {
err = v.execute(v.Context(), JMP, parameter[2:])
if op == opcode.CALLI {
err = v.execute(v.Context(), opcode.JMP, parameter[2:])
if err != nil {
return
}
}
case THROW:
case opcode.THROW:
panic("THROW")
case THROWIFNOT:
case opcode.THROWIFNOT:
if !v.estack.Pop().Bool() {
panic("THROWIFNOT")
}

File diff suppressed because it is too large Load diff