mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
common/compiler: all tests passing for new go common compiler setup
Signed-off-by: RJ Catalano <rj@monax.io>
This commit is contained in:
parent
82e0dd79f4
commit
b39afc674c
3 changed files with 227 additions and 337 deletions
|
|
@ -1,24 +1,17 @@
|
||||||
package compiler
|
package compiler
|
||||||
|
|
||||||
import (
|
// An interface to denote a version specific compiler.
|
||||||
"fmt"
|
|
||||||
"os/exec"
|
|
||||||
)
|
|
||||||
|
|
||||||
// An interface to denote a compiler. It implements two function.
|
|
||||||
// Compile takes in a slice of files and a series of functions made
|
|
||||||
// to represent flag options of the compiler and returns a Compile Return or an error.
|
|
||||||
// The function version() is instantiated upon the creation of the compiler to
|
// The function version() is instantiated upon the creation of the compiler to
|
||||||
// fill the compiler's struct with version details. It fails if there is an error in the parsing.
|
// fill the compiler's struct with version details. It fails if there is an error in the parsing.
|
||||||
type Compiler interface {
|
type Compiler interface {
|
||||||
Compile(files []string, flags FlagOpts) (Return, error)
|
Compile(flags FlagOpts, files ...string) (Return, error)
|
||||||
version() error
|
version() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Practicing inheritance, this struct gives us access to all types of returns.
|
// This struct via embedding gives us access to all types of returns.
|
||||||
// This is written to be extendable to other compilers.
|
// This is written to be extendable to other compilers.
|
||||||
type Return struct {
|
type Return struct {
|
||||||
Error error
|
Typ CompilerType
|
||||||
SolcReturn
|
SolcReturn
|
||||||
//Enter your return struct here...e.g.
|
//Enter your return struct here...e.g.
|
||||||
//SerpentReturn
|
//SerpentReturn
|
||||||
|
|
@ -26,26 +19,18 @@ type Return struct {
|
||||||
//ViperReturn
|
//ViperReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
// Practicing inheritance, this struct allows us to easily create a simple
|
// This struct allows us to easily create a simple interface for
|
||||||
// interface for interacting with our potentially various compilers.
|
// interacting with our potentially various compilers.
|
||||||
type FlagOpts struct {
|
type FlagOpts struct {
|
||||||
SolcFlagOpts
|
SolcFlagOpts
|
||||||
//Enter your FlagOpts struct here...
|
//Enter your FlagOpts struct here...
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitCompiler(compilerName string) (Compiler, error) {
|
type CompilerType byte
|
||||||
if _, err := exec.LookPath(compilerName); err != nil {
|
|
||||||
return nil, fmt.Errorf("compiler: could not find %v in PATH", compilerName)
|
const (
|
||||||
}
|
Solc CompilerType = iota
|
||||||
switch compilerName {
|
// Serpent
|
||||||
case "solc":
|
// Bamboo
|
||||||
s := &Solidity{}
|
// Viper
|
||||||
if err := s.version(); err != nil {
|
)
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("compiler: currently does not support %v for compilation", compilerName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -35,6 +33,22 @@ import (
|
||||||
|
|
||||||
var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`)
|
var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`)
|
||||||
|
|
||||||
|
// Initialize a versioned Solc compiler.
|
||||||
|
func InitSolc(command string) (Compiler, error) {
|
||||||
|
if command == "" {
|
||||||
|
command = "solc"
|
||||||
|
}
|
||||||
|
if _, err := exec.LookPath(command); err != nil {
|
||||||
|
return nil, fmt.Errorf("compiler: could not find %v in PATH", command)
|
||||||
|
}
|
||||||
|
s := &Solidity{NamedCmd: command}
|
||||||
|
if err := s.version(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//The following represents solidity outputs from the compiler that we're interested in
|
//The following represents solidity outputs from the compiler that we're interested in
|
||||||
type SolcReturn struct {
|
type SolcReturn struct {
|
||||||
Warning string
|
Warning string
|
||||||
|
|
@ -51,42 +65,15 @@ type SolcItems struct {
|
||||||
Metadata string `json:"metadata"`
|
Metadata string `json:"metadata"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom UnmarshalJSON is needed for the sake of capturing the warnings that can pop up
|
|
||||||
// in the compiler while still maintaining the results of the compilation.
|
|
||||||
func (ret *SolcReturn) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
trimmedOutput := bytes.TrimSpace(data)
|
|
||||||
jsonBeginsCertainly := bytes.Index(trimmedOutput, []byte(`{"contracts":`))
|
|
||||||
|
|
||||||
if jsonBeginsCertainly > 0 {
|
|
||||||
ret.Warning = string(trimmedOutput[:jsonBeginsCertainly])
|
|
||||||
trimmedOutput = trimmedOutput[jsonBeginsCertainly:]
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(trimmedOutput, &ret)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ret SolcReturn) blend(other SolcReturn) (SolcReturn, error) {
|
|
||||||
for str, items := range other.Contracts {
|
|
||||||
if _, taken := ret.Contracts[str]; taken {
|
|
||||||
return SolcReturn{}, fmt.Errorf("solc: there was an issue in blending bin and sol files, please try them separately")
|
|
||||||
} else {
|
|
||||||
ret.Contracts[str] = items
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Solidity contains information about the solidity compiler.
|
// Solidity contains information about the solidity compiler.
|
||||||
type Solidity struct {
|
type Solidity struct {
|
||||||
Path, Version, FullVersion string
|
NamedCmd, Path, Version, FullVersion string
|
||||||
Major, Minor, Patch int
|
Major, Minor, Patch int
|
||||||
}
|
}
|
||||||
|
|
||||||
//This is a template to define our inputs for the compiler flags
|
//This is a template to define our inputs for the compiler flags
|
||||||
type SolcFlagOpts struct {
|
type SolcFlagOpts struct {
|
||||||
// (Optional) what to get in the output, can be any combination of [abi, bin, userdoc, devdoc, metadata]
|
// (Required) what to get in the output, can be any combination of [abi, bin, userdoc, devdoc, metadata]
|
||||||
// abi: application binary interface. Necessary for interaction with contracts.
|
// abi: application binary interface. Necessary for interaction with contracts.
|
||||||
// bin: binary bytecode. Necessary for creating and deploying and interacting with contracts.
|
// bin: binary bytecode. Necessary for creating and deploying and interacting with contracts.
|
||||||
// userdoc: natspec for users.
|
// userdoc: natspec for users.
|
||||||
|
|
@ -110,24 +97,10 @@ type SolcFlagOpts struct {
|
||||||
Exec string
|
Exec string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Solidity) defaultFlagOpts() (f SolcFlagOpts) {
|
|
||||||
f = SolcFlagOpts{
|
|
||||||
CombinedOutput: []string{"bin", "abi", "userdoc", "devdoc"},
|
|
||||||
StdLib: true,
|
|
||||||
Optimize: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Major >= 0 && s.Minor >= 4 && s.Patch > 6 {
|
|
||||||
f.CombinedOutput = append(f.CombinedOutput, "metadata")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// SolidityVersion runs solc and parses its version output.
|
// SolidityVersion runs solc and parses its version output.
|
||||||
func (s *Solidity) version() error {
|
func (s *Solidity) version() error {
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
cmd := exec.Command("solc", "--version")
|
cmd := exec.Command(s.NamedCmd, "--version")
|
||||||
cmd.Stdout = &out
|
cmd.Stdout = &out
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -135,7 +108,7 @@ func (s *Solidity) version() error {
|
||||||
}
|
}
|
||||||
matches := versionRegexp.FindStringSubmatch(out.String())
|
matches := versionRegexp.FindStringSubmatch(out.String())
|
||||||
if len(matches) != 4 {
|
if len(matches) != 4 {
|
||||||
return fmt.Errorf("can't parse solc version %q", out.String())
|
return fmt.Errorf("%v: can't parse version %q", s.NamedCmd, out.String())
|
||||||
}
|
}
|
||||||
s = &Solidity{Path: cmd.Path, FullVersion: out.String(), Version: matches[0]}
|
s = &Solidity{Path: cmd.Path, FullVersion: out.String(), Version: matches[0]}
|
||||||
if s.Major, err = strconv.Atoi(matches[1]); err != nil {
|
if s.Major, err = strconv.Atoi(matches[1]); err != nil {
|
||||||
|
|
@ -151,62 +124,49 @@ func (s *Solidity) version() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compiles a series of files using the solidity compiler
|
// Compiles a series of files using the solidity compiler
|
||||||
func (s *Solidity) Compile(files []string, flags FlagOpts) (Return, error) {
|
func (s *Solidity) Compile(flags FlagOpts, files ...string) (Return, error) {
|
||||||
|
|
||||||
if reflect.DeepEqual(flags.SolcFlagOpts, (SolcFlagOpts{})) {
|
if reflect.DeepEqual(flags.SolcFlagOpts, (SolcFlagOpts{})) {
|
||||||
flags.SolcFlagOpts = s.defaultFlagOpts()
|
flags.defaultSolcFlagOpts(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
//check files for .bin extension for linking addresses
|
return s.execute(flags.assembleSolcCommand(files...)...)
|
||||||
//separate .sol and .bin files
|
|
||||||
//link .bins separately
|
|
||||||
solFiles, binFiles, err := s.sortAndValidateFiles(files)
|
|
||||||
if err != nil {
|
|
||||||
return Return{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// assemble commands and execute
|
|
||||||
var binResults SolcReturn
|
|
||||||
if len(binFiles) > 0 {
|
|
||||||
solcExecute := flags.assembleSolcCommand(true, binFiles...)
|
|
||||||
binResults, err = s.executeSolc(solcExecute...)
|
|
||||||
if err != nil {
|
|
||||||
return Return{}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var solResults SolcReturn
|
|
||||||
if len(solFiles) > 0 {
|
|
||||||
solcExecute := flags.assembleSolcCommand(false, solFiles...)
|
|
||||||
solResults, err = s.executeSolc(solcExecute...)
|
|
||||||
if err != nil {
|
|
||||||
return Return{}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// blend the two results, even if one of them is empty (more efficient this way)
|
|
||||||
ret, err := solResults.blend(binResults)
|
|
||||||
return Return{SolcReturn: ret}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f SolcFlagOpts) assembleSolcCommand(binary bool, files ...string) (command []string) {
|
func (s *Solidity) Link(libs map[string]common.Address, binary string) (string, error) {
|
||||||
stringifyLibs := func(libs map[string]common.Address) []string {
|
var refinedBinary bytes.Buffer
|
||||||
var combinedLibs []string
|
var stderr bytes.Buffer
|
||||||
for x, y := range f.Libraries {
|
|
||||||
combinedLibs = append(combinedLibs, x+":"+y.String())
|
buf := bytes.NewBufferString(binary)
|
||||||
}
|
linkCmd := exec.Command("solc", "--link", "--libraries", stringifyLibs(libs))
|
||||||
return combinedLibs
|
|
||||||
|
linkCmd.Stdin = buf
|
||||||
|
linkCmd.Stderr = &stderr
|
||||||
|
linkCmd.Stdout = &refinedBinary
|
||||||
|
|
||||||
|
linkCmd.Start()
|
||||||
|
linkCmd.Wait()
|
||||||
|
|
||||||
|
if stderr.String() != "" {
|
||||||
|
return "", errors.New(stderr.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return refinedBinary.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringifyLibs(libs map[string]common.Address) string {
|
||||||
|
var combinedLibs []string
|
||||||
|
for x, y := range libs {
|
||||||
|
combinedLibs = append(combinedLibs, x+":"+y.String())
|
||||||
|
}
|
||||||
|
return strings.Join(combinedLibs, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f SolcFlagOpts) assembleSolcCommand(files ...string) (command []string) {
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case f.Exec != "":
|
case f.Exec != "":
|
||||||
command = append(command, f.Exec)
|
command = append(command, f.Exec)
|
||||||
case binary:
|
|
||||||
if len(f.Libraries) > 0 {
|
|
||||||
combinedLibs := stringifyLibs(f.Libraries)
|
|
||||||
command = append(command, "--link --libraries")
|
|
||||||
command = append(command, strings.Join(combinedLibs, ","))
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
if len(f.Remappings) > 0 {
|
if len(f.Remappings) > 0 {
|
||||||
command = append(command, strings.Join(f.Remappings, " "))
|
command = append(command, strings.Join(f.Remappings, " "))
|
||||||
|
|
@ -215,9 +175,7 @@ func (f SolcFlagOpts) assembleSolcCommand(binary bool, files ...string) (command
|
||||||
command = append(command, "--combined-json", strings.Join(f.CombinedOutput, ","))
|
command = append(command, "--combined-json", strings.Join(f.CombinedOutput, ","))
|
||||||
}
|
}
|
||||||
if len(f.Libraries) > 0 {
|
if len(f.Libraries) > 0 {
|
||||||
combinedLibs := stringifyLibs(f.Libraries)
|
command = append(command, []string{"--libraries", stringifyLibs(f.Libraries)}...)
|
||||||
command = append(command, "--link --libraries")
|
|
||||||
command = append(command, strings.Join(combinedLibs, ","))
|
|
||||||
}
|
}
|
||||||
if f.Optimize {
|
if f.Optimize {
|
||||||
command = append(command, "--optimize")
|
command = append(command, "--optimize")
|
||||||
|
|
@ -232,43 +190,39 @@ func (f SolcFlagOpts) assembleSolcCommand(binary bool, files ...string) (command
|
||||||
return append(command, files...)
|
return append(command, files...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A utility function to sort .sol and .bin files into separate slices
|
func (f *SolcFlagOpts) defaultSolcFlagOpts(s *Solidity) {
|
||||||
func (s *Solidity) sortAndValidateFiles(files []string) ([]string, []string, error) {
|
f = &SolcFlagOpts{
|
||||||
var solFiles []string
|
CombinedOutput: []string{"bin", "abi", "userdoc", "devdoc"},
|
||||||
var binFiles []string
|
StdLib: true,
|
||||||
if len(files) == 0 {
|
Optimize: true,
|
||||||
return nil, nil, errors.New("solc: no source files")
|
|
||||||
}
|
|
||||||
for _, file := range files {
|
|
||||||
if _, err := os.Stat(file); os.IsNotExist(err) {
|
|
||||||
return nil, nil, fmt.Errorf("solc: could not find file %v", file)
|
|
||||||
}
|
|
||||||
switch path.Ext(file) {
|
|
||||||
case ".sol":
|
|
||||||
solFiles = append(solFiles, file)
|
|
||||||
case ".bin":
|
|
||||||
binFiles = append(binFiles, file)
|
|
||||||
default:
|
|
||||||
return nil, nil, fmt.Errorf("solc: unexpected file extension found during compilation: %v", file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return solFiles, binFiles, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Solidity) executeSolc(flagsAndFiles ...string) (output SolcReturn, err error) {
|
|
||||||
var stderr, stdout bytes.Buffer
|
|
||||||
|
|
||||||
cmd := exec.Command("solc", flagsAndFiles...)
|
|
||||||
cmd.Stderr = &stderr
|
|
||||||
cmd.Stdout = &stdout
|
|
||||||
|
|
||||||
if err = cmd.Run(); err != nil {
|
|
||||||
return SolcReturn{}, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = json.Unmarshal(stdout.Bytes(), &output); err != nil {
|
if s.Major >= 0 && s.Minor >= 4 && s.Patch > 6 {
|
||||||
return SolcReturn{}, err
|
f.CombinedOutput = append(f.CombinedOutput, "metadata")
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Solidity) execute(flagsAndFiles ...string) (Return, error) {
|
||||||
|
var stderr, stdout bytes.Buffer
|
||||||
|
var output SolcReturn
|
||||||
|
|
||||||
|
cmd := exec.Command(s.NamedCmd, flagsAndFiles...)
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return Return{}, fmt.Errorf("%v: %v\n%s", s.NamedCmd, err, stderr.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := stdout.Bytes()
|
||||||
|
|
||||||
|
if err := json.Unmarshal(buf, &output); err != nil {
|
||||||
|
return Return{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
output.Warning = string(stderr.Bytes())
|
||||||
|
|
||||||
|
return Return{Solc, output}, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,10 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const solFile = `pragma solidity >= 0.0.0;
|
const regularSolFile = `pragma solidity >= 0.0.0;
|
||||||
contract main {
|
contract main {
|
||||||
uint a;
|
|
||||||
function f() {
|
}`
|
||||||
a = 1;
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
|
|
||||||
const faultySol = `pragma solidity >= 0.0.0;
|
const faultySol = `pragma solidity >= 0.0.0;
|
||||||
contract main {
|
contract main {
|
||||||
|
|
@ -85,6 +82,17 @@ contract C {
|
||||||
}`
|
}`
|
||||||
|
|
||||||
const solFile1 = `pragma solidity >=0.0.0;
|
const solFile1 = `pragma solidity >=0.0.0;
|
||||||
|
import "/somedir/set.sol";
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
Set.Data knownValues;
|
||||||
|
function register(uint value) {
|
||||||
|
if (!Set.insert(knownValues, value))
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
const solFile2 = `pragma solidity >=0.0.0;
|
||||||
|
|
||||||
library Set {
|
library Set {
|
||||||
struct Data { mapping(uint => bool) flags; }
|
struct Data { mapping(uint => bool) flags; }
|
||||||
|
|
@ -113,259 +121,202 @@ library Set {
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
const solFile2 = `pragma solidity >=0.0.0;
|
func writeToTempFile(tmpfile *os.File, content []byte) error {
|
||||||
import "set.sol";
|
|
||||||
|
|
||||||
contract C {
|
if _, err := tmpfile.Write(content); err != nil {
|
||||||
Set.Data knownValues;
|
return err
|
||||||
function register(uint value) {
|
}
|
||||||
if (!Set.insert(knownValues, value))
|
if err := tmpfile.Close(); err != nil {
|
||||||
throw;
|
return err
|
||||||
}
|
}
|
||||||
}`
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func TestSolcCompilerNormal(t *testing.T) {
|
func TestSolcCompilerNormal(t *testing.T) {
|
||||||
solc, err := InitCompiler("solc")
|
|
||||||
|
solc, err := InitSolc("solc")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Skip(err)
|
t.Fatalf("Could not initialize solc: %v", err)
|
||||||
}
|
}
|
||||||
solc = solc.(*Solidity)
|
|
||||||
file, err := os.Create("simpleContract.sol")
|
content := []byte(regularSolFile)
|
||||||
defer os.Remove("simpleContract.sol")
|
tmpfile, err := ioutil.TempFile("", "simpleContract.sol")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
file.WriteString(solFile)
|
defer os.Remove(tmpfile.Name()) // clean up
|
||||||
|
|
||||||
|
err = writeToTempFile(tmpfile, content)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
flags := SolcFlagOpts{
|
flags := SolcFlagOpts{
|
||||||
CombinedOutput: []string{"bin", "abi"},
|
CombinedOutput: []string{"bin", "abi"},
|
||||||
}
|
}
|
||||||
|
|
||||||
solReturn, err := solc.Compile([]string{"simpleContract.sol"}, FlagOpts{SolcFlagOpts: flags})
|
solReturn, err := solc.Compile(FlagOpts{flags}, tmpfile.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Errorf("Expected no errors: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if solReturn.Error != nil || solReturn.Warning != "" || len(solReturn.Contracts) != 1 {
|
if solReturn.Warning != "" || len(solReturn.Contracts) != 1 {
|
||||||
t.Fatalf("Expected no errors or warnings and expected contract items. Got %v for errors, %v for warnings, and %v for contract items", solReturn.Error, solReturn.Warning, solReturn.Contracts)
|
t.Fatalf("Expected no warnings and expected 1 contract item. Got %v for warnings, and %v for contract items", solReturn.Warning, len(solReturn.Contracts))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSolcCompilerError(t *testing.T) {
|
func TestSolcCompilerError(t *testing.T) {
|
||||||
solc, err := InitCompiler("solc")
|
solc, err := InitSolc("solc")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Skip(err)
|
t.Fatalf("Could not initialize solc: %v", err)
|
||||||
}
|
}
|
||||||
solc = solc.(*Solidity)
|
content := []byte(faultySol)
|
||||||
file, err := os.Create("faultyContract.sol")
|
tmpfile, err := ioutil.TempFile("", "faultyContract.sol")
|
||||||
defer os.Remove("faultyContract.sol")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
file.WriteString(faultySol)
|
defer os.Remove(tmpfile.Name()) // clean up
|
||||||
|
|
||||||
|
err = writeToTempFile(tmpfile, content)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
flags := SolcFlagOpts{
|
flags := SolcFlagOpts{
|
||||||
CombinedOutput: []string{"bin", "abi"},
|
CombinedOutput: []string{"bin", "abi"},
|
||||||
}
|
}
|
||||||
|
|
||||||
solReturn, err := solc.Compile([]string{"faultyContract.sol"}, FlagOpts{SolcFlagOpts: flags})
|
_, err = solc.Compile(FlagOpts{SolcFlagOpts: flags}, tmpfile.Name())
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
if err == nil {
|
||||||
}
|
|
||||||
if solReturn.Error == nil {
|
|
||||||
t.Fatal("Expected an error, got nil.")
|
t.Fatal("Expected an error, got nil.")
|
||||||
|
} else if !strings.Contains(err.Error(), "solc") {
|
||||||
|
t.Fatal("Expected error to come directly from compiler, got err from elsewhere: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSolcCompilerWarning(t *testing.T) {
|
func TestSolcCompilerWarning(t *testing.T) {
|
||||||
solc, err := InitCompiler("solc")
|
|
||||||
|
solc, err := InitSolc("solc")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Skip(err)
|
t.Fatalf("Could not initialize solc: %v", err)
|
||||||
}
|
}
|
||||||
solc = solc.(*Solidity)
|
content := []byte(solNoPragma)
|
||||||
file, err := os.Create("simpleContract.sol")
|
tmpfile, err := ioutil.TempFile("", "warningContract.sol")
|
||||||
defer os.Remove("simpleContract.sol")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
file.WriteString(solNoPragma)
|
defer os.Remove(tmpfile.Name()) // clean up
|
||||||
|
|
||||||
|
err = writeToTempFile(tmpfile, content)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
flags := SolcFlagOpts{
|
flags := SolcFlagOpts{
|
||||||
CombinedOutput: []string{"bin", "abi"},
|
CombinedOutput: []string{"bin", "abi"},
|
||||||
}
|
}
|
||||||
|
|
||||||
solReturn, err := solc.Compile([]string{"simpleContract.sol"}, FlagOpts{SolcFlagOpts: flags})
|
solReturn, err := solc.Compile(FlagOpts{SolcFlagOpts: flags}, tmpfile.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
if solReturn.Warning == "" {
|
if solReturn.Warning == "" {
|
||||||
t.Fatal("Expected a warning.")
|
t.Error("Expected a warning, got none.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLinkingBinaries(t *testing.T) {
|
func TestLinkingBinaries(t *testing.T) {
|
||||||
solc, err := InitCompiler("solc")
|
|
||||||
|
solc, err := InitSolc("solc")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Skip(err)
|
t.Fatalf("Could not initialize solc: %v", err)
|
||||||
}
|
}
|
||||||
solc = solc.(*Solidity)
|
content := []byte(simplyLibrarySol)
|
||||||
file, err := os.Create("simpleLibrary.sol")
|
tmpfile, err := ioutil.TempFile("", "libraryContracts.sol")
|
||||||
defer os.Remove("simpleLibrary.sol")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
file.WriteString(simplyLibrarySol)
|
defer os.Remove(tmpfile.Name()) // clean up
|
||||||
|
|
||||||
|
err = writeToTempFile(tmpfile, content)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
flags := SolcFlagOpts{
|
flags := SolcFlagOpts{
|
||||||
CombinedOutput: []string{"bin"},
|
CombinedOutput: []string{"bin"},
|
||||||
}
|
}
|
||||||
|
|
||||||
solReturn, err := solc.Compile([]string{"simpleLibrary.sol"}, FlagOpts{SolcFlagOpts: flags})
|
solReturn, err := solc.Compile(FlagOpts{SolcFlagOpts: flags}, tmpfile.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if solReturn.Error != nil || solReturn.Warning != "" || len(solReturn.Contracts) != 2 {
|
if solReturn.Warning != "" || len(solReturn.Contracts) != 2 {
|
||||||
t.Fatalf("Expected no errors or warnings and expected contract items. Got %v for errors, %v for warnings, and %v for contract items", solReturn.Error, solReturn.Warning, solReturn.Contracts)
|
t.Fatalf("Expected no errors or warnings and expected contract items. Got %v for warnings, and %v for contract items", solReturn.Warning, solReturn.Contracts)
|
||||||
}
|
|
||||||
// note: When solc upgrades to 0.4.10, will need to add "simpleLibrary.sol:" to beginning of this string
|
|
||||||
flags.Libraries = map[string]common.Address{"simpleLibrary.sol:Set": common.StringToAddress("0x692a70d2e424a56d2c6c27aa97d1a86395877b3a")}
|
|
||||||
binFile, err := os.Create("C.bin")
|
|
||||||
defer os.Remove("C.bin")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binFile.WriteString(solReturn.Contracts["simpleLibrary.sol:C"].Bin)
|
output, err := solc.(*Solidity).Link(map[string]common.Address{"Set": common.StringToAddress("0x692a70d2e424a56d2c6c27aa97d1a86395877b3a")}, solReturn.Contracts["C"].Bin)
|
||||||
_, err = solc.(*Solidity).Compile([]string{"./C.bin"}, FlagOpts{SolcFlagOpts: flags})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
output, err := ioutil.ReadFile("C.bin")
|
if strings.Contains(output, "_") {
|
||||||
if err != nil {
|
t.Errorf("Expected binaries to link, but they did not")
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(string(output), "_") {
|
|
||||||
t.Fatal("Expected binaries to link, but they did not")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLinkingBinariesAndNormalCompileMixed(t *testing.T) {
|
|
||||||
solc, err := InitCompiler("solc")
|
|
||||||
if err != nil {
|
|
||||||
t.Skip(err)
|
|
||||||
}
|
|
||||||
solc = solc.(*Solidity)
|
|
||||||
file, err := os.Create("simpleLibrary.sol")
|
|
||||||
defer os.Remove("simpleLibrary.sol")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
file.WriteString(simplyLibrarySol)
|
|
||||||
flags := SolcFlagOpts{
|
|
||||||
CombinedOutput: []string{"bin"},
|
|
||||||
}
|
|
||||||
|
|
||||||
solReturn, err := solc.Compile([]string{"simpleLibrary.sol"}, FlagOpts{SolcFlagOpts: flags})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if solReturn.Error != nil || solReturn.Warning != "" || len(solReturn.Contracts) != 2 {
|
|
||||||
t.Fatalf("Expected no errors or warnings and expected contract items. Got %v for errors, %v for warnings, and %v for contract items", solReturn.Error, solReturn.Warning, solReturn.Contracts)
|
|
||||||
}
|
|
||||||
// note: When solc upgrades to 0.4.10, will need to add "simpleLibrary.sol:" to beginning of this string
|
|
||||||
flags.Libraries = map[string]common.Address{"simpleLibrary.sol:Set": common.StringToAddress("0x692a70d2e424a56d2c6c27aa97d1a86395877b3a")}
|
|
||||||
binFile, err := os.Create("C.bin")
|
|
||||||
defer os.Remove("C.bin")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
binFile.WriteString(solReturn.Contracts["simpleLibrary.sol:C"].Bin)
|
|
||||||
|
|
||||||
solOutput, err := solc.Compile([]string{"./C.bin", "simpleLibrary.sol"}, FlagOpts{SolcFlagOpts: flags})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
binOutput, err := ioutil.ReadFile("C.bin")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(string(binOutput), "_") {
|
|
||||||
t.Fatal("Expected binaries to link, but they did not")
|
|
||||||
}
|
|
||||||
|
|
||||||
if solOutput.Error != nil || solOutput.Warning != "" || len(solOutput.Contracts) != 2 {
|
|
||||||
t.Fatalf("Expected no errors or warnings and expected contract items. Got %v for errors, %v for warnings, and %v for contract items", solReturn.Error, solReturn.Warning, solReturn.Contracts)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMultipleFilesCompiling(t *testing.T) {
|
|
||||||
solc, err := InitCompiler("solc")
|
|
||||||
if err != nil {
|
|
||||||
t.Skip(err)
|
|
||||||
}
|
|
||||||
solc = solc.(*Solidity)
|
|
||||||
set, err := os.Create("set.sol")
|
|
||||||
defer os.Remove("set.sol")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
set.WriteString(solFile1)
|
|
||||||
|
|
||||||
c, err := os.Create("C.sol")
|
|
||||||
defer os.Remove("C.sol")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
c.WriteString(solFile2)
|
|
||||||
flags := SolcFlagOpts{
|
|
||||||
CombinedOutput: []string{"bin", "abi"},
|
|
||||||
}
|
|
||||||
|
|
||||||
solReturn, err := solc.Compile([]string{"C.sol"}, FlagOpts{SolcFlagOpts: flags})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if solReturn.Error != nil || solReturn.Warning != "" || len(solReturn.Contracts) != 2 {
|
|
||||||
t.Fatalf("Expected no errors or warnings and expected contract items. Got %v for errors, %v for warnings, and %v for contract items", solReturn.Error, solReturn.Warning, solReturn.Contracts)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRemappings(t *testing.T) {
|
func TestRemappings(t *testing.T) {
|
||||||
solc, err := InitCompiler("solc")
|
|
||||||
if err != nil {
|
|
||||||
t.Skip(err)
|
|
||||||
}
|
|
||||||
solc = solc.(*Solidity)
|
|
||||||
if err := os.MkdirAll("."+string(filepath.Separator)+"tempDir", 0777); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll("." + string(filepath.Separator) + "tempDir")
|
|
||||||
os.Chdir("tempDir")
|
|
||||||
set, err := os.Create("set.sol")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
os.Chdir("..")
|
|
||||||
set.WriteString(solFile1)
|
|
||||||
|
|
||||||
c, err := os.Create("C.sol")
|
solc, err := InitSolc("solc")
|
||||||
defer os.Remove("C.sol")
|
if err != nil {
|
||||||
|
t.Fatalf("Could not initialize solc: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpfile1, err := ioutil.TempFile("", "C.sol")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(tmpfile1.Name()) // clean up
|
||||||
|
|
||||||
|
err = writeToTempFile(tmpfile1, []byte(solFile1))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, err := ioutil.TempDir("", "tempDir")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer os.RemoveAll(dir) // clean up
|
||||||
|
|
||||||
|
tmpfn := filepath.Join(dir, "set.sol")
|
||||||
|
if err := ioutil.WriteFile(tmpfn, []byte(solFile2), 0666); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpfile2, err := ioutil.TempFile("", "main.sol")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(tmpfile2.Name()) // clean up
|
||||||
|
|
||||||
|
err = writeToTempFile(tmpfile2, []byte(regularSolFile))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
c.WriteString(solFile2)
|
|
||||||
flags := SolcFlagOpts{
|
flags := SolcFlagOpts{
|
||||||
CombinedOutput: []string{"bin", "abi"},
|
CombinedOutput: []string{"bin", "abi"},
|
||||||
Remappings: []string{`set.sol=./tempDir/set.sol`},
|
Remappings: []string{`/somedir/=` + dir + "/"},
|
||||||
}
|
}
|
||||||
|
|
||||||
solReturn, err := solc.Compile([]string{"C.sol"}, FlagOpts{SolcFlagOpts: flags})
|
solReturn, err := solc.Compile(FlagOpts{SolcFlagOpts: flags}, tmpfile1.Name(), tmpfile2.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if solReturn.Error != nil || solReturn.Warning != "" || len(solReturn.Contracts) != 2 {
|
if solReturn.Warning != "" || len(solReturn.Contracts) != 3 {
|
||||||
t.Fatalf("Expected no errors or warnings and expected contract items. Got %v for errors, %v for warnings, and %v for contract items", solReturn.Error, solReturn.Warning, solReturn.Contracts)
|
t.Fatalf("Expected no warnings and expected %v contract items. Got %v for warnings, and %v for contract items", 3, solReturn.Warning, len(solReturn.Contracts))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue