emit: accept multiple opcodes in Opcode()

This commit is contained in:
Evgenii Stratonikov 2020-10-02 11:30:15 +03:00
parent 0e82d4cbd1
commit b2a3a0851e
15 changed files with 145 additions and 162 deletions

View file

@ -102,7 +102,7 @@ func handleCandidate(ctx *cli.Context, method string) error {
gas := flags.Fixed8FromContext(ctx, "gas") gas := flags.Fixed8FromContext(ctx, "gas")
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, client.NeoContractHash, method, acc.PrivateKey().PublicKey().Bytes()) 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{ tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas), transaction.Signer{
Account: acc.Contract.ScriptHash(), Account: acc.Contract.ScriptHash(),
Scopes: transaction.CalledByEntry, Scopes: transaction.CalledByEntry,
@ -160,7 +160,7 @@ func handleVote(ctx *cli.Context) error {
gas := flags.Fixed8FromContext(ctx, "gas") gas := flags.Fixed8FromContext(ctx, "gas")
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, client.NeoContractHash, "vote", addr.BytesBE(), pubArg) 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{ tx, err := c.CreateTxFromScript(w.Bytes(), acc, -1, int64(gas), transaction.Signer{
Account: acc.Contract.ScriptHash(), Account: acc.Contract.ScriptHash(),

View file

@ -176,13 +176,12 @@ func (c *codegen) emitLoadConst(t types.TypeAndValue) {
func (c *codegen) emitLoadField(i int) { func (c *codegen) emitLoadField(i int) {
emit.Int(c.prog.BinWriter, int64(i)) 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) { func (c *codegen) emitStoreStructField(i int) {
emit.Int(c.prog.BinWriter, int64(i)) emit.Int(c.prog.BinWriter, int64(i))
emit.Opcode(c.prog.BinWriter, opcode.ROT) emit.Opcodes(c.prog.BinWriter, opcode.ROT, opcode.SETITEM)
emit.Opcode(c.prog.BinWriter, opcode.SETITEM)
} }
// getVarIndex returns variable type and position in corresponding slot, // 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) { func (c *codegen) emitLoadByIndex(t varType, i int) {
base, _ := getBaseOpcode(t) base, _ := getBaseOpcode(t)
if i < 7 { if i < 7 {
emit.Opcode(c.prog.BinWriter, base+opcode.Opcode(i)) emit.Opcodes(c.prog.BinWriter, base+opcode.Opcode(i))
} else { } else {
emit.Instruction(c.prog.BinWriter, base+7, []byte{byte(i)}) 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. // emitStoreVar stores top value from the evaluation stack in the specified variable.
func (c *codegen) emitStoreVar(pkg string, name string) { func (c *codegen) emitStoreVar(pkg string, name string) {
if name == "_" { if name == "_" {
emit.Opcode(c.prog.BinWriter, opcode.DROP) emit.Opcodes(c.prog.BinWriter, opcode.DROP)
return return
} }
t, i := c.getVarIndex(pkg, name) 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) { func (c *codegen) emitStoreByIndex(t varType, i int) {
_, base := getBaseOpcode(t) _, base := getBaseOpcode(t)
if i < 7 { if i < 7 {
emit.Opcode(c.prog.BinWriter, base+opcode.Opcode(i)) emit.Opcodes(c.prog.BinWriter, base+opcode.Opcode(i))
} else { } else {
emit.Instruction(c.prog.BinWriter, base+7, []byte{byte(i)}) 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: case info&types.IsBoolean != 0:
emit.Bool(c.prog.BinWriter, false) emit.Bool(c.prog.BinWriter, false)
default: default:
emit.Opcode(c.prog.BinWriter, opcode.PUSHNULL) emit.Opcodes(c.prog.BinWriter, opcode.PUSHNULL)
} }
case *types.Struct: case *types.Struct:
num := t.NumFields() num := t.NumFields()
emit.Int(c.prog.BinWriter, int64(num)) 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++ { 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)) emit.Int(c.prog.BinWriter, int64(i))
c.emitDefault(t.Field(i).Type()) c.emitDefault(t.Field(i).Type())
emit.Opcode(c.prog.BinWriter, opcode.SETITEM) emit.Opcodes(c.prog.BinWriter, opcode.SETITEM)
} }
default: 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. // This can be the case with void and named-return functions.
if !isInit && !lastStmtIsReturn(decl) { if !isInit && !lastStmtIsReturn(decl) {
c.saveSequencePoint(decl.Body) 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) 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.X)
ast.Walk(c, t.Index) ast.Walk(c, t.Index)
emit.Opcode(c.prog.BinWriter, opcode.ROT) emit.Opcodes(c.prog.BinWriter, opcode.ROT, opcode.SETITEM)
emit.Opcode(c.prog.BinWriter, opcode.SETITEM)
} }
} }
return nil return nil
@ -527,19 +525,16 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
if n.Low != nil { if n.Low != nil {
ast.Walk(c, n.Low) ast.Walk(c, n.Low)
} else { } else {
emit.Opcode(c.prog.BinWriter, opcode.PUSH0) emit.Opcodes(c.prog.BinWriter, opcode.PUSH0)
} }
if n.High != nil { if n.High != nil {
ast.Walk(c, n.High) ast.Walk(c, n.High)
} else { } else {
emit.Opcode(c.prog.BinWriter, opcode.OVER) emit.Opcodes(c.prog.BinWriter, opcode.OVER, opcode.SIZE)
emit.Opcode(c.prog.BinWriter, opcode.SIZE)
} }
emit.Opcode(c.prog.BinWriter, opcode.OVER) emit.Opcodes(c.prog.BinWriter, opcode.OVER, opcode.SUB, opcode.SUBSTR)
emit.Opcode(c.prog.BinWriter, opcode.SUB)
emit.Opcode(c.prog.BinWriter, opcode.SUBSTR)
return nil return nil
@ -574,7 +569,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
c.processDefers() c.processDefers()
c.saveSequencePoint(n) c.saveSequencePoint(n)
emit.Opcode(c.prog.BinWriter, opcode.RET) emit.Opcodes(c.prog.BinWriter, opcode.RET)
return nil return nil
case *ast.IfStmt: 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` if l := len(cc.List); l != 0 { // if not `default`
for j := range cc.List { 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]) ast.Walk(c, cc.List[j])
emit.Opcode(c.prog.BinWriter, eqOpcode) emit.Opcodes(c.prog.BinWriter, eqOpcode)
if j == l-1 { if j == l-1 {
emit.Jmp(c.prog.BinWriter, opcode.JMPIFNOTL, lEnd) emit.Jmp(c.prog.BinWriter, opcode.JMPIFNOTL, lEnd)
} else { } else {
@ -691,7 +686,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
if tv := c.typeAndValueOf(n); tv.Value != nil { if tv := c.typeAndValueOf(n); tv.Value != nil {
c.emitLoadConst(tv) c.emitLoadConst(tv)
} else if n.Name == "nil" { } else if n.Name == "nil" {
emit.Opcode(c.prog.BinWriter, opcode.PUSHNULL) emit.Opcodes(c.prog.BinWriter, opcode.PUSHNULL)
} else { } else {
c.emitLoadVar("", n.Name) c.emitLoadVar("", n.Name)
} }
@ -714,7 +709,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
ast.Walk(c, n.Elts[i]) ast.Walk(c, n.Elts[i])
} }
emit.Int(c.prog.BinWriter, int64(ln)) emit.Int(c.prog.BinWriter, int64(ln))
emit.Opcode(c.prog.BinWriter, opcode.PACK) emit.Opcodes(c.prog.BinWriter, opcode.PACK)
} }
return nil return nil
@ -786,12 +781,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
if ok && !isInteropPath(typ.String()) { if ok && !isInteropPath(typ.String()) {
// To clone struct fields we create a new array and append struct to it. // To clone struct fields we create a new array and append struct to it.
// This way even non-pointer struct fields will be copied. // This way even non-pointer struct fields will be copied.
emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY0) emit.Opcodes(c.prog.BinWriter, opcode.NEWARRAY0,
emit.Opcode(c.prog.BinWriter, opcode.DUP) opcode.DUP, opcode.ROT, opcode.APPEND,
emit.Opcode(c.prog.BinWriter, opcode.ROT) opcode.PUSH0, opcode.PICKITEM)
emit.Opcode(c.prog.BinWriter, opcode.APPEND)
emit.Opcode(c.prog.BinWriter, opcode.PUSH0)
emit.Opcode(c.prog.BinWriter, opcode.PICKITEM)
} }
} }
// Do not swap for builtin functions. // 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 varSize := len(n.Args) - typ.Params().Len() + 1
c.emitReverse(varSize) c.emitReverse(varSize)
emit.Int(c.prog.BinWriter, int64(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 numArgs -= varSize - 1
} }
c.emitReverse(numArgs) c.emitReverse(numArgs)
@ -822,11 +814,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
c.emitConvert(stackitem.ByteArrayT) c.emitConvert(stackitem.ByteArrayT)
} else if isFunc { } else if isFunc {
c.emitLoadVar("", name) c.emitLoadVar("", name)
emit.Opcode(c.prog.BinWriter, opcode.CALLA) emit.Opcodes(c.prog.BinWriter, opcode.CALLA)
} }
case isLiteral: case isLiteral:
ast.Walk(c, n.Fun) ast.Walk(c, n.Fun)
emit.Opcode(c.prog.BinWriter, opcode.CALLA) emit.Opcodes(c.prog.BinWriter, opcode.CALLA)
case isSyscall(f): case isSyscall(f):
c.convertSyscall(n, f.pkg.Name(), f.name) c.convertSyscall(n, f.pkg.Name(), f.name)
default: default:
@ -843,7 +835,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
sz = f.Results().Len() sz = f.Results().Len()
} }
for i := 0; i < sz; i++ { 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: case token.ADD:
// +10 == 10, no need to do anything in this case // +10 == 10, no need to do anything in this case
case token.SUB: case token.SUB:
emit.Opcode(c.prog.BinWriter, opcode.NEGATE) emit.Opcodes(c.prog.BinWriter, opcode.NEGATE)
case token.NOT: case token.NOT:
emit.Opcode(c.prog.BinWriter, opcode.NOT) emit.Opcodes(c.prog.BinWriter, opcode.NOT)
case token.XOR: case token.XOR:
emit.Opcode(c.prog.BinWriter, opcode.INVERT) emit.Opcodes(c.prog.BinWriter, opcode.INVERT)
default: default:
c.prog.Err = fmt.Errorf("invalid unary operator: %s", n.Op) c.prog.Err = fmt.Errorf("invalid unary operator: %s", n.Op)
return nil return nil
@ -937,7 +929,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
// This will load local whatever X is. // This will load local whatever X is.
ast.Walk(c, n.X) ast.Walk(c, n.X)
ast.Walk(c, n.Index) 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 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 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. // 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) _, isMap := c.typeOf(n.X).Underlying().(*types.Map)
emit.Opcode(c.prog.BinWriter, opcode.DUP) emit.Opcodes(c.prog.BinWriter, opcode.DUP)
if isMap { if isMap {
emit.Opcode(c.prog.BinWriter, opcode.KEYS) emit.Opcodes(c.prog.BinWriter, opcode.KEYS, opcode.DUP)
emit.Opcode(c.prog.BinWriter, opcode.DUP)
} }
emit.Opcode(c.prog.BinWriter, opcode.SIZE) emit.Opcodes(c.prog.BinWriter, opcode.SIZE, opcode.PUSH0)
emit.Opcode(c.prog.BinWriter, opcode.PUSH0)
stackSize := 3 // slice, len(slice), index stackSize := 3 // slice, len(slice), index
if isMap { if isMap {
@ -1064,8 +1054,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
c.pushStackLabel(label, stackSize) c.pushStackLabel(label, stackSize)
c.setLabel(start) c.setLabel(start)
emit.Opcode(c.prog.BinWriter, opcode.OVER) emit.Opcodes(c.prog.BinWriter, opcode.OVER, opcode.OVER)
emit.Opcode(c.prog.BinWriter, opcode.OVER)
emit.Jmp(c.prog.BinWriter, opcode.JMPLEL, end) emit.Jmp(c.prog.BinWriter, opcode.JMPLEL, end)
var keyLoaded bool var keyLoaded bool
@ -1074,11 +1063,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
if isMap { if isMap {
c.rangeLoadKey() c.rangeLoadKey()
if needValue { if needValue {
emit.Opcode(c.prog.BinWriter, opcode.DUP) emit.Opcodes(c.prog.BinWriter, opcode.DUP)
keyLoaded = true keyLoaded = true
} }
} else { } else {
emit.Opcode(c.prog.BinWriter, opcode.DUP) emit.Opcodes(c.prog.BinWriter, opcode.DUP)
} }
c.emitStoreVar("", n.Key.(*ast.Ident).Name) c.emitStoreVar("", n.Key.(*ast.Ident).Name)
} }
@ -1089,9 +1078,10 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
if isMap { if isMap {
// we have loaded only key from key array, now load value // we have loaded only key from key array, now load value
emit.Int(c.prog.BinWriter, 4) emit.Int(c.prog.BinWriter, 4)
emit.Opcode(c.prog.BinWriter, opcode.PICK) // load map itself (+1 because key was pushed) emit.Opcodes(c.prog.BinWriter,
emit.Opcode(c.prog.BinWriter, opcode.SWAP) // key should be on top opcode.PICK, // load map itself (+1 because key was pushed)
emit.Opcode(c.prog.BinWriter, opcode.PICKITEM) opcode.SWAP, // key should be on top
opcode.PICKITEM)
} }
c.emitStoreVar("", n.Value.(*ast.Ident).Name) c.emitStoreVar("", n.Value.(*ast.Ident).Name)
} }
@ -1100,7 +1090,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
c.setLabel(post) 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) emit.Jmp(c.prog.BinWriter, opcode.JMPL, start)
c.setLabel(end) c.setLabel(end)
@ -1164,16 +1154,17 @@ func (c *codegen) processDefers() {
c.setLabel(before) c.setLabel(before)
emit.Int(c.prog.BinWriter, 0) emit.Int(c.prog.BinWriter, 0)
c.emitStoreByIndex(varLocal, c.scope.finallyProcessedIndex) c.emitStoreByIndex(varLocal, c.scope.finallyProcessedIndex)
emit.Opcode(c.prog.BinWriter, opcode.ENDFINALLY) emit.Opcodes(c.prog.BinWriter, opcode.ENDFINALLY)
c.setLabel(after) c.setLabel(after)
} }
} }
func (c *codegen) rangeLoadKey() { func (c *codegen) rangeLoadKey() {
emit.Int(c.prog.BinWriter, 2) emit.Int(c.prog.BinWriter, 2)
emit.Opcode(c.prog.BinWriter, opcode.PICK) // load keys emit.Opcodes(c.prog.BinWriter,
emit.Opcode(c.prog.BinWriter, opcode.OVER) // load index in key array opcode.PICK, // load keys
emit.Opcode(c.prog.BinWriter, opcode.PICKITEM) opcode.OVER, // load index in key array
opcode.PICKITEM)
} }
func isFallthroughStmt(c ast.Node) bool { func isFallthroughStmt(c ast.Node) bool {
@ -1230,11 +1221,11 @@ func (c *codegen) emitBinaryExpr(n *ast.BinaryExpr, needJump bool, cond bool, jm
return return
} else if arg := c.getCompareWithNilArg(n); arg != nil { } else if arg := c.getCompareWithNilArg(n); arg != nil {
ast.Walk(c, arg) ast.Walk(c, arg)
emit.Opcode(c.prog.BinWriter, opcode.ISNULL) emit.Opcodes(c.prog.BinWriter, opcode.ISNULL)
if needJump { if needJump {
c.emitJumpOnCondition(cond == (n.Op == token.EQL), jmpLabel) c.emitJumpOnCondition(cond == (n.Op == token.EQL), jmpLabel)
} else if n.Op == token.NEQ { } else if n.Op == token.NEQ {
emit.Opcode(c.prog.BinWriter, opcode.NOT) emit.Opcodes(c.prog.BinWriter, opcode.NOT)
} }
return return
} }
@ -1299,14 +1290,13 @@ func (c *codegen) dropStackLabel() {
func (c *codegen) dropItems(n int) { func (c *codegen) dropItems(n int) {
if n < 4 { if n < 4 {
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
emit.Opcode(c.prog.BinWriter, opcode.DROP) emit.Opcodes(c.prog.BinWriter, opcode.DROP)
} }
return return
} }
emit.Int(c.prog.BinWriter, int64(n)) emit.Int(c.prog.BinWriter, int64(n))
emit.Opcode(c.prog.BinWriter, opcode.PACK) emit.Opcodes(c.prog.BinWriter, opcode.PACK, opcode.DROP)
emit.Opcode(c.prog.BinWriter, opcode.DROP)
} }
// emitReverse reverses top num items of the stack. // emitReverse reverses top num items of the stack.
@ -1314,14 +1304,14 @@ func (c *codegen) emitReverse(num int) {
switch num { switch num {
case 0, 1: case 0, 1:
case 2: case 2:
emit.Opcode(c.prog.BinWriter, opcode.SWAP) emit.Opcodes(c.prog.BinWriter, opcode.SWAP)
case 3: case 3:
emit.Opcode(c.prog.BinWriter, opcode.REVERSE3) emit.Opcodes(c.prog.BinWriter, opcode.REVERSE3)
case 4: case 4:
emit.Opcode(c.prog.BinWriter, opcode.REVERSE4) emit.Opcodes(c.prog.BinWriter, opcode.REVERSE4)
default: default:
emit.Int(c.prog.BinWriter, int64(num)) 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 // 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. // 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. // 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 { if src.High != nil {
ast.Walk(c, src.High) ast.Walk(c, src.High)
} else { } else {
emit.Opcode(c.prog.BinWriter, opcode.DUP) emit.Opcodes(c.prog.BinWriter, opcode.DUP, opcode.SIZE)
emit.Opcode(c.prog.BinWriter, opcode.SIZE)
} }
if src.Low != nil { if src.Low != nil {
ast.Walk(c, src.Low) ast.Walk(c, src.Low)
@ -1427,17 +1416,13 @@ func (c *codegen) emitSliceHelper(e ast.Expr) {
} }
default: default:
ast.Walk(c, src) ast.Walk(c, src)
emit.Opcode(c.prog.BinWriter, opcode.DUP) emit.Opcodes(c.prog.BinWriter, opcode.DUP, opcode.SIZE)
emit.Opcode(c.prog.BinWriter, opcode.SIZE)
emit.Int(c.prog.BinWriter, 0) emit.Int(c.prog.BinWriter, 0)
} }
if !hasLowIndex { if !hasLowIndex {
emit.Opcode(c.prog.BinWriter, opcode.SWAP) emit.Opcodes(c.prog.BinWriter, opcode.SWAP)
} else { } else {
emit.Opcode(c.prog.BinWriter, opcode.DUP) emit.Opcodes(c.prog.BinWriter, opcode.DUP, opcode.ROT, opcode.SWAP, opcode.SUB)
emit.Opcode(c.prog.BinWriter, opcode.ROT)
emit.Opcode(c.prog.BinWriter, opcode.SWAP)
emit.Opcode(c.prog.BinWriter, opcode.SUB)
} }
} }
@ -1456,22 +1441,21 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
c.emitSliceHelper(expr.Args[0]) c.emitSliceHelper(expr.Args[0])
c.emitSliceHelper(expr.Args[1]) c.emitSliceHelper(expr.Args[1])
emit.Int(c.prog.BinWriter, 3) emit.Int(c.prog.BinWriter, 3)
emit.Opcode(c.prog.BinWriter, opcode.ROLL) emit.Opcodes(c.prog.BinWriter, opcode.ROLL, opcode.MIN)
emit.Opcode(c.prog.BinWriter, opcode.MIN)
if !c.scope.voidCalls[expr] { if !c.scope.voidCalls[expr] {
// insert top item to the bottom of MEMCPY args, so that it is left on stack // 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.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.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": case "make":
typ := c.typeOf(expr.Args[0]) typ := c.typeOf(expr.Args[0])
switch { switch {
case isMap(typ): case isMap(typ):
emit.Opcode(c.prog.BinWriter, opcode.NEWMAP) emit.Opcodes(c.prog.BinWriter, opcode.NEWMAP)
default: default:
if len(expr.Args) == 3 { if len(expr.Args) == 3 {
c.prog.Err = fmt.Errorf("`make()` with a capacity argument is not supported") 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]) ast.Walk(c, expr.Args[1])
if isByteSlice(typ) { if isByteSlice(typ) {
emit.Opcode(c.prog.BinWriter, opcode.NEWBUFFER) emit.Opcodes(c.prog.BinWriter, opcode.NEWBUFFER)
} else { } else {
neoT := toNeoType(typ.(*types.Slice).Elem()) neoT := toNeoType(typ.(*types.Slice).Elem())
emit.Instruction(c.prog.BinWriter, opcode.NEWARRAYT, []byte{byte(neoT)}) emit.Instruction(c.prog.BinWriter, opcode.NEWARRAYT, []byte{byte(neoT)})
} }
} }
case "len": case "len":
emit.Opcode(c.prog.BinWriter, opcode.DUP) emit.Opcodes(c.prog.BinWriter, opcode.DUP, opcode.ISNULL)
emit.Opcode(c.prog.BinWriter, opcode.ISNULL)
emit.Instruction(c.prog.BinWriter, opcode.JMPIF, []byte{2 + 1 + 2}) 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.Instruction(c.prog.BinWriter, opcode.JMP, []byte{2 + 1 + 1})
emit.Opcode(c.prog.BinWriter, opcode.DROP) emit.Opcodes(c.prog.BinWriter, opcode.DROP, opcode.PUSH0)
emit.Opcode(c.prog.BinWriter, opcode.PUSH0)
case "append": case "append":
arg := expr.Args[0] arg := expr.Args[0]
typ := c.typeInfo.Types[arg].Type typ := c.typeInfo.Types[arg].Type
c.emitReverse(len(expr.Args)) c.emitReverse(len(expr.Args))
emit.Opcode(c.prog.BinWriter, opcode.DUP) emit.Opcodes(c.prog.BinWriter, opcode.DUP, opcode.ISNULL)
emit.Opcode(c.prog.BinWriter, opcode.ISNULL)
emit.Instruction(c.prog.BinWriter, opcode.JMPIFNOT, []byte{2 + 3}) emit.Instruction(c.prog.BinWriter, opcode.JMPIFNOT, []byte{2 + 3})
if isByteSlice(typ) { if isByteSlice(typ) {
emit.Opcode(c.prog.BinWriter, opcode.DROP) emit.Opcodes(c.prog.BinWriter, opcode.DROP, opcode.PUSH0, opcode.NEWBUFFER)
emit.Opcode(c.prog.BinWriter, opcode.PUSH0)
emit.Opcode(c.prog.BinWriter, opcode.NEWBUFFER)
} else { } else {
emit.Opcode(c.prog.BinWriter, opcode.DROP) emit.Opcodes(c.prog.BinWriter, opcode.DROP, opcode.NEWARRAY0, opcode.NOP)
emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY0)
emit.Opcode(c.prog.BinWriter, opcode.NOP)
} }
// Jump target. // Jump target.
for range expr.Args[1:] { for range expr.Args[1:] {
if isByteSlice(typ) { if isByteSlice(typ) {
emit.Opcode(c.prog.BinWriter, opcode.SWAP) emit.Opcodes(c.prog.BinWriter, opcode.SWAP, opcode.CAT)
emit.Opcode(c.prog.BinWriter, opcode.CAT)
} else { } else {
emit.Opcode(c.prog.BinWriter, opcode.DUP) emit.Opcodes(c.prog.BinWriter, opcode.DUP, opcode.ROT, opcode.APPEND)
emit.Opcode(c.prog.BinWriter, opcode.ROT)
emit.Opcode(c.prog.BinWriter, opcode.APPEND)
} }
} }
case "panic": case "panic":
emit.Opcode(c.prog.BinWriter, opcode.THROW) emit.Opcodes(c.prog.BinWriter, opcode.THROW)
case "recover": case "recover":
if !c.scope.voidCalls[expr] { if !c.scope.voidCalls[expr] {
c.emitLoadByIndex(varGlobal, c.exceptionIndex) c.emitLoadByIndex(varGlobal, c.exceptionIndex)
} }
emit.Opcode(c.prog.BinWriter, opcode.PUSHNULL) emit.Opcodes(c.prog.BinWriter, opcode.PUSHNULL)
c.emitStoreByIndex(varGlobal, c.exceptionIndex) c.emitStoreByIndex(varGlobal, c.exceptionIndex)
case "delete": case "delete":
emit.Opcode(c.prog.BinWriter, opcode.REMOVE) emit.Opcodes(c.prog.BinWriter, opcode.REMOVE)
case "ToInteger", "ToByteArray", "ToBool": case "ToInteger", "ToByteArray", "ToBool":
typ := stackitem.IntegerT typ := stackitem.IntegerT
switch name { switch name {
@ -1544,9 +1518,9 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
c.prog.Err = errors.New("`Remove` supports only non-byte slices") c.prog.Err = errors.New("`Remove` supports only non-byte slices")
return return
} }
emit.Opcode(c.prog.BinWriter, opcode.REMOVE) emit.Opcodes(c.prog.BinWriter, opcode.REMOVE)
case "Equals": case "Equals":
emit.Opcode(c.prog.BinWriter, opcode.EQUAL) emit.Opcodes(c.prog.BinWriter, opcode.EQUAL)
case "FromAddress": case "FromAddress":
// We can be sure that this is a ast.BasicLit just containing a simple // 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 // 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) emit.Bytes(c.prog.BinWriter, buf)
c.emitConvert(stackitem.BufferT) c.emitConvert(stackitem.BufferT)
for _, i := range varIndices { 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)) emit.Int(c.prog.BinWriter, int64(i))
ast.Walk(c, lit.Elts[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) { 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 { for i := range lit.Elts {
elem := lit.Elts[i].(*ast.KeyValueExpr) 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.Key)
ast.Walk(c, elem.Value) 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 return
} }
emit.Opcode(c.prog.BinWriter, opcode.NOP) emit.Opcodes(c.prog.BinWriter, opcode.NOP)
emit.Int(c.prog.BinWriter, int64(strct.NumFields())) emit.Int(c.prog.BinWriter, int64(strct.NumFields()))
if ptr { if ptr {
emit.Opcode(c.prog.BinWriter, opcode.NEWARRAY) emit.Opcodes(c.prog.BinWriter, opcode.NEWARRAY)
} else { } else {
emit.Opcode(c.prog.BinWriter, opcode.NEWSTRUCT) emit.Opcodes(c.prog.BinWriter, opcode.NEWSTRUCT)
} }
keyedLit := len(lit.Elts) > 0 keyedLit := len(lit.Elts) > 0
@ -1665,7 +1639,7 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit, ptr bool) {
sField := strct.Field(i) sField := strct.Field(i)
var initialized bool var initialized bool
emit.Opcode(c.prog.BinWriter, opcode.DUP) emit.Opcodes(c.prog.BinWriter, opcode.DUP)
emit.Int(c.prog.BinWriter, int64(i)) emit.Int(c.prog.BinWriter, int64(i))
if !keyedLit { if !keyedLit {
@ -1689,7 +1663,7 @@ func (c *codegen) convertStruct(lit *ast.CompositeLit, ptr bool) {
if !initialized { if !initialized {
c.emitDefault(sField.Type()) 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 c.prog.Err = err
return return
} }
emit.Opcode(c.prog.BinWriter, op) emit.Opcodes(c.prog.BinWriter, op)
} }
func convertToken(tok token.Token, typ types.Type) (opcode.Opcode, error) { 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() n, hasInit := c.traverseGlobals()
if n > 0 || hasInit { if n > 0 || hasInit {
emit.Opcode(c.prog.BinWriter, opcode.RET) emit.Opcodes(c.prog.BinWriter, opcode.RET)
c.initEndOffset = c.prog.Len() c.initEndOffset = c.prog.Len()
} }

View file

@ -237,12 +237,12 @@ func TestVerifyTx(t *testing.T) {
} }
emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer",
neoOwner, a.Contract.ScriptHash(), amount) neoOwner, a.Contract.ScriptHash(), amount)
emit.Opcode(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
} }
} }
emit.AppCallWithOperationAndArgs(w.BinWriter, gasHash, "transfer", emit.AppCallWithOperationAndArgs(w.BinWriter, gasHash, "transfer",
neoOwner, testchain.CommitteeScriptHash(), int64(1_000_000_000)) 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) require.NoError(t, w.Err)
txMove := bc.newTestTx(neoOwner, w.Bytes()) txMove := bc.newTestTx(neoOwner, w.Bytes())
@ -782,7 +782,7 @@ func TestSubscriptions(t *testing.T) {
script = io.NewBufBinWriter() script = io.NewBufBinWriter()
emit.Bytes(script.BinWriter, []byte("nay!")) emit.Bytes(script.BinWriter, []byte("nay!"))
emit.Syscall(script.BinWriter, interopnames.SystemRuntimeNotify) emit.Syscall(script.BinWriter, interopnames.SystemRuntimeNotify)
emit.Opcode(script.BinWriter, opcode.THROW) emit.Opcodes(script.BinWriter, opcode.THROW)
require.NoError(t, script.Err) require.NoError(t, script.Err)
txBad := transaction.New(netmode.UnitTestNet, script.Bytes(), 0) txBad := transaction.New(netmode.UnitTestNet, script.Bytes(), 0)
txBad.Signers = []transaction.Signer{{Account: neoOwner}} txBad.Signers = []transaction.Signer{{Account: neoOwner}}

View file

@ -361,7 +361,7 @@ func TestCreateBasicChain(t *testing.T) {
func newNEP5Transfer(sc, from, to util.Uint160, amount int64) *transaction.Transaction { func newNEP5Transfer(sc, from, to util.Uint160, amount int64) *transaction.Transaction {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", from, to, amount) emit.AppCallWithOperationAndArgs(w.BinWriter, sc, "transfer", from, to, amount)
emit.Opcode(w.BinWriter, opcode.ASSERT) emit.Opcodes(w.BinWriter, opcode.ASSERT)
script := w.Bytes() script := w.Bytes()
return transaction.New(testchain.Network(), script, 10000000) return transaction.New(testchain.Network(), script, 10000000)

View file

@ -83,10 +83,10 @@ func (cs *Contracts) GetPersistScript() []byte {
continue continue
} }
emit.Int(w.BinWriter, 0) emit.Int(w.BinWriter, 0)
emit.Opcode(w.BinWriter, opcode.NEWARRAY) emit.Opcodes(w.BinWriter, opcode.NEWARRAY)
emit.String(w.BinWriter, "onPersist") emit.String(w.BinWriter, "onPersist")
emit.AppCall(w.BinWriter, md.Hash) emit.AppCall(w.BinWriter, md.Hash)
emit.Opcode(w.BinWriter, opcode.DROP) emit.Opcodes(w.BinWriter, opcode.DROP)
} }
cs.persistScript = w.Bytes() cs.persistScript = w.Bytes()
return cs.persistScript return cs.persistScript
@ -106,10 +106,10 @@ func (cs *Contracts) GetPostPersistScript() []byte {
continue continue
} }
emit.Int(w.BinWriter, 0) emit.Int(w.BinWriter, 0)
emit.Opcode(w.BinWriter, opcode.NEWARRAY) emit.Opcodes(w.BinWriter, opcode.NEWARRAY)
emit.String(w.BinWriter, "postPersist") emit.String(w.BinWriter, "postPersist")
emit.AppCall(w.BinWriter, md.Hash) emit.AppCall(w.BinWriter, md.Hash)
emit.Opcode(w.BinWriter, opcode.DROP) emit.Opcodes(w.BinWriter, opcode.DROP)
} }
cs.postPersistScript = w.Bytes() cs.postPersistScript = w.Bytes()
return cs.postPersistScript return cs.postPersistScript

View file

@ -56,7 +56,7 @@ func init() {
w.Reset() w.Reset()
emit.Int(w.BinWriter, 0) emit.Int(w.BinWriter, 0)
emit.Opcode(w.BinWriter, opcode.NEWARRAY) emit.Opcodes(w.BinWriter, opcode.NEWARRAY)
emit.String(w.BinWriter, "finish") emit.String(w.BinWriter, "finish")
emit.Bytes(w.BinWriter, h.BytesBE()) emit.Bytes(w.BinWriter, h.BytesBE())
emit.Syscall(w.BinWriter, interopnames.SystemContractCall) emit.Syscall(w.BinWriter, interopnames.SystemContractCall)

View file

@ -23,10 +23,10 @@ func (bc *Blockchain) setNodesByRole(t *testing.T, ok bool, r native.Role, nodes
emit.Bytes(w.BinWriter, pub.Bytes()) emit.Bytes(w.BinWriter, pub.Bytes())
} }
emit.Int(w.BinWriter, int64(len(nodes))) 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, int64(r))
emit.Int(w.BinWriter, 2) emit.Int(w.BinWriter, 2)
emit.Opcode(w.BinWriter, opcode.PACK) emit.Opcodes(w.BinWriter, opcode.PACK)
emit.String(w.BinWriter, "designateAsRole") emit.String(w.BinWriter, "designateAsRole")
emit.AppCall(w.BinWriter, bc.contracts.Designate.Hash) emit.AppCall(w.BinWriter, bc.contracts.Designate.Hash)
require.NoError(t, w.Err) require.NoError(t, w.Err)

View file

@ -27,26 +27,26 @@ import (
func getOracleContractState(h util.Uint160) *state.Contract { func getOracleContractState(h util.Uint160) *state.Contract {
w := io.NewBufBinWriter() w := io.NewBufBinWriter()
emit.Int(w.BinWriter, 5) emit.Int(w.BinWriter, 5)
emit.Opcode(w.BinWriter, opcode.PACK) emit.Opcodes(w.BinWriter, opcode.PACK)
emit.String(w.BinWriter, "request") emit.String(w.BinWriter, "request")
emit.Bytes(w.BinWriter, h.BytesBE()) emit.Bytes(w.BinWriter, h.BytesBE())
emit.Syscall(w.BinWriter, interopnames.SystemContractCall) 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 // `handle` method aborts if len(userData) == 2
offset := w.Len() offset := w.Len()
emit.Opcode(w.BinWriter, opcode.OVER) emit.Opcodes(w.BinWriter, opcode.OVER)
emit.Opcode(w.BinWriter, opcode.SIZE) emit.Opcodes(w.BinWriter, opcode.SIZE)
emit.Int(w.BinWriter, 2) emit.Int(w.BinWriter, 2)
emit.Instruction(w.BinWriter, opcode.JMPNE, []byte{3}) 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.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.Syscall(w.BinWriter, interopnames.SystemBinarySerialize)
emit.String(w.BinWriter, "lastOracleResponse") emit.String(w.BinWriter, "lastOracleResponse")
emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext) emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext)
emit.Syscall(w.BinWriter, interopnames.SystemStoragePut) emit.Syscall(w.BinWriter, interopnames.SystemStoragePut)
emit.Opcode(w.BinWriter, opcode.RET) emit.Opcodes(w.BinWriter, opcode.RET)
m := manifest.NewManifest(h) m := manifest.NewManifest(h)
m.Features = smartcontract.HasStorage m.Features = smartcontract.HasStorage

View file

@ -314,7 +314,7 @@ func (p *PublicKey) GetVerificationScript() []byte {
return buf.Bytes() return buf.Bytes()
} }
emit.Bytes(buf.BinWriter, b) emit.Bytes(buf.BinWriter, b)
emit.Opcode(buf.BinWriter, opcode.PUSHNULL) emit.Opcodes(buf.BinWriter, opcode.PUSHNULL)
emit.Syscall(buf.BinWriter, interopnames.NeoCryptoVerifyWithECDsaSecp256r1) emit.Syscall(buf.BinWriter, interopnames.NeoCryptoVerifyWithECDsaSecp256r1)
return buf.Bytes() return buf.Bytes()

View file

@ -132,7 +132,7 @@ func (c *Client) CreateNEP5MultiTransferTx(acc *wallet.Account, gas int64, recip
for i := range recipients { for i := range recipients {
emit.AppCallWithOperationAndArgs(w.BinWriter, recipients[i].Token, "transfer", from, emit.AppCallWithOperationAndArgs(w.BinWriter, recipients[i].Token, "transfer", from,
recipients[i].Address, recipients[i].Amount) 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{ return c.CreateTxFromScript(w.Bytes(), acc, -1, gas, transaction.Signer{
Account: acc.Contract.ScriptHash(), Account: acc.Contract.ScriptHash(),

View file

@ -107,7 +107,7 @@ func expandArrayIntoScript(script *io.BinWriter, slice []Param) error {
return err return err
} }
emit.Int(script, int64(len(val))) emit.Int(script, int64(len(val)))
emit.Opcode(script, opcode.PACK) emit.Opcodes(script, opcode.PACK)
default: default:
return fmt.Errorf("parameter type %v is not supported", fp.Type) 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 return nil, err
} }
emit.Int(script.BinWriter, int64(len(slice))) emit.Int(script.BinWriter, int64(len(slice)))
emit.Opcode(script.BinWriter, opcode.PACK) emit.Opcodes(script.BinWriter, opcode.PACK)
} }
} }

View file

@ -31,7 +31,7 @@ func CreateMultiSigRedeemScript(m int, publicKeys keys.PublicKeys) ([]byte, erro
emit.Bytes(buf.BinWriter, pubKey.Bytes()) emit.Bytes(buf.BinWriter, pubKey.Bytes())
} }
emit.Int(buf.BinWriter, int64(len(publicKeys))) 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) emit.Syscall(buf.BinWriter, interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1)
return buf.Bytes(), nil return buf.Bytes(), nil

View file

@ -21,18 +21,20 @@ func Instruction(w *io.BinWriter, op opcode.Opcode, b []byte) {
w.WriteBytes(b) w.WriteBytes(b)
} }
// Opcode emits a single VM Instruction without arguments to the given buffer. // Opcodes emits a single VM Instruction without arguments to the given buffer.
func Opcode(w *io.BinWriter, op opcode.Opcode) { func Opcodes(w *io.BinWriter, ops ...opcode.Opcode) {
w.WriteB(byte(op)) for _, op := range ops {
w.WriteB(byte(op))
}
} }
// Bool emits a bool type the given buffer. // Bool emits a bool type the given buffer.
func Bool(w *io.BinWriter, ok bool) { func Bool(w *io.BinWriter, ok bool) {
if ok { if ok {
Opcode(w, opcode.PUSHT) Opcodes(w, opcode.PUSHT)
return return
} }
Opcode(w, opcode.PUSHF) Opcodes(w, opcode.PUSHF)
Instruction(w, opcode.CONVERT, []byte{byte(stackitem.BooleanT)}) 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) { func Int(w *io.BinWriter, i int64) {
switch { switch {
case i == -1: case i == -1:
Opcode(w, opcode.PUSHM1) Opcodes(w, opcode.PUSHM1)
case i >= 0 && i < 16: case i >= 0 && i < 16:
val := opcode.Opcode(int(opcode.PUSH1) - 1 + int(i)) val := opcode.Opcode(int(opcode.PUSH1) - 1 + int(i))
Opcode(w, val) Opcodes(w, val)
default: default:
buf := bigint.ToPreallocatedBytes(big.NewInt(i), make([]byte, 0, 32)) buf := bigint.ToPreallocatedBytes(big.NewInt(i), make([]byte, 0, 32))
// l != 0 becase of switch // l != 0 becase of switch
padSize := byte(8 - bits.LeadingZeros8(byte(len(buf)-1))) 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<<padSize, buf)) w.WriteBytes(padRight(1<<padSize, buf))
} }
} }
@ -83,11 +85,11 @@ func Array(w *io.BinWriter, es ...interface{}) {
w.Err = errors.New("unsupported type") w.Err = errors.New("unsupported type")
return return
} }
Opcode(w, opcode.PUSHNULL) Opcodes(w, opcode.PUSHNULL)
} }
} }
Int(w, int64(len(es))) Int(w, int64(len(es)))
Opcode(w, opcode.PACK) Opcodes(w, opcode.PACK)
} }
// String emits a string to the given buffer. // String emits a string to the given buffer.

View file

@ -181,6 +181,13 @@ func TestEmitBool(t *testing.T) {
assert.Equal(t, opcode.Opcode(result[1]), opcode.PUSH0) assert.Equal(t, opcode.Opcode(result[1]), opcode.PUSH0)
} }
func TestEmitOpcode(t *testing.T) {
w := io.NewBufBinWriter()
Opcodes(w.BinWriter, opcode.PUSH1, opcode.NEWMAP)
result := w.Bytes()
assert.Equal(t, result, []byte{byte(opcode.PUSH1), byte(opcode.NEWMAP)})
}
func TestEmitString(t *testing.T) { func TestEmitString(t *testing.T) {
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
str := "City Of Zion" str := "City Of Zion"

View file

@ -39,7 +39,7 @@ func TestInteropHook(t *testing.T) {
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
emit.Syscall(buf.BinWriter, "foo") emit.Syscall(buf.BinWriter, "foo")
emit.Opcode(buf.BinWriter, opcode.RET) emit.Opcodes(buf.BinWriter, opcode.RET)
v.Load(buf.Bytes()) v.Load(buf.Bytes())
runVM(t, v) runVM(t, v)
assert.Equal(t, 1, v.estack.Len()) assert.Equal(t, 1, v.estack.Len())
@ -773,11 +773,11 @@ func TestSerializeMapCompat(t *testing.T) {
// Create a map, push key and value, add KV to map, serialize. // Create a map, push key and value, add KV to map, serialize.
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
emit.Opcode(buf.BinWriter, opcode.NEWMAP) emit.Opcodes(buf.BinWriter, opcode.NEWMAP)
emit.Opcode(buf.BinWriter, opcode.DUP) emit.Opcodes(buf.BinWriter, opcode.DUP)
emit.Bytes(buf.BinWriter, []byte("key")) emit.Bytes(buf.BinWriter, []byte("key"))
emit.Bytes(buf.BinWriter, []byte("value")) emit.Bytes(buf.BinWriter, []byte("value"))
emit.Opcode(buf.BinWriter, opcode.SETITEM) emit.Opcodes(buf.BinWriter, opcode.SETITEM)
emit.Syscall(buf.BinWriter, interopnames.SystemBinarySerialize) emit.Syscall(buf.BinWriter, interopnames.SystemBinarySerialize)
require.NoError(t, buf.Err) require.NoError(t, buf.Err)
@ -1654,12 +1654,12 @@ func TestSIGN(t *testing.T) {
func TestSimpleCall(t *testing.T) { func TestSimpleCall(t *testing.T) {
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
w := buf.BinWriter w := buf.BinWriter
emit.Opcode(w, opcode.PUSH2) emit.Opcodes(w, opcode.PUSH2)
emit.Instruction(w, opcode.CALL, []byte{03}) emit.Instruction(w, opcode.CALL, []byte{03})
emit.Opcode(w, opcode.RET) emit.Opcodes(w, opcode.RET)
emit.Opcode(w, opcode.PUSH10) emit.Opcodes(w, opcode.PUSH10)
emit.Opcode(w, opcode.ADD) emit.Opcodes(w, opcode.ADD)
emit.Opcode(w, opcode.RET) emit.Opcodes(w, opcode.RET)
result := 12 result := 12
vm := load(buf.Bytes()) vm := load(buf.Bytes())