github.com/core-coin/go-core/v2@v2.1.9/cmd/abigen/main.go (about) 1 // Copyright 2016 by the Authors 2 // This file is part of go-core. 3 // 4 // go-core is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-core is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-core. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "io/ioutil" 23 "os" 24 "regexp" 25 "strings" 26 27 "gopkg.in/urfave/cli.v1" 28 29 "github.com/core-coin/go-core/v2/accounts/abi/bind" 30 "github.com/core-coin/go-core/v2/cmd/utils" 31 "github.com/core-coin/go-core/v2/common/compiler" 32 "github.com/core-coin/go-core/v2/crypto" 33 "github.com/core-coin/go-core/v2/internal/flags" 34 "github.com/core-coin/go-core/v2/log" 35 ) 36 37 var ( 38 // Git SHA1 commit hash of the release (set via linker flags) 39 gitTag = "" 40 gitCommit = "" 41 gitDate = "" 42 43 app *cli.App 44 45 // Flags needed by abigen 46 abiFlag = cli.StringFlag{ 47 Name: "abi", 48 Usage: "Path to the Core contract ABI json to bind, - for STDIN", 49 } 50 binFlag = cli.StringFlag{ 51 Name: "bin", 52 Usage: "Path to the Core contract bytecode (generate deploy method)", 53 } 54 typeFlag = cli.StringFlag{ 55 Name: "type", 56 Usage: "Struct name for the binding (default = package name)", 57 } 58 jsonFlag = cli.StringFlag{ 59 Name: "combined-json", 60 Usage: "Path to the combined-json file generated by compiler", 61 } 62 solFlag = cli.StringFlag{ 63 Name: "sol", 64 Usage: "Path to the Core contract Ylem source to build and bind", 65 } 66 ylemFlag = cli.StringFlag{ 67 Name: "ylem", 68 Usage: "Ylem compiler to use if source builds are requested", 69 Value: "ylem", 70 } 71 excFlag = cli.StringFlag{ 72 Name: "exc", 73 Usage: "Comma separated types to exclude from binding", 74 } 75 pkgFlag = cli.StringFlag{ 76 Name: "pkg", 77 Usage: "Package name to generate the binding into", 78 } 79 outFlag = cli.StringFlag{ 80 Name: "out", 81 Usage: "Output file for the generated binding (default = stdout)", 82 } 83 aliasFlag = cli.StringFlag{ 84 Name: "alias", 85 Usage: "Comma separated aliases for function and event renaming, e.g. foo=bar", 86 } 87 ) 88 89 func init() { 90 app = flags.NewApp(gitTag, gitCommit, gitDate, "core checkpoint helper tool") 91 app.Flags = []cli.Flag{ 92 abiFlag, 93 binFlag, 94 typeFlag, 95 jsonFlag, 96 solFlag, 97 ylemFlag, 98 excFlag, 99 pkgFlag, 100 outFlag, 101 aliasFlag, 102 } 103 app.Action = utils.MigrateFlags(abigen) 104 cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate 105 } 106 107 func abigen(c *cli.Context) error { 108 utils.CheckExclusive(c, abiFlag, jsonFlag, solFlag) // Only one source can be selected. 109 if c.GlobalString(pkgFlag.Name) == "" { 110 utils.Fatalf("No destination package specified (--pkg)") 111 } 112 // If the entire ylem code was specified, build and bind based on that 113 var ( 114 abis []string 115 bins []string 116 types []string 117 sigs []map[string]string 118 libs = make(map[string]string) 119 aliases = make(map[string]string) 120 ) 121 if c.GlobalString(abiFlag.Name) != "" { 122 // Load up the ABI, optional bytecode and type name from the parameters 123 var ( 124 abi []byte 125 err error 126 ) 127 input := c.GlobalString(abiFlag.Name) 128 if input == "-" { 129 abi, err = ioutil.ReadAll(os.Stdin) 130 } else { 131 abi, err = ioutil.ReadFile(input) 132 } 133 if err != nil { 134 utils.Fatalf("Failed to read input ABI: %v", err) 135 } 136 abis = append(abis, string(abi)) 137 138 var bin []byte 139 if binFile := c.GlobalString(binFlag.Name); binFile != "" { 140 if bin, err = ioutil.ReadFile(binFile); err != nil { 141 utils.Fatalf("Failed to read input bytecode: %v", err) 142 } 143 if strings.Contains(string(bin), "//") { 144 utils.Fatalf("Contract has additional library references, please use other mode(e.g. --combined-json) to catch library infos") 145 } 146 } 147 bins = append(bins, string(bin)) 148 149 kind := c.GlobalString(typeFlag.Name) 150 if kind == "" { 151 kind = c.GlobalString(pkgFlag.Name) 152 } 153 types = append(types, kind) 154 } else { 155 // Generate the list of types to exclude from binding 156 exclude := make(map[string]bool) 157 for _, kind := range strings.Split(c.GlobalString(excFlag.Name), ",") { 158 exclude[strings.ToLower(kind)] = true 159 } 160 var err error 161 var contracts map[string]*compiler.Contract 162 163 switch { 164 case c.GlobalIsSet(solFlag.Name): 165 contracts, err = compiler.CompileYlem(c.GlobalString(ylemFlag.Name), c.GlobalString(solFlag.Name)) 166 if err != nil { 167 utils.Fatalf("Failed to build Ylem contract: %v", err) 168 } 169 case c.GlobalIsSet(jsonFlag.Name): 170 jsonOutput, err := ioutil.ReadFile(c.GlobalString(jsonFlag.Name)) 171 if err != nil { 172 utils.Fatalf("Failed to read combined-json from compiler: %v", err) 173 } 174 contracts, err = compiler.ParseCombinedJSON(jsonOutput, "", "", "", "") 175 if err != nil { 176 utils.Fatalf("Failed to read contract information from json output: %v", err) 177 } 178 } 179 // Gather all non-excluded contract for binding 180 for name, contract := range contracts { 181 if exclude[strings.ToLower(name)] { 182 continue 183 } 184 abi, err := json.Marshal(contract.Info.AbiDefinition) // Flatten the compiler parse 185 if err != nil { 186 utils.Fatalf("Failed to parse ABIs from compiler output: %v", err) 187 } 188 abis = append(abis, string(abi)) 189 bins = append(bins, contract.Code) 190 sigs = append(sigs, contract.Hashes) 191 nameParts := strings.Split(name, ":") 192 types = append(types, nameParts[len(nameParts)-1]) 193 194 libPattern := crypto.SHA3Hash([]byte(name)).String()[:36] 195 libs[libPattern] = nameParts[len(nameParts)-1] 196 } 197 } 198 // Extract all aliases from the flags 199 if c.GlobalIsSet(aliasFlag.Name) { 200 // We support multi-versions for aliasing 201 // e.g. 202 // foo=bar,foo2=bar2 203 // foo:bar,foo2:bar2 204 re := regexp.MustCompile(`(?:(\w+)[:=](\w+))`) 205 submatches := re.FindAllStringSubmatch(c.GlobalString(aliasFlag.Name), -1) 206 for _, match := range submatches { 207 aliases[match[1]] = match[2] 208 } 209 } 210 // Generate the contract binding 211 code, err := bind.Bind(types, abis, bins, sigs, c.GlobalString(pkgFlag.Name), libs, aliases) 212 if err != nil { 213 utils.Fatalf("Failed to generate ABI binding: %v", err) 214 } 215 // Either flush it out to a file or display on the standard output 216 if !c.GlobalIsSet(outFlag.Name) { 217 fmt.Printf("%s\n", code) 218 return nil 219 } 220 if err := ioutil.WriteFile(c.GlobalString(outFlag.Name), []byte(code), 0600); err != nil { 221 utils.Fatalf("Failed to write ABI binding: %v", err) 222 } 223 return nil 224 } 225 226 func main() { 227 log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 228 229 if err := app.Run(os.Args); err != nil { 230 fmt.Fprintln(os.Stderr, err) 231 os.Exit(1) 232 } 233 }