github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/equity/compiler/cmd/equitycmd/equitycmd.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "bytes" 6 "fmt" 7 "log" 8 "os" 9 "strings" 10 11 "github.com/bytom/bytom/equity/compiler" 12 ) 13 14 var ( 15 // generateInstPath is the directory (need to combine with GOPATH) for store generated contract instance 16 generateInstPath = "/src/github.com/bytom/bytom/equity/instance/" 17 ) 18 19 func main() { 20 if len(os.Args) != 2 { 21 fmt.Println("command args: [command] [contract file_path]") 22 os.Exit(0) 23 } 24 25 filename := os.Args[1] 26 inputFile, inputError := os.Open(filename) 27 if inputError != nil { 28 fmt.Printf("An error occurred on opening the inputfile\n" + 29 "Does the file exist?\n" + 30 "Have you got acces to it?\n") 31 os.Exit(0) 32 } 33 defer inputFile.Close() 34 35 inputReader := bufio.NewReader(inputFile) 36 contracts, err := compiler.Compile(inputReader) 37 if err != nil { 38 log.Fatal(err) 39 } 40 41 var packageName *string 42 var midstr string 43 var outstr []string 44 45 //change the windows path into unix path 46 filename = strings.Replace(filename, "\\", "/", -1) 47 if strings.Contains(filename, "/") == true { 48 outstr = strings.Split(filename, "/") 49 midstr = outstr[len(outstr)-1] 50 } else { 51 midstr = filename 52 } 53 54 //check whether the filename contains point flag 55 if strings.Contains(midstr, ".") == true { 56 outstr = strings.Split(midstr, ".") 57 packageName = &outstr[0] 58 } else { 59 packageName = &midstr 60 } 61 62 header := new(bytes.Buffer) 63 fmt.Fprintf(header, "package instance\n\n") 64 65 imports := map[string]bool{ 66 "bytes": true, 67 "encoding/hex": true, 68 "fmt": true, 69 "github.com/bytom/bytom/equity/compiler": true, 70 "github.com/bytom/bytom/protocol/vm": true, 71 } 72 73 buf := new(bytes.Buffer) 74 75 if len(contracts) == 1 { 76 fmt.Fprintf(buf, "// %sBodyBytes refer to contract's body\n", contracts[0].Name) 77 fmt.Fprintf(buf, "var %sBodyBytes []byte\n\n", contracts[0].Name) 78 } else { 79 fmt.Fprintf(buf, "var (\n") 80 for _, contract := range contracts { 81 fmt.Fprintf(buf, "\t%sBodyBytes []byte\n", contract.Name) 82 } 83 fmt.Fprintf(buf, ")\n\n") 84 } 85 86 fmt.Fprintf(buf, "func init() {\n") 87 for _, contract := range contracts { 88 fmt.Fprintf(buf, "\t%sBodyBytes, _ = hex.DecodeString(\"%x\")\n", contract.Name, contract.Body) 89 } 90 fmt.Fprintf(buf, "}\n\n") 91 92 for _, contract := range contracts { 93 fmt.Fprintf(buf, "// contract %s(%s) locks %s\n", contract.Name, paramsStr(contract.Params), contract.Value) 94 fmt.Fprintf(buf, "//\n") 95 maxWidth := 0 96 for _, step := range contract.Steps { 97 if len(step.Opcodes) > maxWidth { 98 maxWidth = len(step.Opcodes) 99 } 100 } 101 format := fmt.Sprintf("// %%-%d.%ds %%s\n", maxWidth, maxWidth) 102 for _, step := range contract.Steps { 103 fmt.Fprintf(buf, format, step.Opcodes, step.Stack) 104 } 105 fmt.Fprintf(buf, "\n") 106 107 fmt.Fprintf(buf, "// PayTo%s instantiates contract %s as a program with specific arguments.\n", contract.Name, contract.Name) 108 goParams, newImports := asGoParams(contract.Params) 109 for _, imp := range newImports { 110 imports[imp] = true 111 } 112 fmt.Fprintf(buf, "func PayTo%s(%s) ([]byte, error) {\n", contract.Name, goParams) 113 fmt.Fprintf(buf, "\t_contractParams := []*compiler.Param{\n") 114 for _, param := range contract.Params { 115 fmt.Fprintf(buf, "\t\t{Name: \"%s\", Type: \"%s\"},\n", param.Name, param.Type) 116 } 117 fmt.Fprintf(buf, "\t}\n") 118 fmt.Fprintf(buf, "\tvar _contractArgs []compiler.ContractArg\n") 119 for _, param := range contract.Params { 120 switch param.Type { 121 case "Amount": 122 fmt.Fprintf(buf, "\t_%s := int64(%s)\n", param.Name, param.Name) 123 fmt.Fprintf(buf, "\t_contractArgs = append(_contractArgs, compiler.ContractArg{I: &_%s})\n", param.Name) 124 case "Asset": 125 fmt.Fprintf(buf, "\t_%s := %s.Bytes()\n", param.Name, param.Name) 126 fmt.Fprintf(buf, "\t_contractArgs = append(_contractArgs, compiler.ContractArg{S: (*json.HexBytes)(&_%s)})\n", param.Name) 127 case "Boolean": 128 fmt.Fprintf(buf, "\t_contractArgs = append(_contractArgs, compiler.ContractArg{B: &%s})\n", param.Name) 129 case "Integer": 130 fmt.Fprintf(buf, "\t_contractArgs = append(_contractArgs, compiler.ContractArg{I: &%s})\n", param.Name) 131 case "Hash", "Program", "PublicKey", "Signature", "String": 132 fmt.Fprintf(buf, "\t_contractArgs = append(_contractArgs, compiler.ContractArg{S: (*json.HexBytes)(&%s)})\n", param.Name) 133 } 134 } 135 fmt.Fprintf(buf, "\treturn compiler.Instantiate(%sBodyBytes, _contractParams, %v, _contractArgs)\n", contract.Name, contract.Recursive) 136 fmt.Fprintf(buf, "}\n\n") 137 138 fmt.Fprintf(buf, "// ParsePayTo%s parses the arguments out of an instantiation of contract %s.\n", contract.Name, contract.Name) 139 fmt.Fprintf(buf, "// If the input is not an instantiation of %s, returns an error.\n", contract.Name) 140 fmt.Fprintf(buf, "func ParsePayTo%s(prog []byte) ([][]byte, error) {\n", contract.Name) 141 fmt.Fprintf(buf, "\tvar result [][]byte\n") 142 fmt.Fprintf(buf, "\tinsts, err := vm.ParseProgram(prog)\n") 143 fmt.Fprintf(buf, "\tif err != nil {\n") 144 fmt.Fprintf(buf, "\t\treturn nil, err\n") 145 fmt.Fprintf(buf, "\t}\n") 146 fmt.Fprintf(buf, "\tfor i := 0; i < %d; i++ {\n", len(contract.Params)) 147 fmt.Fprintf(buf, "\t\tif len(insts) == 0 {\n") 148 fmt.Fprintf(buf, "\t\t\treturn nil, fmt.Errorf(\"program too short\")\n") 149 fmt.Fprintf(buf, "\t\t}\n") 150 fmt.Fprintf(buf, "\t\tif !insts[0].IsPushdata() {\n") 151 fmt.Fprintf(buf, "\t\t\treturn nil, fmt.Errorf(\"too few arguments\")\n") 152 fmt.Fprintf(buf, "\t\t}\n") 153 fmt.Fprintf(buf, "\t\tresult = append(result, insts[0].Data)\n") 154 fmt.Fprintf(buf, "\t\tinsts = insts[1:]\n") 155 fmt.Fprintf(buf, "\t}\n") 156 if contract.Recursive { 157 // args... body DEPTH OVER 0 CHECKPREDICATE 158 fmt.Fprintf(buf, "\tif len(insts) == 0 {\n") 159 fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"program too short\")\n") 160 fmt.Fprintf(buf, "\t}\n") 161 fmt.Fprintf(buf, "\tif !insts[0].IsPushdata() {\n") 162 fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"too few arguments\")\n") 163 fmt.Fprintf(buf, "\t}\n") 164 fmt.Fprintf(buf, "\tif !bytes.Equal(%sBodyBytes, insts[0].Data) {\n", contract.Name) 165 fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"body bytes do not match %s\")\n", contract.Name) 166 fmt.Fprintf(buf, "\t}\n") 167 fmt.Fprintf(buf, "\tinsts = insts[1:]\n") 168 } // else args ... DEPTH body 0 CHECKPREDICATE 169 fmt.Fprintf(buf, "\tif len(insts) != 4 {\n") 170 fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"program too short\")\n") 171 fmt.Fprintf(buf, "\t}\n") 172 fmt.Fprintf(buf, "\tif insts[0].Op != vm.OP_DEPTH {\n") 173 fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"wrong program format\")\n") 174 fmt.Fprintf(buf, "\t}\n") 175 if contract.Recursive { 176 fmt.Fprintf(buf, "\tif insts[1].Op != vm.OP_OVER {\n") 177 fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"wrong program format\")\n") 178 fmt.Fprintf(buf, "\t}\n") 179 } else { 180 fmt.Fprintf(buf, "\tif !insts[1].IsPushdata() {\n") 181 fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"wrong program format\")\n") 182 fmt.Fprintf(buf, "\t}\n") 183 fmt.Fprintf(buf, "\tif !bytes.Equal(%sBodyBytes, insts[1].Data) {\n", contract.Name) 184 fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"body bytes do not match %s\")\n", contract.Name) 185 fmt.Fprintf(buf, "\t}\n") 186 } 187 fmt.Fprintf(buf, "\tif !insts[2].IsPushdata() {\n") 188 fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"wrong program format\")\n") 189 fmt.Fprintf(buf, "\t}\n") 190 fmt.Fprintf(buf, "\tv, err := vm.AsInt64(insts[2].Data)\n") 191 fmt.Fprintf(buf, "\tif err != nil {\n") 192 fmt.Fprintf(buf, "\t\treturn nil, err\n") 193 fmt.Fprintf(buf, "\t}\n") 194 fmt.Fprintf(buf, "\tif v != 0 {\n") 195 fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"wrong program format\")\n") 196 fmt.Fprintf(buf, "\t}\n") 197 fmt.Fprintf(buf, "\tif insts[3].Op != vm.OP_CHECKPREDICATE {\n") 198 fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"wrong program format\")\n") 199 fmt.Fprintf(buf, "\t}\n") 200 fmt.Fprintf(buf, "\treturn result, nil\n") 201 fmt.Fprintf(buf, "}\n\n") 202 203 // TODO(bobg): RedeemFoo_Bar functions for marshaling the args to 204 // the Bar clause of contract Foo. 205 } 206 207 fmt.Fprintf(header, "import (\n") 208 for imp := range imports { 209 fmt.Fprintf(header, "\t\"%s\"\n", imp) 210 } 211 fmt.Fprintf(header, ")\n\n") 212 213 //get the Environment variables of GOPATH 214 gopath := os.Getenv("GOPATH") 215 path := gopath + generateInstPath 216 217 //if the directory is not exist, create it 218 _, err = os.Stat(path) 219 if err != nil { 220 if os.IsNotExist(err) { 221 direrr := os.MkdirAll(path, os.ModePerm) 222 if direrr != nil { 223 log.Fatal(direrr) 224 } 225 fmt.Println("the path is create success") 226 } else { 227 log.Fatal(err) 228 } 229 } 230 231 //store buf by create file 232 file, _ := os.Create(path + *packageName + ".go") 233 defer file.Close() 234 file.Write(header.Bytes()) 235 file.Write(buf.Bytes()) 236 fmt.Printf("create file [%s] success!\n", *packageName+".go") 237 } 238 239 func paramsStr(params []*compiler.Param) string { 240 var strs []string 241 for _, p := range params { 242 strs = append(strs, fmt.Sprintf("%s: %s", p.Name, p.Type)) 243 } 244 return strings.Join(strs, ", ") 245 } 246 247 func asGoParams(params []*compiler.Param) (goParams string, imports []string) { 248 var strs []string 249 strFlag := false 250 for _, p := range params { 251 var typ string 252 switch p.Type { 253 case "Amount": 254 typ = "uint64" 255 case "Asset": 256 typ = "bc.AssetID" 257 imports = append(imports, "github.com/bytom/bytom/protocol/bc") 258 strFlag = true 259 case "Boolean": 260 typ = "bool" 261 case "Hash": 262 typ = "[]byte" 263 strFlag = true 264 case "Integer": 265 typ = "int64" 266 case "Program": 267 typ = "[]byte" 268 strFlag = true 269 case "PublicKey": 270 typ = "ed25519.PublicKey" 271 imports = append(imports, "github.com/bytom/bytom/crypto/ed25519") 272 strFlag = true 273 case "Signature": 274 typ = "[]byte" 275 strFlag = true 276 case "String": 277 typ = "[]byte" 278 strFlag = true 279 } 280 strs = append(strs, fmt.Sprintf("%s %s", p.Name, typ)) 281 } 282 283 if strFlag { 284 imports = append(imports, "github.com/bytom/bytom/encoding/json") 285 } 286 return strings.Join(strs, ", "), imports 287 }