main.go 7.5 KB

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