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