diff --git a/cli/wallet/validator.go b/cli/wallet/validator.go index 671f16d8f..16d33fdb4 100644 --- a/cli/wallet/validator.go +++ b/cli/wallet/validator.go @@ -102,7 +102,7 @@ func handleCandidate(ctx *cli.Context, method string) error { gas := flags.Fixed8FromContext(ctx, "gas") w := io.NewBufBinWriter() emit.AppCallWithOperationAndArgs(w.BinWriter, client.NeoContractHash, method, acc.PrivateKey().PublicKey().Bytes()) - emit.Opcode(w.BinWriter, opcode.ASSERT) + emit.Opcodes(w.BinWriter, opcode.ASSERT) tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas), transaction.Signer{ Account: acc.Contract.ScriptHash(), Scopes: transaction.CalledByEntry, @@ -160,7 +160,7 @@ func handleVote(ctx *cli.Context) error { gas := flags.Fixed8FromContext(ctx, "gas") w := io.NewBufBinWriter() emit.AppCallWithOperationAndArgs(w.BinWriter, client.NeoContractHash, "vote", addr.BytesBE(), pubArg) - emit.Opcode(w.BinWriter, opcode.ASSERT) + emit.Opcodes(w.BinWriter, opcode.ASSERT) tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas), transaction.Signer{ Account: acc.Contract.ScriptHash(), diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 4c98a30f8..7152aa171 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -176,13 +176,12 @@ func (c *codegen) emitLoadConst(t types.TypeAndValue) { func (c *codegen) emitLoadField(i int) { emit.Int(c.prog.BinWriter, int64(i)) - emit.Opcode(c.prog.BinWriter, opcode.PICKITEM) + emit.Opcodes(c.prog.BinWriter, opcode.PICKITEM) } func (c *codegen) emitStoreStructField(i int) { emit.Int(c.prog.BinWriter, int64(i)) - emit.Opcode(c.prog.BinWriter, opcode.ROT) - emit.Opcode(c.prog.BinWriter, opcode.SETITEM) + emit.Opcodes(c.prog.BinWriter, opcode.ROT, opcode.SETITEM) } // getVarIndex returns variable type and position in corresponding slot, @@ -226,7 +225,7 @@ func (c *codegen) emitLoadVar(pkg string, name string) { func (c *codegen) emitLoadByIndex(t varType, i int) { base, _ := getBaseOpcode(t) if i < 7 { - emit.Opcode(c.prog.BinWriter, base+opcode.Opcode(i)) + emit.Opcodes(c.prog.BinWriter, base+opcode.Opcode(i)) } else { emit.Instruction(c.prog.BinWriter, base+7, []byte{byte(i)}) } @@ -235,7 +234,7 @@ func (c *codegen) emitLoadByIndex(t varType, i int) { // emitStoreVar stores top value from the evaluation stack in the specified variable. func (c *codegen) emitStoreVar(pkg string, name string) { if name == "_" { - emit.Opcode(c.prog.BinWriter, opcode.DROP) + emit.Opcodes(c.prog.BinWriter, opcode.DROP) return } t, i := c.getVarIndex(pkg, name) @@ -246,7 +245,7 @@ func (c *codegen) emitStoreVar(pkg string, name string) { func (c *codegen) emitStoreByIndex(t varType, i int) { _, base := getBaseOpcode(t) if i < 7 { - emit.Opcode(c.prog.BinWriter, base+opcode.Opcode(i)) + emit.Opcodes(c.prog.BinWriter, base+opcode.Opcode(i)) } else { emit.Instruction(c.prog.BinWriter, base+7, []byte{byte(i)}) } @@ -264,20 +263,20 @@ func (c *codegen) emitDefault(t types.Type) { case info&types.IsBoolean != 0: emit.Bool(c.prog.BinWriter, false) default: - emit.Opcode(c.prog.BinWriter, opcode.PUSHNULL) + emit.Opcodes(c.prog.BinWriter, opcode.PUSHNULL) } case *types.Struct: num := t.NumFields() emit.Int(c.prog.BinWriter, int64(num)) - emit.Opcode(c.prog.BinWriter, opcode.NEWSTRUCT) + emit.Opcodes(c.prog.BinWriter, opcode.NEWSTRUCT) for i := 0; i < num; i++ { - emit.Opcode(c.prog.BinWriter, opcode.DUP) + emit.Opcodes(c.prog.BinWriter, opcode.DUP) emit.Int(c.prog.BinWriter, int64(i)) c.emitDefault(t.Field(i).Type()) - emit.Opcode(c.prog.BinWriter, opcode.SETITEM) + emit.Opcodes(c.prog.BinWriter, opcode.SETITEM) } default: - emit.Opcode(c.prog.BinWriter, opcode.PUSHNULL) + emit.Opcodes(c.prog.BinWriter, opcode.PUSHNULL) } } @@ -389,7 +388,7 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl, pkg *types. // This can be the case with void and named-return functions. if !isInit && !lastStmtIsReturn(decl) { c.saveSequencePoint(decl.Body) - emit.Opcode(c.prog.BinWriter, opcode.RET) + emit.Opcodes(c.prog.BinWriter, opcode.RET) } f.rng.End = uint16(c.prog.Len() - 1) @@ -510,8 +509,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { } ast.Walk(c, t.X) ast.Walk(c, t.Index) - emit.Opcode(c.prog.BinWriter, opcode.ROT) - emit.Opcode(c.prog.BinWriter, opcode.SETITEM) + emit.Opcodes(c.prog.BinWriter, opcode.ROT, opcode.SETITEM) } } return nil @@ -527,19 +525,16 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { if n.Low != nil { ast.Walk(c, n.Low) } else { - emit.Opcode(c.prog.BinWriter, opcode.PUSH0) + emit.Opcodes(c.prog.BinWriter, opcode.PUSH0) } if n.High != nil { ast.Walk(c, n.High) } else { - emit.Opcode(c.prog.BinWriter, opcode.OVER) - emit.Opcode(c.prog.BinWriter, opcode.SIZE) + emit.Opcodes(c.prog.BinWriter, opcode.OVER, opcode.SIZE) } - emit.Opcode(c.prog.BinWriter, opcode.OVER) - emit.Opcode(c.prog.BinWriter, opcode.SUB) - emit.Opcode(c.prog.BinWriter, opcode.SUBSTR) + emit.Opcodes(c.prog.BinWriter, opcode.OVER, opcode.SUB, opcode.SUBSTR) return nil @@ -574,7 +569,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { c.processDefers() c.saveSequencePoint(n) - emit.Opcode(c.prog.BinWriter, opcode.RET) + emit.Opcodes(c.prog.BinWriter, opcode.RET) return nil case *ast.IfStmt: @@ -630,9 +625,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { if l := len(cc.List); l != 0 { // if not `default` for j := range cc.List { - emit.Opcode(c.prog.BinWriter, opcode.DUP) + emit.Opcodes(c.prog.BinWriter, opcode.DUP) ast.Walk(c, cc.List[j]) - emit.Opcode(c.prog.BinWriter, eqOpcode) + emit.Opcodes(c.prog.BinWriter, eqOpcode) if j == l-1 { emit.Jmp(c.prog.BinWriter, opcode.JMPIFNOTL, lEnd) } else { @@ -691,7 +686,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { if tv := c.typeAndValueOf(n); tv.Value != nil { c.emitLoadConst(tv) } else if n.Name == "nil" { - emit.Opcode(c.prog.BinWriter, opcode.PUSHNULL) + emit.Opcodes(c.prog.BinWriter, opcode.PUSHNULL) } else { c.emitLoadVar("", n.Name) } @@ -714,7 +709,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { ast.Walk(c, n.Elts[i]) } emit.Int(c.prog.BinWriter, int64(ln)) - emit.Opcode(c.prog.BinWriter, opcode.PACK) + emit.Opcodes(c.prog.BinWriter, opcode.PACK) } return nil @@ -786,12 +781,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { if ok && !isInteropPath(typ.String()) { // To clone struct fields we create a new array and append struct to it. // This way even non-pointer struct fields will be copied. - emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY0) - emit.Opcode(c.prog.BinWriter, opcode.DUP) - emit.Opcode(c.prog.BinWriter, opcode.ROT) - emit.Opcode(c.prog.BinWriter, opcode.APPEND) - emit.Opcode(c.prog.BinWriter, opcode.PUSH0) - emit.Opcode(c.prog.BinWriter, opcode.PICKITEM) + emit.Opcodes(c.prog.BinWriter, opcode.NEWARRAY0, + opcode.DUP, opcode.ROT, opcode.APPEND, + opcode.PUSH0, opcode.PICKITEM) } } // Do not swap for builtin functions. @@ -802,7 +794,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { varSize := len(n.Args) - typ.Params().Len() + 1 c.emitReverse(varSize) emit.Int(c.prog.BinWriter, int64(varSize)) - emit.Opcode(c.prog.BinWriter, opcode.PACK) + emit.Opcodes(c.prog.BinWriter, opcode.PACK) numArgs -= varSize - 1 } c.emitReverse(numArgs) @@ -822,11 +814,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { c.emitConvert(stackitem.ByteArrayT) } else if isFunc { c.emitLoadVar("", name) - emit.Opcode(c.prog.BinWriter, opcode.CALLA) + emit.Opcodes(c.prog.BinWriter, opcode.CALLA) } case isLiteral: ast.Walk(c, n.Fun) - emit.Opcode(c.prog.BinWriter, opcode.CALLA) + emit.Opcodes(c.prog.BinWriter, opcode.CALLA) case isSyscall(f): c.convertSyscall(n, f.pkg.Name(), f.name) default: @@ -843,7 +835,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { sz = f.Results().Len() } for i := 0; i < sz; i++ { - emit.Opcode(c.prog.BinWriter, opcode.DROP) + emit.Opcodes(c.prog.BinWriter, opcode.DROP) } } @@ -909,11 +901,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: - emit.Opcode(c.prog.BinWriter, opcode.NEGATE) + emit.Opcodes(c.prog.BinWriter, opcode.NEGATE) case token.NOT: - emit.Opcode(c.prog.BinWriter, opcode.NOT) + emit.Opcodes(c.prog.BinWriter, opcode.NOT) case token.XOR: - emit.Opcode(c.prog.BinWriter, opcode.INVERT) + emit.Opcodes(c.prog.BinWriter, opcode.INVERT) default: c.prog.Err = fmt.Errorf("invalid unary operator: %s", n.Op) return nil @@ -937,7 +929,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { // This will load local whatever X is. ast.Walk(c, n.X) ast.Walk(c, n.Index) - emit.Opcode(c.prog.BinWriter, opcode.PICKITEM) // just pickitem here + emit.Opcodes(c.prog.BinWriter, opcode.PICKITEM) // just pickitem here return nil @@ -1049,13 +1041,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { // For slices we iterate index from 0 to len-1, storing array, len and index on stack. // For maps we iterate index from 0 to len-1, storing map, keyarray, size and index on stack. _, isMap := c.typeOf(n.X).Underlying().(*types.Map) - emit.Opcode(c.prog.BinWriter, opcode.DUP) + emit.Opcodes(c.prog.BinWriter, opcode.DUP) if isMap { - emit.Opcode(c.prog.BinWriter, opcode.KEYS) - emit.Opcode(c.prog.BinWriter, opcode.DUP) + emit.Opcodes(c.prog.BinWriter, opcode.KEYS, opcode.DUP) } - emit.Opcode(c.prog.BinWriter, opcode.SIZE) - emit.Opcode(c.prog.BinWriter, opcode.PUSH0) + emit.Opcodes(c.prog.BinWriter, opcode.SIZE, opcode.PUSH0) stackSize := 3 // slice, len(slice), index if isMap { @@ -1064,8 +1054,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { c.pushStackLabel(label, stackSize) c.setLabel(start) - emit.Opcode(c.prog.BinWriter, opcode.OVER) - emit.Opcode(c.prog.BinWriter, opcode.OVER) + emit.Opcodes(c.prog.BinWriter, opcode.OVER, opcode.OVER) emit.Jmp(c.prog.BinWriter, opcode.JMPLEL, end) var keyLoaded bool @@ -1074,11 +1063,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { if isMap { c.rangeLoadKey() if needValue { - emit.Opcode(c.prog.BinWriter, opcode.DUP) + emit.Opcodes(c.prog.BinWriter, opcode.DUP) keyLoaded = true } } else { - emit.Opcode(c.prog.BinWriter, opcode.DUP) + emit.Opcodes(c.prog.BinWriter, opcode.DUP) } c.emitStoreVar("", n.Key.(*ast.Ident).Name) } @@ -1089,9 +1078,10 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { if isMap { // we have loaded only key from key array, now load value emit.Int(c.prog.BinWriter, 4) - emit.Opcode(c.prog.BinWriter, opcode.PICK) // load map itself (+1 because key was pushed) - emit.Opcode(c.prog.BinWriter, opcode.SWAP) // key should be on top - emit.Opcode(c.prog.BinWriter, opcode.PICKITEM) + emit.Opcodes(c.prog.BinWriter, + opcode.PICK, // load map itself (+1 because key was pushed) + opcode.SWAP, // key should be on top + opcode.PICKITEM) } c.emitStoreVar("", n.Value.(*ast.Ident).Name) } @@ -1100,7 +1090,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { c.setLabel(post) - emit.Opcode(c.prog.BinWriter, opcode.INC) + emit.Opcodes(c.prog.BinWriter, opcode.INC) emit.Jmp(c.prog.BinWriter, opcode.JMPL, start) c.setLabel(end) @@ -1164,16 +1154,17 @@ func (c *codegen) processDefers() { c.setLabel(before) emit.Int(c.prog.BinWriter, 0) c.emitStoreByIndex(varLocal, c.scope.finallyProcessedIndex) - emit.Opcode(c.prog.BinWriter, opcode.ENDFINALLY) + emit.Opcodes(c.prog.BinWriter, opcode.ENDFINALLY) c.setLabel(after) } } func (c *codegen) rangeLoadKey() { emit.Int(c.prog.BinWriter, 2) - emit.Opcode(c.prog.BinWriter, opcode.PICK) // load keys - emit.Opcode(c.prog.BinWriter, opcode.OVER) // load index in key array - emit.Opcode(c.prog.BinWriter, opcode.PICKITEM) + emit.Opcodes(c.prog.BinWriter, + opcode.PICK, // load keys + opcode.OVER, // load index in key array + opcode.PICKITEM) } func isFallthroughStmt(c ast.Node) bool { @@ -1230,11 +1221,11 @@ func (c *codegen) emitBinaryExpr(n *ast.BinaryExpr, needJump bool, cond bool, jm return } else if arg := c.getCompareWithNilArg(n); arg != nil { ast.Walk(c, arg) - emit.Opcode(c.prog.BinWriter, opcode.ISNULL) + emit.Opcodes(c.prog.BinWriter, opcode.ISNULL) if needJump { c.emitJumpOnCondition(cond == (n.Op == token.EQL), jmpLabel) } else if n.Op == token.NEQ { - emit.Opcode(c.prog.BinWriter, opcode.NOT) + emit.Opcodes(c.prog.BinWriter, opcode.NOT) } return } @@ -1299,14 +1290,13 @@ func (c *codegen) dropStackLabel() { func (c *codegen) dropItems(n int) { if n < 4 { for i := 0; i < n; i++ { - emit.Opcode(c.prog.BinWriter, opcode.DROP) + emit.Opcodes(c.prog.BinWriter, opcode.DROP) } return } emit.Int(c.prog.BinWriter, int64(n)) - emit.Opcode(c.prog.BinWriter, opcode.PACK) - emit.Opcode(c.prog.BinWriter, opcode.DROP) + emit.Opcodes(c.prog.BinWriter, opcode.PACK, opcode.DROP) } // emitReverse reverses top num items of the stack. @@ -1314,14 +1304,14 @@ func (c *codegen) emitReverse(num int) { switch num { case 0, 1: case 2: - emit.Opcode(c.prog.BinWriter, opcode.SWAP) + emit.Opcodes(c.prog.BinWriter, opcode.SWAP) case 3: - emit.Opcode(c.prog.BinWriter, opcode.REVERSE3) + emit.Opcodes(c.prog.BinWriter, opcode.REVERSE3) case 4: - emit.Opcode(c.prog.BinWriter, opcode.REVERSE4) + emit.Opcodes(c.prog.BinWriter, opcode.REVERSE4) default: emit.Int(c.prog.BinWriter, int64(num)) - emit.Opcode(c.prog.BinWriter, opcode.REVERSEN) + emit.Opcodes(c.prog.BinWriter, opcode.REVERSEN) } } @@ -1400,7 +1390,7 @@ func (c *codegen) convertSyscall(expr *ast.CallExpr, 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. - emit.Opcode(c.prog.BinWriter, opcode.NOP) + emit.Opcodes(c.prog.BinWriter, opcode.NOP) } // emitSliceHelper emits 3 items on stack: slice, its first index, and its size. @@ -1416,8 +1406,7 @@ func (c *codegen) emitSliceHelper(e ast.Expr) { if src.High != nil { ast.Walk(c, src.High) } else { - emit.Opcode(c.prog.BinWriter, opcode.DUP) - emit.Opcode(c.prog.BinWriter, opcode.SIZE) + emit.Opcodes(c.prog.BinWriter, opcode.DUP, opcode.SIZE) } if src.Low != nil { ast.Walk(c, src.Low) @@ -1427,17 +1416,13 @@ func (c *codegen) emitSliceHelper(e ast.Expr) { } default: ast.Walk(c, src) - emit.Opcode(c.prog.BinWriter, opcode.DUP) - emit.Opcode(c.prog.BinWriter, opcode.SIZE) + emit.Opcodes(c.prog.BinWriter, opcode.DUP, opcode.SIZE) emit.Int(c.prog.BinWriter, 0) } if !hasLowIndex { - emit.Opcode(c.prog.BinWriter, opcode.SWAP) + emit.Opcodes(c.prog.BinWriter, opcode.SWAP) } else { - emit.Opcode(c.prog.BinWriter, opcode.DUP) - emit.Opcode(c.prog.BinWriter, opcode.ROT) - emit.Opcode(c.prog.BinWriter, opcode.SWAP) - emit.Opcode(c.prog.BinWriter, opcode.SUB) + emit.Opcodes(c.prog.BinWriter, opcode.DUP, opcode.ROT, opcode.SWAP, opcode.SUB) } } @@ -1456,22 +1441,21 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) { c.emitSliceHelper(expr.Args[0]) c.emitSliceHelper(expr.Args[1]) emit.Int(c.prog.BinWriter, 3) - emit.Opcode(c.prog.BinWriter, opcode.ROLL) - emit.Opcode(c.prog.BinWriter, opcode.MIN) + emit.Opcodes(c.prog.BinWriter, opcode.ROLL, opcode.MIN) if !c.scope.voidCalls[expr] { // insert top item to the bottom of MEMCPY args, so that it is left on stack - emit.Opcode(c.prog.BinWriter, opcode.DUP) + emit.Opcodes(c.prog.BinWriter, opcode.DUP) emit.Int(c.prog.BinWriter, 6) - emit.Opcode(c.prog.BinWriter, opcode.REVERSEN) + emit.Opcodes(c.prog.BinWriter, opcode.REVERSEN) emit.Int(c.prog.BinWriter, 5) - emit.Opcode(c.prog.BinWriter, opcode.REVERSEN) + emit.Opcodes(c.prog.BinWriter, opcode.REVERSEN) } - emit.Opcode(c.prog.BinWriter, opcode.MEMCPY) + emit.Opcodes(c.prog.BinWriter, opcode.MEMCPY) case "make": typ := c.typeOf(expr.Args[0]) switch { case isMap(typ): - emit.Opcode(c.prog.BinWriter, opcode.NEWMAP) + emit.Opcodes(c.prog.BinWriter, opcode.NEWMAP) default: if len(expr.Args) == 3 { c.prog.Err = fmt.Errorf("`make()` with a capacity argument is not supported") @@ -1479,57 +1463,47 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) { } ast.Walk(c, expr.Args[1]) if isByteSlice(typ) { - emit.Opcode(c.prog.BinWriter, opcode.NEWBUFFER) + emit.Opcodes(c.prog.BinWriter, opcode.NEWBUFFER) } else { neoT := toNeoType(typ.(*types.Slice).Elem()) emit.Instruction(c.prog.BinWriter, opcode.NEWARRAYT, []byte{byte(neoT)}) } } case "len": - emit.Opcode(c.prog.BinWriter, opcode.DUP) - emit.Opcode(c.prog.BinWriter, opcode.ISNULL) + emit.Opcodes(c.prog.BinWriter, opcode.DUP, opcode.ISNULL) emit.Instruction(c.prog.BinWriter, opcode.JMPIF, []byte{2 + 1 + 2}) - emit.Opcode(c.prog.BinWriter, opcode.SIZE) + emit.Opcodes(c.prog.BinWriter, opcode.SIZE) emit.Instruction(c.prog.BinWriter, opcode.JMP, []byte{2 + 1 + 1}) - emit.Opcode(c.prog.BinWriter, opcode.DROP) - emit.Opcode(c.prog.BinWriter, opcode.PUSH0) + emit.Opcodes(c.prog.BinWriter, opcode.DROP, opcode.PUSH0) case "append": arg := expr.Args[0] typ := c.typeInfo.Types[arg].Type c.emitReverse(len(expr.Args)) - emit.Opcode(c.prog.BinWriter, opcode.DUP) - emit.Opcode(c.prog.BinWriter, opcode.ISNULL) + emit.Opcodes(c.prog.BinWriter, opcode.DUP, opcode.ISNULL) emit.Instruction(c.prog.BinWriter, opcode.JMPIFNOT, []byte{2 + 3}) if isByteSlice(typ) { - emit.Opcode(c.prog.BinWriter, opcode.DROP) - emit.Opcode(c.prog.BinWriter, opcode.PUSH0) - emit.Opcode(c.prog.BinWriter, opcode.NEWBUFFER) + emit.Opcodes(c.prog.BinWriter, opcode.DROP, opcode.PUSH0, opcode.NEWBUFFER) } else { - emit.Opcode(c.prog.BinWriter, opcode.DROP) - emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY0) - emit.Opcode(c.prog.BinWriter, opcode.NOP) + emit.Opcodes(c.prog.BinWriter, opcode.DROP, opcode.NEWARRAY0, opcode.NOP) } // Jump target. for range expr.Args[1:] { if isByteSlice(typ) { - emit.Opcode(c.prog.BinWriter, opcode.SWAP) - emit.Opcode(c.prog.BinWriter, opcode.CAT) + emit.Opcodes(c.prog.BinWriter, opcode.SWAP, opcode.CAT) } else { - emit.Opcode(c.prog.BinWriter, opcode.DUP) - emit.Opcode(c.prog.BinWriter, opcode.ROT) - emit.Opcode(c.prog.BinWriter, opcode.APPEND) + emit.Opcodes(c.prog.BinWriter, opcode.DUP, opcode.ROT, opcode.APPEND) } } case "panic": - emit.Opcode(c.prog.BinWriter, opcode.THROW) + emit.Opcodes(c.prog.BinWriter, opcode.THROW) case "recover": if !c.scope.voidCalls[expr] { c.emitLoadByIndex(varGlobal, c.exceptionIndex) } - emit.Opcode(c.prog.BinWriter, opcode.PUSHNULL) + emit.Opcodes(c.prog.BinWriter, opcode.PUSHNULL) c.emitStoreByIndex(varGlobal, c.exceptionIndex) case "delete": - emit.Opcode(c.prog.BinWriter, opcode.REMOVE) + emit.Opcodes(c.prog.BinWriter, opcode.REMOVE) case "ToInteger", "ToByteArray", "ToBool": typ := stackitem.IntegerT switch name { @@ -1544,9 +1518,9 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) { c.prog.Err = errors.New("`Remove` supports only non-byte slices") return } - emit.Opcode(c.prog.BinWriter, opcode.REMOVE) + emit.Opcodes(c.prog.BinWriter, opcode.REMOVE) case "Equals": - emit.Opcode(c.prog.BinWriter, opcode.EQUAL) + emit.Opcodes(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 @@ -1607,21 +1581,21 @@ func (c *codegen) convertByteArray(lit *ast.CompositeLit) { emit.Bytes(c.prog.BinWriter, buf) c.emitConvert(stackitem.BufferT) for _, i := range varIndices { - emit.Opcode(c.prog.BinWriter, opcode.DUP) + emit.Opcodes(c.prog.BinWriter, opcode.DUP) emit.Int(c.prog.BinWriter, int64(i)) ast.Walk(c, lit.Elts[i]) - emit.Opcode(c.prog.BinWriter, opcode.SETITEM) + emit.Opcodes(c.prog.BinWriter, opcode.SETITEM) } } func (c *codegen) convertMap(lit *ast.CompositeLit) { - emit.Opcode(c.prog.BinWriter, opcode.NEWMAP) + emit.Opcodes(c.prog.BinWriter, opcode.NEWMAP) for i := range lit.Elts { elem := lit.Elts[i].(*ast.KeyValueExpr) - emit.Opcode(c.prog.BinWriter, opcode.DUP) + emit.Opcodes(c.prog.BinWriter, opcode.DUP) ast.Walk(c, elem.Key) ast.Walk(c, elem.Value) - emit.Opcode(c.prog.BinWriter, opcode.SETITEM) + emit.Opcodes(c.prog.BinWriter, opcode.SETITEM) } } @@ -1646,12 +1620,12 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit, ptr bool) { return } - emit.Opcode(c.prog.BinWriter, opcode.NOP) + emit.Opcodes(c.prog.BinWriter, opcode.NOP) emit.Int(c.prog.BinWriter, int64(strct.NumFields())) if ptr { - emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY) + emit.Opcodes(c.prog.BinWriter, opcode.NEWARRAY) } else { - emit.Opcode(c.prog.BinWriter, opcode.NEWSTRUCT) + emit.Opcodes(c.prog.BinWriter, opcode.NEWSTRUCT) } keyedLit := len(lit.Elts) > 0 @@ -1665,7 +1639,7 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit, ptr bool) { sField := strct.Field(i) var initialized bool - emit.Opcode(c.prog.BinWriter, opcode.DUP) + emit.Opcodes(c.prog.BinWriter, opcode.DUP) emit.Int(c.prog.BinWriter, int64(i)) if !keyedLit { @@ -1689,7 +1663,7 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit, ptr bool) { if !initialized { c.emitDefault(sField.Type()) } - emit.Opcode(c.prog.BinWriter, opcode.SETITEM) + emit.Opcodes(c.prog.BinWriter, opcode.SETITEM) } } @@ -1699,7 +1673,7 @@ func (c *codegen) emitToken(tok token.Token, typ types.Type) { c.prog.Err = err return } - emit.Opcode(c.prog.BinWriter, op) + emit.Opcodes(c.prog.BinWriter, op) } func convertToken(tok token.Token, typ types.Type) (opcode.Opcode, error) { @@ -1805,7 +1779,7 @@ func (c *codegen) compile(info *buildInfo, pkg *loader.PackageInfo) error { n, hasInit := c.traverseGlobals() if n > 0 || hasInit { - emit.Opcode(c.prog.BinWriter, opcode.RET) + emit.Opcodes(c.prog.BinWriter, opcode.RET) c.initEndOffset = c.prog.Len() } diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index 0b069c6b6..d3058776b 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -237,12 +237,12 @@ func TestVerifyTx(t *testing.T) { } emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", neoOwner, a.Contract.ScriptHash(), amount) - emit.Opcode(w.BinWriter, opcode.ASSERT) + emit.Opcodes(w.BinWriter, opcode.ASSERT) } } emit.AppCallWithOperationAndArgs(w.BinWriter, gasHash, "transfer", neoOwner, testchain.CommitteeScriptHash(), int64(1_000_000_000)) - emit.Opcode(w.BinWriter, opcode.ASSERT) + emit.Opcodes(w.BinWriter, opcode.ASSERT) require.NoError(t, w.Err) txMove := bc.newTestTx(neoOwner, w.Bytes()) @@ -782,7 +782,7 @@ func TestSubscriptions(t *testing.T) { script = io.NewBufBinWriter() emit.Bytes(script.BinWriter, []byte("nay!")) emit.Syscall(script.BinWriter, interopnames.SystemRuntimeNotify) - emit.Opcode(script.BinWriter, opcode.THROW) + emit.Opcodes(script.BinWriter, opcode.THROW) require.NoError(t, script.Err) txBad := transaction.New(netmode.UnitTestNet, script.Bytes(), 0) txBad.Signers = []transaction.Signer{{Account: neoOwner}} diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index e918bde1f..5dfe24c90 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -361,7 +361,7 @@ func TestCreateBasicChain(t *testing.T) { func newNEP5Transfer(sc, from, to util.Uint160, amount int64) *transaction.Transaction { w := io.NewBufBinWriter() emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", from, to, amount) - emit.Opcode(w.BinWriter, opcode.ASSERT) + emit.Opcodes(w.BinWriter, opcode.ASSERT) script := w.Bytes() return transaction.New(testchain.Network(), script, 10000000) diff --git a/pkg/core/native/contract.go b/pkg/core/native/contract.go index e3ab6a18b..bd6de2605 100644 --- a/pkg/core/native/contract.go +++ b/pkg/core/native/contract.go @@ -83,10 +83,10 @@ func (cs *Contracts) GetPersistScript() []byte { continue } emit.Int(w.BinWriter, 0) - emit.Opcode(w.BinWriter, opcode.NEWARRAY) + emit.Opcodes(w.BinWriter, opcode.NEWARRAY) emit.String(w.BinWriter, "onPersist") emit.AppCall(w.BinWriter, md.Hash) - emit.Opcode(w.BinWriter, opcode.DROP) + emit.Opcodes(w.BinWriter, opcode.DROP) } cs.persistScript = w.Bytes() return cs.persistScript @@ -106,10 +106,10 @@ func (cs *Contracts) GetPostPersistScript() []byte { continue } emit.Int(w.BinWriter, 0) - emit.Opcode(w.BinWriter, opcode.NEWARRAY) + emit.Opcodes(w.BinWriter, opcode.NEWARRAY) emit.String(w.BinWriter, "postPersist") emit.AppCall(w.BinWriter, md.Hash) - emit.Opcode(w.BinWriter, opcode.DROP) + emit.Opcodes(w.BinWriter, opcode.DROP) } cs.postPersistScript = w.Bytes() return cs.postPersistScript diff --git a/pkg/core/native/oracle.go b/pkg/core/native/oracle.go index 4bd88e11f..2a695bb9d 100644 --- a/pkg/core/native/oracle.go +++ b/pkg/core/native/oracle.go @@ -56,7 +56,7 @@ func init() { w.Reset() emit.Int(w.BinWriter, 0) - emit.Opcode(w.BinWriter, opcode.NEWARRAY) + emit.Opcodes(w.BinWriter, opcode.NEWARRAY) emit.String(w.BinWriter, "finish") emit.Bytes(w.BinWriter, h.BytesBE()) emit.Syscall(w.BinWriter, interopnames.SystemContractCall) diff --git a/pkg/core/native_designate_test.go b/pkg/core/native_designate_test.go index 33bbd6e57..c15098a59 100644 --- a/pkg/core/native_designate_test.go +++ b/pkg/core/native_designate_test.go @@ -23,10 +23,10 @@ func (bc *Blockchain) setNodesByRole(t *testing.T, ok bool, r native.Role, nodes emit.Bytes(w.BinWriter, pub.Bytes()) } emit.Int(w.BinWriter, int64(len(nodes))) - emit.Opcode(w.BinWriter, opcode.PACK) + emit.Opcodes(w.BinWriter, opcode.PACK) emit.Int(w.BinWriter, int64(r)) emit.Int(w.BinWriter, 2) - emit.Opcode(w.BinWriter, opcode.PACK) + emit.Opcodes(w.BinWriter, opcode.PACK) emit.String(w.BinWriter, "designateAsRole") emit.AppCall(w.BinWriter, bc.contracts.Designate.Hash) require.NoError(t, w.Err) diff --git a/pkg/core/native_oracle_test.go b/pkg/core/native_oracle_test.go index 2248c5400..1b93e6ffd 100644 --- a/pkg/core/native_oracle_test.go +++ b/pkg/core/native_oracle_test.go @@ -27,26 +27,26 @@ import ( func getOracleContractState(h util.Uint160) *state.Contract { w := io.NewBufBinWriter() emit.Int(w.BinWriter, 5) - emit.Opcode(w.BinWriter, opcode.PACK) + emit.Opcodes(w.BinWriter, opcode.PACK) emit.String(w.BinWriter, "request") emit.Bytes(w.BinWriter, h.BytesBE()) emit.Syscall(w.BinWriter, interopnames.SystemContractCall) - emit.Opcode(w.BinWriter, opcode.RET) + emit.Opcodes(w.BinWriter, opcode.RET) // `handle` method aborts if len(userData) == 2 offset := w.Len() - emit.Opcode(w.BinWriter, opcode.OVER) - emit.Opcode(w.BinWriter, opcode.SIZE) + emit.Opcodes(w.BinWriter, opcode.OVER) + emit.Opcodes(w.BinWriter, opcode.SIZE) emit.Int(w.BinWriter, 2) emit.Instruction(w.BinWriter, opcode.JMPNE, []byte{3}) - emit.Opcode(w.BinWriter, opcode.ABORT) + emit.Opcodes(w.BinWriter, opcode.ABORT) emit.Int(w.BinWriter, 4) // url, userData, code, result - emit.Opcode(w.BinWriter, opcode.PACK) + emit.Opcodes(w.BinWriter, opcode.PACK) emit.Syscall(w.BinWriter, interopnames.SystemBinarySerialize) emit.String(w.BinWriter, "lastOracleResponse") emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext) emit.Syscall(w.BinWriter, interopnames.SystemStoragePut) - emit.Opcode(w.BinWriter, opcode.RET) + emit.Opcodes(w.BinWriter, opcode.RET) m := manifest.NewManifest(h) m.Features = smartcontract.HasStorage diff --git a/pkg/crypto/keys/publickey.go b/pkg/crypto/keys/publickey.go index f10f4e628..0daa0431c 100644 --- a/pkg/crypto/keys/publickey.go +++ b/pkg/crypto/keys/publickey.go @@ -314,7 +314,7 @@ func (p *PublicKey) GetVerificationScript() []byte { return buf.Bytes() } emit.Bytes(buf.BinWriter, b) - emit.Opcode(buf.BinWriter, opcode.PUSHNULL) + emit.Opcodes(buf.BinWriter, opcode.PUSHNULL) emit.Syscall(buf.BinWriter, interopnames.NeoCryptoVerifyWithECDsaSecp256r1) return buf.Bytes() diff --git a/pkg/rpc/client/nep5.go b/pkg/rpc/client/nep5.go index 1fc5fa89b..876dc13e8 100644 --- a/pkg/rpc/client/nep5.go +++ b/pkg/rpc/client/nep5.go @@ -132,7 +132,7 @@ func (c *Client) CreateNEP5MultiTransferTx(acc *wallet.Account, gas int64, recip for i := range recipients { emit.AppCallWithOperationAndArgs(w.BinWriter, recipients[i].Token, "transfer", from, recipients[i].Address, recipients[i].Amount) - emit.Opcode(w.BinWriter, opcode.ASSERT) + emit.Opcodes(w.BinWriter, opcode.ASSERT) } return c.CreateTxFromScript(w.Bytes(), acc, -1, gas, transaction.Signer{ Account: acc.Contract.ScriptHash(), diff --git a/pkg/rpc/request/txBuilder.go b/pkg/rpc/request/txBuilder.go index 82d8507d8..610b9fc7b 100644 --- a/pkg/rpc/request/txBuilder.go +++ b/pkg/rpc/request/txBuilder.go @@ -107,7 +107,7 @@ func expandArrayIntoScript(script *io.BinWriter, slice []Param) error { return err } emit.Int(script, int64(len(val))) - emit.Opcode(script, opcode.PACK) + emit.Opcodes(script, opcode.PACK) default: return fmt.Errorf("parameter type %v is not supported", fp.Type) } @@ -139,7 +139,7 @@ func CreateFunctionInvocationScript(contract util.Uint160, params Params) ([]byt return nil, err } emit.Int(script.BinWriter, int64(len(slice))) - emit.Opcode(script.BinWriter, opcode.PACK) + emit.Opcodes(script.BinWriter, opcode.PACK) } } diff --git a/pkg/smartcontract/contract.go b/pkg/smartcontract/contract.go index 6a88fe07b..0de8ade41 100644 --- a/pkg/smartcontract/contract.go +++ b/pkg/smartcontract/contract.go @@ -31,7 +31,7 @@ func CreateMultiSigRedeemScript(m int, publicKeys keys.PublicKeys) ([]byte, erro emit.Bytes(buf.BinWriter, pubKey.Bytes()) } emit.Int(buf.BinWriter, int64(len(publicKeys))) - emit.Opcode(buf.BinWriter, opcode.PUSHNULL) + emit.Opcodes(buf.BinWriter, opcode.PUSHNULL) emit.Syscall(buf.BinWriter, interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1) return buf.Bytes(), nil diff --git a/pkg/vm/emit/emit.go b/pkg/vm/emit/emit.go index a5ce828df..a4825e82f 100644 --- a/pkg/vm/emit/emit.go +++ b/pkg/vm/emit/emit.go @@ -21,18 +21,20 @@ func Instruction(w *io.BinWriter, op opcode.Opcode, b []byte) { w.WriteBytes(b) } -// Opcode emits a single VM Instruction without arguments to the given buffer. -func Opcode(w *io.BinWriter, op opcode.Opcode) { - w.WriteB(byte(op)) +// Opcodes emits a single VM Instruction without arguments to the given buffer. +func Opcodes(w *io.BinWriter, ops ...opcode.Opcode) { + for _, op := range ops { + w.WriteB(byte(op)) + } } // Bool emits a bool type the given buffer. func Bool(w *io.BinWriter, ok bool) { if ok { - Opcode(w, opcode.PUSHT) + Opcodes(w, opcode.PUSHT) return } - Opcode(w, opcode.PUSHF) + Opcodes(w, opcode.PUSHF) Instruction(w, opcode.CONVERT, []byte{byte(stackitem.BooleanT)}) } @@ -51,15 +53,15 @@ func padRight(s int, buf []byte) []byte { func Int(w *io.BinWriter, i int64) { switch { case i == -1: - Opcode(w, opcode.PUSHM1) + Opcodes(w, opcode.PUSHM1) case i >= 0 && i < 16: val := opcode.Opcode(int(opcode.PUSH1) - 1 + int(i)) - Opcode(w, val) + Opcodes(w, val) default: buf := bigint.ToPreallocatedBytes(big.NewInt(i), make([]byte, 0, 32)) // l != 0 becase of switch padSize := byte(8 - bits.LeadingZeros8(byte(len(buf)-1))) - Opcode(w, opcode.PUSHINT8+opcode.Opcode(padSize)) + Opcodes(w, opcode.PUSHINT8+opcode.Opcode(padSize)) w.WriteBytes(padRight(1<