Merge pull request #1717 from karalabe/forward-solidity-errors

common/compiler: fix #1598, expose solidity errors
This commit is contained in:
Felix Lange 2015-08-26 19:00:11 +02:00
commit 79b644c7a3

View File

@ -19,6 +19,7 @@ package compiler
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
@ -110,95 +111,82 @@ func (sol *Solidity) Version() string {
return sol.version return sol.version
} }
func (sol *Solidity) Compile(source string) (contracts map[string]*Contract, err error) { // Compile builds and returns all the contracts contained within a source string.
func (sol *Solidity) Compile(source string) (map[string]*Contract, error) {
// Short circuit if no source code was specified
if len(source) == 0 { if len(source) == 0 {
err = fmt.Errorf("empty source") return nil, errors.New("solc: empty source string")
return
} }
// Create a safe place to dump compilation output
wd, err := ioutil.TempDir("", "solc") wd, err := ioutil.TempDir("", "solc")
if err != nil { if err != nil {
return return nil, fmt.Errorf("solc: failed to create temporary build folder: %v", err)
} }
defer os.RemoveAll(wd) defer os.RemoveAll(wd)
in := strings.NewReader(source) // Assemble the compiler command, change to the temp folder and capture any errors
var out bytes.Buffer stderr := new(bytes.Buffer)
// cwd set to temp dir
cmd := exec.Command(sol.solcPath, params...) cmd := exec.Command(sol.solcPath, params...)
cmd.Dir = wd cmd.Dir = wd
cmd.Stdin = in cmd.Stdin = strings.NewReader(source)
cmd.Stdout = &out cmd.Stderr = stderr
err = cmd.Run()
if err != nil {
err = fmt.Errorf("solc error: %v", err)
return
}
if err := cmd.Run(); err != nil {
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 + "/*.binary")
if len(matches) < 1 { if len(matches) < 1 {
err = fmt.Errorf("solc error: missing code output") return nil, fmt.Errorf("solc: no build results found")
return
} }
// Compilation succeeded, assemble and return the contracts
contracts = make(map[string]*Contract) contracts := make(map[string]*Contract)
for _, path := range matches { for _, path := range matches {
_, file := filepath.Split(path) _, file := filepath.Split(path)
base := strings.Split(file, ".")[0] base := strings.Split(file, ".")[0]
codeFile := filepath.Join(wd, base+".binary") // Parse the individual compilation results (code binary, ABI definitions, user and dev docs)
abiDefinitionFile := filepath.Join(wd, base+".abi") var binary []byte
userDocFile := filepath.Join(wd, base+".docuser") if binary, err = ioutil.ReadFile(filepath.Join(wd, base+".binary")); err != nil {
developerDocFile := filepath.Join(wd, base+".docdev") return nil, fmt.Errorf("solc: error reading compiler output for code: %v", err)
var code, abiDefinitionJson, userDocJson, developerDocJson []byte
code, err = ioutil.ReadFile(codeFile)
if err != nil {
err = fmt.Errorf("error reading compiler output for code: %v", err)
return
} }
abiDefinitionJson, err = ioutil.ReadFile(abiDefinitionFile)
if err != nil {
err = fmt.Errorf("error reading compiler output for abiDefinition: %v", err)
return
}
var abiDefinition interface{}
err = json.Unmarshal(abiDefinitionJson, &abiDefinition)
userDocJson, err = ioutil.ReadFile(userDocFile) var abi interface{}
if err != nil { if blob, err := ioutil.ReadFile(filepath.Join(wd, base+".abi")); err != nil {
err = fmt.Errorf("error reading compiler output for userDoc: %v", err) return nil, fmt.Errorf("solc: error reading abi definition: %v", err)
return } else if err = json.Unmarshal(blob, &abi); err != nil {
return nil, fmt.Errorf("solc: error parsing abi definition: %v", err)
} }
var userDoc interface{}
err = json.Unmarshal(userDocJson, &userDoc)
developerDocJson, err = ioutil.ReadFile(developerDocFile) var userdoc interface{}
if err != nil { if blob, err := ioutil.ReadFile(filepath.Join(wd, base+".docuser")); err != nil {
err = fmt.Errorf("error reading compiler output for developerDoc: %v", err) return nil, fmt.Errorf("solc: error reading user doc: %v", err)
return } else if err = json.Unmarshal(blob, &userdoc); err != nil {
return nil, fmt.Errorf("solc: error parsing user doc: %v", err)
} }
var developerDoc interface{}
err = json.Unmarshal(developerDocJson, &developerDoc)
contract := &Contract{ var devdoc interface{}
Code: "0x" + string(code), if blob, err := ioutil.ReadFile(filepath.Join(wd, base+".docdev")); err != nil {
return nil, fmt.Errorf("solc: error reading dev doc: %v", err)
} else if err = json.Unmarshal(blob, &devdoc); err != nil {
return nil, fmt.Errorf("solc: error parsing dev doc: %v", err)
}
// Assemble the final contract
contracts[base] = &Contract{
Code: "0x" + string(binary),
Info: ContractInfo{ Info: ContractInfo{
Source: source, Source: source,
Language: "Solidity", Language: "Solidity",
LanguageVersion: languageVersion, LanguageVersion: languageVersion,
CompilerVersion: sol.version, CompilerVersion: sol.version,
AbiDefinition: abiDefinition, AbiDefinition: abi,
UserDoc: userDoc, UserDoc: userdoc,
DeveloperDoc: developerDoc, DeveloperDoc: devdoc,
}, },
} }
contracts[base] = contract
} }
return contracts, nil
return
} }
func SaveInfo(info *ContractInfo, filename string) (contenthash common.Hash, err error) { func SaveInfo(info *ContractInfo, filename string) (contenthash common.Hash, err error) {