diff --git a/common/compiler/solidity.go b/common/compiler/solidity.go index 7d3c58197b..8d44c1a463 100644 --- a/common/compiler/solidity.go +++ b/common/compiler/solidity.go @@ -25,21 +25,21 @@ import ( "io/ioutil" "os/exec" "regexp" + "strconv" "strings" + "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" ) var ( - versionRegexp = regexp.MustCompile(`[0-9]+\.[0-9]+\.[0-9]+`) - solcParams = []string{ - "--combined-json", "bin,abi,userdoc,devdoc,metadata", - "--add-std", // include standard lib contracts - "--optimize", // code optimizer switched on - } + versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`) + spmu = &sync.Mutex{} // protects access to mutating _solcParams variable (contents are never mutated) + _solcParams = []string{} // zero-len means uninitialized, protected by spmu ) + type Contract struct { Code string `json:"code"` Info ContractInfo `json:"info"` @@ -68,6 +68,58 @@ type solcOutput struct { Version string } +func findSolcParams(solc string) []string { + spmu.Lock() + defer spmu.Unlock() + + if ( len(_solcParams) != 0 ) { + return _solcParams + } else { + recent, _ := atLeast047(solc) // on err, we default to considering the solidity version recent, see atLeast047 + var mbmeta string + if ( recent ) { + mbmeta = ",metadata" + } else { + mbmeta = "" + } + _solcParams = []string{ + "--combined-json", "bin,abi,userdoc,devdoc" + mbmeta, + "--add-std", // include standard lib contracts + "--optimize", // code optimizer switched on + } + return _solcParams + } +} + +func atLeast047(solc string) (bool, error) { + var ( + solidity *Solidity + major int + minor int + patch int + err error + ) + solidity, err = SolidityVersion(solc) + if ( err != nil ) { + return true, err + } + + matches := versionRegexp.FindStringSubmatch( solidity.Version ) + major, err = strconv.Atoi( matches[1] ) + if ( err != nil ) { + return true, err + } + minor, err = strconv.Atoi( matches[2] ) + if ( err != nil ) { + return true, err + } + patch, err = strconv.Atoi( matches[3] ) + if ( err != nil ) { + return true, err + } + return (major > 0 || minor > 4 || patch > 6), nil +} + // SolidityVersion runs solc and parses its version output. func SolidityVersion(solc string) (*Solidity, error) { if solc == "" { @@ -95,10 +147,11 @@ func CompileSolidityString(solc, source string) (map[string]*Contract, error) { if solc == "" { solc = "solc" } + solcParams := findSolcParams(solc) args := append(solcParams, "--") cmd := exec.Command(solc, append(args, "-")...) cmd.Stdin = strings.NewReader(source) - return runsolc(cmd, source) + return runsolc(cmd, solcParams, source) } // CompileSolidity compiles all given Solidity source files. @@ -113,12 +166,13 @@ func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract, if solc == "" { solc = "solc" } + solcParams := findSolcParams(solc) args := append(solcParams, "--") cmd := exec.Command(solc, append(args, sourcefiles...)...) - return runsolc(cmd, source) + return runsolc(cmd, solcParams, source) } -func runsolc(cmd *exec.Cmd, source string) (map[string]*Contract, error) { +func runsolc(cmd *exec.Cmd, solcParams []string, source string) (map[string]*Contract, error) { var stderr, stdout bytes.Buffer cmd.Stderr = &stderr cmd.Stdout = &stdout