gitlab.com/yannislg/go-pulse@v0.0.0-20210722055913-a3e24e95638d/cmd/abigen/main.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum 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-ethereum 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-ethereum. 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 "path/filepath" 25 "regexp" 26 "strings" 27 28 "github.com/ethereum/go-ethereum/accounts/abi" 29 "github.com/ethereum/go-ethereum/accounts/abi/bind" 30 "github.com/ethereum/go-ethereum/cmd/utils" 31 "github.com/ethereum/go-ethereum/common/compiler" 32 "github.com/ethereum/go-ethereum/crypto" 33 "github.com/ethereum/go-ethereum/log" 34 "gopkg.in/urfave/cli.v1" 35 ) 36 37 var ( 38 // Git SHA1 commit hash of the release (set via linker flags) 39 gitCommit = "" 40 gitDate = "" 41 42 app *cli.App 43 44 // Flags needed by abigen 45 abiFlag = cli.StringFlag{ 46 Name: "abi", 47 Usage: "Path to the Ethereum contract ABI json to bind, - for STDIN", 48 } 49 binFlag = cli.StringFlag{ 50 Name: "bin", 51 Usage: "Path to the Ethereum contract bytecode (generate deploy method)", 52 } 53 typeFlag = cli.StringFlag{ 54 Name: "type", 55 Usage: "Struct name for the binding (default = package name)", 56 } 57 jsonFlag = cli.StringFlag{ 58 Name: "combined-json", 59 Usage: "Path to the combined-json file generated by compiler", 60 } 61 solFlag = cli.StringFlag{ 62 Name: "sol", 63 Usage: "Path to the Ethereum contract Solidity source to build and bind", 64 } 65 solcFlag = cli.StringFlag{ 66 Name: "solc", 67 Usage: "Solidity compiler to use if source builds are requested", 68 Value: "solc", 69 } 70 vyFlag = cli.StringFlag{ 71 Name: "vy", 72 Usage: "Path to the Ethereum contract Vyper source to build and bind", 73 } 74 vyperFlag = cli.StringFlag{ 75 Name: "vyper", 76 Usage: "Vyper compiler to use if source builds are requested", 77 Value: "vyper", 78 } 79 excFlag = cli.StringFlag{ 80 Name: "exc", 81 Usage: "Comma separated types to exclude from binding", 82 } 83 pkgFlag = cli.StringFlag{ 84 Name: "pkg", 85 Usage: "Package name to generate the binding into", 86 } 87 outFlag = cli.StringFlag{ 88 Name: "out", 89 Usage: "Output file for the generated binding (default = stdout)", 90 } 91 langFlag = cli.StringFlag{ 92 Name: "lang", 93 Usage: "Destination language for the bindings (go, java, objc)", 94 Value: "go", 95 } 96 aliasFlag = cli.StringFlag{ 97 Name: "alias", 98 Usage: "Comma separated aliases for function and event renaming, e.g. foo=bar", 99 } 100 ) 101 102 func init() { 103 app = utils.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") 104 app.Flags = []cli.Flag{ 105 abiFlag, 106 binFlag, 107 typeFlag, 108 jsonFlag, 109 solFlag, 110 solcFlag, 111 vyFlag, 112 vyperFlag, 113 excFlag, 114 pkgFlag, 115 outFlag, 116 langFlag, 117 aliasFlag, 118 } 119 app.Action = utils.MigrateFlags(abigen) 120 cli.CommandHelpTemplate = utils.OriginCommandHelpTemplate 121 } 122 123 func abigen(c *cli.Context) error { 124 utils.CheckExclusive(c, abiFlag, jsonFlag, solFlag, vyFlag) // Only one source can be selected. 125 if c.GlobalString(pkgFlag.Name) == "" { 126 utils.Fatalf("No destination package specified (--pkg)") 127 } 128 var lang bind.Lang 129 switch c.GlobalString(langFlag.Name) { 130 case "go": 131 lang = bind.LangGo 132 case "java": 133 lang = bind.LangJava 134 case "objc": 135 lang = bind.LangObjC 136 utils.Fatalf("Objc binding generation is uncompleted") 137 default: 138 utils.Fatalf("Unsupported destination language \"%s\" (--lang)", c.GlobalString(langFlag.Name)) 139 } 140 // If the entire solidity code was specified, build and bind based on that 141 var ( 142 abis []string 143 bins []string 144 types []string 145 sigs []map[string]string 146 libs = make(map[string]string) 147 aliases = make(map[string]string) 148 ) 149 if c.GlobalString(abiFlag.Name) != "" { 150 // Load up the ABI, optional bytecode and type name from the parameters 151 var ( 152 abi []byte 153 err error 154 ) 155 input := c.GlobalString(abiFlag.Name) 156 if input == "-" { 157 abi, err = ioutil.ReadAll(os.Stdin) 158 } else { 159 abi, err = ioutil.ReadFile(input) 160 } 161 if err != nil { 162 utils.Fatalf("Failed to read input ABI: %v", err) 163 } 164 abis = append(abis, string(abi)) 165 166 var bin []byte 167 if binFile := c.GlobalString(binFlag.Name); binFile != "" { 168 if bin, err = ioutil.ReadFile(binFile); err != nil { 169 utils.Fatalf("Failed to read input bytecode: %v", err) 170 } 171 if strings.Contains(string(bin), "//") { 172 utils.Fatalf("Contract has additional library references, please use other mode(e.g. --combined-json) to catch library infos") 173 } 174 } 175 bins = append(bins, string(bin)) 176 177 kind := c.GlobalString(typeFlag.Name) 178 if kind == "" { 179 kind = c.GlobalString(pkgFlag.Name) 180 } 181 types = append(types, kind) 182 } else { 183 // Generate the list of types to exclude from binding 184 exclude := make(map[string]bool) 185 for _, kind := range strings.Split(c.GlobalString(excFlag.Name), ",") { 186 exclude[strings.ToLower(kind)] = true 187 } 188 var err error 189 var contracts map[string]*compiler.Contract 190 191 switch { 192 case c.GlobalIsSet(solFlag.Name): 193 contracts, err = compiler.CompileSolidity(c.GlobalString(solcFlag.Name), c.GlobalString(solFlag.Name)) 194 if err != nil { 195 utils.Fatalf("Failed to build Solidity contract: %v", err) 196 } 197 case c.GlobalIsSet(vyFlag.Name): 198 output, err := compiler.CompileVyper(c.GlobalString(vyperFlag.Name), c.GlobalString(vyFlag.Name)) 199 if err != nil { 200 utils.Fatalf("Failed to build Vyper contract: %v", err) 201 } 202 contracts = make(map[string]*compiler.Contract) 203 for n, contract := range output { 204 name := n 205 // Sanitize the combined json names to match the 206 // format expected by solidity. 207 if !strings.Contains(n, ":") { 208 // Remove extra path components 209 name = abi.ToCamelCase(strings.TrimSuffix(filepath.Base(name), ".vy")) 210 } 211 contracts[name] = contract 212 } 213 214 case c.GlobalIsSet(jsonFlag.Name): 215 jsonOutput, err := ioutil.ReadFile(c.GlobalString(jsonFlag.Name)) 216 if err != nil { 217 utils.Fatalf("Failed to read combined-json from compiler: %v", err) 218 } 219 contracts, err = compiler.ParseCombinedJSON(jsonOutput, "", "", "", "") 220 if err != nil { 221 utils.Fatalf("Failed to read contract information from json output: %v", err) 222 } 223 } 224 // Gather all non-excluded contract for binding 225 for name, contract := range contracts { 226 if exclude[strings.ToLower(name)] { 227 continue 228 } 229 abi, err := json.Marshal(contract.Info.AbiDefinition) // Flatten the compiler parse 230 if err != nil { 231 utils.Fatalf("Failed to parse ABIs from compiler output: %v", err) 232 } 233 abis = append(abis, string(abi)) 234 bins = append(bins, contract.Code) 235 sigs = append(sigs, contract.Hashes) 236 nameParts := strings.Split(name, ":") 237 types = append(types, nameParts[len(nameParts)-1]) 238 239 libPattern := crypto.Keccak256Hash([]byte(name)).String()[2:36] 240 libs[libPattern] = nameParts[len(nameParts)-1] 241 } 242 } 243 // Extract all aliases from the flags 244 if c.GlobalIsSet(aliasFlag.Name) { 245 // We support multi-versions for aliasing 246 // e.g. 247 // foo=bar,foo2=bar2 248 // foo:bar,foo2:bar2 249 re := regexp.MustCompile(`(?:(\w+)[:=](\w+))`) 250 submatches := re.FindAllStringSubmatch(c.GlobalString(aliasFlag.Name), -1) 251 for _, match := range submatches { 252 aliases[match[1]] = match[2] 253 } 254 } 255 // Generate the contract binding 256 code, err := bind.Bind(types, abis, bins, sigs, c.GlobalString(pkgFlag.Name), lang, libs, aliases) 257 if err != nil { 258 utils.Fatalf("Failed to generate ABI binding: %v", err) 259 } 260 // Either flush it out to a file or display on the standard output 261 if !c.GlobalIsSet(outFlag.Name) { 262 fmt.Printf("%s\n", code) 263 return nil 264 } 265 if err := ioutil.WriteFile(c.GlobalString(outFlag.Name), []byte(code), 0600); err != nil { 266 utils.Fatalf("Failed to write ABI binding: %v", err) 267 } 268 return nil 269 } 270 271 func main() { 272 log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 273 274 if err := app.Run(os.Args); err != nil { 275 fmt.Fprintln(os.Stderr, err) 276 os.Exit(1) 277 } 278 }