From 5f3256d0e02242992842f8e581d29c39278d0ea4 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Wed, 14 Aug 2019 15:05:54 +0300 Subject: [PATCH 01/44] .gitignore: add *.(orig|rej) --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index adf7fe80f..383d43756 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,7 @@ chains/ chain/ blockchain/ blockchains/ + +# patch +*.orig +*.rej From 33c512032f289160cc74f0d1077faa9d82483ddd Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Wed, 14 Aug 2019 15:40:31 +0300 Subject: [PATCH 02/44] 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). --- pkg/core/util.go | 8 +- pkg/smartcontract/contract.go | 2 +- pkg/smartcontract/contract_test.go | 6 +- pkg/vm/compiler/codegen.go | 132 +++++++++++------------ pkg/vm/compiler/compiler.go | 2 +- pkg/vm/compiler/emit.go | 36 +++---- pkg/vm/context.go | 12 +-- pkg/vm/emit.go | 48 ++++----- pkg/vm/emit_test.go | 12 +-- pkg/vm/instruction_string.go | 118 +++++++++++++++++++++ pkg/vm/instructions.go | 130 +++++++++++++++++++++++ pkg/vm/opcode.go | 131 ----------------------- pkg/vm/opcode_string.go | 118 --------------------- pkg/vm/vm.go | 164 ++++++++++++++--------------- pkg/vm/vm_test.go | 46 ++++---- 15 files changed, 482 insertions(+), 483 deletions(-) create mode 100644 pkg/vm/instruction_string.go create mode 100644 pkg/vm/instructions.go delete mode 100644 pkg/vm/opcode.go delete mode 100644 pkg/vm/opcode_string.go diff --git a/pkg/core/util.go b/pkg/core/util.go index 086f54e57..a5eab4b85 100644 --- a/pkg/core/util.go +++ b/pkg/core/util.go @@ -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\"}]", diff --git a/pkg/smartcontract/contract.go b/pkg/smartcontract/contract.go index a56562475..33214000f 100644 --- a/pkg/smartcontract/contract.go +++ b/pkg/smartcontract/contract.go @@ -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 } diff --git a/pkg/smartcontract/contract_test.go b/pkg/smartcontract/contract_test.go index d8760743c..3e1c4dcf9 100644 --- a/pkg/smartcontract/contract_test.go +++ b/pkg/smartcontract/contract_test.go @@ -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)) } diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index df77461e1..e88e3a861 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -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 diff --git a/pkg/vm/compiler/compiler.go b/pkg/vm/compiler/compiler.go index 28dfa0a3d..a4beb04ff 100644 --- a/pkg/vm/compiler/compiler.go +++ b/pkg/vm/compiler/compiler.go @@ -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 diff --git a/pkg/vm/compiler/emit.go b/pkg/vm/compiler/emit.go index 3221ac745..7805a88c9 100644 --- a/pkg/vm/compiler/emit.go +++ b/pkg/vm/compiler/emit.go @@ -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 diff --git a/pkg/vm/context.go b/pkg/vm/context.go index ed4fef036..043c89acf 100644 --- a/pkg/vm/context.go +++ b/pkg/vm/context.go @@ -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. diff --git a/pkg/vm/emit.go b/pkg/vm/emit.go index 49b794e86..14556b039 100644 --- a/pkg/vm/emit.go +++ b/pkg/vm/emit.go @@ -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 diff --git a/pkg/vm/emit_test.go b/pkg/vm/emit_test.go index 2c127636c..0baf995bc 100644 --- a/pkg/vm/emit_test.go +++ b/pkg/vm/emit_test.go @@ -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)) } diff --git a/pkg/vm/instruction_string.go b/pkg/vm/instruction_string.go new file mode 100644 index 000000000..da98524bb --- /dev/null +++ b/pkg/vm/instruction_string.go @@ -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) + ")" +} diff --git a/pkg/vm/instructions.go b/pkg/vm/instructions.go new file mode 100644 index 000000000..032c0a5c9 --- /dev/null +++ b/pkg/vm/instructions.go @@ -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 +) diff --git a/pkg/vm/opcode.go b/pkg/vm/opcode.go deleted file mode 100644 index 83cf6a6d7..000000000 --- a/pkg/vm/opcode.go +++ /dev/null @@ -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 -) diff --git a/pkg/vm/opcode_string.go b/pkg/vm/opcode_string.go deleted file mode 100644 index 84b34c5e3..000000000 --- a/pkg/vm/opcode_string.go +++ /dev/null @@ -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) + ")" -} diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index f201ae569..420becec2 100644 --- a/pkg/vm/vm.go +++ b/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") } diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index cc67101a8..257271056 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -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 } From 1927bc54d518a813e7be632cd9a0cc9627141e2e Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Mon, 20 Aug 2018 09:07:08 +0200 Subject: [PATCH 03/44] added partial syscall mapping Imported from CityOfZion/neo-storm (26d10c72f6e3d298135ec3995eb2d821640c3b7c). --- pkg/vm/compiler/analysis.go | 3 +- pkg/vm/compiler/codegen.go | 2 +- pkg/vm/compiler/emit.go | 24 ++++++------- pkg/vm/compiler/syscall.go | 69 +++++++++++++++++++++++++++++++++++++ pkg/vm/syscall.go | 19 ---------- 5 files changed, 83 insertions(+), 34 deletions(-) create mode 100644 pkg/vm/compiler/syscall.go delete mode 100644 pkg/vm/syscall.go diff --git a/pkg/vm/compiler/analysis.go b/pkg/vm/compiler/analysis.go index 10ee90242..2c8422aa9 100644 --- a/pkg/vm/compiler/analysis.go +++ b/pkg/vm/compiler/analysis.go @@ -6,7 +6,6 @@ import ( "go/types" "log" - "github.com/CityOfZion/neo-go/pkg/vm" "golang.org/x/tools/go/loader" ) @@ -203,7 +202,7 @@ func isByteArray(lit *ast.CompositeLit, tInfo *types.Info) bool { } func isSyscall(name string) bool { - _, ok := vm.Syscalls[name] + _, ok := syscalls[name] return ok } diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index e88e3a861..3756eaac3 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -532,7 +532,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { } func (c *codegen) convertSyscall(name string) { - api, ok := vm.Syscalls[name] + api, ok := syscalls[name] if !ok { log.Fatalf("unknown VM syscall api: %s", name) } diff --git a/pkg/vm/compiler/emit.go b/pkg/vm/compiler/emit.go index 7805a88c9..584979e5d 100644 --- a/pkg/vm/compiler/emit.go +++ b/pkg/vm/compiler/emit.go @@ -12,16 +12,16 @@ import ( "github.com/CityOfZion/neo-go/pkg/vm" ) -func emit(w *bytes.Buffer, op vm.Instruction, b []byte) error { - if err := w.WriteByte(byte(op)); err != nil { +func emit(w *bytes.Buffer, instr vm.Instruction, b []byte) error { + if err := w.WriteByte(byte(instr)); err != nil { return err } _, err := w.Write(b) return err } -func emitOpcode(w io.ByteWriter, op vm.Instruction) error { - return w.WriteByte(byte(op)) +func emitOpcode(w io.ByteWriter, instr vm.Instruction) error { + return w.WriteByte(byte(instr)) } func emitBool(w io.ByteWriter, ok bool) error { @@ -89,21 +89,21 @@ func emitSyscall(w *bytes.Buffer, api string) error { return emit(w, vm.SYSCALL, buf) } -func emitCall(w *bytes.Buffer, op vm.Instruction, label int16) error { - return emitJmp(w, op, label) +func emitCall(w *bytes.Buffer, instr vm.Instruction, label int16) error { + return emitJmp(w, instr, label) } -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) +func emitJmp(w *bytes.Buffer, instr vm.Instruction, label int16) error { + if !isInstrJmp(instr) { + return fmt.Errorf("opcode %s is not a jump or call type", instr) } buf := make([]byte, 2) binary.LittleEndian.PutUint16(buf, uint16(label)) - return emit(w, op, buf) + return emit(w, instr, buf) } -func isInstructionJmp(op vm.Instruction) bool { - if op == vm.JMP || op == vm.JMPIFNOT || op == vm.JMPIF || op == vm.CALL { +func isInstrJmp(instr vm.Instruction) bool { + if instr == vm.JMP || instr == vm.JMPIFNOT || instr == vm.JMPIF || instr == vm.CALL { return true } return false diff --git a/pkg/vm/compiler/syscall.go b/pkg/vm/compiler/syscall.go new file mode 100644 index 000000000..ec545a51e --- /dev/null +++ b/pkg/vm/compiler/syscall.go @@ -0,0 +1,69 @@ +package compiler + +var syscalls = map[string]string{ + // + // Standard library API + // + + // Storage API + "GetContext": "System.Storage.GetContext", + "Put": "System.Storage.Put", + "Get": "System.Storage.Get", + "Delete": "System.Storage.Delete", + "Find": "System.Storage.Find", + + // Runtime API + "GetTrigger": "System.Runtime.GetTrigger", + "CheckWitness": "System.Runtime.CheckWitness", + "Notify": "System.Runtime.Notify", + "Log": "System.Runtime.Log", + "GetTime": "System.Runtime.GetTime", + "Serialize": "System.Runtime.Serialize", + "Deserialize": "System.Runtime.Deserialize", + + // Blockchain API + "GetHeight": "System.Blockchain.GetHeight", + "GetHeader": "System.Blockchain.GetHeader", + "GetBlock": "System.Blockchain.GetBlock", + "GetTransaction": "System.Blockchain.GetTransaction", + "GetTransactionHeight": "System.Blockchain.GetTransactionHeight", + "GetContract": "System.Blockchain.GetContract", + + // Header API + "GetIndex": "System.Header.GetContract", + "GetHash": "System.Header.GetHash", + "GetPrevHash": "System.Header.GetPrevHash", + "GetTimestamp": "System.Header.GetTimestamp", + + // Block API + "GetTransactionCount": "System.Block.GetTransactionCount", + "GetTransactions": "System.Block.GetTransactions", + // TODO: Find solution for duplicated map entry + "NGetTransaction": "System.Block.GetTransaction", + + // + // NEO specific API + // + + // Blockchain API + "GetAccount": "Neo.Blockchain.GetAccount", + "GetValidators": "Neo.Blockchain.GetValidators", + "GetAsset": "Neo.Blockchain.GetAsset", + + // Header API + "GetVersion": "Neo.Header.GetVersion", + "GetMerkleRoot": "Neo.Header.GetMerkleRoot", + "GetConsensusData": "Neo.Header.GetConsensusData", + "GetNextConsensus": "Neo.Header.GetNextConsensus", + + // Transaction API + "GetType": "Neo.Transaction.GetType", + "GetAttributes": "Neo.Transaction.GetAttributes", + "GetInputs": "Neo.Transaction.GetInputs", + "GetOutputs": "Neo.Transaction.GetOutputs", + "GetReferences": "Neo.Transaction.GetReferences", + "GetUnspentCoins": "Neo.Transaction.GetUnspentCoins", + "GetScript": "Neo.InvocationTransaction.GetScript", + + // TODO: Add the rest of the interop APIS +} diff --git a/pkg/vm/syscall.go b/pkg/vm/syscall.go deleted file mode 100644 index 69f2ee1e3..000000000 --- a/pkg/vm/syscall.go +++ /dev/null @@ -1,19 +0,0 @@ -package vm - -// Syscalls are a mapping between the syscall function name -// and the registered VM interop API. -var Syscalls = map[string]string{ - // Storage API - "GetContext": "Neo.Storage.GetContext", - "Put": "Neo.Storage.Put", - "Get": "Neo.Storage.Get", - "Delete": "Neo.Storage.Delete", - - // Runtime API - "GetTrigger": "Neo.Runtime.GetTrigger", - "CheckWitness": "Neo.Runtime.CheckWitness", - "GetCurrentBlock": "Neo.Runtime.GetCurrentBlock", - "GetTime": "Neo.Runtime.GetTime", - "Notify": "Neo.Runtime.Notify", - "Log": "Neo.Runtime.Log", -} From 86715511d0bd9192cd2331dad7247b54c7f23953 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Mon, 20 Aug 2018 10:59:35 +0200 Subject: [PATCH 04/44] Added examples folder Imported from CityOfZion/neo-storm (77d0e5949470b2648acd37c71116f4469197772b). --- examples/check_witness.go | 17 +++++++++++++++++ interop/runtime/runtime.go | 6 ++++++ interop/util/util.go | 6 ++++++ 3 files changed, 29 insertions(+) create mode 100644 examples/check_witness.go create mode 100644 interop/runtime/runtime.go create mode 100644 interop/util/util.go diff --git a/examples/check_witness.go b/examples/check_witness.go new file mode 100644 index 000000000..17b399cc7 --- /dev/null +++ b/examples/check_witness.go @@ -0,0 +1,17 @@ +package check_witness_contract + +import ( + "github.com/CityOfZion/neo-go-sc/interop/runtime" + "github.com/CityOfZion/neo-go-sc/interop/util" +) + +// Check if the invoker of the contract is the specified owner. + +var owner = util.FromAddress("Aej1fe4mUgou48Zzup5j8sPrE3973cJ5oz") + +func Main() bool { + if runtime.CheckWitness(owner) { + return true + } + return false +} diff --git a/interop/runtime/runtime.go b/interop/runtime/runtime.go new file mode 100644 index 000000000..da0e82bcb --- /dev/null +++ b/interop/runtime/runtime.go @@ -0,0 +1,6 @@ +package runtime + +// CheckWitness verifies if the given hash is the invoker of the contract. +func CheckWitness(hash []byte) bool { + return true +} diff --git a/interop/util/util.go b/interop/util/util.go new file mode 100644 index 000000000..f5b658fdd --- /dev/null +++ b/interop/util/util.go @@ -0,0 +1,6 @@ +package util + +// FromAddress is an utility function that converts an NEO address to its hash. +func FromAddress(address string) []byte { + return nil +} From 9d983ec77bd066dbdf00ec839833708deb566415 Mon Sep 17 00:00:00 2001 From: Jeroen Peeters Date: Mon, 20 Aug 2018 13:22:46 +0200 Subject: [PATCH 05/44] feat: add storage APi's and example Imported from CityOfZion/neo-storm (86ac5c215a2c6ec710f2fd913e0ace63d6ea993e). --- examples/{ => check_witness}/check_witness.go | 0 examples/storage/storage.go | 46 +++++++++++++++++++ interop/storage/storage.go | 19 ++++++++ 3 files changed, 65 insertions(+) rename examples/{ => check_witness}/check_witness.go (100%) create mode 100644 examples/storage/storage.go create mode 100644 interop/storage/storage.go diff --git a/examples/check_witness.go b/examples/check_witness/check_witness.go similarity index 100% rename from examples/check_witness.go rename to examples/check_witness/check_witness.go diff --git a/examples/storage/storage.go b/examples/storage/storage.go new file mode 100644 index 000000000..26a7f5dc7 --- /dev/null +++ b/examples/storage/storage.go @@ -0,0 +1,46 @@ +package storage_contract + +import ( + "github.com/CityOfZion/neo-go-sc/interop/storage" +) + +func Main(operation string, args []interface{}) interface{} { + var ctx = storage.GetContext() + + // Puts value at key + if operation == "put" { + if checkArgs(args, 2) { + key := args[0].([]byte) + value := args[1].([]byte) + storage.Put(ctx, key, value) + return key + } + } + + // Returns the value at passed key + if operation == "get" { + if checkArgs(args, 1) { + key := args[0].([]byte) + return storage.Get(ctx, key) + } + } + + // Deletes the value at passed key + if operation == "delete" { + key := args[0].([]byte) + storage.Delete(ctx, key) + return true + } + + // TODO: storage.Find() + + return false +} + +func checkArgs(args []interface{}, length int) bool { + if len(args) == length { + return true + } + + return false +} diff --git a/interop/storage/storage.go b/interop/storage/storage.go new file mode 100644 index 000000000..de803e87c --- /dev/null +++ b/interop/storage/storage.go @@ -0,0 +1,19 @@ +package storage + +// Context represents the storage context +type Context interface{} + +// GetContext returns the storage context +func GetContext() interface{} { return nil } + +// Put value at given key +func Put(ctx interface{}, key interface{}, value interface{}) {} + +// Get value matching given key +func Get(ctx interface{}, key interface{}) interface{} { return 0 } + +// Delete key value pair from storage +func Delete(ctx interface{}, key interface{}) {} + +// Find values stored on keys partially matching given key +func Find(ctx interface{}, key interface{}) interface{} { return 0 } From 90809ee73ebd34f7b3fffcd6783882827647d016 Mon Sep 17 00:00:00 2001 From: Jeroen Peeters Date: Tue, 21 Aug 2018 09:11:25 +0200 Subject: [PATCH 06/44] chore: use Context interface Imported from CityOfZion/neo-storm (16c6f9fab7de374196a4fb352d781abeebb384c1). --- interop/storage/storage.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/interop/storage/storage.go b/interop/storage/storage.go index de803e87c..8e5c0b6d9 100644 --- a/interop/storage/storage.go +++ b/interop/storage/storage.go @@ -1,19 +1,19 @@ package storage // Context represents the storage context -type Context interface{} +type Context struct{} // GetContext returns the storage context -func GetContext() interface{} { return nil } +func GetContext() Context { return Context{} } // Put value at given key -func Put(ctx interface{}, key interface{}, value interface{}) {} +func Put(ctx Context, key interface{}, value interface{}) {} // Get value matching given key -func Get(ctx interface{}, key interface{}) interface{} { return 0 } +func Get(ctx Context, key interface{}) interface{} { return 0 } // Delete key value pair from storage -func Delete(ctx interface{}, key interface{}) {} +func Delete(ctx Context, key interface{}) {} // Find values stored on keys partially matching given key -func Find(ctx interface{}, key interface{}) interface{} { return 0 } +func Find(ctx Context, key interface{}) interface{} { return 0 } From 29f05c0edb77887ae65d229daf7d0c3c6d1d36c9 Mon Sep 17 00:00:00 2001 From: Jeroen Peeters Date: Tue, 21 Aug 2018 09:23:29 +0200 Subject: [PATCH 07/44] chore: move examples out of separate folder Imported from CityOfZion/neo-storm (7eb644415d4083572c4e74590da056319c3a54fb). --- examples/{check_witness => }/check_witness.go | 0 examples/{storage => }/storage.go | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename examples/{check_witness => }/check_witness.go (100%) rename examples/{storage => }/storage.go (100%) diff --git a/examples/check_witness/check_witness.go b/examples/check_witness.go similarity index 100% rename from examples/check_witness/check_witness.go rename to examples/check_witness.go diff --git a/examples/storage/storage.go b/examples/storage.go similarity index 100% rename from examples/storage/storage.go rename to examples/storage.go From e6c16a6a2469a627d38e2f985a27d19ea0bdf37b Mon Sep 17 00:00:00 2001 From: Jeroen Peeters Date: Tue, 21 Aug 2018 09:29:28 +0200 Subject: [PATCH 08/44] chore: use shorthand in example Imported from CityOfZion/neo-storm (a2f2da87fcfb1a4f8ccdb48a043f98ff47bb3e89). --- examples/storage.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/storage.go b/examples/storage.go index 26a7f5dc7..002c98d62 100644 --- a/examples/storage.go +++ b/examples/storage.go @@ -5,7 +5,7 @@ import ( ) func Main(operation string, args []interface{}) interface{} { - var ctx = storage.GetContext() + ctx := storage.GetContext() // Puts value at key if operation == "put" { From e4c80a001c1f79acf9db7842f2403ee274144d38 Mon Sep 17 00:00:00 2001 From: Jeroen Peeters Date: Tue, 21 Aug 2018 10:55:03 +0200 Subject: [PATCH 09/44] feat: add Log, Notify and Triggers Imported from CityOfZion/neo-storm (5065465e39fd2b308c487f49f75f517620139660). --- examples/check_witness.go | 17 ------------ examples/runtime/runtime.go | 43 +++++++++++++++++++++++++++++++ examples/{ => storage}/storage.go | 0 interop/runtime/runtime.go | 26 ++++++++++++++++++- 4 files changed, 68 insertions(+), 18 deletions(-) delete mode 100644 examples/check_witness.go create mode 100644 examples/runtime/runtime.go rename examples/{ => storage}/storage.go (100%) diff --git a/examples/check_witness.go b/examples/check_witness.go deleted file mode 100644 index 17b399cc7..000000000 --- a/examples/check_witness.go +++ /dev/null @@ -1,17 +0,0 @@ -package check_witness_contract - -import ( - "github.com/CityOfZion/neo-go-sc/interop/runtime" - "github.com/CityOfZion/neo-go-sc/interop/util" -) - -// Check if the invoker of the contract is the specified owner. - -var owner = util.FromAddress("Aej1fe4mUgou48Zzup5j8sPrE3973cJ5oz") - -func Main() bool { - if runtime.CheckWitness(owner) { - return true - } - return false -} diff --git a/examples/runtime/runtime.go b/examples/runtime/runtime.go new file mode 100644 index 000000000..a436dbf9e --- /dev/null +++ b/examples/runtime/runtime.go @@ -0,0 +1,43 @@ +package runtime_contract + +import ( + "github.com/CityOfZion/neo-go-sc/interop/runtime" + "github.com/CityOfZion/neo-go-sc/interop/util" +) + +// Check if the invoker of the contract is the specified owner +var owner = util.FromAddress("Aej1fe4mUgou48Zzup5j8sPrE3973cJ5oz") + +func Main(operation string, args []interface{}) bool { + trigger := runtime.GetTrigger() + + // Log owner upon Verification trigger + if trigger == runtime.Verification() { + if runtime.CheckWitness(owner) { + runtime.Log("Verified Owner") + } + return true + } + + // Discerns between log and notify for this test + if trigger == runtime.Application() { + return handleOperation(operation, args) + } + + return false +} + +func handleOperation(operation string, args []interface{}) bool { + if operation == "log" { + message := args[0].(string) + runtime.Log(message) + return true + } + + if operation == "notify" { + runtime.Notify(args[0]) + return true + } + + return false +} diff --git a/examples/storage.go b/examples/storage/storage.go similarity index 100% rename from examples/storage.go rename to examples/storage/storage.go diff --git a/interop/runtime/runtime.go b/interop/runtime/runtime.go index da0e82bcb..3d85288c4 100644 --- a/interop/runtime/runtime.go +++ b/interop/runtime/runtime.go @@ -1,6 +1,30 @@ package runtime -// CheckWitness verifies if the given hash is the invoker of the contract. +// CheckWitness verifies if the given hash is the invoker of the contract func CheckWitness(hash []byte) bool { return true } + +// Notify passes data to the VM +func Notify(arg interface{}) int { + return 0 +} + +// Log passes a message to the VM +func Log(message string) {} + +// Application returns the Application trigger type +func Application() byte { + return 0x10 +} + +// Verification returns the Verification trigger type +func Verification() byte { + return 0x00 +} + +// GetTrigger return the current trigger type. The return in this function +// Doesn't really matter, this is just an interop placeholder +func GetTrigger() interface{} { + return 0 +} From 523789ee1ca6cb8d62dcf7bc189d9cc2705c632e Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Tue, 21 Aug 2018 12:57:48 +0200 Subject: [PATCH 10/44] Compiler interop APIs (CityOfZion/neo-storm#5) * added draft of block and transaction interop api. * added header interop API * added attribute, transaction, input, output interop API * Added asset, attribute and account interop api. * added Runtime interop apis * added asset renew and create + contract and asset interop apis Imported from CityOfZion/neo-storm (b6810d58b98312a959980f344db24689839574c4). --- interop/account/account.go | 23 +++++++++++++ interop/asset/asset.go | 53 ++++++++++++++++++++++++++++++ interop/attribute/attribute.go | 17 ++++++++++ interop/block/block.go | 25 ++++++++++++++ interop/blockchain/blockchain.go | 53 ++++++++++++++++++++++++++++++ interop/contract/contract.go | 17 ++++++++++ interop/header/header.go | 47 ++++++++++++++++++++++++++ interop/input/input.go | 17 ++++++++++ interop/output/output.go | 22 +++++++++++++ interop/runtime/runtime.go | 34 ++++++++++++++----- interop/storage/storage.go | 3 ++ interop/transaction/transaction.go | 50 ++++++++++++++++++++++++++++ 12 files changed, 353 insertions(+), 8 deletions(-) create mode 100644 interop/account/account.go create mode 100644 interop/asset/asset.go create mode 100644 interop/attribute/attribute.go create mode 100644 interop/block/block.go create mode 100644 interop/blockchain/blockchain.go create mode 100644 interop/contract/contract.go create mode 100644 interop/header/header.go create mode 100644 interop/input/input.go create mode 100644 interop/output/output.go create mode 100644 interop/transaction/transaction.go diff --git a/interop/account/account.go b/interop/account/account.go new file mode 100644 index 000000000..04982aa1b --- /dev/null +++ b/interop/account/account.go @@ -0,0 +1,23 @@ +package account + +// Package account provides function signatures that can be used inside +// smart contracts that are written in the neo-go-sc framework. + +// Account stubs a NEO account type. +type Account struct{} + +// GetScripHash returns the script hash of the given account. +func GetScriptHash(a Account) []byte { + return nil +} + +// GetVotes returns the votes of the given account which should be a slice of +// public key raw bytes. +func GetVotes(a Account) [][]byte { + return nil +} + +// GetBalance returns the balance of for the given account and asset id. +func GetBalance(a Account, assetID []byte) int { + return 0 +} diff --git a/interop/asset/asset.go b/interop/asset/asset.go new file mode 100644 index 000000000..6e8a436db --- /dev/null +++ b/interop/asset/asset.go @@ -0,0 +1,53 @@ +package asset + +// Package asset provides function signatures that can be used inside +// smart contracts that are written in the neo-go-sc framework. + +// Asset stubs a NEO asset type. +type Asset struct{} + +// GetAssetID returns the id of the given asset. +func GetAssetID(a Asset) []byte { + return nil +} + +// GetAssetType returns the type of the given asset. +func GetAssetType(a Asset) byte { + return 0x00 +} + +// GetAmount returns the amount of the given asset. +func GetAmount(a Asset) int { + return 0 +} + +// GetAvailable returns the available of the given asset. +func GetAvailable(a Asset) int { + return 0 +} + +// GetPrecision returns the precision of the given asset. +func GetPrecision(a Asset) byte { + return 0x00 +} + +// GetOwner returns the owner of the given asset. +func GetOwner(a Asset) []byte { + return nil +} + +// GetAdmin returns the admin of the given asset. +func GetAdmin(a Asset) []byte { + return nil +} + +// GetIssuer returns the issuer of the given asset. +func GetIssuer(a Asset) []byte { + return nil +} + +// Create registers a new asset on the blockchain. +func Create(assetType byte, name string, amount int, precision byte, owner, admin, issuer []byte) {} + +// Renew renews the existance of an asset by the given years. +func Renew(asset Asset, years int) {} diff --git a/interop/attribute/attribute.go b/interop/attribute/attribute.go new file mode 100644 index 000000000..b1fb82667 --- /dev/null +++ b/interop/attribute/attribute.go @@ -0,0 +1,17 @@ +package attribute + +// Package attribute provides function signatures that can be used inside +// smart contracts that are written in the neo-go-sc framework. + +// Attribute stubs a NEO transaction attribute type. +type Attribute struct{} + +// GetUsage returns the usage of the given attribute. +func GetUsage(attr Attribute) byte { + return 0x00 +} + +// GetData returns the data of the given attribute. +func GetData(attr Attribute) []byte { + return nil +} diff --git a/interop/block/block.go b/interop/block/block.go new file mode 100644 index 000000000..c1368a6ed --- /dev/null +++ b/interop/block/block.go @@ -0,0 +1,25 @@ +package block + +import "github.com/CityOfZion/neo-go-sc/interop/transaction" + +// Package block provides function signatures that can be used inside +// smart contracts that are written in the neo-go-sc framework. + +// Block stubs a NEO block type. +type Block struct{} + +// GetTransactionCount return the number of recorded transactions in the given block. +func GetTransactionCount(b Block) int { + return 0 +} + +// GetTransactions returns a slice of transactions recorded in the given block. +func GetTransactions(b Block) []transaction.Transaction { + return []transaction.Transaction{} +} + +// GetTransaction returns a transaction from the given a block hash of the +// transaction. +func GetTransaction(b Block, hash []byte) transaction.Transaction { + return transaction.Transaction{} +} diff --git a/interop/blockchain/blockchain.go b/interop/blockchain/blockchain.go new file mode 100644 index 000000000..a3dc184c9 --- /dev/null +++ b/interop/blockchain/blockchain.go @@ -0,0 +1,53 @@ +package blockchain + +import ( + "github.com/CityOfZion/neo-go-sc/interop/account" + "github.com/CityOfZion/neo-go-sc/interop/asset" + "github.com/CityOfZion/neo-go-sc/interop/block" + "github.com/CityOfZion/neo-go-sc/interop/contract" + "github.com/CityOfZion/neo-go-sc/interop/header" + "github.com/CityOfZion/neo-go-sc/interop/transaction" +) + +// Package blockchain provides function signatures that can be used inside +// smart contracts that are written in the neo-go-sc framework. + +// GetHeight returns the height of te block recorded in the current execution scope. +func GetHeight() int { + return 0 +} + +// GetHeader returns the header found by the given hash or index. +func GetHeader(heightOrHash interface{}) header.Header { + return header.Header{} +} + +// GetBlock returns the block found by the given hash or index. +func GetBlock(heightOrHash interface{}) block.Block { + return block.Block{} +} + +// GetTransaction returns the transaction found by the given hash. +func GetTransaction(hash []byte) transaction.Transaction { + return transaction.Transaction{} +} + +// GetContract returns the contract found by the given script hash. +func GetContract(scriptHash []byte) contract.Contract { + return contract.Contract{} +} + +// GetAccount returns the account found by the given script hash. +func GetAccount(scriptHash []byte) account.Account { + return account.Account{} +} + +// GetValidators returns a slice of validator addresses. +func GetValidators() [][]byte { + return nil +} + +// GetAsset returns the asset found by the given asset id. +func GetAsset(assetID []byte) asset.Asset { + return asset.Asset{} +} diff --git a/interop/contract/contract.go b/interop/contract/contract.go new file mode 100644 index 000000000..2c6555751 --- /dev/null +++ b/interop/contract/contract.go @@ -0,0 +1,17 @@ +package contract + +// Package contract provides function signatures that can be used inside +// smart contracts that are written in the neo-go-sc framework. + +// Contract stubs a NEO contract type. +type Contract struct{} + +// GetScript returns the script of the given contract. +func GetScript(c Contract) []byte { + return nil +} + +// IsPayable returns whether the given contract is payable. +func IsPayable(c Contract) bool { + return false +} diff --git a/interop/header/header.go b/interop/header/header.go new file mode 100644 index 000000000..cc7f23052 --- /dev/null +++ b/interop/header/header.go @@ -0,0 +1,47 @@ +package header + +// Package header provides function signatures that can be used inside +// smart contracts that are written in the neo-go-sc framework. + +// Header stubs a NEO block header type. +type Header struct{} + +// GetIndex returns the index of the given header. +func GetIndex(h Header) int { + return 0 +} + +// GetHash returns the hash of the given header. +func GetHash(h Header) []byte { + return nil +} + +// GetPrevHash returns the previous hash of the given header. +func GetPrevHash(h Header) []byte { + return nil +} + +// GetTimestamp returns the timestamp of the given header. +func GetTimestamp(h Header) int { + return 0 +} + +// GetVersion returns the version of the given header. +func GetVersion(h Header) int { + return 0 +} + +// GetMerkleRoot returns the merkle root of the given header. +func GetMerkleRoot(h Header) []byte { + return nil +} + +// GetConsensusData returns the consensus data of the given header. +func GetConsensusData(h Header) int { + return 0 +} + +// GetNextConsensus returns the next consensus of the given header. +func GetNextConsensus(h Header) []byte { + return nil +} diff --git a/interop/input/input.go b/interop/input/input.go new file mode 100644 index 000000000..63f97a1c6 --- /dev/null +++ b/interop/input/input.go @@ -0,0 +1,17 @@ +package input + +// Package input provides function signatures that can be used inside +// smart contracts that are written in the neo-go-sc framework. + +// Input stubs the input of a NEO transaction. +type Input struct{} + +// GetHash returns the hash of the given input. +func GetHash(in Input) []byte { + return nil +} + +// GetIndex returns the index of the given input. +func GetIndex(in Input) int { + return 0 +} diff --git a/interop/output/output.go b/interop/output/output.go new file mode 100644 index 000000000..90bd0d567 --- /dev/null +++ b/interop/output/output.go @@ -0,0 +1,22 @@ +package output + +// Package output provides function signatures that can be used inside +// smart contracts that are written in the neo-go-sc framework. + +// Output stubs the output of a NEO transaction. +type Output struct{} + +// GetAssetID returns the asset id of the given output. +func GetAssetID(out Output) []byte { + return nil +} + +// GetValue returns the value of the given output. +func GetValue(out Output) int { + return 0 +} + +// GetScriptHash returns the script hash of the given output. +func GetScriptHash(out Output) []byte { + return nil +} diff --git a/interop/runtime/runtime.go b/interop/runtime/runtime.go index 3d85288c4..367f07600 100644 --- a/interop/runtime/runtime.go +++ b/interop/runtime/runtime.go @@ -1,17 +1,31 @@ package runtime -// CheckWitness verifies if the given hash is the invoker of the contract +// Package runtime provides function signatures that can be used inside +// smart contracts that are written in the neo-go-sc framework. + +// CheckWitness verifies if the given hash is the invoker of the contract. func CheckWitness(hash []byte) bool { return true } -// Notify passes data to the VM +// Log instucts the VM to log the given message. +func Log(message string) {} + +// Notify an event to the VM. func Notify(arg interface{}) int { return 0 } -// Log passes a message to the VM -func Log(message string) {} +// GetTime returns the timestamp of the most recent block. +func GetTime() int { + return 0 +} + +// GetTrigger returns the smart contract invoke trigger which can be either +// verification or application. +func GetTrigger() byte { + return 0x00 +} // Application returns the Application trigger type func Application() byte { @@ -23,8 +37,12 @@ func Verification() byte { return 0x00 } -// GetTrigger return the current trigger type. The return in this function -// Doesn't really matter, this is just an interop placeholder -func GetTrigger() interface{} { - return 0 +// Serialize serializes and item into a bytearray. +func Serialize(item interface{}) []byte { + return nil +} + +// Deserializes an item from a bytearray. +func Deserialize(b []byte) interface{} { + return nil } diff --git a/interop/storage/storage.go b/interop/storage/storage.go index 8e5c0b6d9..5f6d0b375 100644 --- a/interop/storage/storage.go +++ b/interop/storage/storage.go @@ -1,5 +1,8 @@ package storage +// Package storage provides function signatures that can be used inside +// smart contracts that are written in the neo-go-sc framework. + // Context represents the storage context type Context struct{} diff --git a/interop/transaction/transaction.go b/interop/transaction/transaction.go new file mode 100644 index 000000000..d02ee086e --- /dev/null +++ b/interop/transaction/transaction.go @@ -0,0 +1,50 @@ +package transaction + +import ( + "github.com/CityOfZion/neo-go-sc/interop/attribute" + "github.com/CityOfZion/neo-go-sc/interop/input" + "github.com/CityOfZion/neo-go-sc/interop/output" +) + +// Package transaction provides function signatures that can be used inside +// smart contracts that are written in the neo-go-sc framework. + +// Transaction stubs a NEO transaction type. +type Transaction struct{} + +// GetHash returns the hash of the given transaction. +func GetHash(t Transaction) []byte { + return nil +} + +// GetType returns the type of the given transaction. +func GetType(t Transaction) byte { + return 0x00 +} + +// GetAttributes returns a slice of attributes for the given transaction. +func GetAttributes(t Transaction) []attribute.Attribute { + return []attribute.Attribute{} +} + +// FIXME: What is the correct return type for this? +// GetReferences returns a slice of references for the given transaction. +func GetReferences(t Transaction) interface{} { + return 0 +} + +// FIXME: What is the correct return type for this? +// GetUnspentCoins returns the unspent coins for the given transaction. +func GetUnspentCoins(t Transaction) interface{} { + return 0 +} + +// GetInputs returns the inputs of the given transaction. +func GetInputs(t Transaction) []input.Input { + return []input.Input{} +} + +// GetOutputs returns the outputs of the given transaction. +func GetOutputs(t Transaction) []output.Output { + return []output.Output{} +} From 05cd2775e2273166ab5c647c77260cb47bb44799 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Tue, 21 Aug 2018 13:39:35 +0200 Subject: [PATCH 11/44] renamed path to match the new project name (CityOfZion/neo-storm#8) Imported from CityOfZion/neo-storm (d022d46cd851de78ee041851a80dc34e3b3b68d1). --- examples/runtime/runtime.go | 4 ++-- examples/storage/storage.go | 2 +- interop/account/account.go | 2 +- interop/asset/asset.go | 2 +- interop/attribute/attribute.go | 2 +- interop/block/block.go | 4 ++-- interop/blockchain/blockchain.go | 14 +++++++------- interop/contract/contract.go | 2 +- interop/header/header.go | 2 +- interop/input/input.go | 2 +- interop/output/output.go | 2 +- interop/runtime/runtime.go | 2 +- interop/storage/storage.go | 2 +- interop/transaction/transaction.go | 8 ++++---- 14 files changed, 25 insertions(+), 25 deletions(-) diff --git a/examples/runtime/runtime.go b/examples/runtime/runtime.go index a436dbf9e..6c11632ee 100644 --- a/examples/runtime/runtime.go +++ b/examples/runtime/runtime.go @@ -1,8 +1,8 @@ package runtime_contract import ( - "github.com/CityOfZion/neo-go-sc/interop/runtime" - "github.com/CityOfZion/neo-go-sc/interop/util" + "github.com/CityOfZion/neo-storm/interop/runtime" + "github.com/CityOfZion/neo-storm/interop/util" ) // Check if the invoker of the contract is the specified owner diff --git a/examples/storage/storage.go b/examples/storage/storage.go index 002c98d62..bca5c86e5 100644 --- a/examples/storage/storage.go +++ b/examples/storage/storage.go @@ -1,7 +1,7 @@ package storage_contract import ( - "github.com/CityOfZion/neo-go-sc/interop/storage" + "github.com/CityOfZion/neo-storm/interop/storage" ) func Main(operation string, args []interface{}) interface{} { diff --git a/interop/account/account.go b/interop/account/account.go index 04982aa1b..cb60fac54 100644 --- a/interop/account/account.go +++ b/interop/account/account.go @@ -1,7 +1,7 @@ package account // Package account provides function signatures that can be used inside -// smart contracts that are written in the neo-go-sc framework. +// smart contracts that are written in the neo-storm framework. // Account stubs a NEO account type. type Account struct{} diff --git a/interop/asset/asset.go b/interop/asset/asset.go index 6e8a436db..e3242b777 100644 --- a/interop/asset/asset.go +++ b/interop/asset/asset.go @@ -1,7 +1,7 @@ package asset // Package asset provides function signatures that can be used inside -// smart contracts that are written in the neo-go-sc framework. +// smart contracts that are written in the neo-storm framework. // Asset stubs a NEO asset type. type Asset struct{} diff --git a/interop/attribute/attribute.go b/interop/attribute/attribute.go index b1fb82667..e53a06165 100644 --- a/interop/attribute/attribute.go +++ b/interop/attribute/attribute.go @@ -1,7 +1,7 @@ package attribute // Package attribute provides function signatures that can be used inside -// smart contracts that are written in the neo-go-sc framework. +// smart contracts that are written in the neo-storm framework. // Attribute stubs a NEO transaction attribute type. type Attribute struct{} diff --git a/interop/block/block.go b/interop/block/block.go index c1368a6ed..11fc9f6b4 100644 --- a/interop/block/block.go +++ b/interop/block/block.go @@ -1,9 +1,9 @@ package block -import "github.com/CityOfZion/neo-go-sc/interop/transaction" +import "github.com/CityOfZion/neo-storm/interop/transaction" // Package block provides function signatures that can be used inside -// smart contracts that are written in the neo-go-sc framework. +// smart contracts that are written in the neo-storm framework. // Block stubs a NEO block type. type Block struct{} diff --git a/interop/blockchain/blockchain.go b/interop/blockchain/blockchain.go index a3dc184c9..80f12a676 100644 --- a/interop/blockchain/blockchain.go +++ b/interop/blockchain/blockchain.go @@ -1,16 +1,16 @@ package blockchain import ( - "github.com/CityOfZion/neo-go-sc/interop/account" - "github.com/CityOfZion/neo-go-sc/interop/asset" - "github.com/CityOfZion/neo-go-sc/interop/block" - "github.com/CityOfZion/neo-go-sc/interop/contract" - "github.com/CityOfZion/neo-go-sc/interop/header" - "github.com/CityOfZion/neo-go-sc/interop/transaction" + "github.com/CityOfZion/neo-storm/interop/account" + "github.com/CityOfZion/neo-storm/interop/asset" + "github.com/CityOfZion/neo-storm/interop/block" + "github.com/CityOfZion/neo-storm/interop/contract" + "github.com/CityOfZion/neo-storm/interop/header" + "github.com/CityOfZion/neo-storm/interop/transaction" ) // Package blockchain provides function signatures that can be used inside -// smart contracts that are written in the neo-go-sc framework. +// smart contracts that are written in the neo-storm framework. // GetHeight returns the height of te block recorded in the current execution scope. func GetHeight() int { diff --git a/interop/contract/contract.go b/interop/contract/contract.go index 2c6555751..c1fffcdb4 100644 --- a/interop/contract/contract.go +++ b/interop/contract/contract.go @@ -1,7 +1,7 @@ package contract // Package contract provides function signatures that can be used inside -// smart contracts that are written in the neo-go-sc framework. +// smart contracts that are written in the neo-storm framework. // Contract stubs a NEO contract type. type Contract struct{} diff --git a/interop/header/header.go b/interop/header/header.go index cc7f23052..29fa5d9da 100644 --- a/interop/header/header.go +++ b/interop/header/header.go @@ -1,7 +1,7 @@ package header // Package header provides function signatures that can be used inside -// smart contracts that are written in the neo-go-sc framework. +// smart contracts that are written in the neo-storm framework. // Header stubs a NEO block header type. type Header struct{} diff --git a/interop/input/input.go b/interop/input/input.go index 63f97a1c6..cdc0a0336 100644 --- a/interop/input/input.go +++ b/interop/input/input.go @@ -1,7 +1,7 @@ package input // Package input provides function signatures that can be used inside -// smart contracts that are written in the neo-go-sc framework. +// smart contracts that are written in the neo-storm framework. // Input stubs the input of a NEO transaction. type Input struct{} diff --git a/interop/output/output.go b/interop/output/output.go index 90bd0d567..08f2230df 100644 --- a/interop/output/output.go +++ b/interop/output/output.go @@ -1,7 +1,7 @@ package output // Package output provides function signatures that can be used inside -// smart contracts that are written in the neo-go-sc framework. +// smart contracts that are written in the neo-storm framework. // Output stubs the output of a NEO transaction. type Output struct{} diff --git a/interop/runtime/runtime.go b/interop/runtime/runtime.go index 367f07600..9f27ec001 100644 --- a/interop/runtime/runtime.go +++ b/interop/runtime/runtime.go @@ -1,7 +1,7 @@ package runtime // Package runtime provides function signatures that can be used inside -// smart contracts that are written in the neo-go-sc framework. +// smart contracts that are written in the neo-storm framework. // CheckWitness verifies if the given hash is the invoker of the contract. func CheckWitness(hash []byte) bool { diff --git a/interop/storage/storage.go b/interop/storage/storage.go index 5f6d0b375..b280e834f 100644 --- a/interop/storage/storage.go +++ b/interop/storage/storage.go @@ -1,7 +1,7 @@ package storage // Package storage provides function signatures that can be used inside -// smart contracts that are written in the neo-go-sc framework. +// smart contracts that are written in the neo-storm framework. // Context represents the storage context type Context struct{} diff --git a/interop/transaction/transaction.go b/interop/transaction/transaction.go index d02ee086e..e845a1171 100644 --- a/interop/transaction/transaction.go +++ b/interop/transaction/transaction.go @@ -1,13 +1,13 @@ package transaction import ( - "github.com/CityOfZion/neo-go-sc/interop/attribute" - "github.com/CityOfZion/neo-go-sc/interop/input" - "github.com/CityOfZion/neo-go-sc/interop/output" + "github.com/CityOfZion/neo-storm/interop/attribute" + "github.com/CityOfZion/neo-storm/interop/input" + "github.com/CityOfZion/neo-storm/interop/output" ) // Package transaction provides function signatures that can be used inside -// smart contracts that are written in the neo-go-sc framework. +// smart contracts that are written in the neo-storm framework. // Transaction stubs a NEO transaction type. type Transaction struct{} From d804b517fc809ac108ec8af83e27e673a4a3e4b5 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Wed, 14 Aug 2019 18:49:56 +0300 Subject: [PATCH 12/44] examples/token-sale: drop binary avm from the repo It's easily reproduced from the token_sale.go and it's confusing the compiler test. --- examples/token-sale/token_sale.avm | Bin 2722 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 examples/token-sale/token_sale.avm diff --git a/examples/token-sale/token_sale.avm b/examples/token-sale/token_sale.avm deleted file mode 100755 index 790e1bdc8157940b6bac27c1c5be518d9b1e58e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2722 zcmcIm%}&%%6m9_#1QiHDcM_usae;B63wH*iD}-r*0frwh?S+|4XG%IPh`Mm$N>@gf z6VL^TJ6-`(FeW~LFX1D&@O-DYoia`*nBb=OwCCLO^PTUWTYd1P>}-`ajxx%}^Atr(;YMrB%+C z{HmAtTGu%JDSADJ9wPebW5@K`$1mpoUM{Vv&of3z?&BSMCR z*Xh$U9Yo_;jmxYQF?Pt+B8Y2-AL)sa6FcX27c!hvV|eK5H_pE?r=e2B5Z@`U1XJqS z*kAmDLCX<kk~o36*0p0Y8%fwWk=#j{M125SCG&8NGq K5jWlwtp5SF>p#N) From 2fbb269c0d88069bdb0bdde63038b32aa12911c8 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Tue, 21 Aug 2018 14:51:16 +0200 Subject: [PATCH 13/44] added compiler to test all example files. (CityOfZion/neo-storm#9) Imported from CityOfZion/neo-storm (e756a91b292f525f2cd7e6d6c05b46df582c8ece). --- pkg/vm/compiler/compiler_test.go | 50 ++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 pkg/vm/compiler/compiler_test.go diff --git a/pkg/vm/compiler/compiler_test.go b/pkg/vm/compiler/compiler_test.go new file mode 100644 index 000000000..ac17fcc25 --- /dev/null +++ b/pkg/vm/compiler/compiler_test.go @@ -0,0 +1,50 @@ +package compiler_test + +import ( + "io/ioutil" + "os" + "path" + "testing" + + "github.com/CityOfZion/neo-go/pkg/vm/compiler" +) + +const examplePath = "../../../examples" + +func TestExamplesFolder(t *testing.T) { + infos, err := ioutil.ReadDir(examplePath) + if err != nil { + t.Fatal(err) + } + + for _, info := range infos { + infos, err := ioutil.ReadDir(path.Join(examplePath, info.Name())) + if err != nil { + t.Fatal(err) + } + if len(infos) > 1 { + t.Fatal("detected smart contract folder with more then 1 contract file") + } + if len(infos) == 0 { + t.Fatal("detected smart contract folder with no contract in it") + } + filename := infos[0].Name() + targetPath := path.Join(examplePath, info.Name(), filename) + if err := compileFile(targetPath); err != nil { + t.Fatal(err) + } + } +} + +func compileFile(src string) error { + o := compiler.Options{ + Outfile: "tmp/contract.avm", + } + + file, err := os.Open(src) + if err != nil { + return err + } + _, err = compiler.Compile(file, &o) + return err +} From 0b33cf3193382bc77acc2942c69fab0868becb69 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Wed, 22 Aug 2018 09:51:35 +0200 Subject: [PATCH 14/44] new mapping for interop api (CityOfZion/neo-storm#10) * new mapping for interop api * Fixed interop API mapping + added missing apis * added engine apis Imported from CityOfZion/neo-storm (ec5e6c8e2b587704a1e071e83b633d2d3a235300). --- examples/engine/engine.go | 22 ++++++ interop/contract/contract.go | 38 +++++++++ interop/engine/engine.go | 29 +++++++ pkg/vm/compiler/analysis.go | 17 ++-- pkg/vm/compiler/codegen.go | 13 ++-- pkg/vm/compiler/func_scope.go | 4 + pkg/vm/compiler/syscall.go | 141 ++++++++++++++++++---------------- 7 files changed, 181 insertions(+), 83 deletions(-) create mode 100644 examples/engine/engine.go create mode 100644 interop/engine/engine.go diff --git a/examples/engine/engine.go b/examples/engine/engine.go new file mode 100644 index 000000000..c436dc33f --- /dev/null +++ b/examples/engine/engine.go @@ -0,0 +1,22 @@ +package engine_contract + +import ( + "github.com/CityOfZion/neo-storm/interop/engine" + "github.com/CityOfZion/neo-storm/interop/runtime" +) + +func Main() bool { + tx := engine.GetScriptContainer() + runtime.Notify(tx) + + callingScriptHash := engine.GetCallingScriptHash() + runtime.Notify(callingScriptHash) + + execScriptHash := engine.GetExecutingScriptHash() + runtime.Notify(execScriptHash) + + entryScriptHash := engine.GetEntryScriptHash() + runtime.Notify(entryScriptHash) + + return true +} diff --git a/interop/contract/contract.go b/interop/contract/contract.go index c1fffcdb4..d9f4676e6 100644 --- a/interop/contract/contract.go +++ b/interop/contract/contract.go @@ -1,5 +1,7 @@ package contract +import "github.com/CityOfZion/neo-storm/interop/storage" + // Package contract provides function signatures that can be used inside // smart contracts that are written in the neo-storm framework. @@ -15,3 +17,39 @@ func GetScript(c Contract) []byte { func IsPayable(c Contract) bool { return false } + +// GetStorageContext returns the storage context for the given contract. +func GetStorageContext(c Contract) storage.Context { + return storage.Context{} +} + +// Create creates a new contract. +// @FIXME What is the type of the returnType here? +func Create( + script []byte, + params []interface{}, + returnType byte, + properties interface{}, + name, + version, + author, + email, + description string) { +} + +// Migrate migrates a new contract. +// @FIXME What is the type of the returnType here? +func Migrate( + script []byte, + params []interface{}, + returnType byte, + properties interface{}, + name, + version, + author, + email, + description string) { +} + +// Destroy deletes a contract that is registered on the blockchain. +func Destroy(c Contract) {} diff --git a/interop/engine/engine.go b/interop/engine/engine.go new file mode 100644 index 000000000..2e2835927 --- /dev/null +++ b/interop/engine/engine.go @@ -0,0 +1,29 @@ +package engine + +import "github.com/CityOfZion/neo-storm/interop/transaction" + +// Package engine provides function signatures that can be used inside +// smart contracts that are written in the neo-storm framework. + +// GetScriptContainer returns the transaction that is in the execution context. +func GetScriptContainer() transaction.Transaction { + return transaction.Transaction{} +} + +// GetExecutingScriptHash returns the script hash of the contract that is +// currently being executed. +func GetExecutingScriptHash() []byte { + return nil +} + +// GetCallingScriptHash returns the script hash of the contract that started +// the execution of the current script. +func GetCallingScriptHash() []byte { + return nil +} + +// GetEntryScriptHash returns the script hash of the contract the started the +// execution from the start. +func GetEntryScriptHash() []byte { + return nil +} diff --git a/pkg/vm/compiler/analysis.go b/pkg/vm/compiler/analysis.go index 2c8422aa9..891aadd64 100644 --- a/pkg/vm/compiler/analysis.go +++ b/pkg/vm/compiler/analysis.go @@ -201,19 +201,12 @@ func isByteArray(lit *ast.CompositeLit, tInfo *types.Info) bool { return false } -func isSyscall(name string) bool { - _, ok := syscalls[name] - return ok -} - -// isNoRetSyscall checks if the syscall has a return value. -func isNoRetSyscall(name string) bool { - for _, s := range noRetSyscalls { - if s == name { - return true - } +func isSyscall(fun *funcScope) bool { + if fun.selector == nil { + return false } - return false + _, ok := syscalls[fun.selector.Name][fun.name] + return ok } func isStringType(t types.Type) bool { diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index 3756eaac3..1a0233f7a 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -185,7 +185,7 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl) { } // Load in all the global variables in to the scope of the function. // This is not necessary for syscalls. - if !isSyscall(f.name) { + if !isSyscall(f) { c.convertGlobals(file) } @@ -394,7 +394,10 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { // Dont forget to add 1 extra argument when its a method. numArgs++ } + f, ok = c.funcs[fun.Sel.Name] + // @FIXME this could cause runtime errors. + f.selector = fun.X.(*ast.Ident) if !ok { log.Fatalf("could not resolve function %s", fun.Sel.Name) } @@ -433,8 +436,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { // Use the ident to check, builtins are not in func scopes. // We can be sure builtins are of type *ast.Ident. c.convertBuiltin(n) - case isSyscall(f.name): - c.convertSyscall(f.name) + case isSyscall(f): + c.convertSyscall(f.selector.Name, f.name) default: emitCall(c.prog, vm.CALL, int16(f.label)) } @@ -531,8 +534,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { return c } -func (c *codegen) convertSyscall(name string) { - api, ok := syscalls[name] +func (c *codegen) convertSyscall(api, name string) { + api, ok := syscalls[api][name] if !ok { log.Fatalf("unknown VM syscall api: %s", name) } diff --git a/pkg/vm/compiler/func_scope.go b/pkg/vm/compiler/func_scope.go index 7fdc5f843..a71fcda07 100644 --- a/pkg/vm/compiler/func_scope.go +++ b/pkg/vm/compiler/func_scope.go @@ -10,6 +10,10 @@ type funcScope struct { // identifier of the function. name string + // Selector of the function if there is any. Only functions imported + // from other packages should have a selector. + selector *ast.Ident + // The declaration of the function in the AST. Nil if this scope is not a function. decl *ast.FuncDecl diff --git a/pkg/vm/compiler/syscall.go b/pkg/vm/compiler/syscall.go index ec545a51e..0ac9d45a0 100644 --- a/pkg/vm/compiler/syscall.go +++ b/pkg/vm/compiler/syscall.go @@ -1,69 +1,78 @@ package compiler -var syscalls = map[string]string{ - // - // Standard library API - // - - // Storage API - "GetContext": "System.Storage.GetContext", - "Put": "System.Storage.Put", - "Get": "System.Storage.Get", - "Delete": "System.Storage.Delete", - "Find": "System.Storage.Find", - - // Runtime API - "GetTrigger": "System.Runtime.GetTrigger", - "CheckWitness": "System.Runtime.CheckWitness", - "Notify": "System.Runtime.Notify", - "Log": "System.Runtime.Log", - "GetTime": "System.Runtime.GetTime", - "Serialize": "System.Runtime.Serialize", - "Deserialize": "System.Runtime.Deserialize", - - // Blockchain API - "GetHeight": "System.Blockchain.GetHeight", - "GetHeader": "System.Blockchain.GetHeader", - "GetBlock": "System.Blockchain.GetBlock", - "GetTransaction": "System.Blockchain.GetTransaction", - "GetTransactionHeight": "System.Blockchain.GetTransactionHeight", - "GetContract": "System.Blockchain.GetContract", - - // Header API - "GetIndex": "System.Header.GetContract", - "GetHash": "System.Header.GetHash", - "GetPrevHash": "System.Header.GetPrevHash", - "GetTimestamp": "System.Header.GetTimestamp", - - // Block API - "GetTransactionCount": "System.Block.GetTransactionCount", - "GetTransactions": "System.Block.GetTransactions", - // TODO: Find solution for duplicated map entry - "NGetTransaction": "System.Block.GetTransaction", - - // - // NEO specific API - // - - // Blockchain API - "GetAccount": "Neo.Blockchain.GetAccount", - "GetValidators": "Neo.Blockchain.GetValidators", - "GetAsset": "Neo.Blockchain.GetAsset", - - // Header API - "GetVersion": "Neo.Header.GetVersion", - "GetMerkleRoot": "Neo.Header.GetMerkleRoot", - "GetConsensusData": "Neo.Header.GetConsensusData", - "GetNextConsensus": "Neo.Header.GetNextConsensus", - - // Transaction API - "GetType": "Neo.Transaction.GetType", - "GetAttributes": "Neo.Transaction.GetAttributes", - "GetInputs": "Neo.Transaction.GetInputs", - "GetOutputs": "Neo.Transaction.GetOutputs", - "GetReferences": "Neo.Transaction.GetReferences", - "GetUnspentCoins": "Neo.Transaction.GetUnspentCoins", - "GetScript": "Neo.InvocationTransaction.GetScript", - - // TODO: Add the rest of the interop APIS +var syscalls = map[string]map[string]string{ + "storage": { + "GetContext": "System.Storage.GetContext", + "Put": "System.Storage.Put", + "Get": "System.Storage.Get", + "Delete": "System.Storage.Delete", + "Find": "System.Storage.Find", + }, + "runtime": { + "GetTrigger": "System.Runtime.GetTrigger", + "CheckWitness": "System.Runtime.CheckWitness", + "Notify": "System.Runtime.Notify", + "Log": "System.Runtime.Log", + "GetTime": "System.Runtime.GetTime", + "Serialize": "System.Runtime.Serialize", + "Deserialize": "System.Runtime.Deserialize", + }, + "blockchain": { + "GetHeight": "System.Blockchain.GetHeight", + "GetHeader": "System.Blockchain.GetHeader", + "GetBlock": "System.Blockchain.GetBlock", + "GetTransaction": "System.Blockchain.GetTransaction", + "GetContract": "System.Blockchain.GetContract", + "GetAccount": "Neo.Blockchain.GetAccount", + "GetValidators": "Neo.Blockchain.GetValidators", + "GetAsset": "Neo.Blockchain.GetAsset", + }, + "header": { + "GetIndex": "System.Header.GetIndex", + "GetHash": "System.Header.GetHash", + "GetPrevHash": "System.Header.GetPrevHash", + "GetTimestamp": "System.Header.GetTimestamp", + "GetVersion": "Neo.Header.GetVersion", + "GetMerkleRoot": "Neo.Header.GetMerkleRoot", + "GetConsensusData": "Neo.Header.GetConsensusData", + "GetNextConsensus": "Neo.Header.GetNextConsensus", + }, + "block": { + "GetTransactionCount": "System.Block.GetTransactionCount", + "GetTransactions": "System.Block.GetTransactions", + "GetTransaction": "System.Block.GetTransaction", + }, + "transaction": { + "GetType": "Neo.Transaction.GetType", + "GetAttributes": "Neo.Transaction.GetAttributes", + "GetInputs": "Neo.Transaction.GetInputs", + "GetOutputs": "Neo.Transaction.GetOutputs", + "GetReferences": "Neo.Transaction.GetReferences", + "GetUnspentCoins": "Neo.Transaction.GetUnspentCoins", + "GetScript": "Neo.Transaction.GetScript", + }, + "asset": { + "GetAssetID": "Neo.Asset.GetAssetID", + "GetAssetType": "Neo.Asset.GetAssetType", + "GetAmount": "Neo.Asset.GetAmount", + "Create": "Neo.Asset.Create", + "Renew": "Neo.Asset.Renew", + }, + "contract": { + "GetScript": "Neo.Contract.GetScript", + "IsPayable": "Neo.Contract.IsPayable", + "Create": "Neo.Contract.Create", + "Destroy": "Neo.Contract.Destroy", + "Migrate": "Neo.Contract.Migrate", + "GetStorageContext": "Neo.Contract.GetStorageContext", + }, + "input": { + "GetHash": "Neo.Input.GetHash", + "GetIndex": "Neo.Input.GetIndex", + }, + "output": { + "GetAssetID": "Neo.Output.GetAssetID", + "GetValue": "Neo.Output.GetValue", + "GetScriptHash": "Neo.Output.GetScriptHash", + }, } From 9e15ab04ce2efef6d015c411aab97062d2596020 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Wed, 22 Aug 2018 10:08:06 +0200 Subject: [PATCH 15/44] Added missing execution interop api (CityOfZion/neo-storm#14) Imported from CityOfZion/neo-storm (ab12273da74e0d35df8863f08f1a914723d2bdba). --- pkg/vm/compiler/syscall.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/vm/compiler/syscall.go b/pkg/vm/compiler/syscall.go index 0ac9d45a0..1e42f633f 100644 --- a/pkg/vm/compiler/syscall.go +++ b/pkg/vm/compiler/syscall.go @@ -75,4 +75,10 @@ var syscalls = map[string]map[string]string{ "GetValue": "Neo.Output.GetValue", "GetScriptHash": "Neo.Output.GetScriptHash", }, + "engine": { + "GetScriptContainer": "System.ExecutionEngine.GetScriptContainer", + "GetCallingScriptHash": "System.ExecutionEngine.GetCallingScriptHash", + "GetEntryScriptHash": "System.ExecutionEngine.GetEntryScriptHash", + "GetExecutingScriptHash": "System.ExecutionEngine.GetExecutingScriptHash", + }, } From 8bfaed0e4b938f24c7748ecf0f7672925d9fffa8 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Wed, 22 Aug 2018 10:12:57 +0200 Subject: [PATCH 16/44] added in the crypto helper api for smart contracts. (CityOfZion/neo-storm#15) Imported from CityOfZion/neo-storm (ad6e9dae46846f97a7da6dd48bf55ad554d612b3). --- interop/crypto/crypto.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 interop/crypto/crypto.go diff --git a/interop/crypto/crypto.go b/interop/crypto/crypto.go new file mode 100644 index 000000000..b9d71325e --- /dev/null +++ b/interop/crypto/crypto.go @@ -0,0 +1,24 @@ +package crypto + +// Package crypto provides function signatures that can be used inside +// smart contracts that are written in the neo-storm framework. + +// SHA1 computes the sha1 hash of b. +func SHA1(b []byte) []byte { + return nil +} + +// SHA256 computes the sha256 hash of b. +func SHA256(b []byte) []byte { + return nil +} + +// Hash160 computes the sha256 + ripemd160 of b. +func Hash160(b []byte) []byte { + return nil +} + +// Hash256 computes the sha256^2 hash of b. +func Hash256(b []byte) []byte { + return nil +} From b3037cd598a6de6b6e2992fdc74858c31c3c1879 Mon Sep 17 00:00:00 2001 From: Jeroen Peeters Date: Wed, 22 Aug 2018 18:23:19 +0200 Subject: [PATCH 17/44] Token Example (CityOfZion/neo-storm#12) * feat: add token example * feat: code splitted package * feat: use updated apis Imported from CityOfZion/neo-storm (e2bab450d7355b559ae2d70a87f557e8a6dbfff6). --- .gitignore | 1 + examples/token/token.go | 70 ++++++++++++++++ examples/token/vendor/token/token.go | 115 +++++++++++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 examples/token/token.go create mode 100644 examples/token/vendor/token/token.go diff --git a/.gitignore b/.gitignore index 383d43756..b6c1b81c1 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ # Added by CoZ developers vendor/ bin/ +!examples/**/vendor # text editors # vscode diff --git a/examples/token/token.go b/examples/token/token.go new file mode 100644 index 000000000..6505ce454 --- /dev/null +++ b/examples/token/token.go @@ -0,0 +1,70 @@ +package token_contract + +import ( + "token" + + "github.com/CityOfZion/neo-storm/interop/storage" + "github.com/CityOfZion/neo-storm/interop/util" +) + +const ( + decimals = 8 + multiplier = 100000000 +) + +var owner = util.FromAddress("AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y") + +// CreateToken initializes the Token Interface for the Smart Contract to operate with +func CreateToken() token.Token { + return token.Token{ + Name: "Awesome NEO Token", + Symbol: "ANT", + Decimals: decimals, + Owner: owner, + TotalSupply: 11000000 * multiplier, + CirculationKey: "TokenCirculation", + } +} + +// Main function = contract entry +func Main(operation string, args []interface{}) interface{} { + token := CreateToken() + + if operation == "name" { + return token.Name + } + if operation == "symbol" { + return token.Symbol + } + if operation == "decimals" { + return token.Decimals + } + + // The following operations need ctx + ctx := storage.GetContext() + + if operation == "totalSupply" { + return token.GetSupply(ctx) + } + if operation == "balanceOf" { + hodler := args[0].([]byte) + return token.BalanceOf(ctx, hodler) + } + if operation == "transfer" && CheckArgs(args, 3) { + from := args[0].([]byte) + to := args[1].([]byte) + amount := args[2].(int) + return token.Transfer(ctx, from, to, amount) + } + + return true +} + +// CheckArgs checks args array against a length indicator +func CheckArgs(args []interface{}, length int) bool { + if len(args) == length { + return true + } + + return false +} diff --git a/examples/token/vendor/token/token.go b/examples/token/vendor/token/token.go new file mode 100644 index 000000000..7a064350c --- /dev/null +++ b/examples/token/vendor/token/token.go @@ -0,0 +1,115 @@ +package token + +import ( + "github.com/CityOfZion/neo-storm/interop/engine" + "github.com/CityOfZion/neo-storm/interop/runtime" + "github.com/CityOfZion/neo-storm/interop/storage" +) + +// Token holds all token info +type Token struct { + // Token name + Name string + // Ticker symbol + Symbol string + // Amount of decimals + Decimals int + // Token owner address + Owner []byte + // Total tokens * multiplier + TotalSupply int + // Storage key for circulation value + CirculationKey string +} + +// TODO: Transfer event +// DoTransfer := action.RegisterAction("transfer", "from", "to", "amount") + +// GetSupply gets the token totalSupply value from VM storage +func (t Token) GetSupply(ctx storage.Context) interface{} { + return storage.Get(ctx, t.CirculationKey) +} + +// BalanceOf gets the token balance of a specific address +func (t Token) BalanceOf(ctx storage.Context, hodler []byte) interface{} { + return storage.Get(ctx, hodler) +} + +// Transfer token from one user to another +func (t Token) Transfer(ctx storage.Context, from []byte, to []byte, amount int) bool { + amountFrom := t.CanTransfer(ctx, from, to, amount) + if amountFrom == -1 { + return false + } + + if amountFrom == 0 { + storage.Delete(ctx, from) + } + + if amountFrom > 0 { + diff := amountFrom - amount + storage.Put(ctx, from, diff) + } + + amountTo := storage.Get(ctx, to).(int) + totalAmountTo := amountTo + amount + storage.Put(ctx, to, totalAmountTo) + // DoTransfer(from, to, amount) + return true +} + +// CanTransfer returns the amount it can transfer +func (t Token) CanTransfer(ctx storage.Context, from []byte, to []byte, amount int) int { + if len(to) != 20 && !IsUsableAddress(from) { + return -1 + } + + amountFrom := storage.Get(ctx, from).(int) + if amountFrom < amount { + return -1 + } + + // Tell Transfer the result is equal - special case since it uses Delete + if amountFrom == amount { + return 0 + } + + // return amountFrom value back to Transfer, reduces extra Get + return amountFrom +} + +// IsUsableAddress checks if the sender is either the correct NEO address or SC address +func IsUsableAddress(addr []byte) bool { + if len(addr) == 20 { + + if runtime.CheckWitness(addr) { + return true + } + + // Check if a smart contract is calling scripthash + callingScriptHash := engine.GetCallingScriptHash() + if EqualAddresses(callingScriptHash, addr) { + return true + } + } + + return false +} + +// EqualAddresses compares two addresses if they're equal +// also returns false if one of the two - or both - aren't actual addresses +func EqualAddresses(a []byte, b []byte) bool { + aLen := len(a) + bLen := len(b) + if aLen != bLen || aLen != 20 || bLen != 20 { + return false + } + + for i := 0; i < aLen; i++ { + if a[i] != b[i] { + return false + } + } + + return true +} From 1f8ccdba16d023b76ecb21f072f2e1667e87362f Mon Sep 17 00:00:00 2001 From: Jeroen Peeters Date: Wed, 22 Aug 2018 18:49:30 +0200 Subject: [PATCH 18/44] chore: move token example to nep5 as package name (CityOfZion/neo-storm#19) * feat: add token example * feat: code splitted package * feat: use updated apis * chore: change token namespace to nep5 * chore: add transfer event and readme updates Imported from CityOfZion/neo-storm (63ec2d7dc23a60f128a8b383ceda1eaa15d919c1). --- examples/token/token.go | 6 +- examples/token/vendor/nep5/nep5.go | 112 +++++++++++++++++++++++++++++ interop/runtime/runtime.go | 4 +- pkg/vm/compiler/compiler_test.go | 2 +- 4 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 examples/token/vendor/nep5/nep5.go diff --git a/examples/token/token.go b/examples/token/token.go index 6505ce454..73b3ffba7 100644 --- a/examples/token/token.go +++ b/examples/token/token.go @@ -1,7 +1,7 @@ package token_contract import ( - "token" + "nep5" "github.com/CityOfZion/neo-storm/interop/storage" "github.com/CityOfZion/neo-storm/interop/util" @@ -15,8 +15,8 @@ const ( var owner = util.FromAddress("AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y") // CreateToken initializes the Token Interface for the Smart Contract to operate with -func CreateToken() token.Token { - return token.Token{ +func CreateToken() nep5.Token { + return nep5.Token{ Name: "Awesome NEO Token", Symbol: "ANT", Decimals: decimals, diff --git a/examples/token/vendor/nep5/nep5.go b/examples/token/vendor/nep5/nep5.go new file mode 100644 index 000000000..301ff6117 --- /dev/null +++ b/examples/token/vendor/nep5/nep5.go @@ -0,0 +1,112 @@ +package nep5 + +import ( + "github.com/CityOfZion/neo-storm/interop/engine" + "github.com/CityOfZion/neo-storm/interop/runtime" + "github.com/CityOfZion/neo-storm/interop/storage" +) + +// Token holds all token info +type Token struct { + // Token name + Name string + // Ticker symbol + Symbol string + // Amount of decimals + Decimals int + // Token owner address + Owner []byte + // Total tokens * multiplier + TotalSupply int + // Storage key for circulation value + CirculationKey string +} + +// GetSupply gets the token totalSupply value from VM storage +func (t Token) GetSupply(ctx storage.Context) interface{} { + return storage.Get(ctx, t.CirculationKey) +} + +// BalanceOf gets the token balance of a specific address +func (t Token) BalanceOf(ctx storage.Context, hodler []byte) interface{} { + return storage.Get(ctx, hodler) +} + +// Transfer token from one user to another +func (t Token) Transfer(ctx storage.Context, from []byte, to []byte, amount int) bool { + amountFrom := t.CanTransfer(ctx, from, to, amount) + if amountFrom == -1 { + return false + } + + if amountFrom == 0 { + storage.Delete(ctx, from) + } + + if amountFrom > 0 { + diff := amountFrom - amount + storage.Put(ctx, from, diff) + } + + amountTo := storage.Get(ctx, to).(int) + totalAmountTo := amountTo + amount + storage.Put(ctx, to, totalAmountTo) + runtime.Notify("transfer", from, to, amount) + return true +} + +// CanTransfer returns the amount it can transfer +func (t Token) CanTransfer(ctx storage.Context, from []byte, to []byte, amount int) int { + if len(to) != 20 && !IsUsableAddress(from) { + return -1 + } + + amountFrom := storage.Get(ctx, from).(int) + if amountFrom < amount { + return -1 + } + + // Tell Transfer the result is equal - special case since it uses Delete + if amountFrom == amount { + return 0 + } + + // return amountFrom value back to Transfer, reduces extra Get + return amountFrom +} + +// IsUsableAddress checks if the sender is either the correct NEO address or SC address +func IsUsableAddress(addr []byte) bool { + if len(addr) == 20 { + + if runtime.CheckWitness(addr) { + return true + } + + // Check if a smart contract is calling scripthash + callingScriptHash := engine.GetCallingScriptHash() + if EqualAddresses(callingScriptHash, addr) { + return true + } + } + + return false +} + +// EqualAddresses compares two addresses if they're equal +// also returns false if one of the two - or both - aren't actual addresses +func EqualAddresses(a []byte, b []byte) bool { + aLen := len(a) + bLen := len(b) + if aLen != bLen || aLen != 20 || bLen != 20 { + return false + } + + for i := 0; i < aLen; i++ { + if a[i] != b[i] { + return false + } + } + + return true +} diff --git a/interop/runtime/runtime.go b/interop/runtime/runtime.go index 9f27ec001..40df58b17 100644 --- a/interop/runtime/runtime.go +++ b/interop/runtime/runtime.go @@ -12,7 +12,7 @@ func CheckWitness(hash []byte) bool { func Log(message string) {} // Notify an event to the VM. -func Notify(arg interface{}) int { +func Notify(arg ...interface{}) int { return 0 } @@ -42,7 +42,7 @@ func Serialize(item interface{}) []byte { return nil } -// Deserializes an item from a bytearray. +// Deserialize an item from a bytearray. func Deserialize(b []byte) interface{} { return nil } diff --git a/pkg/vm/compiler/compiler_test.go b/pkg/vm/compiler/compiler_test.go index ac17fcc25..a42bd418d 100644 --- a/pkg/vm/compiler/compiler_test.go +++ b/pkg/vm/compiler/compiler_test.go @@ -23,7 +23,7 @@ func TestExamplesFolder(t *testing.T) { t.Fatal(err) } if len(infos) > 1 { - t.Fatal("detected smart contract folder with more then 1 contract file") + t.Fatal("detected smart contract folder with more than 1 contract file") } if len(infos) == 0 { t.Fatal("detected smart contract folder with no contract in it") From b997eeb051aa095d293f16bbe1b90eadd8c2d0d2 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Wed, 22 Aug 2018 19:07:36 +0200 Subject: [PATCH 19/44] fixed token example and fixed compiler test with multiple dirs (CityOfZion/neo-storm#20) Imported from CityOfZion/neo-storm (2d0814a04c34f320dee41674066ccd766a7a8ea1). --- examples/token/{vendor => }/nep5/nep5.go | 0 examples/token/token.go | 2 +- examples/token/{vendor => }/token/token.go | 0 pkg/vm/compiler/compiler_test.go | 15 +++++++++++---- 4 files changed, 12 insertions(+), 5 deletions(-) rename examples/token/{vendor => }/nep5/nep5.go (100%) rename examples/token/{vendor => }/token/token.go (100%) diff --git a/examples/token/vendor/nep5/nep5.go b/examples/token/nep5/nep5.go similarity index 100% rename from examples/token/vendor/nep5/nep5.go rename to examples/token/nep5/nep5.go diff --git a/examples/token/token.go b/examples/token/token.go index 73b3ffba7..834d0ffbd 100644 --- a/examples/token/token.go +++ b/examples/token/token.go @@ -1,7 +1,7 @@ package token_contract import ( - "nep5" + "github.com/CityOfZion/neo-storm/examples/token/nep5" "github.com/CityOfZion/neo-storm/interop/storage" "github.com/CityOfZion/neo-storm/interop/util" diff --git a/examples/token/vendor/token/token.go b/examples/token/token/token.go similarity index 100% rename from examples/token/vendor/token/token.go rename to examples/token/token/token.go diff --git a/pkg/vm/compiler/compiler_test.go b/pkg/vm/compiler/compiler_test.go index a42bd418d..1ab46d1ae 100644 --- a/pkg/vm/compiler/compiler_test.go +++ b/pkg/vm/compiler/compiler_test.go @@ -22,13 +22,11 @@ func TestExamplesFolder(t *testing.T) { if err != nil { t.Fatal(err) } - if len(infos) > 1 { - t.Fatal("detected smart contract folder with more than 1 contract file") - } if len(infos) == 0 { t.Fatal("detected smart contract folder with no contract in it") } - filename := infos[0].Name() + + filename := filterFilename(infos) targetPath := path.Join(examplePath, info.Name(), filename) if err := compileFile(targetPath); err != nil { t.Fatal(err) @@ -36,6 +34,15 @@ func TestExamplesFolder(t *testing.T) { } } +func filterFilename(infos []os.FileInfo) string { + for _, info := range infos { + if !info.IsDir() { + return info.Name() + } + } + return "" +} + func compileFile(src string) error { o := compiler.Options{ Outfile: "tmp/contract.avm", From f14833893c0b3799369876e82f46b20a0885abe1 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Thu, 23 Aug 2018 10:17:42 +0200 Subject: [PATCH 20/44] CityOfZion/neo-storm#17 Implemented util.CompareBytes (CityOfZion/neo-storm#21) Imported from CityOfZion/neo-storm (c0ee185a7cfd2c222fb7b4c8ca19885844d53855). --- examples/token/token/token.go | 22 ++-------------------- interop/util/util.go | 6 ++++++ pkg/vm/compiler/analysis.go | 10 ++-------- pkg/vm/compiler/codegen.go | 2 ++ 4 files changed, 12 insertions(+), 28 deletions(-) diff --git a/examples/token/token/token.go b/examples/token/token/token.go index 7a064350c..9aa10e6b2 100644 --- a/examples/token/token/token.go +++ b/examples/token/token/token.go @@ -4,6 +4,7 @@ import ( "github.com/CityOfZion/neo-storm/interop/engine" "github.com/CityOfZion/neo-storm/interop/runtime" "github.com/CityOfZion/neo-storm/interop/storage" + "github.com/CityOfZion/neo-storm/interop/util" ) // Token holds all token info @@ -81,35 +82,16 @@ func (t Token) CanTransfer(ctx storage.Context, from []byte, to []byte, amount i // IsUsableAddress checks if the sender is either the correct NEO address or SC address func IsUsableAddress(addr []byte) bool { if len(addr) == 20 { - if runtime.CheckWitness(addr) { return true } // Check if a smart contract is calling scripthash callingScriptHash := engine.GetCallingScriptHash() - if EqualAddresses(callingScriptHash, addr) { + if util.CompareBytes(callingScriptHash, addr) { return true } } return false } - -// EqualAddresses compares two addresses if they're equal -// also returns false if one of the two - or both - aren't actual addresses -func EqualAddresses(a []byte, b []byte) bool { - aLen := len(a) - bLen := len(b) - if aLen != bLen || aLen != 20 || bLen != 20 { - return false - } - - for i := 0; i < aLen; i++ { - if a[i] != b[i] { - return false - } - } - - return true -} diff --git a/interop/util/util.go b/interop/util/util.go index f5b658fdd..02dce23a3 100644 --- a/interop/util/util.go +++ b/interop/util/util.go @@ -4,3 +4,9 @@ package util func FromAddress(address string) []byte { return nil } + +// CompareBytes compares a with b and will return true whether a and b +// are equal. +func CompareBytes(a, b []byte) bool { + return false +} diff --git a/pkg/vm/compiler/analysis.go b/pkg/vm/compiler/analysis.go index 891aadd64..aef876a7f 100644 --- a/pkg/vm/compiler/analysis.go +++ b/pkg/vm/compiler/analysis.go @@ -13,14 +13,8 @@ var ( // Go language builtin functions and custom builtin utility functions. builtinFuncs = []string{ "len", "append", "SHA256", - "SHA1", "Hash256", "Hash160", "FromAddress", - } - - // VM system calls that have no return value. - noRetSyscalls = []string{ - "Notify", "Log", "Put", "Register", "Delete", - "SetVotes", "ContractDestroy", "MerkleRoot", "Hash", - "PrevHash", "GetHeader", + "SHA1", "Hash256", "Hash160", + "FromAddress", "CompareBytes", } ) diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index 1a0233f7a..9d872e2d3 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -571,6 +571,8 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) { emitOpcode(c.prog, vm.HASH256) case "Hash160": emitOpcode(c.prog, vm.HASH160) + case "CompareBytes": + emitOpcode(c.prog, vm.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 From df173c295dd0402317d4b707f428df2e75f22aa3 Mon Sep 17 00:00:00 2001 From: Jeroen Peeters Date: Thu, 23 Aug 2018 19:44:17 +0200 Subject: [PATCH 21/44] chore: change CompareBytes to EqualBytes (CityOfZion/neo-storm#22) * chore: change CompareBytes to EqualBytes * chore: remove trailing spaces * chore: rename EqualBytes to Equals Imported from CityOfZion/neo-storm (da16e967d9631e132488731a42966bccb5ad7f30). --- examples/token/nep5/nep5.go | 21 +------- examples/token/token/token.go | 97 ----------------------------------- interop/util/util.go | 4 +- pkg/vm/compiler/analysis.go | 2 +- pkg/vm/compiler/codegen.go | 2 +- 5 files changed, 6 insertions(+), 120 deletions(-) delete mode 100644 examples/token/token/token.go diff --git a/examples/token/nep5/nep5.go b/examples/token/nep5/nep5.go index 301ff6117..cd38ab81a 100644 --- a/examples/token/nep5/nep5.go +++ b/examples/token/nep5/nep5.go @@ -4,6 +4,7 @@ import ( "github.com/CityOfZion/neo-storm/interop/engine" "github.com/CityOfZion/neo-storm/interop/runtime" "github.com/CityOfZion/neo-storm/interop/storage" + "github.com/CityOfZion/neo-storm/interop/util" ) // Token holds all token info @@ -85,28 +86,10 @@ func IsUsableAddress(addr []byte) bool { // Check if a smart contract is calling scripthash callingScriptHash := engine.GetCallingScriptHash() - if EqualAddresses(callingScriptHash, addr) { + if util.Equals(callingScriptHash, addr) { return true } } return false } - -// EqualAddresses compares two addresses if they're equal -// also returns false if one of the two - or both - aren't actual addresses -func EqualAddresses(a []byte, b []byte) bool { - aLen := len(a) - bLen := len(b) - if aLen != bLen || aLen != 20 || bLen != 20 { - return false - } - - for i := 0; i < aLen; i++ { - if a[i] != b[i] { - return false - } - } - - return true -} diff --git a/examples/token/token/token.go b/examples/token/token/token.go deleted file mode 100644 index 9aa10e6b2..000000000 --- a/examples/token/token/token.go +++ /dev/null @@ -1,97 +0,0 @@ -package token - -import ( - "github.com/CityOfZion/neo-storm/interop/engine" - "github.com/CityOfZion/neo-storm/interop/runtime" - "github.com/CityOfZion/neo-storm/interop/storage" - "github.com/CityOfZion/neo-storm/interop/util" -) - -// Token holds all token info -type Token struct { - // Token name - Name string - // Ticker symbol - Symbol string - // Amount of decimals - Decimals int - // Token owner address - Owner []byte - // Total tokens * multiplier - TotalSupply int - // Storage key for circulation value - CirculationKey string -} - -// TODO: Transfer event -// DoTransfer := action.RegisterAction("transfer", "from", "to", "amount") - -// GetSupply gets the token totalSupply value from VM storage -func (t Token) GetSupply(ctx storage.Context) interface{} { - return storage.Get(ctx, t.CirculationKey) -} - -// BalanceOf gets the token balance of a specific address -func (t Token) BalanceOf(ctx storage.Context, hodler []byte) interface{} { - return storage.Get(ctx, hodler) -} - -// Transfer token from one user to another -func (t Token) Transfer(ctx storage.Context, from []byte, to []byte, amount int) bool { - amountFrom := t.CanTransfer(ctx, from, to, amount) - if amountFrom == -1 { - return false - } - - if amountFrom == 0 { - storage.Delete(ctx, from) - } - - if amountFrom > 0 { - diff := amountFrom - amount - storage.Put(ctx, from, diff) - } - - amountTo := storage.Get(ctx, to).(int) - totalAmountTo := amountTo + amount - storage.Put(ctx, to, totalAmountTo) - // DoTransfer(from, to, amount) - return true -} - -// CanTransfer returns the amount it can transfer -func (t Token) CanTransfer(ctx storage.Context, from []byte, to []byte, amount int) int { - if len(to) != 20 && !IsUsableAddress(from) { - return -1 - } - - amountFrom := storage.Get(ctx, from).(int) - if amountFrom < amount { - return -1 - } - - // Tell Transfer the result is equal - special case since it uses Delete - if amountFrom == amount { - return 0 - } - - // return amountFrom value back to Transfer, reduces extra Get - return amountFrom -} - -// IsUsableAddress checks if the sender is either the correct NEO address or SC address -func IsUsableAddress(addr []byte) bool { - if len(addr) == 20 { - if runtime.CheckWitness(addr) { - return true - } - - // Check if a smart contract is calling scripthash - callingScriptHash := engine.GetCallingScriptHash() - if util.CompareBytes(callingScriptHash, addr) { - return true - } - } - - return false -} diff --git a/interop/util/util.go b/interop/util/util.go index 02dce23a3..1f05d4941 100644 --- a/interop/util/util.go +++ b/interop/util/util.go @@ -5,8 +5,8 @@ func FromAddress(address string) []byte { return nil } -// CompareBytes compares a with b and will return true whether a and b +// Equals compares a with b and will return true whether a and b // are equal. -func CompareBytes(a, b []byte) bool { +func Equals(a, b interface{}) bool { return false } diff --git a/pkg/vm/compiler/analysis.go b/pkg/vm/compiler/analysis.go index aef876a7f..011901f2a 100644 --- a/pkg/vm/compiler/analysis.go +++ b/pkg/vm/compiler/analysis.go @@ -14,7 +14,7 @@ var ( builtinFuncs = []string{ "len", "append", "SHA256", "SHA1", "Hash256", "Hash160", - "FromAddress", "CompareBytes", + "FromAddress", "Equals", } ) diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index 9d872e2d3..fbc7bb63e 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -571,7 +571,7 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) { emitOpcode(c.prog, vm.HASH256) case "Hash160": emitOpcode(c.prog, vm.HASH160) - case "CompareBytes": + case "Equals": emitOpcode(c.prog, vm.EQUAL) case "FromAddress": // We can be sure that this is a ast.BasicLit just containing a simple From 3fc25e14311c6480ae82d2e921d62c9dc9ac6b70 Mon Sep 17 00:00:00 2001 From: Ankur Srivastava Date: Sat, 25 Aug 2018 16:40:15 +0200 Subject: [PATCH 22/44] fixes CityOfZion/neo-storm#16 * A new command `cli init --name testcontract` now creates a directory testcontract/main.go Imported from CityOfZion/neo-storm (331585e51ce13b6fe902b7a352b150c5b457a4f5). --- cli/smartcontract/smart_contract.go | 62 ++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 57a4a4a2b..14d81da6b 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -4,16 +4,33 @@ import ( "context" "encoding/hex" "encoding/json" + "errors" "fmt" "io/ioutil" + "os" + "path/filepath" "github.com/CityOfZion/neo-go/pkg/rpc" "github.com/CityOfZion/neo-go/pkg/vm/compiler" "github.com/urfave/cli" ) -const ( - errNoInput = "Input file is mandatory and should be passed using -i flag." +var ( + errNoInput = errors.New("No input file was found, specify an input file with the '--in or -i' flag") + errNoSmartContractName = errors.New("No name was provided, specify the '--name or -n' flag") + errFileExist = errors.New("A file with given smart-contract name already exists") +) + +var ( + // smartContractTmpl is written to a file when used with `init` command. + // %s is parsed to be the smartContractName + smartContractTmpl = `package %s + +import "github.com/CityOfZion/neo-storm/interop/runtime" + +func Main(op string, args []interface{}) { + runtime.Notify("Hello world!") +}` ) // NewCommand returns a new contract command. @@ -63,10 +80,51 @@ func NewCommand() cli.Command { }, }, }, + { + Name: "init", + Usage: "initialize a new smart-contract in a directory with boiler plate code", + Action: initSmartContract, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "name, n", + Usage: "name of the smart-contract to be initialized", + }, + }, + }, }, } } +// initSmartContract initializes a given directory with some boiler plate code. +func initSmartContract(ctx *cli.Context) error { + scName := ctx.String("name") + if scName == "" { + return cli.NewExitError(errNoSmartContractName, 1) + } + + // Check if the file already exists, if yes, exit + if _, err := os.Stat(scName); err == nil { + return cli.NewExitError(errFileExist, 1) + } + + basePath := scName + fileName := "main.go" + + // create base directory + err := os.Mkdir(basePath, os.ModePerm) + if err != nil { + return cli.NewExitError(err, 1) + } + + data := []byte(fmt.Sprintf(smartContractTmpl, scName)) + err = ioutil.WriteFile(filepath.Join(basePath, fileName), data, 0644) + if err != nil { + return cli.NewExitError(err, 1) + } + fmt.Printf("Successfully initialized smart contract [%s]\n", scName) + return nil +} + func contractCompile(ctx *cli.Context) error { src := ctx.String("in") if len(src) == 0 { From 55966c7e078dfa9dbba53c17e05ded651fcf960c Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Fri, 31 Aug 2018 10:23:57 +0200 Subject: [PATCH 23/44] Draft of iterator and enumerator (CityOfZion/neo-storm#26) * Draft of iterator and enumerator * Added iterator API to the syscall mapping * Added draft of the enumerator.go file * Added enumerator interop API. * Updated the changelog Imported from CityOfZion/neo-storm (156093318b8612e810965bb1ea26e1babfb46cdd). --- examples/iterator/iterator.go | 18 ++++++++++++++++++ interop/enumerator/enumerator.go | 29 +++++++++++++++++++++++++++++ interop/iterator/iterator.go | 28 ++++++++++++++++++++++++++++ interop/storage/storage.go | 6 ++++-- pkg/vm/compiler/syscall.go | 6 ++++++ 5 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 examples/iterator/iterator.go create mode 100644 interop/enumerator/enumerator.go create mode 100644 interop/iterator/iterator.go diff --git a/examples/iterator/iterator.go b/examples/iterator/iterator.go new file mode 100644 index 000000000..4ccf996b3 --- /dev/null +++ b/examples/iterator/iterator.go @@ -0,0 +1,18 @@ +package iterator_contract + +import ( + "github.com/CityOfZion/neo-storm/interop/iterator" + "github.com/CityOfZion/neo-storm/interop/runtime" + "github.com/CityOfZion/neo-storm/interop/storage" +) + +func Main() bool { + iter := storage.Find(storage.GetContext(), []byte("foo")) + values := iterator.Values(iter) + keys := iterator.Keys(iter) + + runtime.Notify("found storage values", values) + runtime.Notify("found storage keys", keys) + + return true +} diff --git a/interop/enumerator/enumerator.go b/interop/enumerator/enumerator.go new file mode 100644 index 000000000..e2b906c34 --- /dev/null +++ b/interop/enumerator/enumerator.go @@ -0,0 +1,29 @@ +package enumerator + +// Package enumerator provides function signatures that can be used inside +// smart contracts that are written in the neo-storm framework. + +// TODO: Check enumerator use cases and add them to the examples folder. + +// Enumerator stubs a NEO enumerator type. +type Enumerator struct{} + +// Create creates a new enumerator from the given items. +func Create(items []interface{}) Enumerator { + return Enumerator{} +} + +// Next returns the next item in the iteration. +func Next(e Enumerator) interface{} { + return nil +} + +// Value returns the enumerator value. +func Value(e Enumerator) interface{} { + return nil +} + +// Concat concats the 2 given enumerators. +func Concat(a, b Enumerator) Enumerator { + return Enumerator{} +} diff --git a/interop/iterator/iterator.go b/interop/iterator/iterator.go new file mode 100644 index 000000000..352cf3f17 --- /dev/null +++ b/interop/iterator/iterator.go @@ -0,0 +1,28 @@ +package iterator + +// Package iterator provides function signatures that can be used inside +// smart contracts that are written in the neo-storm framework. + +// Iterator stubs a NEO iterator object type. +type Iterator struct{} + +// Create creates an iterator from the given items. +func Create(items []interface{}) Iterator { + return Iterator{} +} + +// TODO: Better description for this. +// Key returns the iterator key. +func Key(it Iterator) interface{} { + return nil +} + +// Keys returns the iterator keys. +func Keys(it Iterator) []interface{} { + return nil +} + +// Values returns the iterator values. +func Values(it Iterator) []interface{} { + return nil +} diff --git a/interop/storage/storage.go b/interop/storage/storage.go index b280e834f..25cf4ef34 100644 --- a/interop/storage/storage.go +++ b/interop/storage/storage.go @@ -1,5 +1,7 @@ package storage +import "github.com/CityOfZion/neo-storm/interop/iterator" + // Package storage provides function signatures that can be used inside // smart contracts that are written in the neo-storm framework. @@ -18,5 +20,5 @@ func Get(ctx Context, key interface{}) interface{} { return 0 } // Delete key value pair from storage func Delete(ctx Context, key interface{}) {} -// Find values stored on keys partially matching given key -func Find(ctx Context, key interface{}) interface{} { return 0 } +// Find returns an iterator.Iterator over the keys that matched the given key. +func Find(ctx Context, key interface{}) iterator.Iterator { return iterator.Iterator{} } diff --git a/pkg/vm/compiler/syscall.go b/pkg/vm/compiler/syscall.go index 1e42f633f..7a9d05146 100644 --- a/pkg/vm/compiler/syscall.go +++ b/pkg/vm/compiler/syscall.go @@ -81,4 +81,10 @@ var syscalls = map[string]map[string]string{ "GetEntryScriptHash": "System.ExecutionEngine.GetEntryScriptHash", "GetExecutingScriptHash": "System.ExecutionEngine.GetExecutingScriptHash", }, + "iterator": { + "Create": "Neo.Iterator.Create", + "Key": "Neo.Iterator.Key", + "Keys": "Neo.Iterator.Keys", + "Values": "Neo.Iterator.Values", + }, } From 54a886a7fee27e6e1642423acbfab151972c0636 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Fri, 14 Sep 2018 13:25:53 +0200 Subject: [PATCH 24/44] Added docs folder with first draft of the runtime and smart contract API (CityOfZion/neo-storm#31) * Added docs folder with first draft of the runtime and smart contract API * Draft of the runtime/neo smart contract api * Added more API documentation. * Added the last API documentation for the NEO runtime and interop functions. Imported from CityOfZion/neo-storm (bc7749ee08f2f48b87f13400e5917ee28e854d86). --- docs/runtime.md | 523 +++++++++++++++++++++++++++++++++++++++ interop/engine/engine.go | 2 +- 2 files changed, 524 insertions(+), 1 deletion(-) create mode 100644 docs/runtime.md diff --git a/docs/runtime.md b/docs/runtime.md new file mode 100644 index 000000000..92ed485d0 --- /dev/null +++ b/docs/runtime.md @@ -0,0 +1,523 @@ +# Runtime +A brief overview of NEO smart contract API's that can be used in the neo-storm framework. + +# Overview +1. [Account]() +2. [Asset]() +3. [Attribute]() +4. [Block]() +5. [Blockchain]() +6. [Contract]() +7. [Crypto]() +8. [Engine]() +9. [Enumerator]() +10. [Iterator]() +11. [Header]() +12. [Input]() +13. [Output]() +14. [Runtime]() +15. [Storage]() +16. [Transaction]() +17. [Util]() + +## Account +#### GetScriptHash +``` +GetScriptHash(a Account) []byte +``` +Returns the script hash of the given account. + +#### GetVotes +``` +GetVotes(a Account) [][]byte +``` +Returns the the votes (a slice of public keys) of the given account. + +#### GetBalance +``` +GetBalance(a Account, assetID []byte) int +``` +Returns the balance of the given asset id for the given account. + +## Asset +#### GetAssetID +``` +GetAssetID(a Asset) []byte +``` +Returns the id of the given asset. + +#### GetAmount +``` +GetAmount(a Asset) int +``` +Returns the amount of the given asset id. + +#### GetAvailable +``` +GetAvailable(a Asset) int +``` +Returns the available amount of the given asset. + +#### GetPrecision +``` +GetPrecision(a Asset) byte +``` +Returns the precision of the given Asset. + +#### GetOwner +``` +GetOwner(a Asset) []byte +``` +Returns the owner of the given asset. + +#### GetAdmin +``` +GetAdmin(a Asset) []byte +``` +Returns the admin of the given asset. + +#### GetIssuer +``` +GetIssuer(a Asset) []byte +``` +Returns the issuer of the given asset. + +#### Create +``` +Create(type byte, name string, amount int, precision byte, owner, admin, issuer []byte) +``` +Creates a new asset on the blockchain. + +#### Renew +``` +Renew(asset Asset, years int) +``` +Renews the given asset as long as the given years. + +## Attribute +#### GetUsage +``` +GetUsage(attr Attribute) []byte +``` +Returns the usage of the given attribute. + +#### GetData +``` +GetData(attr Attribute) []byte +``` +Returns the data of the given attribute. + +## Block +#### GetTransactionCount +``` +GetTransactionCount(b Block) int +``` +Returns the number of transactions that are recorded in the given block. + +#### GetTransactions +``` +GetTransactions(b Block) []transaction.Transaction +``` +Returns a slice of the transactions that are recorded in the given block. + +#### GetTransaction +``` +GetTransaction(b Block, hash []byte) transaction.Transaction +``` +Returns the transaction by the given hash that is recorded in the given block. + +## Blockchain +#### GetHeight +``` +GetHeight() int +``` +Returns the current height of the blockchain. + +#### GetHeader +``` +GetHeader(heightOrHash []interface{}) header.Header +``` +Return the header by the given hash or index. + +#### GetBlock +``` +GetBlock(heightOrHash interface{}) block.Block +``` +Returns the block by the given hash or index. + +#### GetTransaction +``` +GetTransaction(hash []byte) transaction.Transaction +``` +Returns a transaction by the given hash. + +#### GetContract +``` +GetContract(scriptHash []byte) contract.Contract +``` +Returns the contract found by the given script hash. + +#### GetAccount +``` +GetAccount(scriptHash []byte) account.Account +``` +Returns the account found by the given script hash. + +#### GetValiditors +``` +GetValidators() [][]byte +``` +Returns a list of validators public keys. + +#### GetAsset +``` +GetAsset(assetID []byte) asset.Asset +``` +Returns the asset found by the given asset id. + +## Contract +#### GetScript +``` +GetScript(c Contract) []byte +``` +Return the script of the given contract. + +#### IsPayable +``` +IsPayable(c Contract) bool +``` +Returns whether the given contract is payable. + +#### GetStorageContext +``` +GetStorageContext(c Contract) +``` +Returns the storage context of the given contract. + +#### Create +``` +Create( + script []byte, + params []interface{}, + returnType byte, + properties interface{}, + name, + version, + author, + email, + description string) +``` +Creates a new contract on the blockchain. + +#### Migrate +``` +Migrate( + script []byte, + params []interface{}, + returnType byte, + properties interface{}, + name, + version, + author, + email, + description string) +``` +Migrates a contract on the blockchain. + +#### Destroy +``` +Destroy(c Contract) +``` +Deletes the given contract from the blockchain. + +## Crypto +#### SHA1 +``` +SHA1(data []byte) []byte +``` +Computes the sha1 hash of the given bytes + +#### SHA256 +``` +SHA256(data []byte) []byte +``` +Computes the sha256 hash of the given bytes + +#### Hash256 +``` +Hash256(data []byte) []byte +``` +Computes the sha256^2 of the given data. + +#### Hash160 +``` +Hash160(data []byte) []byte) []byte +``` +Computes the ripemd160 over the sha256 hash of the given data. + +## Engine +#### GetScriptContainer +``` +GetScriptContainer() transaction.Transaction +``` +Returns the transaction that is in the context of the VM execution. + +#### GetExecutingScriptHash +``` +GetExecutingScriptHash() []byte +``` +Returns the script hash of the contract that is currently being executed. + +#### GetCallingScriptHash +``` +GetCallingScriptHash() []byte +``` +Returns the script hash of the contract that has started the execution of the current script. + +#### GetEntryScriptHash +``` +GetEntryScriptHash() []byte +``` +Returns the script hash of the contract that started the execution from the start. + +## Enumerator +#### Create +``` +Create(items []inteface{}) Enumerator +``` +Create a enumerator from the given items. + +#### Next +``` +Next(e Enumerator) interface{} +``` +Returns the next item from the given enumerator. + +#### Value +``` +Value(e Enumerator) interface{} +``` +Returns the enumerator value. + +## Iterator +#### Create +``` +Create(items []inteface{}) Iterator +``` +Creates an iterator from the given items. + +#### Key +``` +Key(it Iterator) interface{} +``` +Return the key from the given iterator. + +#### Keys +``` +Keys(it Iterator) []interface{} +``` +Returns the iterator's keys + +#### Values +``` +Values(it Iterator) []interface{} +``` +Returns the iterator's values + +## Header +#### GetIndex +``` +GetIndex(h Header) int +``` +Returns the height of the given header. + +#### GetHash +``` +GetHash(h Header) []byte +``` +Returns the hash of the given header. + +#### GetPrevHash +``` +GetPrevhash(h Header) []byte +``` +Returns the previous hash of the given header. + +#### GetTimestamp +``` +GetTimestamp(h Header) int +``` +Returns the timestamp of the given header. + +#### GetVersion +``` +GetVersion(h Header) int +``` +Returns the version of the given header. + +#### GetMerkleroot +``` +GetMerkleRoot(h Header) []byte +``` +Returns the merkle root of the given header. + +#### GetConsensusData +``` +GetConsensusData(h Header) int +``` +Returns the consensus data of the given header. + +#### GetNextConsensus +``` +GetNextConsensus(h Header) []byte +``` +Returns the next consensus of the given header. + +## Input +#### GetHash +``` +GetHash(in Input) []byte +``` +Returns the hash field of the given input. + +#### GetIndex +``` +GetIndex(in Input) int +``` +Returns the index field of the given input. + +## Output +#### GetAssetID +``` +GetAssetId(out Output) []byte +``` +Returns the asset id field of the given output. + +#### GetValue +``` +GetValue(out Output) int +``` +Returns the value field of the given output. + +#### GetScriptHash +``` +GetScriptHash(out Output) []byte +``` +Returns the script hash field of the given output. + +## Runtime +#### CheckWitness +``` +CheckWitness(hash []byte) bool +``` +Verifies if the given hash is the hash of the contract owner. + +#### Log +``` +Log(message string) +``` +Logs the given message. + +#### Notify +``` +Notify(args ...interface{}) int +``` +Notify any number of arguments to the VM. + +#### GetTime +``` +GetTime() int +``` +Returns the current time based on the highest block in the chain. + +#### GetTrigger +``` +GetTrigger() byte +``` +Returns the trigger type of the execution. + +#### Serialize +``` +Serialize(item interface{}) []byte +``` +Serialize the given stack item to a slice of bytes. + +#### Deserialize +``` +Deserialize(data []byte) interface{} +``` +Deserializes the given data to a stack item. + +## Storage +#### GetContext +``` +GetContext() Context +``` +Returns the current storage context. + +#### Put +``` +Put(ctx Context, key, value []interface{}) +``` +Stores the given value at the given key. + +#### Get +``` +Get(ctx Context, key interface{}) interface{} +``` +Returns the value found at the given key. + +#### Delete +``` +Delete(ctx Context, key interface{}) +``` +Delete's the given key from storage. + +#### Find +``` +Find(ctx Context, key interface{}) iterator.Iterator +``` +Find returns an iterator key-values that match the given key. + +## Transaction +#### GetHash +``` +GetHash(t Transacfion) []byte +``` +Returns the hash for the given transaction. + +#### GetType +``` +GetType(t Transacfion) byte +``` +Returns the type of the given transaction. + +#### GetAttributes +``` +GetAttributes(t Transacfion) []attribute.Attribute +``` +Returns the attributes of the given transaction. + +#### GetReferences +``` +GetReferences(t Transacfion) interface{} +``` +Returns the references of the given transaction. + +#### GetUnspentCoins +``` +GetUnspentCoins(t Transacfion) interface{} +``` +Returns the unspent coins of the given transaction. + +#### GetOutputs +``` +GetOutputs(t Transacfion) []output.Output +``` +Returns the outputs of the given transaction + +#### GetInputs +``` +GetInputs(t Transacfion) []input.Input +``` +Returns the inputs of the given transaction diff --git a/interop/engine/engine.go b/interop/engine/engine.go index 2e2835927..0b2c838f1 100644 --- a/interop/engine/engine.go +++ b/interop/engine/engine.go @@ -22,7 +22,7 @@ func GetCallingScriptHash() []byte { return nil } -// GetEntryScriptHash returns the script hash of the contract the started the +// GetEntryScriptHash returns the script hash of the contract that started the // execution from the start. func GetEntryScriptHash() []byte { return nil From f547708e10b9ac4885208f28f72be3fd10dffda2 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Tue, 16 Oct 2018 08:33:29 +0200 Subject: [PATCH 25/44] Implemented detailed init command (CityOfZion/neo-storm#37) * Implemented detailed init command * add command for skipping contract information Imported from CityOfZion/neo-storm (0ef8b983ef43ef2eb8e9f190f1f36dc0e839bbc1). --- cli/smartcontract/smart_contract.go | 90 +++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 10 deletions(-) diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 14d81da6b..0ae5e2585 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -1,6 +1,8 @@ package smartcontract import ( + "bufio" + "bytes" "context" "encoding/hex" "encoding/json" @@ -89,6 +91,10 @@ func NewCommand() cli.Command { Name: "name, n", Usage: "name of the smart-contract to be initialized", }, + cli.BoolFlag{ + Name: "skip-details, skip", + Usage: "skip filling in the projects and contract details", + }, }, }, }, @@ -97,31 +103,40 @@ func NewCommand() cli.Command { // initSmartContract initializes a given directory with some boiler plate code. func initSmartContract(ctx *cli.Context) error { - scName := ctx.String("name") - if scName == "" { + contractName := ctx.String("name") + if contractName == "" { return cli.NewExitError(errNoSmartContractName, 1) } // Check if the file already exists, if yes, exit - if _, err := os.Stat(scName); err == nil { + if _, err := os.Stat(contractName); err == nil { return cli.NewExitError(errFileExist, 1) } - basePath := scName + basePath := contractName fileName := "main.go" // create base directory - err := os.Mkdir(basePath, os.ModePerm) - if err != nil { + if err := os.Mkdir(basePath, os.ModePerm); err != nil { return cli.NewExitError(err, 1) } - data := []byte(fmt.Sprintf(smartContractTmpl, scName)) - err = ioutil.WriteFile(filepath.Join(basePath, fileName), data, 0644) - if err != nil { + // Ask contract information and write a storm.yml file unless the -skip-details flag is set. + // TODO: Fix the missing storm.yml file with the `init` command when the package manager is in place. + if !ctx.Bool("skip-details") { + details := parseContractDetails() + if err := ioutil.WriteFile(filepath.Join(basePath, "storm.yml"), details.toStormFile(), 0644); err != nil { + return cli.NewExitError(err, 1) + } + } + + data := []byte(fmt.Sprintf(smartContractTmpl, contractName)) + if err := ioutil.WriteFile(filepath.Join(basePath, fileName), data, 0644); err != nil { return cli.NewExitError(err, 1) } - fmt.Printf("Successfully initialized smart contract [%s]\n", scName) + + fmt.Printf("Successfully initialized smart contract [%s]\n", contractName) + return nil } @@ -190,3 +205,58 @@ func contractDumpOpcode(ctx *cli.Context) error { } return nil } + +type ContractDetails struct { + Author string + Email string + Version string + ProjectName string + Description string +} + +func (d ContractDetails) toStormFile() []byte { + buf := new(bytes.Buffer) + + buf.WriteString("# Storm specific configuration. Do not modify this unless you know what you are doing!\n") + buf.WriteString("storm:\n") + buf.WriteString(" version: 1.0\n") + + buf.WriteString("\n") + + buf.WriteString("# Project section contains information about your smart contract\n") + buf.WriteString("project:\n") + buf.WriteString(" author: " + d.Author) + buf.WriteString(" email: " + d.Email) + buf.WriteString(" version: " + d.Version) + buf.WriteString(" name: " + d.ProjectName) + buf.WriteString(" description: " + d.Description) + + buf.WriteString("\n") + + buf.WriteString("# Module section contains a list of imported modules\n") + buf.WriteString("# This will be automatically managed by the neo-storm package manager\n") + buf.WriteString("modules: \n") + return buf.Bytes() +} + +func parseContractDetails() ContractDetails { + details := ContractDetails{} + reader := bufio.NewReader(os.Stdin) + + fmt.Print("Author: ") + details.Author, _ = reader.ReadString('\n') + + fmt.Print("Email: ") + details.Email, _ = reader.ReadString('\n') + + fmt.Print("Version: ") + details.Version, _ = reader.ReadString('\n') + + fmt.Print("Project name: ") + details.ProjectName, _ = reader.ReadString('\n') + + fmt.Print("Description: ") + details.Description, _ = reader.ReadString('\n') + + return details +} From b97e5aafec499aa35db08c8bfea59858203f067d Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Wed, 17 Oct 2018 19:19:01 +0200 Subject: [PATCH 26/44] Fix/bugs (CityOfZion/neo-storm#38) * Fixed bug where void functions cleaned up their mess multiple times * Compiler improvements * Fixed Neo APIs naming convention * Added NOP after syscall for matching AVM files with neo-python. Imported from CityOfZion/neo-storm (f93a28ef87d272a74f821d45ae0c6735a8c610be). --- pkg/vm/compiler/codegen.go | 31 ++++++++------------- pkg/vm/compiler/syscall.go | 56 +++++++++++++++++++------------------- 2 files changed, 39 insertions(+), 48 deletions(-) diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index fbc7bb63e..0c4d3b991 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -87,18 +87,13 @@ func (c *codegen) emitLoadLocal(name string) { } func (c *codegen) emitLoadLocalPos(pos int) { - emitOpcode(c.prog, vm.FROMALTSTACK) - emitOpcode(c.prog, vm.DUP) - emitOpcode(c.prog, vm.TOALTSTACK) - + emitOpcode(c.prog, vm.DUPFROMALTSTACK) emitInt(c.prog, int64(pos)) emitOpcode(c.prog, vm.PICKITEM) } func (c *codegen) emitStoreLocal(pos int) { - emitOpcode(c.prog, vm.FROMALTSTACK) - emitOpcode(c.prog, vm.DUP) - emitOpcode(c.prog, vm.TOALTSTACK) + emitOpcode(c.prog, vm.DUPFROMALTSTACK) if pos < 0 { log.Fatalf("invalid position to store local: %d", pos) @@ -144,6 +139,10 @@ func (c *codegen) convertFuncDecl(file ast.Node, decl *ast.FuncDecl) { f, ok = c.funcs[decl.Name.Name] if ok { + // If this function is a syscall we will not convert it to bytecode. + if isSyscall(f) { + return + } c.setLabel(f.label) } else { f = c.newFunc(decl) @@ -262,14 +261,13 @@ 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.JMP, 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.NOP) // @OPTIMIZE emitOpcode(c.prog, vm.FROMALTSTACK) emitOpcode(c.prog, vm.DROP) // Cleanup the stack. emitOpcode(c.prog, vm.RET) @@ -425,11 +423,6 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { } } - // 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.NOP) - // Check builtin first to avoid nil pointer on funcScope! switch { case isBuiltin: @@ -442,11 +435,6 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { 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.DROP) - } return nil case *ast.SelectorExpr: @@ -540,7 +528,10 @@ func (c *codegen) convertSyscall(api, name string) { log.Fatalf("unknown VM syscall api: %s", name) } emitSyscall(c.prog, api) - emitOpcode(c.prog, vm.NOP) // @OPTIMIZE + + // This NOP instruction is basically not needed, but if we do, we have a + // one to one matching avm file with neo-python which is very nice for debugging. + emitOpcode(c.prog, vm.NOP) } func (c *codegen) convertBuiltin(expr *ast.CallExpr) { diff --git a/pkg/vm/compiler/syscall.go b/pkg/vm/compiler/syscall.go index 7a9d05146..fe07f027f 100644 --- a/pkg/vm/compiler/syscall.go +++ b/pkg/vm/compiler/syscall.go @@ -2,45 +2,45 @@ package compiler var syscalls = map[string]map[string]string{ "storage": { - "GetContext": "System.Storage.GetContext", - "Put": "System.Storage.Put", - "Get": "System.Storage.Get", - "Delete": "System.Storage.Delete", - "Find": "System.Storage.Find", + "GetContext": "Neo.Storage.GetContext", + "Put": "Neo.Storage.Put", + "Get": "Neo.Storage.Get", + "Delete": "Neo.Storage.Delete", + "Find": "Neo.Storage.Find", }, "runtime": { - "GetTrigger": "System.Runtime.GetTrigger", - "CheckWitness": "System.Runtime.CheckWitness", - "Notify": "System.Runtime.Notify", - "Log": "System.Runtime.Log", - "GetTime": "System.Runtime.GetTime", - "Serialize": "System.Runtime.Serialize", - "Deserialize": "System.Runtime.Deserialize", + "GetTrigger": "Neo.Runtime.GetTrigger", + "CheckWitness": "Neo.Runtime.CheckWitness", + "Notify": "Neo.Runtime.Notify", + "Log": "Neo.Runtime.Log", + "GetTime": "Neo.Runtime.GetTime", + "Serialize": "Neo.Runtime.Serialize", + "Deserialize": "Neo.Runtime.Deserialize", }, "blockchain": { - "GetHeight": "System.Blockchain.GetHeight", - "GetHeader": "System.Blockchain.GetHeader", - "GetBlock": "System.Blockchain.GetBlock", - "GetTransaction": "System.Blockchain.GetTransaction", - "GetContract": "System.Blockchain.GetContract", + "GetHeight": "Neo.Blockchain.GetHeight", + "GetHeader": "Neo.Blockchain.GetHeader", + "GetBlock": "Neo.Blockchain.GetBlock", + "GetTransaction": "Neo.Blockchain.GetTransaction", + "GetContract": "Neo.Blockchain.GetContract", "GetAccount": "Neo.Blockchain.GetAccount", "GetValidators": "Neo.Blockchain.GetValidators", "GetAsset": "Neo.Blockchain.GetAsset", }, "header": { - "GetIndex": "System.Header.GetIndex", - "GetHash": "System.Header.GetHash", - "GetPrevHash": "System.Header.GetPrevHash", - "GetTimestamp": "System.Header.GetTimestamp", + "GetIndex": "Neo.Header.GetIndex", + "GetHash": "Neo.Header.GetHash", + "GetPrevHash": "Neo.Header.GetPrevHash", + "GetTimestamp": "Neo.Header.GetTimestamp", "GetVersion": "Neo.Header.GetVersion", "GetMerkleRoot": "Neo.Header.GetMerkleRoot", "GetConsensusData": "Neo.Header.GetConsensusData", "GetNextConsensus": "Neo.Header.GetNextConsensus", }, "block": { - "GetTransactionCount": "System.Block.GetTransactionCount", - "GetTransactions": "System.Block.GetTransactions", - "GetTransaction": "System.Block.GetTransaction", + "GetTransactionCount": "Neo.Block.GetTransactionCount", + "GetTransactions": "Neo.Block.GetTransactions", + "GetTransaction": "Neo.Block.GetTransaction", }, "transaction": { "GetType": "Neo.Transaction.GetType", @@ -76,10 +76,10 @@ var syscalls = map[string]map[string]string{ "GetScriptHash": "Neo.Output.GetScriptHash", }, "engine": { - "GetScriptContainer": "System.ExecutionEngine.GetScriptContainer", - "GetCallingScriptHash": "System.ExecutionEngine.GetCallingScriptHash", - "GetEntryScriptHash": "System.ExecutionEngine.GetEntryScriptHash", - "GetExecutingScriptHash": "System.ExecutionEngine.GetExecutingScriptHash", + "GetScriptContainer": "Neo.ExecutionEngine.GetScriptContainer", + "GetCallingScriptHash": "Neo.ExecutionEngine.GetCallingScriptHash", + "GetEntryScriptHash": "Neo.ExecutionEngine.GetEntryScriptHash", + "GetExecutingScriptHash": "Neo.ExecutionEngine.GetExecutingScriptHash", }, "iterator": { "Create": "Neo.Iterator.Create", From 0880e88fa5b1d258fb4e3aa08a97798c66e1f280 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Sat, 20 Oct 2018 07:11:00 +0200 Subject: [PATCH 27/44] Fixed bug in else stmts (CityOfZion/neo-storm#42) * Fixed bug in else stmts * Fixed if else bug * Back to %v for formatting instructions Imported from CityOfZion/neo-storm (ea8440e1454207753c8d209ce7c2cf724fd4ea16). --- cli/smartcontract/smart_contract.go | 3 +-- pkg/vm/compiler/codegen.go | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 0ae5e2585..2c7a7b12a 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -173,8 +173,7 @@ func testInvoke(ctx *cli.Context) error { // On the long term the internal VM will run the script. // TODO: remove RPC dependency, hardcoded node. endpoint := "http://seed5.bridgeprotocol.io:10332" - opts := rpc.ClientOptions{} - client, err := rpc.NewClient(context.TODO(), endpoint, opts) + client, err := rpc.NewClient(context.TODO(), endpoint, rpc.ClientOptions{}) if err != nil { return cli.NewExitError(err, 1) } diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index 0c4d3b991..9457c4130 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -257,11 +257,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { log.Fatal("multiple returns not supported.") } - // @OPTIMIZE: We could skip these 3 instructions for each return statement. - // 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.JMP, int16(l)) c.setLabel(l) if len(n.Results) > 0 { @@ -276,6 +272,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { case *ast.IfStmt: lIf := c.newLabel() lElse := c.newLabel() + lElseEnd := c.newLabel() + if n.Cond != nil { ast.Walk(c, n.Cond) emitJmp(c.prog, vm.JMPIFNOT, int16(lElse)) @@ -283,15 +281,15 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { c.setLabel(lIf) ast.Walk(c, n.Body) - if n.Else != nil { - // TODO: handle else statements. - // emitJmp(c.prog, vm.JMP, int16(lEnd)) + emitJmp(c.prog, vm.JMP, int16(lElseEnd)) } + c.setLabel(lElse) if n.Else != nil { ast.Walk(c, n.Else) } + c.setLabel(lElseEnd) return nil case *ast.BasicLit: @@ -659,7 +657,11 @@ func (c *codegen) convertToken(tok token.Token) { case token.GEQ: emitOpcode(c.prog, vm.GTE) case token.EQL: - emitOpcode(c.prog, vm.NUMEQUAL) + // It seems that (looking to the python compiler) that comparing for + // equal (==) needs to return the instruction EQUAL. Where comparing + // (anything) to not equal (!=) needs to use the opcode NUMNOTEQUAL + // even for comparing strings. + emitOpcode(c.prog, vm.EQUAL) case token.NEQ: emitOpcode(c.prog, vm.NUMNOTEQUAL) case token.DEC: From 69511e053f75fbfd3f3dd8daf1ff03206b4fcd38 Mon Sep 17 00:00:00 2001 From: BlackTrace <1078242064@qq.com> Date: Sat, 20 Oct 2018 13:11:50 +0800 Subject: [PATCH 28/44] update right neo api (CityOfZion/neo-storm#40) Imported from CityOfZion/neo-storm (eee635918c80a9444dc1b37e537f9ecaf1a83d33). --- pkg/vm/compiler/syscall.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/vm/compiler/syscall.go b/pkg/vm/compiler/syscall.go index fe07f027f..57e510c5e 100644 --- a/pkg/vm/compiler/syscall.go +++ b/pkg/vm/compiler/syscall.go @@ -76,10 +76,10 @@ var syscalls = map[string]map[string]string{ "GetScriptHash": "Neo.Output.GetScriptHash", }, "engine": { - "GetScriptContainer": "Neo.ExecutionEngine.GetScriptContainer", - "GetCallingScriptHash": "Neo.ExecutionEngine.GetCallingScriptHash", - "GetEntryScriptHash": "Neo.ExecutionEngine.GetEntryScriptHash", - "GetExecutingScriptHash": "Neo.ExecutionEngine.GetExecutingScriptHash", + "GetScriptContainer": "System.ExecutionEngine.GetScriptContainer", + "GetCallingScriptHash": "System.ExecutionEngine.GetCallingScriptHash", + "GetEntryScriptHash": "System.ExecutionEngine.GetEntryScriptHash", + "GetExecutingScriptHash": "System.ExecutionEngine.GetExecutingScriptHash", }, "iterator": { "Create": "Neo.Iterator.Create", From 459d3654a2a2663219aac9606663202650bef358 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Tue, 23 Oct 2018 10:23:03 +0200 Subject: [PATCH 29/44] fixed missing syscall transaction.GetHash() (CityOfZion/neo-storm#43) Several bug fixes and improvements Imported from CityOfZion/neo-storm (8e8fe5c215bfaed51452482f4f28cc9956a1f69b). --- cli/smartcontract/smart_contract.go | 44 ++++++++++++++--------------- interop/transaction/transaction.go | 4 +-- pkg/vm/compiler/codegen.go | 16 +++++++++++ pkg/vm/compiler/compiler.go | 23 ++++++++++----- pkg/vm/compiler/syscall.go | 1 + 5 files changed, 56 insertions(+), 32 deletions(-) diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 2c7a7b12a..8501153b8 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -71,17 +71,6 @@ func NewCommand() cli.Command { }, }, }, - { - Name: "opdump", - Usage: "dump the opcode of a .go file", - Action: contractDumpOpcode, - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "in, i", - Usage: "Input file for the smart contract", - }, - }, - }, { Name: "init", Usage: "initialize a new smart-contract in a directory with boiler plate code", @@ -97,6 +86,17 @@ func NewCommand() cli.Command { }, }, }, + { + Name: "inspect", + Usage: "creates a user readable dump of the program instructions", + Action: inspect, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "in, i", + Usage: "input file of the program", + }, + }, + }, }, } } @@ -172,7 +172,7 @@ func testInvoke(ctx *cli.Context) error { // For now we will hardcode the endpoint. // On the long term the internal VM will run the script. // TODO: remove RPC dependency, hardcoded node. - endpoint := "http://seed5.bridgeprotocol.io:10332" + endpoint := "http://node1.ams2.bridgeprotocol.io:10332" client, err := rpc.NewClient(context.TODO(), endpoint, rpc.ClientOptions{}) if err != nil { return cli.NewExitError(err, 1) @@ -194,17 +194,6 @@ func testInvoke(ctx *cli.Context) error { return nil } -func contractDumpOpcode(ctx *cli.Context) error { - src := ctx.String("in") - if len(src) == 0 { - return cli.NewExitError(errNoInput, 1) - } - if err := compiler.DumpOpcode(src); err != nil { - return cli.NewExitError(err, 1) - } - return nil -} - type ContractDetails struct { Author string Email string @@ -259,3 +248,12 @@ func parseContractDetails() ContractDetails { return details } + +func inspect(ctx *cli.Context) error { + src := ctx.String("in") + if len(src) == 0 { + return cli.NewExitError(errNoInput, 1) + } + compiler.CompileAndInspect(src) + return nil +} diff --git a/interop/transaction/transaction.go b/interop/transaction/transaction.go index e845a1171..44ba46728 100644 --- a/interop/transaction/transaction.go +++ b/interop/transaction/transaction.go @@ -29,8 +29,8 @@ func GetAttributes(t Transaction) []attribute.Attribute { // FIXME: What is the correct return type for this? // GetReferences returns a slice of references for the given transaction. -func GetReferences(t Transaction) interface{} { - return 0 +func GetReferences(t Transaction) []interface{} { + return []interface{}{} } // FIXME: What is the correct return type for this? diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index 9457c4130..223688ad3 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -8,6 +8,7 @@ import ( "go/token" "go/types" "log" + "strconv" "strings" "github.com/CityOfZion/neo-go/pkg/crypto" @@ -248,6 +249,21 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { default: log.Fatal("nested selector assigns not supported yet") } + + // Assignments to index expressions. + // slice[0] = 10 + case *ast.IndexExpr: + ast.Walk(c, n.Rhs[i]) + name := t.X.(*ast.Ident).Name + c.emitLoadLocal(name) + // For now storm only supports basic index operations. Hence we + // cast this to an *ast.BasicLit (1, 2 , 3) + indexStr := t.Index.(*ast.BasicLit).Value + index, err := strconv.Atoi(indexStr) + if err != nil { + log.Fatal("failed to convert slice index to integer") + } + c.emitStoreStructField(index) } } return nil diff --git a/pkg/vm/compiler/compiler.go b/pkg/vm/compiler/compiler.go index a4beb04ff..6b479b07a 100644 --- a/pkg/vm/compiler/compiler.go +++ b/pkg/vm/compiler/compiler.go @@ -90,16 +90,15 @@ func CompileAndSave(src string, o *Options) error { if err != nil { return fmt.Errorf("Error while trying to compile smart contract file: %v", err) } - if o.Debug { - log.Println(hex.EncodeToString(b)) - } + + log.Println(hex.EncodeToString(b)) out := fmt.Sprintf("%s.%s", o.Outfile, o.Ext) return ioutil.WriteFile(out, b, os.ModePerm) } -// DumpOpcode compiles the program and dumps the opcode in a user friendly format. -func DumpOpcode(src string) error { +// CompileAndInspect compiles the program and dumps the opcode in a user friendly format. +func CompileAndInspect(src string) error { b, err := ioutil.ReadFile(src) if err != nil { return err @@ -111,8 +110,18 @@ 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.Instruction(b[i])) + for i := 0; i <= len(b)-1; { + instr := vm.Instruction(b[i]) + if instr >= vm.PUSHBYTES1 && instr <= vm.PUSHBYTES75 { + fmt.Fprintf(w, "%d\t0x%x\t%s\t\n", i, b[i], fmt.Sprintf("PUSHBYTES%d", int(instr))) + for x := 0; x < int(instr); x++ { + fmt.Fprintf(w, "%d\t0x%x\t%s\t\n", i, b[i+1+x], string(b[i+1+x])) + } + i += int(instr) + 1 + continue + } + fmt.Fprintf(w, "%d\t0x%x\t%s\t\n", i, b[i], instr) + i++ } w.Flush() return nil diff --git a/pkg/vm/compiler/syscall.go b/pkg/vm/compiler/syscall.go index 57e510c5e..62e24f4c9 100644 --- a/pkg/vm/compiler/syscall.go +++ b/pkg/vm/compiler/syscall.go @@ -43,6 +43,7 @@ var syscalls = map[string]map[string]string{ "GetTransaction": "Neo.Block.GetTransaction", }, "transaction": { + "GetHash": "Neo.Transaction.GetHash", "GetType": "Neo.Transaction.GetType", "GetAttributes": "Neo.Transaction.GetAttributes", "GetInputs": "Neo.Transaction.GetInputs", From a765561b3aee07bfd0286fc2824dfecbc03a91c2 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Fri, 26 Oct 2018 16:02:32 +0200 Subject: [PATCH 30/44] implemented bitwise instructions and fixed loading constants of type uint (CityOfZion/neo-storm#49) Imported from CityOfZion/neo-storm (b8a9b14dacc4fd6a62c236b2e89545684435a8fb). --- pkg/vm/compiler/codegen.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index 223688ad3..0071bf131 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -58,7 +58,7 @@ func (c *codegen) emitLoadConst(t types.TypeAndValue) { switch typ := t.Type.Underlying().(type) { case *types.Basic: switch typ.Kind() { - case types.Int, types.UntypedInt: + case types.Int, types.UntypedInt, types.Uint: val, _ := constant.Int64Val(t.Value) emitInt(c.prog, val) case types.String, types.UntypedString: @@ -686,6 +686,16 @@ func (c *codegen) convertToken(tok token.Token) { emitOpcode(c.prog, vm.INC) case token.NOT: emitOpcode(c.prog, vm.NOT) + case token.AND: + emitOpcode(c.prog, vm.AND) + case token.OR: + emitOpcode(c.prog, vm.OR) + case token.SHL: + emitOpcode(c.prog, vm.SHL) + case token.SHR: + emitOpcode(c.prog, vm.SHR) + case token.XOR: + emitOpcode(c.prog, vm.XOR) default: log.Fatalf("compiler could not convert token: %s", tok) } From 36b253872fab62e76bb4e58d7816307337c055a0 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Fri, 26 Oct 2018 21:16:06 +0200 Subject: [PATCH 31/44] WIP Imported from CityOfZion/neo-storm (cbfc89972e977fa808e9f68c9ad5c6c18bef291d). --- pkg/vm/compiler/codegen.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index 0071bf131..8a1ceb622 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -430,10 +430,29 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { if !isBuiltin { if numArgs == 2 { emitOpcode(c.prog, vm.SWAP) - } - if numArgs == 3 { + } else if numArgs == 3 { emitInt(c.prog, 2) emitOpcode(c.prog, vm.XSWAP) + } else { + half := int(numArgs / 2) + + for i := 0; i < half; i++ { + to := numArgs - 1 - i + + emitInt(c.prog, int64(to)) + emitOpcode(c.prog, vm.PICK) + + emitInt(c.prog, int64(i+1)) + emitOpcode(c.prog, vm.PICK) + + emitInt(c.prog, int64(to+2)) + emitOpcode(c.prog, vm.XSWAP) + emitOpcode(c.prog, vm.DROP) + + emitInt(c.prog, int64(i+1)) + emitOpcode(c.prog, vm.XSWAP) + emitOpcode(c.prog, vm.DROP) + } } } From 74602b6143f030b3e5e9ff9410f3092c5adf404c Mon Sep 17 00:00:00 2001 From: fyrchik Date: Mon, 29 Oct 2018 18:36:13 +0300 Subject: [PATCH 32/44] concatenate strings using CAT opcode (CityOfZion/neo-storm#54) Imported from CityOfZion/neo-storm (7d759a23e3af792657c7515645b890eadfa7329f). --- pkg/vm/compiler/codegen.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index 8a1ceb622..60c6bf081 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -372,14 +372,26 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { // example: // const x = 10 // x + 2 will results into 12 - if tinfo := c.typeInfo.Types[n]; tinfo.Value != nil { + tinfo := c.typeInfo.Types[n] + if tinfo.Value != nil { c.emitLoadConst(tinfo) return nil } ast.Walk(c, n.X) ast.Walk(c, n.Y) - c.convertToken(n.Op) + + // VM has separate opcode for string concatenation + if n.Op == token.ADD { + typ, ok := tinfo.Type.Underlying().(*types.Basic) + if ok && typ.Kind() == types.String { + emitOpcode(c.prog, vm.CAT) + } else { + emitOpcode(c.prog, vm.ADD) + } + } else { + c.convertToken(n.Op) + } return nil } From 1883a11f449f4b131c905c908ae62e3837e84e6d Mon Sep 17 00:00:00 2001 From: fyrchik Date: Mon, 29 Oct 2018 18:37:08 +0300 Subject: [PATCH 33/44] swap arguments for functions with more than 3 arguments (CityOfZion/neo-storm#51) Imported from CityOfZion/neo-storm (402ebb1d6226e2a30d8fdc19663227361cc72ca0). --- pkg/vm/compiler/codegen.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index 60c6bf081..e91c11d49 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -466,6 +466,12 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { emitOpcode(c.prog, vm.DROP) } } + if numArgs > 3 { + for i := 1; i < numArgs; i++ { + emitInt(c.prog, int64(i)) + emitOpcode(c.prog, vm.ROLL) + } + } } // Check builtin first to avoid nil pointer on funcScope! From 5ba835d25b6aa67dfbbf059409b789da067cce6d Mon Sep 17 00:00:00 2001 From: Evgenii Date: Fri, 15 Feb 2019 16:38:16 +0300 Subject: [PATCH 34/44] compiler: process packages in deterministic order Imported from CityOfZion/neo-storm#60 PR. --- pkg/vm/compiler/codegen.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index e91c11d49..70ba960e9 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -8,6 +8,7 @@ import ( "go/token" "go/types" "log" + "sort" "strconv" "strings" @@ -773,8 +774,16 @@ func CodeGen(info *buildInfo) (*bytes.Buffer, error) { // convert the entry point first c.convertFuncDecl(mainFile, main) + // sort map keys to generate code deterministically + keys := make([]*types.Package, 0, len(info.program.AllPackages)) + for p := range info.program.AllPackages { + keys = append(keys, p) + } + sort.Slice(keys, func(i, j int) bool { return keys[i].Path() < keys[j].Path() }) + // Generate the code for the program - for _, pkg := range info.program.AllPackages { + for _, k := range keys { + pkg := info.program.AllPackages[k] c.typeInfo = &pkg.Info for _, f := range pkg.Files { From 05c07a8567a454038dd61a9eb4ba1c9ee9bbc1a0 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Tue, 19 Feb 2019 16:14:55 +0300 Subject: [PATCH 35/44] compiler: fix argument handling for function arity >= 3 Imported from CityOfZion/neo-storm#61 PR. --- pkg/vm/compiler/codegen.go | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index 70ba960e9..fbcfa5027 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -447,27 +447,6 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { emitInt(c.prog, 2) emitOpcode(c.prog, vm.XSWAP) } else { - half := int(numArgs / 2) - - for i := 0; i < half; i++ { - to := numArgs - 1 - i - - emitInt(c.prog, int64(to)) - emitOpcode(c.prog, vm.PICK) - - emitInt(c.prog, int64(i+1)) - emitOpcode(c.prog, vm.PICK) - - emitInt(c.prog, int64(to+2)) - emitOpcode(c.prog, vm.XSWAP) - emitOpcode(c.prog, vm.DROP) - - emitInt(c.prog, int64(i+1)) - emitOpcode(c.prog, vm.XSWAP) - emitOpcode(c.prog, vm.DROP) - } - } - if numArgs > 3 { for i := 1; i < numArgs; i++ { emitInt(c.prog, int64(i)) emitOpcode(c.prog, vm.ROLL) From 2daebdfce2e5166c806b4be34603e0806aaac679 Mon Sep 17 00:00:00 2001 From: Evgenii Date: Tue, 19 Feb 2019 16:50:34 +0300 Subject: [PATCH 36/44] compiler: convert unary operators properly Imported from CityOfZion/neo-storm#62 PR. --- pkg/vm/compiler/codegen.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index fbcfa5027..45993eb37 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -484,7 +484,22 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { case *ast.UnaryExpr: ast.Walk(c, n.X) - c.convertToken(n.Op) + // From https://golang.org/ref/spec#Operators + // there can be only following unary operators + // "+" | "-" | "!" | "^" | "*" | "&" | "<-" . + // of which last three are not used in SC + switch n.Op { + case token.ADD: + // +10 == 10, no need to do anything in this case + case token.SUB: + emitOpcode(c.prog, vm.NEGATE) + case token.NOT: + emitOpcode(c.prog, vm.NOT) + case token.XOR: + emitOpcode(c.prog, vm.INVERT) + default: + log.Fatalf("invalid unary operator: %s", n.Op) + } return nil case *ast.IncDecStmt: From 01330e7ed78b611b64aa9fbaf38bb83f7c4e5c95 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Wed, 14 Aug 2019 20:29:32 +0300 Subject: [PATCH 37/44] cli: add error return check for compiler.CompileAndInspect() GolangCI complains: Error return value of compiler.CompileAndInspect is not checked (from errcheck) --- cli/smartcontract/smart_contract.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 8501153b8..2dd69bf94 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -254,6 +254,8 @@ func inspect(ctx *cli.Context) error { if len(src) == 0 { return cli.NewExitError(errNoInput, 1) } - compiler.CompileAndInspect(src) + if err := compiler.CompileAndInspect(src); err != nil { + return cli.NewExitError(err, 1) + } return nil } From 810f096811429d074d64715fa1d0ceb1f205cbd1 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 15 Aug 2019 18:22:56 +0300 Subject: [PATCH 38/44] compiler: change codegen to emit NUMEQUAL instead of EQUAL This is wrong, see issue #294, but it makes our VM tests work (as VM is missing EQUAL implementation), so until #294 is properly resolved we're better have this kind of wrong code generation. --- pkg/vm/compiler/codegen.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index 45993eb37..b819da95d 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -705,11 +705,10 @@ func (c *codegen) convertToken(tok token.Token) { case token.GEQ: emitOpcode(c.prog, vm.GTE) case token.EQL: - // It seems that (looking to the python compiler) that comparing for - // equal (==) needs to return the instruction EQUAL. Where comparing - // (anything) to not equal (!=) needs to use the opcode NUMNOTEQUAL - // even for comparing strings. - emitOpcode(c.prog, vm.EQUAL) + // TODO: this is wrong (and the next one also is), see issue #294 + // Changing it EQUAL is not that big of an improvement, so we're + // using NUMEQUAL for now + emitOpcode(c.prog, vm.NUMEQUAL) case token.NEQ: emitOpcode(c.prog, vm.NUMNOTEQUAL) case token.DEC: From 1a4055a96248899d3145b5daa36968bc4ad41f3a Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 15 Aug 2019 18:25:22 +0300 Subject: [PATCH 39/44] compiler: fix codegen for OR, fixes failing TestLOR 0880e88fa5b1d258fb4e3aa08a97798c66e1f280 breaks it by introducing a new label that is not counted here. --- pkg/vm/compiler/codegen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index b819da95d..a0b3e852a 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -361,7 +361,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { case token.LOR: ast.Walk(c, n.X) - emitJmp(c.prog, vm.JMPIF, int16(len(c.l)-2)) + emitJmp(c.prog, vm.JMPIF, int16(len(c.l) - 3)) ast.Walk(c, n.Y) return nil From 7cd91610df58846d23da240f74f10b143fa28f66 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 15 Aug 2019 18:26:52 +0300 Subject: [PATCH 40/44] compiler: quick and dirty inspection fix for JMP instrs These were interpreted completely wrong, they actually have two next bytes indicating an offset. This patch is a quick fix, actually more work is needed here to properly display various instructions. --- pkg/vm/compiler/compiler.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/vm/compiler/compiler.go b/pkg/vm/compiler/compiler.go index 6b479b07a..828e8983c 100644 --- a/pkg/vm/compiler/compiler.go +++ b/pkg/vm/compiler/compiler.go @@ -122,6 +122,12 @@ func CompileAndInspect(src string) error { } fmt.Fprintf(w, "%d\t0x%x\t%s\t\n", i, b[i], instr) i++ + if instr == vm.JMP || instr == vm.JMPIF || instr == vm.JMPIFNOT || instr == vm.CALL { + for x := 0; x < 2; x++ { + fmt.Fprintf(w, "%d\t0x%x\t%d\t\n", i, b[i + x], b[i + x]) + } + i += 2 + } } w.Flush() return nil From a1e3655560e35d8e3980952e945b6342883f013d Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 15 Aug 2019 19:41:51 +0300 Subject: [PATCH 41/44] interop: move into pkg/interop, replace pkg/vm/api neo-storm has developed more wrappers for syscall APIs, so they can and should be used as a drop-in replacement for pkg/vm/api. Moving it out of vm, as it's not exactly related to the VM itself. --- cli/smartcontract/smart_contract.go | 2 +- examples/engine/engine.go | 4 +- examples/iterator/iterator.go | 6 +-- examples/runtime/runtime.go | 4 +- examples/storage/storage.go | 2 +- examples/token-sale/token_sale.go | 6 +-- examples/token/nep5/nep5.go | 8 ++-- examples/token/token.go | 6 +-- {interop => pkg/interop}/account/account.go | 2 +- {interop => pkg/interop}/asset/asset.go | 2 +- .../interop}/attribute/attribute.go | 2 +- {interop => pkg/interop}/block/block.go | 4 +- .../interop}/blockchain/blockchain.go | 14 +++--- {interop => pkg/interop}/contract/contract.go | 4 +- {interop => pkg/interop}/crypto/crypto.go | 2 +- {interop => pkg/interop}/engine/engine.go | 4 +- .../interop}/enumerator/enumerator.go | 2 +- {interop => pkg/interop}/header/header.go | 2 +- {interop => pkg/interop}/input/input.go | 2 +- {interop => pkg/interop}/iterator/iterator.go | 2 +- {interop => pkg/interop}/output/output.go | 2 +- {interop => pkg/interop}/runtime/runtime.go | 2 +- {interop => pkg/interop}/storage/storage.go | 4 +- .../interop}/transaction/transaction.go | 8 ++-- {interop => pkg/interop}/util/util.go | 0 pkg/vm/README.md | 2 +- pkg/vm/api/asset/asset.go | 31 ------------- pkg/vm/api/block/block.go | 41 ----------------- pkg/vm/api/crypto/util.go | 21 --------- pkg/vm/api/header/header.go | 24 ---------- pkg/vm/api/runtime/runtime.go | 45 ------------------- pkg/vm/api/storage/storage.go | 19 -------- pkg/vm/api/transaction/transaction.go | 27 ----------- pkg/vm/api/types/block.go | 9 ---- pkg/vm/api/util/util.go | 6 --- pkg/vm/compiler/README.md | 8 ++-- pkg/vm/tests/syscall_test.go | 2 +- pkg/vm/tests/util_test.go | 8 ++-- 38 files changed, 58 insertions(+), 281 deletions(-) rename {interop => pkg/interop}/account/account.go (89%) rename {interop => pkg/interop}/asset/asset.go (94%) rename {interop => pkg/interop}/attribute/attribute.go (85%) rename {interop => pkg/interop}/block/block.go (83%) rename {interop => pkg/interop}/blockchain/blockchain.go (76%) rename {interop => pkg/interop}/contract/contract.go (90%) rename {interop => pkg/interop}/crypto/crypto.go (87%) rename {interop => pkg/interop}/engine/engine.go (85%) rename {interop => pkg/interop}/enumerator/enumerator.go (91%) rename {interop => pkg/interop}/header/header.go (94%) rename {interop => pkg/interop}/input/input.go (84%) rename {interop => pkg/interop}/iterator/iterator.go (90%) rename {interop => pkg/interop}/output/output.go (88%) rename {interop => pkg/interop}/runtime/runtime.go (94%) rename {interop => pkg/interop}/storage/storage.go (84%) rename {interop => pkg/interop}/transaction/transaction.go (84%) rename {interop => pkg/interop}/util/util.go (100%) delete mode 100644 pkg/vm/api/asset/asset.go delete mode 100644 pkg/vm/api/block/block.go delete mode 100644 pkg/vm/api/crypto/util.go delete mode 100644 pkg/vm/api/header/header.go delete mode 100644 pkg/vm/api/runtime/runtime.go delete mode 100644 pkg/vm/api/storage/storage.go delete mode 100644 pkg/vm/api/transaction/transaction.go delete mode 100644 pkg/vm/api/types/block.go delete mode 100644 pkg/vm/api/util/util.go diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 2dd69bf94..5bfe32c14 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -28,7 +28,7 @@ var ( // %s is parsed to be the smartContractName smartContractTmpl = `package %s -import "github.com/CityOfZion/neo-storm/interop/runtime" +import "github.com/CityOfZion/neo-go/pkg/interop/runtime" func Main(op string, args []interface{}) { runtime.Notify("Hello world!") diff --git a/examples/engine/engine.go b/examples/engine/engine.go index c436dc33f..aa210abdf 100644 --- a/examples/engine/engine.go +++ b/examples/engine/engine.go @@ -1,8 +1,8 @@ package engine_contract import ( - "github.com/CityOfZion/neo-storm/interop/engine" - "github.com/CityOfZion/neo-storm/interop/runtime" + "github.com/CityOfZion/neo-go/pkg/interop/engine" + "github.com/CityOfZion/neo-go/pkg/interop/runtime" ) func Main() bool { diff --git a/examples/iterator/iterator.go b/examples/iterator/iterator.go index 4ccf996b3..0809b173f 100644 --- a/examples/iterator/iterator.go +++ b/examples/iterator/iterator.go @@ -1,9 +1,9 @@ package iterator_contract import ( - "github.com/CityOfZion/neo-storm/interop/iterator" - "github.com/CityOfZion/neo-storm/interop/runtime" - "github.com/CityOfZion/neo-storm/interop/storage" + "github.com/CityOfZion/neo-go/pkg/interop/iterator" + "github.com/CityOfZion/neo-go/pkg/interop/runtime" + "github.com/CityOfZion/neo-go/pkg/interop/storage" ) func Main() bool { diff --git a/examples/runtime/runtime.go b/examples/runtime/runtime.go index 6c11632ee..4d914e445 100644 --- a/examples/runtime/runtime.go +++ b/examples/runtime/runtime.go @@ -1,8 +1,8 @@ package runtime_contract import ( - "github.com/CityOfZion/neo-storm/interop/runtime" - "github.com/CityOfZion/neo-storm/interop/util" + "github.com/CityOfZion/neo-go/pkg/interop/runtime" + "github.com/CityOfZion/neo-go/pkg/interop/util" ) // Check if the invoker of the contract is the specified owner diff --git a/examples/storage/storage.go b/examples/storage/storage.go index bca5c86e5..319e9e71f 100644 --- a/examples/storage/storage.go +++ b/examples/storage/storage.go @@ -1,7 +1,7 @@ package storage_contract import ( - "github.com/CityOfZion/neo-storm/interop/storage" + "github.com/CityOfZion/neo-go/pkg/interop/storage" ) func Main(operation string, args []interface{}) interface{} { diff --git a/examples/token-sale/token_sale.go b/examples/token-sale/token_sale.go index 4402d8ccc..2dd8edb0f 100644 --- a/examples/token-sale/token_sale.go +++ b/examples/token-sale/token_sale.go @@ -1,9 +1,9 @@ package tokensale import ( - "github.com/CityOfZion/neo-go/pkg/vm/api/runtime" - "github.com/CityOfZion/neo-go/pkg/vm/api/storage" - "github.com/CityOfZion/neo-go/pkg/vm/api/util" + "github.com/CityOfZion/neo-go/pkg/interop/runtime" + "github.com/CityOfZion/neo-go/pkg/interop/storage" + "github.com/CityOfZion/neo-go/pkg/interop/util" ) const ( diff --git a/examples/token/nep5/nep5.go b/examples/token/nep5/nep5.go index cd38ab81a..e4bc2267e 100644 --- a/examples/token/nep5/nep5.go +++ b/examples/token/nep5/nep5.go @@ -1,10 +1,10 @@ package nep5 import ( - "github.com/CityOfZion/neo-storm/interop/engine" - "github.com/CityOfZion/neo-storm/interop/runtime" - "github.com/CityOfZion/neo-storm/interop/storage" - "github.com/CityOfZion/neo-storm/interop/util" + "github.com/CityOfZion/neo-go/pkg/interop/engine" + "github.com/CityOfZion/neo-go/pkg/interop/runtime" + "github.com/CityOfZion/neo-go/pkg/interop/storage" + "github.com/CityOfZion/neo-go/pkg/interop/util" ) // Token holds all token info diff --git a/examples/token/token.go b/examples/token/token.go index 834d0ffbd..1f1c62fa8 100644 --- a/examples/token/token.go +++ b/examples/token/token.go @@ -1,10 +1,10 @@ package token_contract import ( - "github.com/CityOfZion/neo-storm/examples/token/nep5" + "github.com/CityOfZion/neo-go/examples/token/nep5" - "github.com/CityOfZion/neo-storm/interop/storage" - "github.com/CityOfZion/neo-storm/interop/util" + "github.com/CityOfZion/neo-go/pkg/interop/storage" + "github.com/CityOfZion/neo-go/pkg/interop/util" ) const ( diff --git a/interop/account/account.go b/pkg/interop/account/account.go similarity index 89% rename from interop/account/account.go rename to pkg/interop/account/account.go index cb60fac54..c25903c1b 100644 --- a/interop/account/account.go +++ b/pkg/interop/account/account.go @@ -1,7 +1,7 @@ package account // Package account provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // Account stubs a NEO account type. type Account struct{} diff --git a/interop/asset/asset.go b/pkg/interop/asset/asset.go similarity index 94% rename from interop/asset/asset.go rename to pkg/interop/asset/asset.go index e3242b777..a7a46db97 100644 --- a/interop/asset/asset.go +++ b/pkg/interop/asset/asset.go @@ -1,7 +1,7 @@ package asset // Package asset provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // Asset stubs a NEO asset type. type Asset struct{} diff --git a/interop/attribute/attribute.go b/pkg/interop/attribute/attribute.go similarity index 85% rename from interop/attribute/attribute.go rename to pkg/interop/attribute/attribute.go index e53a06165..6147b5be2 100644 --- a/interop/attribute/attribute.go +++ b/pkg/interop/attribute/attribute.go @@ -1,7 +1,7 @@ package attribute // Package attribute provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // Attribute stubs a NEO transaction attribute type. type Attribute struct{} diff --git a/interop/block/block.go b/pkg/interop/block/block.go similarity index 83% rename from interop/block/block.go rename to pkg/interop/block/block.go index 11fc9f6b4..2f3bf6738 100644 --- a/interop/block/block.go +++ b/pkg/interop/block/block.go @@ -1,9 +1,9 @@ package block -import "github.com/CityOfZion/neo-storm/interop/transaction" +import "github.com/CityOfZion/neo-go/pkg/interop/transaction" // Package block provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // Block stubs a NEO block type. type Block struct{} diff --git a/interop/blockchain/blockchain.go b/pkg/interop/blockchain/blockchain.go similarity index 76% rename from interop/blockchain/blockchain.go rename to pkg/interop/blockchain/blockchain.go index 80f12a676..d27bdaa07 100644 --- a/interop/blockchain/blockchain.go +++ b/pkg/interop/blockchain/blockchain.go @@ -1,16 +1,16 @@ package blockchain import ( - "github.com/CityOfZion/neo-storm/interop/account" - "github.com/CityOfZion/neo-storm/interop/asset" - "github.com/CityOfZion/neo-storm/interop/block" - "github.com/CityOfZion/neo-storm/interop/contract" - "github.com/CityOfZion/neo-storm/interop/header" - "github.com/CityOfZion/neo-storm/interop/transaction" + "github.com/CityOfZion/neo-go/pkg/interop/account" + "github.com/CityOfZion/neo-go/pkg/interop/asset" + "github.com/CityOfZion/neo-go/pkg/interop/block" + "github.com/CityOfZion/neo-go/pkg/interop/contract" + "github.com/CityOfZion/neo-go/pkg/interop/header" + "github.com/CityOfZion/neo-go/pkg/interop/transaction" ) // Package blockchain provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // GetHeight returns the height of te block recorded in the current execution scope. func GetHeight() int { diff --git a/interop/contract/contract.go b/pkg/interop/contract/contract.go similarity index 90% rename from interop/contract/contract.go rename to pkg/interop/contract/contract.go index d9f4676e6..55f60c0ad 100644 --- a/interop/contract/contract.go +++ b/pkg/interop/contract/contract.go @@ -1,9 +1,9 @@ package contract -import "github.com/CityOfZion/neo-storm/interop/storage" +import "github.com/CityOfZion/neo-go/pkg/interop/storage" // Package contract provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // Contract stubs a NEO contract type. type Contract struct{} diff --git a/interop/crypto/crypto.go b/pkg/interop/crypto/crypto.go similarity index 87% rename from interop/crypto/crypto.go rename to pkg/interop/crypto/crypto.go index b9d71325e..6877fd46e 100644 --- a/interop/crypto/crypto.go +++ b/pkg/interop/crypto/crypto.go @@ -1,7 +1,7 @@ package crypto // Package crypto provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // SHA1 computes the sha1 hash of b. func SHA1(b []byte) []byte { diff --git a/interop/engine/engine.go b/pkg/interop/engine/engine.go similarity index 85% rename from interop/engine/engine.go rename to pkg/interop/engine/engine.go index 0b2c838f1..057d42728 100644 --- a/interop/engine/engine.go +++ b/pkg/interop/engine/engine.go @@ -1,9 +1,9 @@ package engine -import "github.com/CityOfZion/neo-storm/interop/transaction" +import "github.com/CityOfZion/neo-go/pkg/interop/transaction" // Package engine provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // GetScriptContainer returns the transaction that is in the execution context. func GetScriptContainer() transaction.Transaction { diff --git a/interop/enumerator/enumerator.go b/pkg/interop/enumerator/enumerator.go similarity index 91% rename from interop/enumerator/enumerator.go rename to pkg/interop/enumerator/enumerator.go index e2b906c34..8da72424d 100644 --- a/interop/enumerator/enumerator.go +++ b/pkg/interop/enumerator/enumerator.go @@ -1,7 +1,7 @@ package enumerator // Package enumerator provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // TODO: Check enumerator use cases and add them to the examples folder. diff --git a/interop/header/header.go b/pkg/interop/header/header.go similarity index 94% rename from interop/header/header.go rename to pkg/interop/header/header.go index 29fa5d9da..44fc2d9e6 100644 --- a/interop/header/header.go +++ b/pkg/interop/header/header.go @@ -1,7 +1,7 @@ package header // Package header provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // Header stubs a NEO block header type. type Header struct{} diff --git a/interop/input/input.go b/pkg/interop/input/input.go similarity index 84% rename from interop/input/input.go rename to pkg/interop/input/input.go index cdc0a0336..047637226 100644 --- a/interop/input/input.go +++ b/pkg/interop/input/input.go @@ -1,7 +1,7 @@ package input // Package input provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // Input stubs the input of a NEO transaction. type Input struct{} diff --git a/interop/iterator/iterator.go b/pkg/interop/iterator/iterator.go similarity index 90% rename from interop/iterator/iterator.go rename to pkg/interop/iterator/iterator.go index 352cf3f17..c63d3b93d 100644 --- a/interop/iterator/iterator.go +++ b/pkg/interop/iterator/iterator.go @@ -1,7 +1,7 @@ package iterator // Package iterator provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // Iterator stubs a NEO iterator object type. type Iterator struct{} diff --git a/interop/output/output.go b/pkg/interop/output/output.go similarity index 88% rename from interop/output/output.go rename to pkg/interop/output/output.go index 08f2230df..6f40ac544 100644 --- a/interop/output/output.go +++ b/pkg/interop/output/output.go @@ -1,7 +1,7 @@ package output // Package output provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // Output stubs the output of a NEO transaction. type Output struct{} diff --git a/interop/runtime/runtime.go b/pkg/interop/runtime/runtime.go similarity index 94% rename from interop/runtime/runtime.go rename to pkg/interop/runtime/runtime.go index 40df58b17..fd07d7bd6 100644 --- a/interop/runtime/runtime.go +++ b/pkg/interop/runtime/runtime.go @@ -1,7 +1,7 @@ package runtime // Package runtime provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // CheckWitness verifies if the given hash is the invoker of the contract. func CheckWitness(hash []byte) bool { diff --git a/interop/storage/storage.go b/pkg/interop/storage/storage.go similarity index 84% rename from interop/storage/storage.go rename to pkg/interop/storage/storage.go index 25cf4ef34..2391fd550 100644 --- a/interop/storage/storage.go +++ b/pkg/interop/storage/storage.go @@ -1,9 +1,9 @@ package storage -import "github.com/CityOfZion/neo-storm/interop/iterator" +import "github.com/CityOfZion/neo-go/pkg/interop/iterator" // Package storage provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // Context represents the storage context type Context struct{} diff --git a/interop/transaction/transaction.go b/pkg/interop/transaction/transaction.go similarity index 84% rename from interop/transaction/transaction.go rename to pkg/interop/transaction/transaction.go index 44ba46728..550c796d4 100644 --- a/interop/transaction/transaction.go +++ b/pkg/interop/transaction/transaction.go @@ -1,13 +1,13 @@ package transaction import ( - "github.com/CityOfZion/neo-storm/interop/attribute" - "github.com/CityOfZion/neo-storm/interop/input" - "github.com/CityOfZion/neo-storm/interop/output" + "github.com/CityOfZion/neo-go/pkg/interop/attribute" + "github.com/CityOfZion/neo-go/pkg/interop/input" + "github.com/CityOfZion/neo-go/pkg/interop/output" ) // Package transaction provides function signatures that can be used inside -// smart contracts that are written in the neo-storm framework. +// smart contracts that are written in the neo-go framework. // Transaction stubs a NEO transaction type. type Transaction struct{} diff --git a/interop/util/util.go b/pkg/interop/util/util.go similarity index 100% rename from interop/util/util.go rename to pkg/interop/util/util.go diff --git a/pkg/vm/README.md b/pkg/vm/README.md index 46e21b560..cff6635d4 100644 --- a/pkg/vm/README.md +++ b/pkg/vm/README.md @@ -117,7 +117,7 @@ You can invoke smart contracts with arguments. Take the following ***roll the di ``` package rollthedice -import "github.com/CityOfZion/neo-go/pkg/vm/api/runtime" +import "github.com/CityOfZion/neo-go/pkg/interop/runtime" func Main(method string, args []interface{}) int { if method == "rollDice" { diff --git a/pkg/vm/api/asset/asset.go b/pkg/vm/api/asset/asset.go deleted file mode 100644 index edc4aa99a..000000000 --- a/pkg/vm/api/asset/asset.go +++ /dev/null @@ -1,31 +0,0 @@ -package asset - -import "github.com/CityOfZion/neo-go/pkg/core" - -// GetAssetID returns the id of the given asset. -func GetAssetID(asset *core.AssetState) []byte { return nil } - -// TODO: Verify if we need to return a uint8 here. -// GetAssetType returns the type of the given asset. -func GetAssetType(asset *core.AssetState) uint8 { return 0x00 } - -// GetAmount returns the amount of the given asset. -func GetAmount(asset *core.AssetState) uint64 { return 0 } - -// GetAvailable returns the available amount of the given asset. -func GetAvailable(asset *core.AssetState) uint64 { return 0 } - -// GetPrecision returns the precision the given asset. -func GetPrecision(asset *core.AssetState) uint8 { return 0 } - -// GetOwner returns the owner the given asset. -func GetOwner(asset *core.AssetState) []byte { return nil } - -// GetIssuer returns the issuer the given asset. -func GetIssuer(asset *core.AssetState) []byte { return nil } - -// Create a new asset specified by the given parameters. -func Create(typ uint8, name string, amount uint64, owner, admin, issuer []byte) {} - -// Renew the given asset for the given x years. -func Renew(asset *core.AssetState, years uint32) {} diff --git a/pkg/vm/api/block/block.go b/pkg/vm/api/block/block.go deleted file mode 100644 index ad3b4d8a1..000000000 --- a/pkg/vm/api/block/block.go +++ /dev/null @@ -1,41 +0,0 @@ -package block - -import ( - "github.com/CityOfZion/neo-go/pkg/core" - "github.com/CityOfZion/neo-go/pkg/core/transaction" -) - -// GetTransactionCount returns the number of transactions that are recorded in -// the given block. -func GetTransactionCount(block *core.Block) int { return 0 } - -// GetTransactions returns a list of transactions that are recorded in this block. -func GetTransactions(block *core.Block) []*transaction.Transaction { return nil } - -// GetIndex returns the index of the given block. -func GetIndex(block *core.Block) uint32 { return 0 } - -// GetHash returns the hash of the given block. -func GetHash(block *core.Block) []byte { return nil } - -// GetHash returns the version of the given block. -func GetVersion(block *core.Block) uint32 { return 0 } - -// GetHash returns the previous hash of the given block. -func GetPrevHash(block *core.Block) []byte { return nil } - -// GetHash returns the merkle root of the given block. -func GetMerkleRoot(block *core.Block) []byte { return nil } - -// GetHash returns the timestamp of the given block. -func GetTimestamp(block *core.Block) uint32 { return 0 } - -// GetHash returns the next validator address of the given block. -func GetNextConsensus(block *core.Block) []byte { return nil } - -// GetConsensusData returns the consensus data of the given block. -func GetConsensusData(block *core.Block) uint64 { return 0 } - -// GetTransaction returns a specific transaction that is recorded in the given block -// by the given index. -func GetTransaction(block *core.Block, index int) *transaction.Transaction { return nil } diff --git a/pkg/vm/api/crypto/util.go b/pkg/vm/api/crypto/util.go deleted file mode 100644 index d2f734564..000000000 --- a/pkg/vm/api/crypto/util.go +++ /dev/null @@ -1,21 +0,0 @@ -package crypto - -// SHA1 computes the sha1 hash of b. -func SHA1(b []byte) []byte { - return nil -} - -// SHA256 computes the sha256 hash of b. -func SHA256(b []byte) []byte { - return nil -} - -// Hash160 .. -func Hash160(b []byte) []byte { - return nil -} - -// Hash256 .. -func Hash256(b []byte) []byte { - return nil -} diff --git a/pkg/vm/api/header/header.go b/pkg/vm/api/header/header.go deleted file mode 100644 index c4254bd94..000000000 --- a/pkg/vm/api/header/header.go +++ /dev/null @@ -1,24 +0,0 @@ -package header - -import "github.com/CityOfZion/neo-go/pkg/core" - -// GetIndex returns the index of the given header. -func GetIndex(header *core.Header) uint32 { return 0 } - -// GetHash returns the hash of the given header. -func GetHash(header *core.Header) []byte { return nil } - -// GetHash returns the version of the given header. -func GetVersion(header *core.Header) uint32 { return 0 } - -// GetHash returns the previous hash of the given header. -func GetPrevHash(header *core.Header) []byte { return nil } - -// GetHash returns the merkle root of the given header. -func GetMerkleRoot(header *core.Header) []byte { return nil } - -// GetHash returns the timestamp of the given header. -func GetTimestamp(header *core.Header) uint32 { return 0 } - -// GetHash returns the next validator address of the given header. -func GetNextConsensus(header *core.Header) []byte { return nil } diff --git a/pkg/vm/api/runtime/runtime.go b/pkg/vm/api/runtime/runtime.go deleted file mode 100644 index 685db4937..000000000 --- a/pkg/vm/api/runtime/runtime.go +++ /dev/null @@ -1,45 +0,0 @@ -package runtime - -// CheckWitness verifies if the invoker is the owner of the contract. -func CheckWitness(hash []byte) bool { - return true -} - -// GetTime returns the timestamp of the most recent block. -func GetTime() int { - return 0 -} - -// Notify an event to the VM. -func Notify(arg interface{}) int { - return 0 -} - -// Log instructs the VM to log the given message. -func Log(message string) {} - -// Application returns the application trigger type. -func Application() byte { - return 0x10 -} - -// Verification returns the verification trigger type. -func Verification() byte { - return 0x00 -} - -// GetTrigger return the current trigger type. The return in this function -// doesn't really mather, this is just an interop placeholder. -func GetTrigger() interface{} { - return 0 -} - -// Serialize serializes and item into a bytearray. -func Serialize(item interface{}) []byte { - return nil -} - -// Deserialize an item from a bytearray. -func Deserialize(b []byte) interface{} { - return nil -} diff --git a/pkg/vm/api/storage/storage.go b/pkg/vm/api/storage/storage.go deleted file mode 100644 index ed8cea536..000000000 --- a/pkg/vm/api/storage/storage.go +++ /dev/null @@ -1,19 +0,0 @@ -package storage - -// Context represents the storage context. -type Context interface{} - -// GetContext returns the storage context. -func GetContext() interface{} { return nil } - -// Put stores a value in to the storage. -func Put(ctx interface{}, key interface{}, value interface{}) {} - -// Get returns the value from the storage. -func Get(ctx interface{}, key interface{}) interface{} { return 0 } - -// Delete removes a stored key value pair. -func Delete(ctx interface{}, key interface{}) {} - -// Find entries somewhat matching the given key. -func Find(ctx interface{}, key interface{}) interface{} { return 0 } diff --git a/pkg/vm/api/transaction/transaction.go b/pkg/vm/api/transaction/transaction.go deleted file mode 100644 index e0744e217..000000000 --- a/pkg/vm/api/transaction/transaction.go +++ /dev/null @@ -1,27 +0,0 @@ -package transaction - -import "github.com/CityOfZion/neo-go/pkg/core/transaction" - -// GetType returns the type of the given transaction. -// TODO: Double check if the type returned should be of type uint8. -func GetType(tx *transaction.Transaction) uint8 { return 0x00 } - -// GetTXHash returns the hash of the given transaction. -func GetTXHash(tx *transaction.Transaction) []byte { return nil } - -// GetAttributes returns the attributes of the given transaction. -func GetAttributes(tx *transaction.Transaction) []*transaction.Attribute { return nil } - -// GetInputs returns the inputs of the given transaction. -func GetInputs(tx *transaction.Transaction) []*transaction.Input { return nil } - -// GetOutputs returns the outputs of the given transaction. -func GetOutputs(tx *transaction.Transaction) []*transaction.Output { return nil } - -// TODO: What does this return as data type? -// GetReferences returns the outputs of the given transaction. -// func GetReferences(tx *transaction.Transaction) { } - -// TODO: What does this return as data type? -// GetUnspentCoins returns the unspent coins of the given transaction. -// func GetUnspentCoins(tx *transaction.Transaction) { } diff --git a/pkg/vm/api/types/block.go b/pkg/vm/api/types/block.go deleted file mode 100644 index 928449db6..000000000 --- a/pkg/vm/api/types/block.go +++ /dev/null @@ -1,9 +0,0 @@ -package types - -// Block represents a block in the blockchain. -type Block struct{} - -// Index returns the height of the block. -func (b Block) Index() int { - return 0 -} diff --git a/pkg/vm/api/util/util.go b/pkg/vm/api/util/util.go deleted file mode 100644 index fee3d9b05..000000000 --- a/pkg/vm/api/util/util.go +++ /dev/null @@ -1,6 +0,0 @@ -package util - -// FromAddress returns the underlying bytes from the given address string. -func FromAddress(address string) []byte { - return nil -} diff --git a/pkg/vm/compiler/README.md b/pkg/vm/compiler/README.md index 3d2cbb44f..9592950e5 100644 --- a/pkg/vm/compiler/README.md +++ b/pkg/vm/compiler/README.md @@ -118,8 +118,8 @@ Will output something like: package mycontract import ( - "github.com/CityOfZion/neo-go/pkg/vm/api/runtime" - "github.com/CityOfZion/neo-go/pkg/vm/api/util" + "github.com/CityOfZion/neo-go/pkg/interop/runtime" + "github.com/CityOfZion/neo-go/pkg/interop/util" ) var owner = util.FromAddress("AJX1jGfj3qPBbpAKjY527nPbnrnvSx9nCg") @@ -142,8 +142,8 @@ func Main() bool { package mytoken import ( - "github.com/CityOfZion/neo-go/pkg/vm/api/runtime" - "github.com/CityOfZion/neo-go/pkg/vm/api/storage" + "github.com/CityOfZion/neo-go/pkg/interop/runtime" + "github.com/CityOfZion/neo-go/pkg/interop/storage" ) var owner = util.FromAddress("AJX1jGfj3qPBbpAKjY527nPbnrnvSx9nCg") diff --git a/pkg/vm/tests/syscall_test.go b/pkg/vm/tests/syscall_test.go index 5b3e4c883..a19e9dcb3 100644 --- a/pkg/vm/tests/syscall_test.go +++ b/pkg/vm/tests/syscall_test.go @@ -8,7 +8,7 @@ func TestStoragePutGet(t *testing.T) { src := ` package foo - import "github.com/CityOfZion/neo-go/pkg/vm/api/storage" + import "github.com/CityOfZion/neo-go/pkg/interop/storage" func Main() string { ctx := storage.GetContext() diff --git a/pkg/vm/tests/util_test.go b/pkg/vm/tests/util_test.go index db56be0a3..2da750d91 100644 --- a/pkg/vm/tests/util_test.go +++ b/pkg/vm/tests/util_test.go @@ -8,7 +8,7 @@ func TestSHA256(t *testing.T) { src := ` package foo import ( - "github.com/CityOfZion/neo-go/pkg/vm/api/crypto" + "github.com/CityOfZion/neo-go/pkg/interop/crypto" ) func Main() []byte { src := []byte{0x97} @@ -23,7 +23,7 @@ func TestSHA1(t *testing.T) { src := ` package foo import ( - "github.com/CityOfZion/neo-go/pkg/vm/api/crypto" + "github.com/CityOfZion/neo-go/pkg/interop/crypto" ) func Main() []byte { src := []byte{0x97} @@ -38,7 +38,7 @@ func TestHash160(t *testing.T) { src := ` package foo import ( - "github.com/CityOfZion/neo-go/pkg/vm/api/crypto" + "github.com/CityOfZion/neo-go/pkg/interop/crypto" ) func Main() []byte { src := []byte{0x97} @@ -53,7 +53,7 @@ func TestHash256(t *testing.T) { src := ` package foo import ( - "github.com/CityOfZion/neo-go/pkg/vm/api/crypto" + "github.com/CityOfZion/neo-go/pkg/interop/crypto" ) func Main() []byte { src := []byte{0x97} From 57c7df4dff299c8e3896efc4ff62feeb84a69017 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 15 Aug 2019 19:51:07 +0300 Subject: [PATCH 42/44] *: remove remaining references to neo-storm, update README README update partially reverts c8d7671d268be1c17befbd8d57761b5b6da41d6f and updates it with current commands and sample output. --- README.md | 52 ++++++++++++++++++++++++++++- cli/smartcontract/smart_contract.go | 12 +++---- docs/runtime.md | 2 +- 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d6b06371d..38f245873 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,57 @@ ApplicationConfiguration: ``` ## Writing smart contracts in Go -Golang's development is been moved to a separate repository which you can find here [neo-storm](https://github.com/CityOfZion/neo-storm) +In depth documentation about the **neo-go** compiler and smart contract examples can be found inside the [compiler package](https://github.com/CityOfZion/neo-go/tree/master/pkg/vm/compiler). + +### Compile a smart contract + +``` +./bin/neo-go contract compile -i mycontract.go +``` + +By default the filename will be the name of your `.go` file with the `.avm` extension, the file will be located in the same directory where you called the command from. If you want another location for your compiled contract: + +``` +./bin/neo-go contract compile -i mycontract.go --out /Users/foo/bar/contract.avm +``` + +### Debugging your smart contract +You can dump the opcodes generated by the compiler with the following command: + +``` +./bin/neo-go contract inspect -i mycontract.go +``` + +This will result in something like this: + +``` +INDEX OPCODE DESC +0 0x54 PUSH4 +1 0xc5 NEWARRAY +2 0x6b TOALTSTACK +3 0x5a PUSH10 +4 0x6a DUPFROMALTSTACK +5 0x0 PUSH0 +6 0x52 PUSH2 +7 0x7a ROLL +8 0xc4 SETITEM +9 0x6a DUPFROMALTSTACK +10 0x0 PUSH0 +11 0xc3 PICKITEM +12 0x5a PUSH10 +13 0xa2 GTE +14 0x64 JMPIFNOT +15 0x7 7 +15 0x0 0 +17 0x51 PUSH1 +18 0x6c FROMALTSTACK +19 0x75 DROP +20 0x66 RET +21 0x0 PUSH0 +22 0x6c FROMALTSTACK +23 0x75 DROP +24 0x66 RET +``` # Contributing diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 5bfe32c14..333aa01c1 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -121,11 +121,11 @@ func initSmartContract(ctx *cli.Context) error { return cli.NewExitError(err, 1) } - // Ask contract information and write a storm.yml file unless the -skip-details flag is set. - // TODO: Fix the missing storm.yml file with the `init` command when the package manager is in place. + // Ask contract information and write a neo-go.yml file unless the -skip-details flag is set. + // TODO: Fix the missing neo-go.yml file with the `init` command when the package manager is in place. if !ctx.Bool("skip-details") { details := parseContractDetails() - if err := ioutil.WriteFile(filepath.Join(basePath, "storm.yml"), details.toStormFile(), 0644); err != nil { + if err := ioutil.WriteFile(filepath.Join(basePath, "neo-go.yml"), details.toStormFile(), 0644); err != nil { return cli.NewExitError(err, 1) } } @@ -205,8 +205,8 @@ type ContractDetails struct { func (d ContractDetails) toStormFile() []byte { buf := new(bytes.Buffer) - buf.WriteString("# Storm specific configuration. Do not modify this unless you know what you are doing!\n") - buf.WriteString("storm:\n") + buf.WriteString("# NEO-GO specific configuration. Do not modify this unless you know what you are doing!\n") + buf.WriteString("neo-go:\n") buf.WriteString(" version: 1.0\n") buf.WriteString("\n") @@ -222,7 +222,7 @@ func (d ContractDetails) toStormFile() []byte { buf.WriteString("\n") buf.WriteString("# Module section contains a list of imported modules\n") - buf.WriteString("# This will be automatically managed by the neo-storm package manager\n") + buf.WriteString("# This will be automatically managed by the neo-go package manager\n") buf.WriteString("modules: \n") return buf.Bytes() } diff --git a/docs/runtime.md b/docs/runtime.md index 92ed485d0..e98b3af20 100644 --- a/docs/runtime.md +++ b/docs/runtime.md @@ -1,5 +1,5 @@ # Runtime -A brief overview of NEO smart contract API's that can be used in the neo-storm framework. +A brief overview of NEO smart contract API's that can be used in the neo-go framework. # Overview 1. [Account]() From 1e09037902c28c0216383bfbb403faa3967d6948 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 15 Aug 2019 19:53:21 +0300 Subject: [PATCH 43/44] pkg/vm/compiler: update README s/opdump/inspect/ and new sample output. --- pkg/vm/compiler/README.md | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/pkg/vm/compiler/README.md b/pkg/vm/compiler/README.md index 9592950e5..88287451e 100644 --- a/pkg/vm/compiler/README.md +++ b/pkg/vm/compiler/README.md @@ -68,24 +68,39 @@ By default the filename will be the name of your .go file with the .avm extensio You can dump the opcodes generated by the compiler with the following command: ``` -./bin/neo-go contract opdump -i mycontract.go +./bin/neo-go contract inspect -i mycontract.go ``` This will result in something like this: ``` INDEX OPCODE DESC -0 0x52 OpPush2 -1 0xc5 OpNewArray -2 0x6b OpToAltStack -3 0x 0 OpPush0 -4 0x6c OpFromAltStack -5 0x76 OpDup -6 0x6b OpToAltStack -7 0x 0 OpPush0 -8 0x52 OpPush2 -9 0x7a OpRoll -10 0xc4 OpSetItem +0 0x54 PUSH4 +1 0xc5 NEWARRAY +2 0x6b TOALTSTACK +3 0x1 PUSHBYTES1 +3 0x2a * +5 0x6a DUPFROMALTSTACK +6 0x0 PUSH0 +7 0x52 PUSH2 +8 0x7a ROLL +9 0xc4 SETITEM +10 0x6a DUPFROMALTSTACK +11 0x0 PUSH0 +12 0xc3 PICKITEM +13 0x5a PUSH10 +14 0xa2 GTE +15 0x64 JMPIFNOT +16 0x7 7 +16 0x0 0 +18 0x51 PUSH1 +19 0x6c FROMALTSTACK +20 0x75 DROP +21 0x66 RET +22 0x0 PUSH0 +23 0x6c FROMALTSTACK +24 0x75 DROP +25 0x66 RET ``` ### Test invoke a compiled contract From d58fbe0c88b7848ce4d8ef300d594b7cc39f94cc Mon Sep 17 00:00:00 2001 From: Evgenii Date: Fri, 16 Aug 2019 13:05:07 +0300 Subject: [PATCH 44/44] compiler: use separate opcodes for string and number equality --- pkg/vm/compiler/codegen.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/pkg/vm/compiler/codegen.go b/pkg/vm/compiler/codegen.go index a0b3e852a..080f72368 100644 --- a/pkg/vm/compiler/codegen.go +++ b/pkg/vm/compiler/codegen.go @@ -382,15 +382,22 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { ast.Walk(c, n.X) ast.Walk(c, n.Y) - // VM has separate opcode for string concatenation - if n.Op == token.ADD { - typ, ok := tinfo.Type.Underlying().(*types.Basic) - if ok && typ.Kind() == types.String { + switch { + case n.Op == token.ADD: + // VM has separate opcodes for number and string concatenation + if isStringType(tinfo.Type) { emitOpcode(c.prog, vm.CAT) } else { emitOpcode(c.prog, vm.ADD) } - } else { + case n.Op == token.EQL: + // VM has separate opcodes for number and string equality + if isStringType(tinfo.Type) { + emitOpcode(c.prog, vm.EQUAL) + } else { + emitOpcode(c.prog, vm.NUMEQUAL) + } + default: c.convertToken(n.Op) } return nil