aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2015-08-26 00:42:05 +0800
committerPéter Szilágyi <peterke@gmail.com>2015-08-26 15:04:23 +0800
commit101418b27537d065d55b3c8fcba6a9d450de8dec (patch)
tree4df1d9baa8fa02ce7b5b98178ae4277331ea80ff /common
parentabce09954b6901b446c004ee06b389c338922f28 (diff)
downloadgo-tangerine-101418b27537d065d55b3c8fcba6a9d450de8dec.tar.gz
go-tangerine-101418b27537d065d55b3c8fcba6a9d450de8dec.tar.zst
go-tangerine-101418b27537d065d55b3c8fcba6a9d450de8dec.zip
common/compiler: fix #1598, expose solidity errors
Diffstat (limited to 'common')
-rw-r--r--common/compiler/solidity.go104
1 files changed, 46 insertions, 58 deletions
diff --git a/common/compiler/solidity.go b/common/compiler/solidity.go
index 56928ac27..67815a726 100644
--- a/common/compiler/solidity.go
+++ b/common/compiler/solidity.go
@@ -19,6 +19,7 @@ package compiler
import (
"bytes"
"encoding/json"
+ "errors"
"fmt"
"io/ioutil"
"os"
@@ -110,95 +111,82 @@ func (sol *Solidity) Version() string {
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 {
- err = fmt.Errorf("empty source")
- return
+ return nil, errors.New("solc: empty source string")
}
-
+ // Create a safe place to dump compilation output
wd, err := ioutil.TempDir("", "solc")
if err != nil {
- return
+ return nil, fmt.Errorf("solc: failed to create temporary build folder: %v", err)
}
defer os.RemoveAll(wd)
- in := strings.NewReader(source)
- var out bytes.Buffer
- // cwd set to temp dir
+ // Assemble the compiler command, change to the temp folder and capture any errors
+ stderr := new(bytes.Buffer)
+
cmd := exec.Command(sol.solcPath, params...)
cmd.Dir = wd
- cmd.Stdin = in
- cmd.Stdout = &out
- err = cmd.Run()
- if err != nil {
- err = fmt.Errorf("solc error: %v", err)
- return
- }
+ cmd.Stdin = strings.NewReader(source)
+ cmd.Stderr = stderr
+ 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")
if len(matches) < 1 {
- err = fmt.Errorf("solc error: missing code output")
- return
+ return nil, fmt.Errorf("solc: no build results found")
}
-
- contracts = make(map[string]*Contract)
+ // Compilation succeeded, assemble and return the contracts
+ contracts := make(map[string]*Contract)
for _, path := range matches {
_, file := filepath.Split(path)
base := strings.Split(file, ".")[0]
- codeFile := filepath.Join(wd, base+".binary")
- abiDefinitionFile := filepath.Join(wd, base+".abi")
- userDocFile := filepath.Join(wd, base+".docuser")
- developerDocFile := filepath.Join(wd, base+".docdev")
-
- 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
+ // 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 {
+ return nil, fmt.Errorf("solc: error reading compiler output for code: %v", err)
}
- 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)
- if err != nil {
- err = fmt.Errorf("error reading compiler output for userDoc: %v", err)
- return
+ var abi interface{}
+ if blob, err := ioutil.ReadFile(filepath.Join(wd, base+".abi")); err != nil {
+ return nil, fmt.Errorf("solc: error reading abi definition: %v", err)
+ } 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)
- if err != nil {
- err = fmt.Errorf("error reading compiler output for developerDoc: %v", err)
- return
+ var userdoc interface{}
+ if blob, err := ioutil.ReadFile(filepath.Join(wd, base+".docuser")); err != nil {
+ return nil, fmt.Errorf("solc: error reading user doc: %v", err)
+ } 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{
- Code: "0x" + string(code),
+ var devdoc interface{}
+ 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{
Source: source,
Language: "Solidity",
LanguageVersion: languageVersion,
CompilerVersion: sol.version,
- AbiDefinition: abiDefinition,
- UserDoc: userDoc,
- DeveloperDoc: developerDoc,
+ AbiDefinition: abi,
+ UserDoc: userdoc,
+ DeveloperDoc: devdoc,
},
}
-
- contracts[base] = contract
}
-
- return
+ return contracts, nil
}
func SaveInfo(info *ContractInfo, filename string) (contenthash common.Hash, err error) {