From 459d3654a2a2663219aac9606663202650bef358 Mon Sep 17 00:00:00 2001 From: Anthony De Meulemeester Date: Tue, 23 Oct 2018 10:23:03 +0200 Subject: [PATCH] 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",