github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/common/compiler/solidity.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2015 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  //包编译器包装solidity编译器可执行文件(solc)。
    26  package compiler
    27  
    28  import (
    29  	"bytes"
    30  	"encoding/json"
    31  	"errors"
    32  	"fmt"
    33  	"io/ioutil"
    34  	"os/exec"
    35  	"regexp"
    36  	"strconv"
    37  	"strings"
    38  )
    39  
    40  var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`)
    41  
    42  //合同包含有关已编译合同的信息及其代码。
    43  type Contract struct {
    44  	Code string       `json:"code"`
    45  	Info ContractInfo `json:"info"`
    46  }
    47  
    48  //收缩信息包含有关已编译合同的信息,包括访问
    49  //到ABI定义、用户和开发人员文档以及元数据。
    50  //
    51  //取决于源、语言版本、编译器版本和编译器
    52  //选项将提供有关如何编译合同的信息。
    53  type ContractInfo struct {
    54  	Source          string      `json:"source"`
    55  	Language        string      `json:"language"`
    56  	LanguageVersion string      `json:"languageVersion"`
    57  	CompilerVersion string      `json:"compilerVersion"`
    58  	CompilerOptions string      `json:"compilerOptions"`
    59  	AbiDefinition   interface{} `json:"abiDefinition"`
    60  	UserDoc         interface{} `json:"userDoc"`
    61  	DeveloperDoc    interface{} `json:"developerDoc"`
    62  	Metadata        string      `json:"metadata"`
    63  }
    64  
    65  //
    66  type Solidity struct {
    67  	Path, Version, FullVersion string
    68  	Major, Minor, Patch        int
    69  }
    70  
    71  //——组合输出格式
    72  type solcOutput struct {
    73  	Contracts map[string]struct {
    74  		Bin, Abi, Devdoc, Userdoc, Metadata string
    75  	}
    76  	Version string
    77  }
    78  
    79  func (s *Solidity) makeArgs() []string {
    80  	p := []string{
    81  		"--combined-json", "bin,abi,userdoc,devdoc",
    82  "--optimize", //代码优化器已打开
    83  	}
    84  	if s.Major > 0 || s.Minor > 4 || s.Patch > 6 {
    85  		p[1] += ",metadata"
    86  	}
    87  	return p
    88  }
    89  
    90  //solidityversion运行solc并解析其版本输出。
    91  func SolidityVersion(solc string) (*Solidity, error) {
    92  	if solc == "" {
    93  		solc = "solc"
    94  	}
    95  	var out bytes.Buffer
    96  	cmd := exec.Command(solc, "--version")
    97  	cmd.Stdout = &out
    98  	err := cmd.Run()
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	matches := versionRegexp.FindStringSubmatch(out.String())
   103  	if len(matches) != 4 {
   104  		return nil, fmt.Errorf("can't parse solc version %q", out.String())
   105  	}
   106  	s := &Solidity{Path: cmd.Path, FullVersion: out.String(), Version: matches[0]}
   107  	if s.Major, err = strconv.Atoi(matches[1]); err != nil {
   108  		return nil, err
   109  	}
   110  	if s.Minor, err = strconv.Atoi(matches[2]); err != nil {
   111  		return nil, err
   112  	}
   113  	if s.Patch, err = strconv.Atoi(matches[3]); err != nil {
   114  		return nil, err
   115  	}
   116  	return s, nil
   117  }
   118  
   119  //CompilesOlidityString生成并返回源字符串中包含的所有协定。
   120  func CompileSolidityString(solc, source string) (map[string]*Contract, error) {
   121  	if len(source) == 0 {
   122  		return nil, errors.New("solc: empty source string")
   123  	}
   124  	s, err := SolidityVersion(solc)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	args := append(s.makeArgs(), "--")
   129  	cmd := exec.Command(s.Path, append(args, "-")...)
   130  	cmd.Stdin = strings.NewReader(source)
   131  	return s.run(cmd, source)
   132  }
   133  
   134  //compilesolidity编译所有给定的solidity源文件。
   135  func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract, error) {
   136  	if len(sourcefiles) == 0 {
   137  		return nil, errors.New("solc: no source files")
   138  	}
   139  	source, err := slurpFiles(sourcefiles)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  	s, err := SolidityVersion(solc)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	args := append(s.makeArgs(), "--")
   148  	cmd := exec.Command(s.Path, append(args, sourcefiles...)...)
   149  	return s.run(cmd, source)
   150  }
   151  
   152  func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, error) {
   153  	var stderr, stdout bytes.Buffer
   154  	cmd.Stderr = &stderr
   155  	cmd.Stdout = &stdout
   156  	if err := cmd.Run(); err != nil {
   157  		return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes())
   158  	}
   159  
   160  	return ParseCombinedJSON(stdout.Bytes(), source, s.Version, s.Version, strings.Join(s.makeArgs(), " "))
   161  }
   162  
   163  //parsecombinedjson接受solc的直接输出——组合输出运行和
   164  //将其解析为字符串协定名称到协定结构的映射。这个
   165  //提供的源、语言和编译器版本以及编译器选项都是
   166  //传递到合同结构中。
   167  //
   168  //SOLC输出应该包含ABI、用户文档和开发文档。
   169  //
   170  //如果JSON格式不正确或缺少数据,或者如果JSON
   171  //嵌入在JSON中的格式不正确。
   172  func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) {
   173  	var output solcOutput
   174  	if err := json.Unmarshal(combinedJSON, &output); err != nil {
   175  		return nil, err
   176  	}
   177  
   178  //编译成功,组装并返回合同。
   179  	contracts := make(map[string]*Contract)
   180  	for name, info := range output.Contracts {
   181  //分析各个编译结果。
   182  		var abi interface{}
   183  		if err := json.Unmarshal([]byte(info.Abi), &abi); err != nil {
   184  			return nil, fmt.Errorf("solc: error reading abi definition (%v)", err)
   185  		}
   186  		var userdoc interface{}
   187  		if err := json.Unmarshal([]byte(info.Userdoc), &userdoc); err != nil {
   188  			return nil, fmt.Errorf("solc: error reading user doc: %v", err)
   189  		}
   190  		var devdoc interface{}
   191  		if err := json.Unmarshal([]byte(info.Devdoc), &devdoc); err != nil {
   192  			return nil, fmt.Errorf("solc: error reading dev doc: %v", err)
   193  		}
   194  		contracts[name] = &Contract{
   195  			Code: "0x" + info.Bin,
   196  			Info: ContractInfo{
   197  				Source:          source,
   198  				Language:        "Solidity",
   199  				LanguageVersion: languageVersion,
   200  				CompilerVersion: compilerVersion,
   201  				CompilerOptions: compilerOptions,
   202  				AbiDefinition:   abi,
   203  				UserDoc:         userdoc,
   204  				DeveloperDoc:    devdoc,
   205  				Metadata:        info.Metadata,
   206  			},
   207  		}
   208  	}
   209  	return contracts, nil
   210  }
   211  
   212  func slurpFiles(files []string) (string, error) {
   213  	var concat bytes.Buffer
   214  	for _, file := range files {
   215  		content, err := ioutil.ReadFile(file)
   216  		if err != nil {
   217  			return "", err
   218  		}
   219  		concat.Write(content)
   220  	}
   221  	return concat.String(), nil
   222  }