forked from TrueCloudLab/neoneo-go
vm: switch from Opcode to Instruction
Which matches the changes done in neo-storm and also make this codebase closer to the `dev` branch (that also uses Instruction).
This commit is contained in:
parent
5f3256d0e0
commit
33c512032f
15 changed files with 482 additions and 483 deletions
|
@ -35,7 +35,7 @@ func createGenesisBlock(cfg config.ProtocolConfiguration) (*Block, error) {
|
|||
NextConsensus: nextConsensus,
|
||||
Script: &transaction.Witness{
|
||||
InvocationScript: []byte{},
|
||||
VerificationScript: []byte{byte(vm.Opusht)},
|
||||
VerificationScript: []byte{byte(vm.PUSHT)},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,7 @@ func createGenesisBlock(cfg config.ProtocolConfiguration) (*Block, error) {
|
|||
Scripts: []*transaction.Witness{
|
||||
{
|
||||
InvocationScript: []byte{},
|
||||
VerificationScript: []byte{byte(vm.Opusht)},
|
||||
VerificationScript: []byte{byte(vm.PUSHT)},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -97,7 +97,7 @@ func createGenesisBlock(cfg config.ProtocolConfiguration) (*Block, error) {
|
|||
}
|
||||
|
||||
func governingTokenTX() *transaction.Transaction {
|
||||
admin, _ := util.Uint160FromScript([]byte{byte(vm.Opusht)})
|
||||
admin, _ := util.Uint160FromScript([]byte{byte(vm.PUSHT)})
|
||||
registerTX := &transaction.RegisterTX{
|
||||
AssetType: transaction.GoverningToken,
|
||||
Name: "[{\"lang\":\"zh-CN\",\"name\":\"小蚁股\"},{\"lang\":\"en\",\"name\":\"AntShare\"}]",
|
||||
|
@ -120,7 +120,7 @@ func governingTokenTX() *transaction.Transaction {
|
|||
}
|
||||
|
||||
func utilityTokenTX() *transaction.Transaction {
|
||||
admin, _ := util.Uint160FromScript([]byte{byte(vm.Opushf)})
|
||||
admin, _ := util.Uint160FromScript([]byte{byte(vm.PUSHF)})
|
||||
registerTX := &transaction.RegisterTX{
|
||||
AssetType: transaction.UtilityToken,
|
||||
Name: "[{\"lang\":\"zh-CN\",\"name\":\"小蚁币\"},{\"lang\":\"en\",\"name\":\"AntCoin\"}]",
|
||||
|
|
|
@ -34,7 +34,7 @@ func CreateMultiSigRedeemScript(m int, publicKeys crypto.PublicKeys) ([]byte, er
|
|||
if err := vm.EmitInt(buf, int64(len(publicKeys))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := vm.EmitOpcode(buf, vm.Ocheckmultisig); err != nil {
|
||||
if err := vm.EmitOpcode(buf, vm.CHECKMULTISIG); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ func TestCreateMultiSigRedeemScript(t *testing.T) {
|
|||
|
||||
buf := bytes.NewBuffer(out)
|
||||
b, _ := buf.ReadByte()
|
||||
assert.Equal(t, vm.Opush3, vm.Opcode(b))
|
||||
assert.Equal(t, vm.PUSH3, vm.Instruction(b))
|
||||
|
||||
for i := 0; i < len(validators); i++ {
|
||||
b, err := util.ReadVarBytes(buf)
|
||||
|
@ -35,7 +35,7 @@ func TestCreateMultiSigRedeemScript(t *testing.T) {
|
|||
}
|
||||
|
||||
b, _ = buf.ReadByte()
|
||||
assert.Equal(t, vm.Opush3, vm.Opcode(b))
|
||||
assert.Equal(t, vm.PUSH3, vm.Instruction(b))
|
||||
b, _ = buf.ReadByte()
|
||||
assert.Equal(t, vm.Ocheckmultisig, vm.Opcode(b))
|
||||
assert.Equal(t, vm.CHECKMULTISIG, vm.Instruction(b))
|
||||
}
|
||||
|
|
|
@ -87,18 +87,18 @@ func (c *codegen) emitLoadLocal(name string) {
|
|||
}
|
||||
|
||||
func (c *codegen) emitLoadLocalPos(pos int) {
|
||||
emitOpcode(c.prog, vm.Ofromaltstack)
|
||||
emitOpcode(c.prog, vm.Odup)
|
||||
emitOpcode(c.prog, vm.Otoaltstack)
|
||||
emitOpcode(c.prog, vm.FROMALTSTACK)
|
||||
emitOpcode(c.prog, vm.DUP)
|
||||
emitOpcode(c.prog, vm.TOALTSTACK)
|
||||
|
||||
emitInt(c.prog, int64(pos))
|
||||
emitOpcode(c.prog, vm.Opickitem)
|
||||
emitOpcode(c.prog, vm.PICKITEM)
|
||||
}
|
||||
|
||||
func (c *codegen) emitStoreLocal(pos int) {
|
||||
emitOpcode(c.prog, vm.Ofromaltstack)
|
||||
emitOpcode(c.prog, vm.Odup)
|
||||
emitOpcode(c.prog, vm.Otoaltstack)
|
||||
emitOpcode(c.prog, vm.FROMALTSTACK)
|
||||
emitOpcode(c.prog, vm.DUP)
|
||||
emitOpcode(c.prog, vm.TOALTSTACK)
|
||||
|
||||
if pos < 0 {
|
||||
log.Fatalf("invalid position to store local: %d", pos)
|
||||
|
@ -106,19 +106,19 @@ func (c *codegen) emitStoreLocal(pos int) {
|
|||
|
||||
emitInt(c.prog, int64(pos))
|
||||
emitInt(c.prog, 2)
|
||||
emitOpcode(c.prog, vm.Oroll)
|
||||
emitOpcode(c.prog, vm.Osetitem)
|
||||
emitOpcode(c.prog, vm.ROLL)
|
||||
emitOpcode(c.prog, vm.SETITEM)
|
||||
}
|
||||
|
||||
func (c *codegen) emitLoadField(i int) {
|
||||
emitInt(c.prog, int64(i))
|
||||
emitOpcode(c.prog, vm.Opickitem)
|
||||
emitOpcode(c.prog, vm.PICKITEM)
|
||||
}
|
||||
|
||||
func (c *codegen) emitStoreStructField(i int) {
|
||||
emitInt(c.prog, int64(i))
|
||||
emitOpcode(c.prog, vm.Orot)
|
||||
emitOpcode(c.prog, vm.Osetitem)
|
||||
emitOpcode(c.prog, vm.ROT)
|
||||
emitOpcode(c.prog, vm.SETITEM)
|
||||
}
|
||||
|
||||
// convertGlobals will traverse the AST and only convert global declarations.
|
||||
|
@ -155,8 +155,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, f.stackSize()+countGlobals(file))
|
||||
emitOpcode(c.prog, vm.Onewarray)
|
||||
emitOpcode(c.prog, vm.Otoaltstack)
|
||||
emitOpcode(c.prog, vm.NEWARRAY)
|
||||
emitOpcode(c.prog, vm.TOALTSTACK)
|
||||
|
||||
// We need to handle methods, which in Go, is just syntactic sugar.
|
||||
// The method receiver will be passed in as first argument.
|
||||
|
@ -193,9 +193,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, vm.Ofromaltstack)
|
||||
emitOpcode(c.prog, vm.Odrop)
|
||||
emitOpcode(c.prog, vm.Oret)
|
||||
emitOpcode(c.prog, vm.FROMALTSTACK)
|
||||
emitOpcode(c.prog, vm.DROP)
|
||||
emitOpcode(c.prog, vm.RET)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,17 +262,17 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
// To be backwards compatible we will put them them in.
|
||||
// See issue #65 (https://github.com/CityOfZion/neo-go/issues/65)
|
||||
l := c.newLabel()
|
||||
emitJmp(c.prog, vm.Ojmp, int16(l))
|
||||
emitJmp(c.prog, vm.JMP, int16(l))
|
||||
c.setLabel(l)
|
||||
|
||||
if len(n.Results) > 0 {
|
||||
ast.Walk(c, n.Results[0])
|
||||
}
|
||||
|
||||
emitOpcode(c.prog, vm.Onop) // @OPTIMIZE
|
||||
emitOpcode(c.prog, vm.Ofromaltstack)
|
||||
emitOpcode(c.prog, vm.Odrop) // Cleanup the stack.
|
||||
emitOpcode(c.prog, vm.Oret)
|
||||
emitOpcode(c.prog, vm.NOP) // @OPTIMIZE
|
||||
emitOpcode(c.prog, vm.FROMALTSTACK)
|
||||
emitOpcode(c.prog, vm.DROP) // Cleanup the stack.
|
||||
emitOpcode(c.prog, vm.RET)
|
||||
return nil
|
||||
|
||||
case *ast.IfStmt:
|
||||
|
@ -280,7 +280,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
lElse := c.newLabel()
|
||||
if n.Cond != nil {
|
||||
ast.Walk(c, n.Cond)
|
||||
emitJmp(c.prog, vm.Ojmpifnot, int16(lElse))
|
||||
emitJmp(c.prog, vm.JMPIFNOT, int16(lElse))
|
||||
}
|
||||
|
||||
c.setLabel(lIf)
|
||||
|
@ -288,7 +288,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
|
||||
if n.Else != nil {
|
||||
// TODO: handle else statements.
|
||||
// emitJmp(c.prog, vm.Ojmp, int16(lEnd))
|
||||
// emitJmp(c.prog, vm.JMP, int16(lEnd))
|
||||
}
|
||||
c.setLabel(lElse)
|
||||
if n.Else != nil {
|
||||
|
@ -327,7 +327,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
c.emitLoadConst(c.typeInfo.Types[n.Elts[i]])
|
||||
}
|
||||
emitInt(c.prog, int64(ln))
|
||||
emitOpcode(c.prog, vm.Opack)
|
||||
emitOpcode(c.prog, vm.PACK)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -342,13 +342,13 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
switch n.Op {
|
||||
case token.LAND:
|
||||
ast.Walk(c, n.X)
|
||||
emitJmp(c.prog, vm.Ojmpifnot, int16(len(c.l)-1))
|
||||
emitJmp(c.prog, vm.JMPIFNOT, int16(len(c.l)-1))
|
||||
ast.Walk(c, n.Y)
|
||||
return nil
|
||||
|
||||
case token.LOR:
|
||||
ast.Walk(c, n.X)
|
||||
emitJmp(c.prog, vm.Ojmpif, int16(len(c.l)-2))
|
||||
emitJmp(c.prog, vm.JMPIF, int16(len(c.l)-2))
|
||||
ast.Walk(c, n.Y)
|
||||
return nil
|
||||
|
||||
|
@ -414,18 +414,18 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
// Do not swap for builtin functions.
|
||||
if !isBuiltin {
|
||||
if numArgs == 2 {
|
||||
emitOpcode(c.prog, vm.Oswap)
|
||||
emitOpcode(c.prog, vm.SWAP)
|
||||
}
|
||||
if numArgs == 3 {
|
||||
emitInt(c.prog, 2)
|
||||
emitOpcode(c.prog, vm.Oxswap)
|
||||
emitOpcode(c.prog, vm.XSWAP)
|
||||
}
|
||||
}
|
||||
|
||||
// c# compiler adds a NOP (0x61) before every function call. Dont think its relevant
|
||||
// and we could easily removed it, but to be consistent with the original compiler I
|
||||
// will put them in. ^^
|
||||
emitOpcode(c.prog, vm.Onop)
|
||||
emitOpcode(c.prog, vm.NOP)
|
||||
|
||||
// Check builtin first to avoid nil pointer on funcScope!
|
||||
switch {
|
||||
|
@ -436,13 +436,13 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
case isSyscall(f.name):
|
||||
c.convertSyscall(f.name)
|
||||
default:
|
||||
emitCall(c.prog, vm.Ocall, int16(f.label))
|
||||
emitCall(c.prog, vm.CALL, int16(f.label))
|
||||
}
|
||||
|
||||
// If we are not assigning this function to a variable we need to drop
|
||||
// (cleanup) the top stack item. It's not a void but you get the point \o/.
|
||||
if _, ok := c.scope.voidCalls[n]; ok {
|
||||
emitOpcode(c.prog, vm.Odrop)
|
||||
emitOpcode(c.prog, vm.DROP)
|
||||
}
|
||||
return nil
|
||||
|
||||
|
@ -490,7 +490,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
c.emitLoadField(int(val))
|
||||
default:
|
||||
ast.Walk(c, n.Index)
|
||||
emitOpcode(c.prog, vm.Opickitem) // just pickitem here
|
||||
emitOpcode(c.prog, vm.PICKITEM) // just pickitem here
|
||||
}
|
||||
return nil
|
||||
|
||||
|
@ -508,14 +508,14 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
|||
ast.Walk(c, n.Cond)
|
||||
|
||||
// Jump if the condition is false
|
||||
emitJmp(c.prog, vm.Ojmpifnot, int16(fend))
|
||||
emitJmp(c.prog, vm.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, vm.Ojmp, int16(fstart))
|
||||
emitJmp(c.prog, vm.JMP, int16(fstart))
|
||||
c.setLabel(fend)
|
||||
|
||||
return nil
|
||||
|
@ -537,7 +537,7 @@ func (c *codegen) convertSyscall(name string) {
|
|||
log.Fatalf("unknown VM syscall api: %s", name)
|
||||
}
|
||||
emitSyscall(c.prog, api)
|
||||
emitOpcode(c.prog, vm.Onop) // @OPTIMIZE
|
||||
emitOpcode(c.prog, vm.NOP) // @OPTIMIZE
|
||||
}
|
||||
|
||||
func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
||||
|
@ -554,20 +554,20 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
|||
arg := expr.Args[0]
|
||||
typ := c.typeInfo.Types[arg].Type
|
||||
if isStringType(typ) {
|
||||
emitOpcode(c.prog, vm.Osize)
|
||||
emitOpcode(c.prog, vm.SIZE)
|
||||
} else {
|
||||
emitOpcode(c.prog, vm.Oarraysize)
|
||||
emitOpcode(c.prog, vm.ARRAYSIZE)
|
||||
}
|
||||
case "append":
|
||||
emitOpcode(c.prog, vm.Oappend)
|
||||
emitOpcode(c.prog, vm.APPEND)
|
||||
case "SHA256":
|
||||
emitOpcode(c.prog, vm.Osha256)
|
||||
emitOpcode(c.prog, vm.SHA256)
|
||||
case "SHA1":
|
||||
emitOpcode(c.prog, vm.Osha1)
|
||||
emitOpcode(c.prog, vm.SHA1)
|
||||
case "Hash256":
|
||||
emitOpcode(c.prog, vm.Ohash256)
|
||||
emitOpcode(c.prog, vm.HASH256)
|
||||
case "Hash160":
|
||||
emitOpcode(c.prog, vm.Ohash160)
|
||||
emitOpcode(c.prog, vm.HASH160)
|
||||
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
|
||||
|
@ -601,10 +601,10 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
|||
log.Fatalf("the given literal is not of type struct: %v", lit)
|
||||
}
|
||||
|
||||
emitOpcode(c.prog, vm.Onop)
|
||||
emitOpcode(c.prog, vm.NOP)
|
||||
emitInt(c.prog, int64(strct.NumFields()))
|
||||
emitOpcode(c.prog, vm.Onewstruct)
|
||||
emitOpcode(c.prog, vm.Otoaltstack)
|
||||
emitOpcode(c.prog, vm.NEWSTRUCT)
|
||||
emitOpcode(c.prog, vm.TOALTSTACK)
|
||||
|
||||
// We need to locally store all the fields, even if they are not initialized.
|
||||
// We will initialize all fields to their "zero" value.
|
||||
|
@ -633,45 +633,45 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit) {
|
|||
c.emitLoadConst(typeAndVal)
|
||||
c.emitStoreLocal(i)
|
||||
}
|
||||
emitOpcode(c.prog, vm.Ofromaltstack)
|
||||
emitOpcode(c.prog, vm.FROMALTSTACK)
|
||||
}
|
||||
|
||||
func (c *codegen) convertToken(tok token.Token) {
|
||||
switch tok {
|
||||
case token.ADD_ASSIGN:
|
||||
emitOpcode(c.prog, vm.Oadd)
|
||||
emitOpcode(c.prog, vm.ADD)
|
||||
case token.SUB_ASSIGN:
|
||||
emitOpcode(c.prog, vm.Osub)
|
||||
emitOpcode(c.prog, vm.SUB)
|
||||
case token.MUL_ASSIGN:
|
||||
emitOpcode(c.prog, vm.Omul)
|
||||
emitOpcode(c.prog, vm.MUL)
|
||||
case token.QUO_ASSIGN:
|
||||
emitOpcode(c.prog, vm.Odiv)
|
||||
emitOpcode(c.prog, vm.DIV)
|
||||
case token.ADD:
|
||||
emitOpcode(c.prog, vm.Oadd)
|
||||
emitOpcode(c.prog, vm.ADD)
|
||||
case token.SUB:
|
||||
emitOpcode(c.prog, vm.Osub)
|
||||
emitOpcode(c.prog, vm.SUB)
|
||||
case token.MUL:
|
||||
emitOpcode(c.prog, vm.Omul)
|
||||
emitOpcode(c.prog, vm.MUL)
|
||||
case token.QUO:
|
||||
emitOpcode(c.prog, vm.Odiv)
|
||||
emitOpcode(c.prog, vm.DIV)
|
||||
case token.LSS:
|
||||
emitOpcode(c.prog, vm.Olt)
|
||||
emitOpcode(c.prog, vm.LT)
|
||||
case token.LEQ:
|
||||
emitOpcode(c.prog, vm.Olte)
|
||||
emitOpcode(c.prog, vm.LTE)
|
||||
case token.GTR:
|
||||
emitOpcode(c.prog, vm.Ogt)
|
||||
emitOpcode(c.prog, vm.GT)
|
||||
case token.GEQ:
|
||||
emitOpcode(c.prog, vm.Ogte)
|
||||
emitOpcode(c.prog, vm.GTE)
|
||||
case token.EQL:
|
||||
emitOpcode(c.prog, vm.Onumequal)
|
||||
emitOpcode(c.prog, vm.NUMEQUAL)
|
||||
case token.NEQ:
|
||||
emitOpcode(c.prog, vm.Onumnotequal)
|
||||
emitOpcode(c.prog, vm.NUMNOTEQUAL)
|
||||
case token.DEC:
|
||||
emitOpcode(c.prog, vm.Odec)
|
||||
emitOpcode(c.prog, vm.DEC)
|
||||
case token.INC:
|
||||
emitOpcode(c.prog, vm.Oinc)
|
||||
emitOpcode(c.prog, vm.INC)
|
||||
case token.NOT:
|
||||
emitOpcode(c.prog, vm.Onot)
|
||||
emitOpcode(c.prog, vm.NOT)
|
||||
default:
|
||||
log.Fatalf("compiler could not convert token: %s", tok)
|
||||
}
|
||||
|
@ -750,8 +750,8 @@ func (c *codegen) writeJumps() {
|
|||
b := c.prog.Bytes()
|
||||
for i, op := range b {
|
||||
j := i + 1
|
||||
switch vm.Opcode(op) {
|
||||
case vm.Ojmp, vm.Ojmpifnot, vm.Ojmpif, vm.Ocall:
|
||||
switch vm.Instruction(op) {
|
||||
case vm.JMP, vm.JMPIFNOT, vm.JMPIF, vm.CALL:
|
||||
index := int16(binary.LittleEndian.Uint16(b[j : j+2]))
|
||||
if int(index) > len(c.l) || int(index) < 0 {
|
||||
continue
|
||||
|
|
|
@ -112,7 +112,7 @@ func DumpOpcode(src string) error {
|
|||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 4, ' ', 0)
|
||||
fmt.Fprintln(w, "INDEX\tOPCODE\tDESC\t")
|
||||
for i := 0; i < len(b); i++ {
|
||||
fmt.Fprintf(w, "%d\t0x%2x\t%s\t\n", i, b[i], vm.Opcode(b[i]))
|
||||
fmt.Fprintf(w, "%d\t0x%2x\t%s\t\n", i, b[i], vm.Instruction(b[i]))
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"github.com/CityOfZion/neo-go/pkg/vm"
|
||||
)
|
||||
|
||||
func emit(w *bytes.Buffer, op vm.Opcode, b []byte) error {
|
||||
func emit(w *bytes.Buffer, op vm.Instruction, b []byte) error {
|
||||
if err := w.WriteByte(byte(op)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -20,26 +20,26 @@ func emit(w *bytes.Buffer, op vm.Opcode, b []byte) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func emitOpcode(w io.ByteWriter, op vm.Opcode) error {
|
||||
func emitOpcode(w io.ByteWriter, op vm.Instruction) error {
|
||||
return w.WriteByte(byte(op))
|
||||
}
|
||||
|
||||
func emitBool(w io.ByteWriter, ok bool) error {
|
||||
if ok {
|
||||
return emitOpcode(w, vm.Opusht)
|
||||
return emitOpcode(w, vm.PUSHT)
|
||||
}
|
||||
return emitOpcode(w, vm.Opushf)
|
||||
return emitOpcode(w, vm.PUSHF)
|
||||
}
|
||||
|
||||
func emitInt(w *bytes.Buffer, i int64) error {
|
||||
if i == -1 {
|
||||
return emitOpcode(w, vm.Opushm1)
|
||||
return emitOpcode(w, vm.PUSHM1)
|
||||
}
|
||||
if i == 0 {
|
||||
return emitOpcode(w, vm.Opushf)
|
||||
return emitOpcode(w, vm.PUSHF)
|
||||
}
|
||||
if i > 0 && i < 16 {
|
||||
val := vm.Opcode(int(vm.Opush1) - 1 + int(i))
|
||||
val := vm.Instruction(int(vm.PUSH1) - 1 + int(i))
|
||||
return emitOpcode(w, val)
|
||||
}
|
||||
|
||||
|
@ -59,18 +59,18 @@ func emitBytes(w *bytes.Buffer, b []byte) error {
|
|||
)
|
||||
|
||||
switch {
|
||||
case n <= int(vm.Opushbytes75):
|
||||
return emit(w, vm.Opcode(n), b)
|
||||
case n <= int(vm.PUSHBYTES75):
|
||||
return emit(w, vm.Instruction(n), b)
|
||||
case n < 0x100:
|
||||
err = emit(w, vm.Opushdata1, []byte{byte(n)})
|
||||
err = emit(w, vm.PUSHDATA1, []byte{byte(n)})
|
||||
case n < 0x10000:
|
||||
buf := make([]byte, 2)
|
||||
binary.LittleEndian.PutUint16(buf, uint16(n))
|
||||
err = emit(w, vm.Opushdata2, buf)
|
||||
err = emit(w, vm.PUSHDATA2, buf)
|
||||
default:
|
||||
buf := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(buf, uint32(n))
|
||||
err = emit(w, vm.Opushdata4, buf)
|
||||
err = emit(w, vm.PUSHDATA4, buf)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -86,15 +86,15 @@ func emitSyscall(w *bytes.Buffer, api string) error {
|
|||
buf := make([]byte, len(api)+1)
|
||||
buf[0] = byte(len(api))
|
||||
copy(buf[1:], []byte(api))
|
||||
return emit(w, vm.Osyscall, buf)
|
||||
return emit(w, vm.SYSCALL, buf)
|
||||
}
|
||||
|
||||
func emitCall(w *bytes.Buffer, op vm.Opcode, label int16) error {
|
||||
func emitCall(w *bytes.Buffer, op vm.Instruction, label int16) error {
|
||||
return emitJmp(w, op, label)
|
||||
}
|
||||
|
||||
func emitJmp(w *bytes.Buffer, op vm.Opcode, label int16) error {
|
||||
if !isOpcodeJmp(op) {
|
||||
func emitJmp(w *bytes.Buffer, op vm.Instruction, label int16) error {
|
||||
if !isInstructionJmp(op) {
|
||||
return fmt.Errorf("opcode %s is not a jump or call type", op)
|
||||
}
|
||||
buf := make([]byte, 2)
|
||||
|
@ -102,8 +102,8 @@ func emitJmp(w *bytes.Buffer, op vm.Opcode, label int16) error {
|
|||
return emit(w, op, buf)
|
||||
}
|
||||
|
||||
func isOpcodeJmp(op vm.Opcode) bool {
|
||||
if op == vm.Ojmp || op == vm.Ojmpifnot || op == vm.Ojmpif || op == vm.Ocall {
|
||||
func isInstructionJmp(op vm.Instruction) bool {
|
||||
if op == vm.JMP || op == vm.JMPIFNOT || op == vm.JMPIF || op == vm.CALL {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
|
@ -26,12 +26,12 @@ func NewContext(b []byte) *Context {
|
|||
}
|
||||
|
||||
// Next return the next instruction to execute.
|
||||
func (c *Context) Next() Opcode {
|
||||
func (c *Context) Next() Instruction {
|
||||
c.ip++
|
||||
if c.ip >= len(c.prog) {
|
||||
return Oret
|
||||
return RET
|
||||
}
|
||||
return Opcode(c.prog[c.ip])
|
||||
return Instruction(c.prog[c.ip])
|
||||
}
|
||||
|
||||
// IP returns the absolute instruction without taking 0 into account.
|
||||
|
@ -47,11 +47,11 @@ func (c *Context) LenInstr() int {
|
|||
}
|
||||
|
||||
// CurrInstr returns the current instruction and opcode.
|
||||
func (c *Context) CurrInstr() (int, Opcode) {
|
||||
func (c *Context) CurrInstr() (int, Instruction) {
|
||||
if c.ip < 0 {
|
||||
return c.ip, Opcode(0x00)
|
||||
return c.ip, Instruction(0x00)
|
||||
}
|
||||
return c.ip, Opcode(c.prog[c.ip])
|
||||
return c.ip, Instruction(c.prog[c.ip])
|
||||
}
|
||||
|
||||
// Copy returns an new exact copy of c.
|
||||
|
|
|
@ -11,8 +11,8 @@ import (
|
|||
"github.com/CityOfZion/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// Emit a VM Opcode with data to the given buffer.
|
||||
func Emit(w *bytes.Buffer, op Opcode, b []byte) error {
|
||||
// Emit a VM Instruction with data to the given buffer.
|
||||
func Emit(w *bytes.Buffer, op Instruction, b []byte) error {
|
||||
if err := w.WriteByte(byte(op)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -20,29 +20,29 @@ func Emit(w *bytes.Buffer, op Opcode, b []byte) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// EmitOpcode emits a single VM Opcode the given buffer.
|
||||
func EmitOpcode(w io.ByteWriter, op Opcode) error {
|
||||
// EmitOpcode emits a single VM Instruction the given buffer.
|
||||
func EmitOpcode(w io.ByteWriter, op Instruction) 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, Opusht)
|
||||
return EmitOpcode(w, PUSHT)
|
||||
}
|
||||
return EmitOpcode(w, Opushf)
|
||||
return EmitOpcode(w, PUSHF)
|
||||
}
|
||||
|
||||
// EmitInt emits a int type to the given buffer.
|
||||
func EmitInt(w *bytes.Buffer, i int64) error {
|
||||
if i == -1 {
|
||||
return EmitOpcode(w, Opushm1)
|
||||
return EmitOpcode(w, PUSHM1)
|
||||
}
|
||||
if i == 0 {
|
||||
return EmitOpcode(w, Opushf)
|
||||
return EmitOpcode(w, PUSHF)
|
||||
}
|
||||
if i > 0 && i < 16 {
|
||||
val := Opcode(int(Opush1) - 1 + int(i))
|
||||
val := Instruction(int(PUSH1) - 1 + int(i))
|
||||
return EmitOpcode(w, val)
|
||||
}
|
||||
|
||||
|
@ -63,18 +63,18 @@ func EmitBytes(w *bytes.Buffer, b []byte) error {
|
|||
n = len(b)
|
||||
)
|
||||
|
||||
if n <= int(Opushbytes75) {
|
||||
return Emit(w, Opcode(n), b)
|
||||
if n <= int(PUSHBYTES75) {
|
||||
return Emit(w, Instruction(n), b)
|
||||
} else if n < 0x100 {
|
||||
err = Emit(w, Opushdata1, []byte{byte(n)})
|
||||
err = Emit(w, PUSHDATA1, []byte{byte(n)})
|
||||
} else if n < 0x10000 {
|
||||
buf := make([]byte, 2)
|
||||
binary.LittleEndian.PutUint16(buf, uint16(n))
|
||||
err = Emit(w, Opushdata2, buf)
|
||||
err = Emit(w, PUSHDATA2, buf)
|
||||
} else {
|
||||
buf := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(buf, uint32(n))
|
||||
err = Emit(w, Opushdata4, buf)
|
||||
err = Emit(w, PUSHDATA4, buf)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -92,17 +92,17 @@ func EmitSyscall(w *bytes.Buffer, api string) error {
|
|||
buf := make([]byte, len(api)+1)
|
||||
buf[0] = byte(len(api))
|
||||
copy(buf[1:], []byte(api))
|
||||
return Emit(w, Osyscall, buf)
|
||||
return Emit(w, SYSCALL, buf)
|
||||
}
|
||||
|
||||
// EmitCall emits a call Opcode with label to the given buffer.
|
||||
func EmitCall(w *bytes.Buffer, op Opcode, label int16) error {
|
||||
// EmitCall emits a call Instruction with label to the given buffer.
|
||||
func EmitCall(w *bytes.Buffer, op Instruction, label int16) error {
|
||||
return EmitJmp(w, op, label)
|
||||
}
|
||||
|
||||
// EmitJmp emits a jump Opcode along with label to the given buffer.
|
||||
func EmitJmp(w *bytes.Buffer, op Opcode, label int16) error {
|
||||
if !isOpcodeJmp(op) {
|
||||
// EmitJmp emits a jump Instruction along with label to the given buffer.
|
||||
func EmitJmp(w *bytes.Buffer, op Instruction, label int16) error {
|
||||
if !isInstructionJmp(op) {
|
||||
return fmt.Errorf("opcode %s is not a jump or call type", op.String())
|
||||
}
|
||||
buf := make([]byte, 2)
|
||||
|
@ -113,9 +113,9 @@ func EmitJmp(w *bytes.Buffer, op Opcode, 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 := Oappcall
|
||||
op := APPCALL
|
||||
if tailCall {
|
||||
op = Otailcall
|
||||
op = TAILCALL
|
||||
}
|
||||
return Emit(w, op, scriptHash.Bytes())
|
||||
}
|
||||
|
@ -142,8 +142,8 @@ func EmitAppCallWithOperation(w *bytes.Buffer, scriptHash util.Uint160, operatio
|
|||
return EmitAppCall(w, scriptHash, false)
|
||||
}
|
||||
|
||||
func isOpcodeJmp(op Opcode) bool {
|
||||
if op == Ojmp || op == Ojmpifnot || op == Ojmpif || op == Ocall {
|
||||
func isInstructionJmp(op Instruction) bool {
|
||||
if op == JMP || op == JMPIFNOT || op == JMPIF || op == CALL {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
func TestEmitInt(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
EmitInt(buf, 10)
|
||||
assert.Equal(t, Opcode(buf.Bytes()[0]), Opush10)
|
||||
assert.Equal(t, Instruction(buf.Bytes()[0]), PUSH10)
|
||||
buf.Reset()
|
||||
EmitInt(buf, 100)
|
||||
assert.Equal(t, buf.Bytes()[0], uint8(1))
|
||||
|
@ -26,8 +26,8 @@ func TestEmitBool(t *testing.T) {
|
|||
buf := new(bytes.Buffer)
|
||||
EmitBool(buf, true)
|
||||
EmitBool(buf, false)
|
||||
assert.Equal(t, Opcode(buf.Bytes()[0]), Opush1)
|
||||
assert.Equal(t, Opcode(buf.Bytes()[1]), Opush0)
|
||||
assert.Equal(t, Instruction(buf.Bytes()[0]), PUSH1)
|
||||
assert.Equal(t, Instruction(buf.Bytes()[1]), PUSH0)
|
||||
}
|
||||
|
||||
func TestEmitString(t *testing.T) {
|
||||
|
@ -48,7 +48,7 @@ func TestEmitSyscall(t *testing.T) {
|
|||
buf := new(bytes.Buffer)
|
||||
for _, syscall := range syscalls {
|
||||
EmitSyscall(buf, syscall)
|
||||
assert.Equal(t, Opcode(buf.Bytes()[0]), Osyscall)
|
||||
assert.Equal(t, Instruction(buf.Bytes()[0]), SYSCALL)
|
||||
assert.Equal(t, buf.Bytes()[1], uint8(len(syscall)))
|
||||
assert.Equal(t, buf.Bytes()[2:], []byte(syscall))
|
||||
buf.Reset()
|
||||
|
@ -57,8 +57,8 @@ func TestEmitSyscall(t *testing.T) {
|
|||
|
||||
func TestEmitCall(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
EmitCall(buf, Ojmp, 100)
|
||||
assert.Equal(t, Opcode(buf.Bytes()[0]), Ojmp)
|
||||
EmitCall(buf, JMP, 100)
|
||||
assert.Equal(t, Instruction(buf.Bytes()[0]), JMP)
|
||||
label := binary.LittleEndian.Uint16(buf.Bytes()[1:3])
|
||||
assert.Equal(t, label, uint16(100))
|
||||
}
|
||||
|
|
118
pkg/vm/instruction_string.go
Normal file
118
pkg/vm/instruction_string.go
Normal file
|
@ -0,0 +1,118 @@
|
|||
// Code generated by "stringer -type=Instruction"; DO NOT EDIT.
|
||||
|
||||
package vm
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _Instruction_name = "PUSH0PUSHBYTES1PUSHBYTES75PUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPIFJMPIFNOTCALLRETAPPCALLSYSCALLTAILCALLDUPFROMALTSTACKTOALTSTACKFROMALTSTACKXDROPXSWAPXTUCKDEPTHDROPDUPNIPOVERPICKROLLROTSWAPTUCKCATSUBSTRLEFTRIGHTSIZEINVERTANDORXOREQUALINCDECSIGNNEGATEABSNOTNZADDSUBMULDIVMODSHLSHRBOOLANDBOOLORNUMEQUALNUMNOTEQUALLTGTLTEGTEMINMAXWITHINSHA1SHA256HASH160HASH256CHECKSIGCHECKMULTISIGARRAYSIZEPACKUNPACKPICKITEMSETITEMNEWARRAYNEWSTRUCTAPPENDREVERSEREMOVETHROWTHROWIFNOT"
|
||||
|
||||
var _Instruction_map = map[Instruction]string{
|
||||
0: _Instruction_name[0:5],
|
||||
1: _Instruction_name[5:15],
|
||||
75: _Instruction_name[15:26],
|
||||
76: _Instruction_name[26:35],
|
||||
77: _Instruction_name[35:44],
|
||||
78: _Instruction_name[44:53],
|
||||
79: _Instruction_name[53:59],
|
||||
81: _Instruction_name[59:64],
|
||||
82: _Instruction_name[64:69],
|
||||
83: _Instruction_name[69:74],
|
||||
84: _Instruction_name[74:79],
|
||||
85: _Instruction_name[79:84],
|
||||
86: _Instruction_name[84:89],
|
||||
87: _Instruction_name[89:94],
|
||||
88: _Instruction_name[94:99],
|
||||
89: _Instruction_name[99:104],
|
||||
90: _Instruction_name[104:110],
|
||||
91: _Instruction_name[110:116],
|
||||
92: _Instruction_name[116:122],
|
||||
93: _Instruction_name[122:128],
|
||||
94: _Instruction_name[128:134],
|
||||
95: _Instruction_name[134:140],
|
||||
96: _Instruction_name[140:146],
|
||||
97: _Instruction_name[146:149],
|
||||
98: _Instruction_name[149:152],
|
||||
99: _Instruction_name[152:157],
|
||||
100: _Instruction_name[157:165],
|
||||
101: _Instruction_name[165:169],
|
||||
102: _Instruction_name[169:172],
|
||||
103: _Instruction_name[172:179],
|
||||
104: _Instruction_name[179:186],
|
||||
105: _Instruction_name[186:194],
|
||||
106: _Instruction_name[194:209],
|
||||
107: _Instruction_name[209:219],
|
||||
108: _Instruction_name[219:231],
|
||||
109: _Instruction_name[231:236],
|
||||
114: _Instruction_name[236:241],
|
||||
115: _Instruction_name[241:246],
|
||||
116: _Instruction_name[246:251],
|
||||
117: _Instruction_name[251:255],
|
||||
118: _Instruction_name[255:258],
|
||||
119: _Instruction_name[258:261],
|
||||
120: _Instruction_name[261:265],
|
||||
121: _Instruction_name[265:269],
|
||||
122: _Instruction_name[269:273],
|
||||
123: _Instruction_name[273:276],
|
||||
124: _Instruction_name[276:280],
|
||||
125: _Instruction_name[280:284],
|
||||
126: _Instruction_name[284:287],
|
||||
127: _Instruction_name[287:293],
|
||||
128: _Instruction_name[293:297],
|
||||
129: _Instruction_name[297:302],
|
||||
130: _Instruction_name[302:306],
|
||||
131: _Instruction_name[306:312],
|
||||
132: _Instruction_name[312:315],
|
||||
133: _Instruction_name[315:317],
|
||||
134: _Instruction_name[317:320],
|
||||
135: _Instruction_name[320:325],
|
||||
139: _Instruction_name[325:328],
|
||||
140: _Instruction_name[328:331],
|
||||
141: _Instruction_name[331:335],
|
||||
143: _Instruction_name[335:341],
|
||||
144: _Instruction_name[341:344],
|
||||
145: _Instruction_name[344:347],
|
||||
146: _Instruction_name[347:349],
|
||||
147: _Instruction_name[349:352],
|
||||
148: _Instruction_name[352:355],
|
||||
149: _Instruction_name[355:358],
|
||||
150: _Instruction_name[358:361],
|
||||
151: _Instruction_name[361:364],
|
||||
152: _Instruction_name[364:367],
|
||||
153: _Instruction_name[367:370],
|
||||
154: _Instruction_name[370:377],
|
||||
155: _Instruction_name[377:383],
|
||||
156: _Instruction_name[383:391],
|
||||
158: _Instruction_name[391:402],
|
||||
159: _Instruction_name[402:404],
|
||||
160: _Instruction_name[404:406],
|
||||
161: _Instruction_name[406:409],
|
||||
162: _Instruction_name[409:412],
|
||||
163: _Instruction_name[412:415],
|
||||
164: _Instruction_name[415:418],
|
||||
165: _Instruction_name[418:424],
|
||||
167: _Instruction_name[424:428],
|
||||
168: _Instruction_name[428:434],
|
||||
169: _Instruction_name[434:441],
|
||||
170: _Instruction_name[441:448],
|
||||
172: _Instruction_name[448:456],
|
||||
174: _Instruction_name[456:469],
|
||||
192: _Instruction_name[469:478],
|
||||
193: _Instruction_name[478:482],
|
||||
194: _Instruction_name[482:488],
|
||||
195: _Instruction_name[488:496],
|
||||
196: _Instruction_name[496:503],
|
||||
197: _Instruction_name[503:511],
|
||||
198: _Instruction_name[511:520],
|
||||
200: _Instruction_name[520:526],
|
||||
201: _Instruction_name[526:533],
|
||||
202: _Instruction_name[533:539],
|
||||
240: _Instruction_name[539:544],
|
||||
241: _Instruction_name[544:554],
|
||||
}
|
||||
|
||||
func (i Instruction) String() string {
|
||||
if str, ok := _Instruction_map[i]; ok {
|
||||
return str
|
||||
}
|
||||
return "Instruction(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
130
pkg/vm/instructions.go
Normal file
130
pkg/vm/instructions.go
Normal file
|
@ -0,0 +1,130 @@
|
|||
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
|
||||
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
|
||||
CHECKMULTISIG Instruction = 0xAE
|
||||
|
||||
// Array
|
||||
ARRAYSIZE Instruction = 0xC0
|
||||
PACK Instruction = 0xC1
|
||||
UNPACK Instruction = 0xC2
|
||||
PICKITEM Instruction = 0xC3
|
||||
SETITEM Instruction = 0xC4
|
||||
NEWARRAY Instruction = 0xC5
|
||||
NEWSTRUCT Instruction = 0xC6
|
||||
APPEND Instruction = 0xC8
|
||||
REVERSE Instruction = 0xC9
|
||||
REMOVE Instruction = 0xCA
|
||||
|
||||
// Exceptions
|
||||
THROW Instruction = 0xF0
|
||||
THROWIFNOT Instruction = 0xF1
|
||||
)
|
131
pkg/vm/opcode.go
131
pkg/vm/opcode.go
|
@ -1,131 +0,0 @@
|
|||
package vm
|
||||
|
||||
//go:generate stringer -type=Opcode
|
||||
|
||||
// Opcode is an single operational instruction for the GO NEO virtual machine.
|
||||
type Opcode byte
|
||||
|
||||
// List of supported opcodes.
|
||||
const (
|
||||
// Constants
|
||||
Opush0 Opcode = 0x00 // An empty array of bytes is pushed onto the stack.
|
||||
Opushf = Opush0
|
||||
Opushbytes1 Opcode = 0x01 // 0x01-0x4B The next opcode bytes is data to be pushed onto the stack
|
||||
Opushbytes75 Opcode = 0x4B
|
||||
Opushdata1 Opcode = 0x4C // The next byte contains the number of bytes to be pushed onto the stack.
|
||||
Opushdata2 Opcode = 0x4D // The next two bytes contain the number of bytes to be pushed onto the stack.
|
||||
Opushdata4 Opcode = 0x4E // The next four bytes contain the number of bytes to be pushed onto the stack.
|
||||
Opushm1 Opcode = 0x4F // The number -1 is pushed onto the stack.
|
||||
Opush1 Opcode = 0x51
|
||||
Opusht = Opush1
|
||||
Opush2 Opcode = 0x52 // The number 2 is pushed onto the stack.
|
||||
Opush3 Opcode = 0x53 // The number 3 is pushed onto the stack.
|
||||
Opush4 Opcode = 0x54 // The number 4 is pushed onto the stack.
|
||||
Opush5 Opcode = 0x55 // The number 5 is pushed onto the stack.
|
||||
Opush6 Opcode = 0x56 // The number 6 is pushed onto the stack.
|
||||
Opush7 Opcode = 0x57 // The number 7 is pushed onto the stack.
|
||||
Opush8 Opcode = 0x58 // The number 8 is pushed onto the stack.
|
||||
Opush9 Opcode = 0x59 // The number 9 is pushed onto the stack.
|
||||
Opush10 Opcode = 0x5A // The number 10 is pushed onto the stack.
|
||||
Opush11 Opcode = 0x5B // The number 11 is pushed onto the stack.
|
||||
Opush12 Opcode = 0x5C // The number 12 is pushed onto the stack.
|
||||
Opush13 Opcode = 0x5D // The number 13 is pushed onto the stack.
|
||||
Opush14 Opcode = 0x5E // The number 14 is pushed onto the stack.
|
||||
Opush15 Opcode = 0x5F // The number 15 is pushed onto the stack.
|
||||
Opush16 Opcode = 0x60 // The number 16 is pushed onto the stack.
|
||||
|
||||
// Flow control
|
||||
Onop Opcode = 0x61 // No operation.
|
||||
Ojmp Opcode = 0x62
|
||||
Ojmpif Opcode = 0x63
|
||||
Ojmpifnot Opcode = 0x64
|
||||
Ocall Opcode = 0x65
|
||||
Oret Opcode = 0x66
|
||||
Oappcall Opcode = 0x67
|
||||
Osyscall Opcode = 0x68
|
||||
Otailcall Opcode = 0x69
|
||||
|
||||
// The stack
|
||||
Odupfromaltstack Opcode = 0x6A
|
||||
Otoaltstack Opcode = 0x6B // Puts the input onto the top of the alt stack. Removes it from the main stack.
|
||||
Ofromaltstack Opcode = 0x6C // Puts the input onto the top of the main stack. Removes it from the alt stack.
|
||||
Oxdrop Opcode = 0x6D
|
||||
Oxswap Opcode = 0x72
|
||||
Oxtuck Opcode = 0x73
|
||||
Odepth Opcode = 0x74 // Puts the number of stack items onto the stack.
|
||||
Odrop Opcode = 0x75 // Removes the top stack item.
|
||||
Odup Opcode = 0x76 // Duplicates the top stack item.
|
||||
Onip Opcode = 0x77 // Removes the second-to-top stack item.
|
||||
Oover Opcode = 0x78 // Copies the second-to-top stack item to the top.
|
||||
Opick Opcode = 0x79 // The item n back in the stack is copied to the top.
|
||||
Oroll Opcode = 0x7A // The item n back in the stack is moved to the top.
|
||||
Orot Opcode = 0x7B // The top three items on the stack are rotated to the left.
|
||||
Oswap Opcode = 0x7C // The top two items on the stack are swapped.
|
||||
Otuck Opcode = 0x7D // The item at the top of the stack is copied and inserted before the second-to-top item.
|
||||
|
||||
// Splice
|
||||
Ocat Opcode = 0x7E // Concatenates two strings.
|
||||
Osubstr Opcode = 0x7F // Returns a section of a string.
|
||||
Oleft Opcode = 0x80 // Keeps only characters left of the specified point in a string.
|
||||
Oright Opcode = 0x81 // Keeps only characters right of the specified point in a string.
|
||||
Osize Opcode = 0x82 // Returns the length of the input string.
|
||||
|
||||
// Bitwise logic
|
||||
Oinvert Opcode = 0x83 // Flips all of the bits in the input.
|
||||
Oand Opcode = 0x84 // Boolean and between each bit in the inputs.
|
||||
Oor Opcode = 0x85 // Boolean or between each bit in the inputs.
|
||||
Oxor Opcode = 0x86 // Boolean exclusive or between each bit in the inputs.
|
||||
Oequal Opcode = 0x87 // Returns 1 if the inputs are exactly equal, 0 otherwise.
|
||||
|
||||
// Arithmetic
|
||||
// Note: Arithmetic inputs are limited to signed 32-bit integers, but may overflow their output.
|
||||
Oinc Opcode = 0x8B // 1 is added to the input.
|
||||
Odec Opcode = 0x8C // 1 is subtracted from the input.
|
||||
Osign Opcode = 0x8D
|
||||
Onegate Opcode = 0x8F // The sign of the input is flipped.
|
||||
Oabs Opcode = 0x90 // The input is made positive.
|
||||
Onot Opcode = 0x91 // If the input is 0 or 1, it is flipped. Otherwise the output will be 0.
|
||||
Onz Opcode = 0x92 // Returns 0 if the input is 0. 1 otherwise.
|
||||
Oadd Opcode = 0x93 // a is added to b.
|
||||
Osub Opcode = 0x94 // b is subtracted from a.
|
||||
Omul Opcode = 0x95 // a is multiplied by b.
|
||||
Odiv Opcode = 0x96 // a is divided by b.
|
||||
Omod Opcode = 0x97 // Returns the remainder after dividing a by b.
|
||||
Oshl Opcode = 0x98 // Shifts a left b bits, preserving sign.
|
||||
Oshr Opcode = 0x99 // Shifts a right b bits, preserving sign.
|
||||
Obooland Opcode = 0x9A // If both a and b are not 0, the output is 1. Otherwise 0.
|
||||
Oboolor Opcode = 0x9B // If a or b is not 0, the output is 1. Otherwise 0.
|
||||
Onumequal Opcode = 0x9C // Returns 1 if the numbers are equal, 0 otherwise.
|
||||
Onumnotequal Opcode = 0x9E // Returns 1 if the numbers are not equal, 0 otherwise.
|
||||
Olt Opcode = 0x9F // Returns 1 if a is less than b, 0 otherwise.
|
||||
Ogt Opcode = 0xA0 // Returns 1 if a is greater than b, 0 otherwise.
|
||||
Olte Opcode = 0xA1 // Returns 1 if a is less than or equal to b, 0 otherwise.
|
||||
Ogte Opcode = 0xA2 // Returns 1 if a is greater than or equal to b, 0 otherwise.
|
||||
Omin Opcode = 0xA3 // Returns the smaller of a and b.
|
||||
Omax Opcode = 0xA4 // Returns the larger of a and b.
|
||||
Owithin Opcode = 0xA5 // Returns 1 if x is within the specified range (left-inclusive), 0 otherwise.
|
||||
|
||||
// Crypto
|
||||
Osha1 Opcode = 0xA7 // The input is hashed using SHA-1.
|
||||
Osha256 Opcode = 0xA8 // The input is hashed using SHA-256.
|
||||
Ohash160 Opcode = 0xA9
|
||||
Ohash256 Opcode = 0xAA
|
||||
Ochecksig Opcode = 0xAC
|
||||
Ocheckmultisig Opcode = 0xAE
|
||||
|
||||
// array
|
||||
Oarraysize Opcode = 0xC0
|
||||
Opack Opcode = 0xC1
|
||||
Ounpack Opcode = 0xC2
|
||||
Opickitem Opcode = 0xC3
|
||||
Osetitem Opcode = 0xC4
|
||||
Onewarray Opcode = 0xC5 // Pops size from stack and creates a new array with that size, and pushes the array into the stack
|
||||
Onewstruct Opcode = 0xC6
|
||||
Oappend Opcode = 0xC8
|
||||
Oreverse Opcode = 0xC9
|
||||
Oremove Opcode = 0xCA
|
||||
|
||||
// exceptions
|
||||
Othrow Opcode = 0xF0
|
||||
Othrowifnot Opcode = 0xF1
|
||||
)
|
|
@ -1,118 +0,0 @@
|
|||
// Code generated by "stringer -type=Opcode"; DO NOT EDIT.
|
||||
|
||||
package vm
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _Opcode_name = "Opush0Opushbytes1Opushbytes75Opushdata1Opushdata2Opushdata4Opushm1Opush1Opush2Opush3Opush4Opush5Opush6Opush7Opush8Opush9Opush10Opush11Opush12Opush13Opush14Opush15Opush16OnopOjmpOjmpifOjmpifnotOcallOretOappcallOsyscallOtailcallOdupfromaltstackOtoaltstackOfromaltstackOxdropOxswapOxtuckOdepthOdropOdupOnipOoverOpickOrollOrotOswapOtuckOcatOsubstrOleftOrightOsizeOinvertOandOorOxorOequalOincOdecOsignOnegateOabsOnotOnzOaddOsubOmulOdivOmodOshlOshrOboolandOboolorOnumequalOnumnotequalOltOgtOlteOgteOminOmaxOwithinOsha1Osha256Ohash160Ohash256OchecksigOcheckmultisigOarraysizeOpackOunpackOpickitemOsetitemOnewarrayOnewstructOappendOreverseOremoveOthrowOthrowifnot"
|
||||
|
||||
var _Opcode_map = map[Opcode]string{
|
||||
0: _Opcode_name[0:6],
|
||||
1: _Opcode_name[6:17],
|
||||
75: _Opcode_name[17:29],
|
||||
76: _Opcode_name[29:39],
|
||||
77: _Opcode_name[39:49],
|
||||
78: _Opcode_name[49:59],
|
||||
79: _Opcode_name[59:66],
|
||||
81: _Opcode_name[66:72],
|
||||
82: _Opcode_name[72:78],
|
||||
83: _Opcode_name[78:84],
|
||||
84: _Opcode_name[84:90],
|
||||
85: _Opcode_name[90:96],
|
||||
86: _Opcode_name[96:102],
|
||||
87: _Opcode_name[102:108],
|
||||
88: _Opcode_name[108:114],
|
||||
89: _Opcode_name[114:120],
|
||||
90: _Opcode_name[120:127],
|
||||
91: _Opcode_name[127:134],
|
||||
92: _Opcode_name[134:141],
|
||||
93: _Opcode_name[141:148],
|
||||
94: _Opcode_name[148:155],
|
||||
95: _Opcode_name[155:162],
|
||||
96: _Opcode_name[162:169],
|
||||
97: _Opcode_name[169:173],
|
||||
98: _Opcode_name[173:177],
|
||||
99: _Opcode_name[177:183],
|
||||
100: _Opcode_name[183:192],
|
||||
101: _Opcode_name[192:197],
|
||||
102: _Opcode_name[197:201],
|
||||
103: _Opcode_name[201:209],
|
||||
104: _Opcode_name[209:217],
|
||||
105: _Opcode_name[217:226],
|
||||
106: _Opcode_name[226:242],
|
||||
107: _Opcode_name[242:253],
|
||||
108: _Opcode_name[253:266],
|
||||
109: _Opcode_name[266:272],
|
||||
114: _Opcode_name[272:278],
|
||||
115: _Opcode_name[278:284],
|
||||
116: _Opcode_name[284:290],
|
||||
117: _Opcode_name[290:295],
|
||||
118: _Opcode_name[295:299],
|
||||
119: _Opcode_name[299:303],
|
||||
120: _Opcode_name[303:308],
|
||||
121: _Opcode_name[308:313],
|
||||
122: _Opcode_name[313:318],
|
||||
123: _Opcode_name[318:322],
|
||||
124: _Opcode_name[322:327],
|
||||
125: _Opcode_name[327:332],
|
||||
126: _Opcode_name[332:336],
|
||||
127: _Opcode_name[336:343],
|
||||
128: _Opcode_name[343:348],
|
||||
129: _Opcode_name[348:354],
|
||||
130: _Opcode_name[354:359],
|
||||
131: _Opcode_name[359:366],
|
||||
132: _Opcode_name[366:370],
|
||||
133: _Opcode_name[370:373],
|
||||
134: _Opcode_name[373:377],
|
||||
135: _Opcode_name[377:383],
|
||||
139: _Opcode_name[383:387],
|
||||
140: _Opcode_name[387:391],
|
||||
141: _Opcode_name[391:396],
|
||||
143: _Opcode_name[396:403],
|
||||
144: _Opcode_name[403:407],
|
||||
145: _Opcode_name[407:411],
|
||||
146: _Opcode_name[411:414],
|
||||
147: _Opcode_name[414:418],
|
||||
148: _Opcode_name[418:422],
|
||||
149: _Opcode_name[422:426],
|
||||
150: _Opcode_name[426:430],
|
||||
151: _Opcode_name[430:434],
|
||||
152: _Opcode_name[434:438],
|
||||
153: _Opcode_name[438:442],
|
||||
154: _Opcode_name[442:450],
|
||||
155: _Opcode_name[450:457],
|
||||
156: _Opcode_name[457:466],
|
||||
158: _Opcode_name[466:478],
|
||||
159: _Opcode_name[478:481],
|
||||
160: _Opcode_name[481:484],
|
||||
161: _Opcode_name[484:488],
|
||||
162: _Opcode_name[488:492],
|
||||
163: _Opcode_name[492:496],
|
||||
164: _Opcode_name[496:500],
|
||||
165: _Opcode_name[500:507],
|
||||
167: _Opcode_name[507:512],
|
||||
168: _Opcode_name[512:519],
|
||||
169: _Opcode_name[519:527],
|
||||
170: _Opcode_name[527:535],
|
||||
172: _Opcode_name[535:544],
|
||||
174: _Opcode_name[544:558],
|
||||
192: _Opcode_name[558:568],
|
||||
193: _Opcode_name[568:573],
|
||||
194: _Opcode_name[573:580],
|
||||
195: _Opcode_name[580:589],
|
||||
196: _Opcode_name[589:597],
|
||||
197: _Opcode_name[597:606],
|
||||
198: _Opcode_name[606:616],
|
||||
200: _Opcode_name[616:623],
|
||||
201: _Opcode_name[623:631],
|
||||
202: _Opcode_name[631:638],
|
||||
240: _Opcode_name[638:644],
|
||||
241: _Opcode_name[644:655],
|
||||
}
|
||||
|
||||
func (i Opcode) String() string {
|
||||
if str, ok := _Opcode_map[i]; ok {
|
||||
return str
|
||||
}
|
||||
return "Opcode(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
164
pkg/vm/vm.go
164
pkg/vm/vm.go
|
@ -104,7 +104,7 @@ func (v *VM) PrintOps() {
|
|||
} else {
|
||||
cursor = ""
|
||||
}
|
||||
fmt.Fprintf(w, "%d\t0x%2x\t%s\t%s\n", i, prog[i], Opcode(prog[i]).String(), cursor)
|
||||
fmt.Fprintf(w, "%d\t0x%2x\t%s\t%s\n", i, prog[i], Instruction(prog[i]).String(), cursor)
|
||||
|
||||
}
|
||||
w.Flush()
|
||||
|
@ -228,7 +228,7 @@ func (v *VM) Step() {
|
|||
}
|
||||
|
||||
// execute performs an instruction cycle in the VM. Acting on the instruction (opcode).
|
||||
func (v *VM) execute(ctx *Context, op Opcode) {
|
||||
func (v *VM) execute(ctx *Context, op Instruction) {
|
||||
// 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.
|
||||
defer func() {
|
||||
|
@ -239,57 +239,57 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
}
|
||||
}()
|
||||
|
||||
if op >= Opushbytes1 && op <= Opushbytes75 {
|
||||
if op >= PUSHBYTES1 && op <= PUSHBYTES75 {
|
||||
b := ctx.readBytes(int(op))
|
||||
v.estack.PushVal(b)
|
||||
return
|
||||
}
|
||||
|
||||
switch op {
|
||||
case Opushm1, Opush1, Opush2, Opush3, Opush4, Opush5,
|
||||
Opush6, Opush7, Opush8, Opush9, Opush10, Opush11,
|
||||
Opush12, Opush13, Opush14, Opush15, Opush16:
|
||||
val := int(op) - int(Opush1) + 1
|
||||
case PUSHM1, PUSH1, PUSH2, PUSH3, PUSH4, PUSH5,
|
||||
PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11,
|
||||
PUSH12, PUSH13, PUSH14, PUSH15, PUSH16:
|
||||
val := int(op) - int(PUSH1) + 1
|
||||
v.estack.PushVal(val)
|
||||
|
||||
case Opush0:
|
||||
case PUSH0:
|
||||
v.estack.PushVal(0)
|
||||
|
||||
case Opushdata1:
|
||||
case PUSHDATA1:
|
||||
n := ctx.readByte()
|
||||
b := ctx.readBytes(int(n))
|
||||
v.estack.PushVal(b)
|
||||
|
||||
case Opushdata2:
|
||||
case PUSHDATA2:
|
||||
n := ctx.readUint16()
|
||||
b := ctx.readBytes(int(n))
|
||||
v.estack.PushVal(b)
|
||||
|
||||
case Opushdata4:
|
||||
case PUSHDATA4:
|
||||
n := ctx.readUint32()
|
||||
b := ctx.readBytes(int(n))
|
||||
v.estack.PushVal(b)
|
||||
|
||||
// Stack operations.
|
||||
case Otoaltstack:
|
||||
case TOALTSTACK:
|
||||
v.astack.Push(v.estack.Pop())
|
||||
|
||||
case Ofromaltstack:
|
||||
case FROMALTSTACK:
|
||||
v.estack.Push(v.astack.Pop())
|
||||
|
||||
case Odupfromaltstack:
|
||||
case DUPFROMALTSTACK:
|
||||
v.estack.Push(v.astack.Dup(0))
|
||||
|
||||
case Odup:
|
||||
case DUP:
|
||||
v.estack.Push(v.estack.Dup(0))
|
||||
|
||||
case Oswap:
|
||||
case SWAP:
|
||||
a := v.estack.Pop()
|
||||
b := v.estack.Pop()
|
||||
v.estack.Push(a)
|
||||
v.estack.Push(b)
|
||||
|
||||
case Oxswap:
|
||||
case XSWAP:
|
||||
n := int(v.estack.Pop().BigInt().Int64())
|
||||
if n < 0 {
|
||||
panic("XSWAP: invalid length")
|
||||
|
@ -305,7 +305,7 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
b.value = aval
|
||||
}
|
||||
|
||||
case Otuck:
|
||||
case TUCK:
|
||||
n := int(v.estack.Pop().BigInt().Int64())
|
||||
if n <= 0 {
|
||||
panic("OTUCK: invalid length")
|
||||
|
@ -313,7 +313,7 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
|
||||
v.estack.InsertAt(v.estack.Peek(0), n)
|
||||
|
||||
case Orot:
|
||||
case ROT:
|
||||
c := v.estack.Pop()
|
||||
b := v.estack.Pop()
|
||||
a := v.estack.Pop()
|
||||
|
@ -322,21 +322,21 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
v.estack.Push(c)
|
||||
v.estack.Push(a)
|
||||
|
||||
case Odepth:
|
||||
case DEPTH:
|
||||
v.estack.PushVal(v.estack.Len())
|
||||
|
||||
case Onip:
|
||||
case NIP:
|
||||
elem := v.estack.Pop()
|
||||
_ = v.estack.Pop()
|
||||
v.estack.Push(elem)
|
||||
|
||||
case Oover:
|
||||
case OVER:
|
||||
b := v.estack.Pop()
|
||||
a := v.estack.Peek(0)
|
||||
v.estack.Push(b)
|
||||
v.estack.Push(a)
|
||||
|
||||
case Oroll:
|
||||
case ROLL:
|
||||
n := int(v.estack.Pop().BigInt().Int64())
|
||||
if n < 0 {
|
||||
panic("negative stack item returned")
|
||||
|
@ -345,105 +345,105 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
v.estack.Push(v.estack.RemoveAt(n))
|
||||
}
|
||||
|
||||
case Odrop:
|
||||
case DROP:
|
||||
v.estack.Pop()
|
||||
|
||||
case Oequal:
|
||||
case EQUAL:
|
||||
panic("TODO EQUAL")
|
||||
|
||||
// Bit operations.
|
||||
case Oand:
|
||||
case AND:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(new(big.Int).And(b, a))
|
||||
|
||||
case Oor:
|
||||
case OR:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(new(big.Int).Or(b, a))
|
||||
|
||||
case Oxor:
|
||||
case XOR:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(new(big.Int).Xor(b, a))
|
||||
|
||||
// Numeric operations.
|
||||
case Oadd:
|
||||
case ADD:
|
||||
a := v.estack.Pop().BigInt()
|
||||
b := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(new(big.Int).Add(a, b))
|
||||
|
||||
case Osub:
|
||||
case SUB:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(new(big.Int).Sub(a, b))
|
||||
|
||||
case Odiv:
|
||||
case DIV:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(new(big.Int).Div(a, b))
|
||||
|
||||
case Omul:
|
||||
case MUL:
|
||||
a := v.estack.Pop().BigInt()
|
||||
b := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(new(big.Int).Mul(a, b))
|
||||
|
||||
case Omod:
|
||||
case MOD:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(new(big.Int).Mod(a, b))
|
||||
|
||||
case Oshl:
|
||||
case SHL:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(new(big.Int).Lsh(a, uint(b.Int64())))
|
||||
|
||||
case Oshr:
|
||||
case SHR:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(new(big.Int).Rsh(a, uint(b.Int64())))
|
||||
|
||||
case Obooland:
|
||||
case BOOLAND:
|
||||
b := v.estack.Pop().Bool()
|
||||
a := v.estack.Pop().Bool()
|
||||
v.estack.PushVal(a && b)
|
||||
|
||||
case Oboolor:
|
||||
case BOOLOR:
|
||||
b := v.estack.Pop().Bool()
|
||||
a := v.estack.Pop().Bool()
|
||||
v.estack.PushVal(a || b)
|
||||
|
||||
case Onumequal:
|
||||
case NUMEQUAL:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(a.Cmp(b) == 0)
|
||||
|
||||
case Onumnotequal:
|
||||
case NUMNOTEQUAL:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(a.Cmp(b) != 0)
|
||||
|
||||
case Olt:
|
||||
case LT:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(a.Cmp(b) == -1)
|
||||
|
||||
case Ogt:
|
||||
case GT:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(a.Cmp(b) == 1)
|
||||
|
||||
case Olte:
|
||||
case LTE:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(a.Cmp(b) <= 0)
|
||||
|
||||
case Ogte:
|
||||
case GTE:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(a.Cmp(b) >= 0)
|
||||
|
||||
case Omin:
|
||||
case MIN:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
val := a
|
||||
|
@ -452,7 +452,7 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
}
|
||||
v.estack.PushVal(val)
|
||||
|
||||
case Omax:
|
||||
case MAX:
|
||||
b := v.estack.Pop().BigInt()
|
||||
a := v.estack.Pop().BigInt()
|
||||
val := a
|
||||
|
@ -461,52 +461,52 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
}
|
||||
v.estack.PushVal(val)
|
||||
|
||||
case Owithin:
|
||||
case 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 Oinc:
|
||||
case INC:
|
||||
x := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(new(big.Int).Add(x, big.NewInt(1)))
|
||||
|
||||
case Odec:
|
||||
case DEC:
|
||||
x := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(new(big.Int).Sub(x, big.NewInt(1)))
|
||||
|
||||
case Osign:
|
||||
case SIGN:
|
||||
x := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(x.Sign())
|
||||
|
||||
case Onegate:
|
||||
case NEGATE:
|
||||
x := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(x.Neg(x))
|
||||
|
||||
case Oabs:
|
||||
case ABS:
|
||||
x := v.estack.Pop().BigInt()
|
||||
v.estack.PushVal(x.Abs(x))
|
||||
|
||||
case Onot:
|
||||
case NOT:
|
||||
x := v.estack.Pop().Bool()
|
||||
v.estack.PushVal(!x)
|
||||
|
||||
case Onz:
|
||||
case NZ:
|
||||
panic("todo NZ")
|
||||
// x := v.estack.Pop().BigInt()
|
||||
|
||||
// Object operations.
|
||||
case Onewarray:
|
||||
case NEWARRAY:
|
||||
n := v.estack.Pop().BigInt().Int64()
|
||||
items := make([]StackItem, n)
|
||||
v.estack.PushVal(&ArrayItem{items})
|
||||
|
||||
case Onewstruct:
|
||||
case NEWSTRUCT:
|
||||
n := v.estack.Pop().BigInt().Int64()
|
||||
items := make([]StackItem, n)
|
||||
v.estack.PushVal(&StructItem{items})
|
||||
|
||||
case Oappend:
|
||||
case APPEND:
|
||||
itemElem := v.estack.Pop()
|
||||
arrElem := v.estack.Pop()
|
||||
|
||||
|
@ -522,11 +522,11 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
panic("APPEND: not of underlying type Array")
|
||||
}
|
||||
|
||||
case Oreverse:
|
||||
case REVERSE:
|
||||
|
||||
case Oremove:
|
||||
case REMOVE:
|
||||
|
||||
case Opack:
|
||||
case PACK:
|
||||
n := int(v.estack.Pop().BigInt().Int64())
|
||||
if n < 0 || n > v.estack.Len() {
|
||||
panic("OPACK: invalid length")
|
||||
|
@ -539,10 +539,10 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
|
||||
v.estack.PushVal(items)
|
||||
|
||||
case Ounpack:
|
||||
case UNPACK:
|
||||
panic("TODO")
|
||||
|
||||
case Opickitem:
|
||||
case PICKITEM:
|
||||
var (
|
||||
key = v.estack.Pop()
|
||||
obj = v.estack.Pop()
|
||||
|
@ -562,7 +562,7 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
panic("PICKITEM: unknown type")
|
||||
}
|
||||
|
||||
case Osetitem:
|
||||
case SETITEM:
|
||||
var (
|
||||
item = v.estack.Pop().value
|
||||
key = v.estack.Pop()
|
||||
|
@ -582,7 +582,7 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
panic(fmt.Sprintf("SETITEM: invalid item type %s", t))
|
||||
}
|
||||
|
||||
case Oarraysize:
|
||||
case 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.
|
||||
|
@ -595,7 +595,7 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
panic("ARRAYSIZE: item not of type []StackItem")
|
||||
}
|
||||
|
||||
case Osize:
|
||||
case SIZE:
|
||||
elem := v.estack.Pop()
|
||||
arr, ok := elem.value.Value().([]uint8)
|
||||
if !ok {
|
||||
|
@ -603,7 +603,7 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
}
|
||||
v.estack.PushVal(len(arr))
|
||||
|
||||
case Ojmp, Ojmpif, Ojmpifnot:
|
||||
case JMP, JMPIF, JMPIFNOT:
|
||||
var (
|
||||
rOffset = int16(ctx.readUint16())
|
||||
offset = ctx.ip + int(rOffset) - 3 // sizeOf(int16 + uint8)
|
||||
|
@ -612,9 +612,9 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
panic(fmt.Sprintf("JMP: invalid offset %d ip at %d", offset, ctx.ip))
|
||||
}
|
||||
cond := true
|
||||
if op > Ojmp {
|
||||
if op > JMP {
|
||||
cond = v.estack.Pop().Bool()
|
||||
if op == Ojmpifnot {
|
||||
if op == JMPIFNOT {
|
||||
cond = !cond
|
||||
}
|
||||
}
|
||||
|
@ -622,12 +622,12 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
ctx.ip = offset
|
||||
}
|
||||
|
||||
case Ocall:
|
||||
case CALL:
|
||||
v.istack.PushVal(ctx.Copy())
|
||||
ctx.ip += 2
|
||||
v.execute(v.Context(), Ojmp)
|
||||
v.execute(v.Context(), JMP)
|
||||
|
||||
case Osyscall:
|
||||
case SYSCALL:
|
||||
api := ctx.readVarBytes()
|
||||
ifunc, ok := v.interop[string(api)]
|
||||
if !ok {
|
||||
|
@ -637,7 +637,7 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
panic(fmt.Sprintf("failed to invoke syscall: %s", err))
|
||||
}
|
||||
|
||||
case Oappcall, Otailcall:
|
||||
case APPCALL, TAILCALL:
|
||||
if len(v.scripts) == 0 {
|
||||
panic("script table is empty")
|
||||
}
|
||||
|
@ -652,32 +652,32 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
panic("could not find script")
|
||||
}
|
||||
|
||||
if op == Otailcall {
|
||||
if op == TAILCALL {
|
||||
_ = v.istack.Pop()
|
||||
}
|
||||
|
||||
v.LoadScript(script)
|
||||
|
||||
case Oret:
|
||||
case RET:
|
||||
_ = v.istack.Pop()
|
||||
if v.istack.Len() == 0 {
|
||||
v.state = haltState
|
||||
}
|
||||
|
||||
// Cryptographic operations.
|
||||
case Osha1:
|
||||
case SHA1:
|
||||
b := v.estack.Pop().Bytes()
|
||||
sha := sha1.New()
|
||||
sha.Write(b)
|
||||
v.estack.PushVal(sha.Sum(nil))
|
||||
|
||||
case Osha256:
|
||||
case SHA256:
|
||||
b := v.estack.Pop().Bytes()
|
||||
sha := sha256.New()
|
||||
sha.Write(b)
|
||||
v.estack.PushVal(sha.Sum(nil))
|
||||
|
||||
case Ohash160:
|
||||
case HASH160:
|
||||
b := v.estack.Pop().Bytes()
|
||||
sha := sha256.New()
|
||||
sha.Write(b)
|
||||
|
@ -686,7 +686,7 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
ripemd.Write(h)
|
||||
v.estack.PushVal(ripemd.Sum(nil))
|
||||
|
||||
case Ohash256:
|
||||
case HASH256:
|
||||
b := v.estack.Pop().Bytes()
|
||||
sha := sha256.New()
|
||||
sha.Write(b)
|
||||
|
@ -695,19 +695,19 @@ func (v *VM) execute(ctx *Context, op Opcode) {
|
|||
sha.Write(h)
|
||||
v.estack.PushVal(sha.Sum(nil))
|
||||
|
||||
case Ochecksig:
|
||||
case CHECKSIG:
|
||||
// pubkey := v.estack.Pop().Bytes()
|
||||
// sig := v.estack.Pop().Bytes()
|
||||
|
||||
case Ocheckmultisig:
|
||||
case CHECKMULTISIG:
|
||||
|
||||
case Onop:
|
||||
case NOP:
|
||||
// unlucky ^^
|
||||
|
||||
case Othrow:
|
||||
case THROW:
|
||||
panic("THROW")
|
||||
|
||||
case Othrowifnot:
|
||||
case THROWIFNOT:
|
||||
if !v.estack.Pop().Bool() {
|
||||
panic("THROWIFNOT")
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ func TestInteropHook(t *testing.T) {
|
|||
|
||||
buf := new(bytes.Buffer)
|
||||
EmitSyscall(buf, "foo")
|
||||
EmitOpcode(buf, Oret)
|
||||
EmitOpcode(buf, RET)
|
||||
v.Load(buf.Bytes())
|
||||
v.Run()
|
||||
assert.Equal(t, 1, v.estack.Len())
|
||||
|
@ -51,7 +51,7 @@ func TestPushBytes1to75(t *testing.T) {
|
|||
assert.IsType(t, elem.Bytes(), b)
|
||||
assert.Equal(t, 0, vm.estack.Len())
|
||||
|
||||
vm.execute(nil, Oret)
|
||||
vm.execute(nil, RET)
|
||||
|
||||
assert.Equal(t, 0, vm.astack.Len())
|
||||
assert.Equal(t, 0, vm.istack.Len())
|
||||
|
@ -61,7 +61,7 @@ func TestPushBytes1to75(t *testing.T) {
|
|||
|
||||
func TestPushm1to16(t *testing.T) {
|
||||
var prog []byte
|
||||
for i := int(Opushm1); i <= int(Opush16); i++ {
|
||||
for i := int(PUSHM1); i <= int(PUSH16); i++ {
|
||||
if i == 80 {
|
||||
continue // opcode layout we got here.
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ func TestPushm1to16(t *testing.T) {
|
|||
}
|
||||
|
||||
vm := load(prog)
|
||||
for i := int(Opushm1); i <= int(Opush16); i++ {
|
||||
for i := int(PUSHM1); i <= int(PUSH16); i++ {
|
||||
if i == 80 {
|
||||
continue // nice opcode layout we got here.
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ func TestPushm1to16(t *testing.T) {
|
|||
|
||||
elem := vm.estack.Pop()
|
||||
assert.IsType(t, &BigIntegerItem{}, elem.value)
|
||||
val := i - int(Opush1) + 1
|
||||
val := i - int(PUSH1) + 1
|
||||
assert.Equal(t, elem.BigInt().Int64(), int64(val))
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ func TestPushData4(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
prog := makeProgram(Oadd)
|
||||
prog := makeProgram(ADD)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(4)
|
||||
vm.estack.PushVal(2)
|
||||
|
@ -104,7 +104,7 @@ func TestAdd(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestMul(t *testing.T) {
|
||||
prog := makeProgram(Omul)
|
||||
prog := makeProgram(MUL)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(4)
|
||||
vm.estack.PushVal(2)
|
||||
|
@ -113,7 +113,7 @@ func TestMul(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDiv(t *testing.T) {
|
||||
prog := makeProgram(Odiv)
|
||||
prog := makeProgram(DIV)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(4)
|
||||
vm.estack.PushVal(2)
|
||||
|
@ -122,7 +122,7 @@ func TestDiv(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSub(t *testing.T) {
|
||||
prog := makeProgram(Osub)
|
||||
prog := makeProgram(SUB)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(4)
|
||||
vm.estack.PushVal(2)
|
||||
|
@ -131,7 +131,7 @@ func TestSub(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLT(t *testing.T) {
|
||||
prog := makeProgram(Olt)
|
||||
prog := makeProgram(LT)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(4)
|
||||
vm.estack.PushVal(3)
|
||||
|
@ -140,7 +140,7 @@ func TestLT(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLTE(t *testing.T) {
|
||||
prog := makeProgram(Olte)
|
||||
prog := makeProgram(LTE)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(2)
|
||||
vm.estack.PushVal(3)
|
||||
|
@ -149,7 +149,7 @@ func TestLTE(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGT(t *testing.T) {
|
||||
prog := makeProgram(Ogt)
|
||||
prog := makeProgram(GT)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(9)
|
||||
vm.estack.PushVal(3)
|
||||
|
@ -159,7 +159,7 @@ func TestGT(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGTE(t *testing.T) {
|
||||
prog := makeProgram(Ogte)
|
||||
prog := makeProgram(GTE)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(3)
|
||||
vm.estack.PushVal(3)
|
||||
|
@ -168,7 +168,7 @@ func TestGTE(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDepth(t *testing.T) {
|
||||
prog := makeProgram(Odepth)
|
||||
prog := makeProgram(DEPTH)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(1)
|
||||
vm.estack.PushVal(2)
|
||||
|
@ -178,7 +178,7 @@ func TestDepth(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNumEqual(t *testing.T) {
|
||||
prog := makeProgram(Onumequal)
|
||||
prog := makeProgram(NUMEQUAL)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(1)
|
||||
vm.estack.PushVal(2)
|
||||
|
@ -187,7 +187,7 @@ func TestNumEqual(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNumNotEqual(t *testing.T) {
|
||||
prog := makeProgram(Onumnotequal)
|
||||
prog := makeProgram(NUMNOTEQUAL)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(2)
|
||||
vm.estack.PushVal(2)
|
||||
|
@ -196,7 +196,7 @@ func TestNumNotEqual(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestINC(t *testing.T) {
|
||||
prog := makeProgram(Oinc)
|
||||
prog := makeProgram(INC)
|
||||
vm := load(prog)
|
||||
vm.estack.PushVal(1)
|
||||
vm.Run()
|
||||
|
@ -204,13 +204,13 @@ func TestINC(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAppCall(t *testing.T) {
|
||||
prog := []byte{byte(Oappcall)}
|
||||
prog := []byte{byte(APPCALL)}
|
||||
hash := util.Uint160{}
|
||||
prog = append(prog, hash.Bytes()...)
|
||||
prog = append(prog, byte(Oret))
|
||||
prog = append(prog, byte(RET))
|
||||
|
||||
vm := load(prog)
|
||||
vm.scripts[hash] = makeProgram(Odepth)
|
||||
vm.scripts[hash] = makeProgram(DEPTH)
|
||||
vm.estack.PushVal(2)
|
||||
|
||||
vm.Run()
|
||||
|
@ -231,12 +231,12 @@ func TestSimpleCall(t *testing.T) {
|
|||
assert.Equal(t, result, int(vm.estack.Pop().BigInt().Int64()))
|
||||
}
|
||||
|
||||
func makeProgram(opcodes ...Opcode) []byte {
|
||||
prog := make([]byte, len(opcodes)+1) // Oret
|
||||
func makeProgram(opcodes ...Instruction) []byte {
|
||||
prog := make([]byte, len(opcodes)+1) // RET
|
||||
for i := 0; i < len(opcodes); i++ {
|
||||
prog[i] = byte(opcodes[i])
|
||||
}
|
||||
prog[len(prog)-1] = byte(Oret)
|
||||
prog[len(prog)-1] = byte(RET)
|
||||
return prog
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue