diff --git a/common/compiler/solidity.go b/common/compiler/solidity.go index 67815a726..5ded4fc6e 100644 --- a/common/compiler/solidity.go +++ b/common/compiler/solidity.go @@ -34,15 +34,10 @@ import ( "github.com/ethereum/go-ethereum/logger/glog" ) -const ( - // flair = "Christian and Lefteris (c) 2014-2015" - flair = "" - languageVersion = "0" -) - var ( - versionRegExp = regexp.MustCompile("[0-9]+.[0-9]+.[0-9]+") - params = []string{ + versionRegExp = regexp.MustCompile("[0-9]+\\.[0-9]+\\.[0-9]+") + newAPIRegexp = regexp.MustCompile("0\\.1\\.[2-9][0-9]*") + paramsLegacy = []string{ "--binary", // Request to output the contract in binary (hexadecimal). "file", // "--json-abi", // Request to output the contract's JSON ABI interface. @@ -54,6 +49,15 @@ var ( "--add-std", "1", } + paramsNew = []string{ + "--bin", // Request to output the contract in binary (hexadecimal). + "--abi", // Request to output the contract's JSON ABI interface. + "--userdoc", // Request to output the contract's Natspec user documentation. + "--devdoc", // Request to output the contract's Natspec developer documentation. + "--add-std", // include standard lib contracts + "--optimize=1", // code optimizer switched on + "-o", // output directory + } ) type Contract struct { @@ -66,14 +70,17 @@ type ContractInfo struct { Language string `json:"language"` LanguageVersion string `json:"languageVersion"` CompilerVersion string `json:"compilerVersion"` + CompilerOptions string `json:"compilerOptions"` AbiDefinition interface{} `json:"abiDefinition"` UserDoc interface{} `json:"userDoc"` DeveloperDoc interface{} `json:"developerDoc"` } type Solidity struct { - solcPath string - version string + solcPath string + version string + fullVersion string + legacy bool } func New(solcPath string) (sol *Solidity, err error) { @@ -94,17 +101,22 @@ func New(solcPath string) (sol *Solidity, err error) { return } - version := versionRegExp.FindString(out.String()) + fullVersion := out.String() + version := versionRegExp.FindString(fullVersion) + legacy := !newAPIRegexp.MatchString(version) + sol = &Solidity{ - solcPath: solcPath, - version: version, + solcPath: solcPath, + version: version, + fullVersion: fullVersion, + legacy: legacy, } glog.V(logger.Info).Infoln(sol.Info()) return } func (sol *Solidity) Info() string { - return fmt.Sprintf("solc v%s\nSolidity Compiler: %s\n%s", sol.version, sol.solcPath, flair) + return fmt.Sprintf("%s\npath: %s", sol.fullVersion, sol.solcPath) } func (sol *Solidity) Version() string { @@ -127,6 +139,15 @@ func (sol *Solidity) Compile(source string) (map[string]*Contract, error) { // Assemble the compiler command, change to the temp folder and capture any errors stderr := new(bytes.Buffer) + var params []string + if sol.legacy { + params = paramsLegacy + } else { + params = paramsNew + params = append(params, wd) + } + compilerOptions := strings.Join(params, " ") + cmd := exec.Command(sol.solcPath, params...) cmd.Dir = wd cmd.Stdin = strings.NewReader(source) @@ -136,7 +157,7 @@ func (sol *Solidity) Compile(source string) (map[string]*Contract, error) { return nil, fmt.Errorf("solc: %v\n%s", err, string(stderr.Bytes())) } // Sanity check that something was actually built - matches, _ := filepath.Glob(wd + "/*.binary") + matches, _ := filepath.Glob(wd + "/*\\.bin*") if len(matches) < 1 { return nil, fmt.Errorf("solc: no build results found") } @@ -148,7 +169,11 @@ func (sol *Solidity) Compile(source string) (map[string]*Contract, error) { // Parse the individual compilation results (code binary, ABI definitions, user and dev docs) var binary []byte - if binary, err = ioutil.ReadFile(filepath.Join(wd, base+".binary")); err != nil { + binext := ".bin" + if sol.legacy { + binext = ".binary" + } + if binary, err = ioutil.ReadFile(filepath.Join(wd, base+binext)); err != nil { return nil, fmt.Errorf("solc: error reading compiler output for code: %v", err) } @@ -178,8 +203,9 @@ func (sol *Solidity) Compile(source string) (map[string]*Contract, error) { Info: ContractInfo{ Source: source, Language: "Solidity", - LanguageVersion: languageVersion, + LanguageVersion: sol.version, CompilerVersion: sol.version, + CompilerOptions: compilerOptions, AbiDefinition: abi, UserDoc: userdoc, DeveloperDoc: devdoc, diff --git a/common/compiler/solidity_test.go b/common/compiler/solidity_test.go index 3303bc15a..905a5957c 100644 --- a/common/compiler/solidity_test.go +++ b/common/compiler/solidity_test.go @@ -26,7 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" ) -const solcVersion = "0.9.23" +const solcVersion = "0.1.1" var ( source = ` @@ -37,16 +37,16 @@ contract test { } } ` - code = "0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056" - info = `{"source":"\ncontract test {\n /// @notice Will multiply ` + "`a`" + ` by 7.\n function multiply(uint a) returns(uint d) {\n return a * 7;\n }\n}\n","language":"Solidity","languageVersion":"0","compilerVersion":"0.9.23","abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}},"developerDoc":{"methods":{}}}` + code = "0x6060604052606d8060116000396000f30060606040526000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa1146037576035565b005b6046600480359060200150605c565b6040518082815260200191505060405180910390f35b60006007820290506068565b91905056" + info = `{"source":"\ncontract test {\n /// @notice Will multiply ` + "`a`" + ` by 7.\n function multiply(uint a) returns(uint d) {\n return a * 7;\n }\n}\n","language":"Solidity","languageVersion":"0.1.1","compilerVersion":"0.1.1","compilerOptions":"--binary file --json-abi file --natspec-user file --natspec-dev file --add-std 1","abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}},"developerDoc":{"methods":{}}}` - infohash = common.HexToHash("0xea782f674eb898e477c20e8a7cf11c2c28b09fa68b5278732104f7a101aed255") + infohash = common.HexToHash("0x9f3803735e7f16120c5a140ab3f02121fd3533a9655c69b33a10e78752cc49b0") ) func TestCompiler(t *testing.T) { sol, err := New("") if err != nil { - t.Skip("solc not found: skip") + t.Skip("solc not found: skip: %v", err) } else if sol.Version() != solcVersion { t.Skip("WARNING: skipping due to a newer version of solc found (%v, expect %v)", sol.Version(), solcVersion) } @@ -111,4 +111,4 @@ func TestSaveInfo(t *testing.T) { if cinfohash != infohash { t.Errorf("content hash for info is incorrect. expected %v, got %v", infohash.Hex(), cinfohash.Hex()) } -} \ No newline at end of file +}