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 }