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  }