diff --git a/cli/main.go b/cli/main.go index ed42f82..ec4fa53 100644 --- a/cli/main.go +++ b/cli/main.go @@ -85,6 +85,17 @@ func main() { }, }, }, + { + 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", + }, + }, + }, } ctl.Run(os.Args) } @@ -158,7 +169,7 @@ func contractTestInvoke(ctx *cli.Context) error { } // FIXME: Make this configurable (probably in the general storm.yml file/config) - endpoint := "http://seed3.ngd.network: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) @@ -234,3 +245,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/compiler/codegen.go b/compiler/codegen.go index fed9050..bfffde9 100644 --- a/compiler/codegen.go +++ b/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/compiler/compiler.go b/compiler/compiler.go index 682ce5a..cf70edb 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -15,6 +15,7 @@ import ( "strings" "text/tabwriter" + "github.com/CityOfZion/neo-storm/vm" "golang.org/x/tools/go/loader" ) @@ -89,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 @@ -110,9 +110,19 @@ 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++ { - // TODO: generate stringer for instruction. - // 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/compiler/syscall.go b/compiler/syscall.go index 57e510c..62e24f4 100644 --- a/compiler/syscall.go +++ b/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", diff --git a/interop/transaction/transaction.go b/interop/transaction/transaction.go index e845a11..44ba467 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/vm/instruction_string.go b/vm/instruction_string.go new file mode 100644 index 0000000..da98524 --- /dev/null +++ b/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) + ")" +}