main.go 8.0 KB

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