github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/common/compiler/solidity.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package compiler wraps the Solidity compiler executable (solc).
    18  package compiler
    19  
    20  import (
    21  	"bytes"
    22  	"encoding/json"
    23  	"errors"
    24  	"fmt"
    25  	"io/ioutil"
    26  	"os/exec"
    27  	"regexp"
    28  	"strings"
    29  
    30  	"github.com/atheioschain/go-atheios/common"
    31  	"github.com/atheioschain/go-atheios/crypto"
    32  )
    33  
    34  var (
    35  	versionRegexp = regexp.MustCompile(`[0-9]+\.[0-9]+\.[0-9]+`)
    36  	solcParams    = []string{
    37  		"--combined-json", "bin,abi,userdoc,devdoc",
    38  		"--add-std",  // include standard lib contracts
    39  		"--optimize", // code optimizer switched on
    40  	}
    41  )
    42  
    43  type Contract struct {
    44  	Code string       `json:"code"`
    45  	Info ContractInfo `json:"info"`
    46  }
    47  
    48  type ContractInfo struct {
    49  	Source          string      `json:"source"`
    50  	Language        string      `json:"language"`
    51  	LanguageVersion string      `json:"languageVersion"`
    52  	CompilerVersion string      `json:"compilerVersion"`
    53  	CompilerOptions string      `json:"compilerOptions"`
    54  	AbiDefinition   interface{} `json:"abiDefinition"`
    55  	UserDoc         interface{} `json:"userDoc"`
    56  	DeveloperDoc    interface{} `json:"developerDoc"`
    57  }
    58  
    59  // Solidity contains information about the solidity compiler.
    60  type Solidity struct {
    61  	Path, Version, FullVersion string
    62  }
    63  
    64  // --combined-output format
    65  type solcOutput struct {
    66  	Contracts map[string]struct{ Bin, Abi, Devdoc, Userdoc string }
    67  	Version   string
    68  }
    69  
    70  // SolidityVersion runs solc and parses its version output.
    71  func SolidityVersion(solc string) (*Solidity, error) {
    72  	if solc == "" {
    73  		solc = "solc"
    74  	}
    75  	var out bytes.Buffer
    76  	cmd := exec.Command(solc, "--version")
    77  	cmd.Stdout = &out
    78  	if err := cmd.Run(); err != nil {
    79  		return nil, err
    80  	}
    81  	s := &Solidity{
    82  		Path:        cmd.Path,
    83  		FullVersion: out.String(),
    84  		Version:     versionRegexp.FindString(out.String()),
    85  	}
    86  	return s, nil
    87  }
    88  
    89  // CompileSolidityString builds and returns all the contracts contained within a source string.
    90  func CompileSolidityString(solc, source string) (map[string]*Contract, error) {
    91  	if len(source) == 0 {
    92  		return nil, errors.New("solc: empty source string")
    93  	}
    94  	if solc == "" {
    95  		solc = "solc"
    96  	}
    97  	args := append(solcParams, "--")
    98  	cmd := exec.Command(solc, append(args, "-")...)
    99  	cmd.Stdin = strings.NewReader(source)
   100  	return runsolc(cmd, source)
   101  }
   102  
   103  // CompileSolidity compiles all given Solidity source files.
   104  func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract, error) {
   105  	if len(sourcefiles) == 0 {
   106  		return nil, errors.New("solc: no source files")
   107  	}
   108  	source, err := slurpFiles(sourcefiles)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	if solc == "" {
   113  		solc = "solc"
   114  	}
   115  	args := append(solcParams, "--")
   116  	cmd := exec.Command(solc, append(args, sourcefiles...)...)
   117  	return runsolc(cmd, source)
   118  }
   119  
   120  func runsolc(cmd *exec.Cmd, source string) (map[string]*Contract, error) {
   121  	var stderr, stdout bytes.Buffer
   122  	cmd.Stderr = &stderr
   123  	cmd.Stdout = &stdout
   124  	if err := cmd.Run(); err != nil {
   125  		return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes())
   126  	}
   127  	var output solcOutput
   128  	if err := json.Unmarshal(stdout.Bytes(), &output); err != nil {
   129  		return nil, err
   130  	}
   131  	shortVersion := versionRegexp.FindString(output.Version)
   132  
   133  	// Compilation succeeded, assemble and return the contracts.
   134  	contracts := make(map[string]*Contract)
   135  	for name, info := range output.Contracts {
   136  		// Parse the individual compilation results.
   137  		var abi interface{}
   138  		if err := json.Unmarshal([]byte(info.Abi), &abi); err != nil {
   139  			return nil, fmt.Errorf("solc: error reading abi definition (%v)", err)
   140  		}
   141  		var userdoc interface{}
   142  		if err := json.Unmarshal([]byte(info.Userdoc), &userdoc); err != nil {
   143  			return nil, fmt.Errorf("solc: error reading user doc: %v", err)
   144  		}
   145  		var devdoc interface{}
   146  		if err := json.Unmarshal([]byte(info.Devdoc), &devdoc); err != nil {
   147  			return nil, fmt.Errorf("solc: error reading dev doc: %v", err)
   148  		}
   149  		contracts[name] = &Contract{
   150  			Code: "0x" + info.Bin,
   151  			Info: ContractInfo{
   152  				Source:          source,
   153  				Language:        "Solidity",
   154  				LanguageVersion: shortVersion,
   155  				CompilerVersion: shortVersion,
   156  				CompilerOptions: strings.Join(solcParams, " "),
   157  				AbiDefinition:   abi,
   158  				UserDoc:         userdoc,
   159  				DeveloperDoc:    devdoc,
   160  			},
   161  		}
   162  	}
   163  	return contracts, nil
   164  }
   165  
   166  func slurpFiles(files []string) (string, error) {
   167  	var concat bytes.Buffer
   168  	for _, file := range files {
   169  		content, err := ioutil.ReadFile(file)
   170  		if err != nil {
   171  			return "", err
   172  		}
   173  		concat.Write(content)
   174  	}
   175  	return concat.String(), nil
   176  }
   177  
   178  // SaveInfo serializes info to the given file and returns its Keccak256 hash.
   179  func SaveInfo(info *ContractInfo, filename string) (common.Hash, error) {
   180  	infojson, err := json.Marshal(info)
   181  	if err != nil {
   182  		return common.Hash{}, err
   183  	}
   184  	contenthash := common.BytesToHash(crypto.Keccak256(infojson))
   185  	return contenthash, ioutil.WriteFile(filename, infojson, 0600)
   186  }