github.com/core-coin/go-core/v2@v2.1.9/cmd/abigen/main.go (about)

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