forked from cerc-io/plugeth
		
	common/compiler: simplify solc wrapper
Support for legacy version 0.9.x is gone. The compiler version is no longer cached. Compilation results (and the version) are read directly from stdout using the --combined-json flag. As a workaround for ethereum/solidity#651, source code is written to a temporary file before compilation. Integration of solc in package ethapi and cmd/abigen is now much simpler because the compiler wrapper is no longer passed around as a pointer. Fixes #2806, accidentally
This commit is contained in:
		
							parent
							
								
									84d11c19fd
								
							
						
					
					
						commit
						1a9e66915b
					
				| @ -68,18 +68,7 @@ func main() { | ||||
| 		for _, kind := range strings.Split(*excFlag, ",") { | ||||
| 			exclude[strings.ToLower(kind)] = true | ||||
| 		} | ||||
| 		// Build the Solidity source into bindable components
 | ||||
| 		solc, err := compiler.New(*solcFlag) | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("Failed to locate Solidity compiler: %v\n", err) | ||||
| 			os.Exit(-1) | ||||
| 		} | ||||
| 		source, err := ioutil.ReadFile(*solFlag) | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("Failed to read Soldity source code: %v\n", err) | ||||
| 			os.Exit(-1) | ||||
| 		} | ||||
| 		contracts, err := solc.Compile(string(source)) | ||||
| 		contracts, err := compiler.CompileSolidity(*solcFlag, *solFlag) | ||||
| 		if err != nil { | ||||
| 			fmt.Printf("Failed to build Solidity contract: %v\n", err) | ||||
| 			os.Exit(-1) | ||||
|  | ||||
| @ -14,6 +14,7 @@ | ||||
| // You should have received a copy of the GNU Lesser General Public License
 | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| // Package compiler wraps the Solidity compiler executable (solc).
 | ||||
| package compiler | ||||
| 
 | ||||
| import ( | ||||
| @ -21,42 +22,23 @@ import ( | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/crypto" | ||||
| 	"github.com/ethereum/go-ethereum/logger" | ||||
| 	"github.com/ethereum/go-ethereum/logger/glog" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	versionRegexp = regexp.MustCompile("[0-9]+\\.[0-9]+\\.[0-9]+") | ||||
| 	legacyRegexp  = regexp.MustCompile("0\\.(9\\..*|1\\.[01])") | ||||
| 	paramsLegacy  = []string{ | ||||
| 		"--binary",       // Request to output the contract in binary (hexadecimal).
 | ||||
| 		"file",           //
 | ||||
| 		"--json-abi",     // Request to output the contract's JSON ABI interface.
 | ||||
| 		"file",           //
 | ||||
| 		"--natspec-user", // Request to output the contract's Natspec user documentation.
 | ||||
| 		"file",           //
 | ||||
| 		"--natspec-dev",  // Request to output the contract's Natspec developer documentation.
 | ||||
| 		"file", | ||||
| 		"--add-std", | ||||
| 		"1", | ||||
| 	} | ||||
| 	paramsNew = []string{ | ||||
| 		"--bin",      // Request to output the contract in binary (hexadecimal).
 | ||||
| 		"--abi",      // Request to output the contract's JSON ABI interface.
 | ||||
| 		"--userdoc",  // Request to output the contract's Natspec user documentation.
 | ||||
| 		"--devdoc",   // Request to output the contract's Natspec developer documentation.
 | ||||
| 	solcParams    = []string{ | ||||
| 		"--combined-json", "bin,abi,userdoc,devdoc", | ||||
| 		"--add-std",  // include standard lib contracts
 | ||||
| 		"--optimize", // code optimizer switched on
 | ||||
| 		"-o",         // output directory
 | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| @ -76,135 +58,112 @@ type ContractInfo struct { | ||||
| 	DeveloperDoc    interface{} `json:"developerDoc"` | ||||
| } | ||||
| 
 | ||||
| // Solidity contains information about the solidity compiler.
 | ||||
| type Solidity struct { | ||||
| 	solcPath    string | ||||
| 	version     string | ||||
| 	fullVersion string | ||||
| 	legacy      bool | ||||
| 	Path, Version, FullVersion string | ||||
| } | ||||
| 
 | ||||
| func New(solcPath string) (sol *Solidity, err error) { | ||||
| 	// set default solc
 | ||||
| 	if len(solcPath) == 0 { | ||||
| 		solcPath = "solc" | ||||
| 	} | ||||
| 	solcPath, err = exec.LookPath(solcPath) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| // --combined-output format
 | ||||
| type solcOutput struct { | ||||
| 	Contracts map[string]struct{ Bin, Abi, Devdoc, Userdoc string } | ||||
| 	Version   string | ||||
| } | ||||
| 
 | ||||
| 	cmd := exec.Command(solcPath, "--version") | ||||
| // SolidityVersion runs solc and parses its version output.
 | ||||
| func SolidityVersion(solc string) (*Solidity, error) { | ||||
| 	if solc == "" { | ||||
| 		solc = "solc" | ||||
| 	} | ||||
| 	var out bytes.Buffer | ||||
| 	cmd := exec.Command(solc, "--version") | ||||
| 	cmd.Stdout = &out | ||||
| 	err = cmd.Run() | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	if err := cmd.Run(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	s := &Solidity{ | ||||
| 		Path:        cmd.Path, | ||||
| 		FullVersion: out.String(), | ||||
| 		Version:     versionRegexp.FindString(out.String()), | ||||
| 	} | ||||
| 	return s, nil | ||||
| } | ||||
| 
 | ||||
| 	fullVersion := out.String() | ||||
| 	version := versionRegexp.FindString(fullVersion) | ||||
| 	legacy := legacyRegexp.MatchString(version) | ||||
| 
 | ||||
| 	sol = &Solidity{ | ||||
| 		solcPath:    solcPath, | ||||
| 		version:     version, | ||||
| 		fullVersion: fullVersion, | ||||
| 		legacy:      legacy, | ||||
| 	} | ||||
| 	glog.V(logger.Info).Infoln(sol.Info()) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (sol *Solidity) Info() string { | ||||
| 	return fmt.Sprintf("%s\npath: %s", sol.fullVersion, sol.solcPath) | ||||
| } | ||||
| 
 | ||||
| func (sol *Solidity) Version() string { | ||||
| 	return sol.version | ||||
| } | ||||
| 
 | ||||
| // 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
 | ||||
| // CompileSolidityString builds and returns all the contracts contained within a source string.
 | ||||
| func CompileSolidityString(solc, source string) (map[string]*Contract, error) { | ||||
| 	if len(source) == 0 { | ||||
| 		return nil, errors.New("solc: empty source string") | ||||
| 	} | ||||
| 	// Create a safe place to dump compilation output
 | ||||
| 	wd, err := ioutil.TempDir("", "solc") | ||||
| 	if solc == "" { | ||||
| 		solc = "solc" | ||||
| 	} | ||||
| 	// Write source to a temporary file. Compiling stdin used to be supported
 | ||||
| 	// but seems to produce an exception with solc 0.3.5.
 | ||||
| 	infile, err := ioutil.TempFile("", "geth-compile-solidity") | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("solc: failed to create temporary build folder: %v", err) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer os.RemoveAll(wd) | ||||
| 
 | ||||
| 	// Assemble the compiler command, change to the temp folder and capture any errors
 | ||||
| 	stderr := new(bytes.Buffer) | ||||
| 
 | ||||
| 	var params []string | ||||
| 	if sol.legacy { | ||||
| 		params = paramsLegacy | ||||
| 	} else { | ||||
| 		params = paramsNew | ||||
| 		params = append(params, wd) | ||||
| 	defer os.Remove(infile.Name()) | ||||
| 	if _, err := io.WriteString(infile, source); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if err := infile.Close(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	compilerOptions := strings.Join(params, " ") | ||||
| 
 | ||||
| 	cmd := exec.Command(sol.solcPath, params...) | ||||
| 	cmd.Stdin = strings.NewReader(source) | ||||
| 	cmd.Stderr = stderr | ||||
| 	return CompileSolidity(solc, infile.Name()) | ||||
| } | ||||
| 
 | ||||
| // CompileSolidity compiles all given Solidity source files.
 | ||||
| func CompileSolidity(solc string, sourcefiles ...string) (map[string]*Contract, error) { | ||||
| 	if len(sourcefiles) == 0 { | ||||
| 		return nil, errors.New("solc: no source ") | ||||
| 	} | ||||
| 	source, err := slurpFiles(sourcefiles) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if solc == "" { | ||||
| 		solc = "solc" | ||||
| 	} | ||||
| 
 | ||||
| 	var stderr, stdout bytes.Buffer | ||||
| 	args := append(solcParams, "--") | ||||
| 	cmd := exec.Command(solc, append(args, sourcefiles...)...) | ||||
| 	cmd.Stderr = &stderr | ||||
| 	cmd.Stdout = &stdout | ||||
| 	if err := cmd.Run(); err != nil { | ||||
| 		return nil, fmt.Errorf("solc: %v\n%s", err, string(stderr.Bytes())) | ||||
| 		return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes()) | ||||
| 	} | ||||
| 	// Sanity check that something was actually built
 | ||||
| 	matches, _ := filepath.Glob(filepath.Join(wd, "*.bin*")) | ||||
| 	if len(matches) < 1 { | ||||
| 		return nil, fmt.Errorf("solc: no build results found") | ||||
| 	var output solcOutput | ||||
| 	if err := json.Unmarshal(stdout.Bytes(), &output); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	// Compilation succeeded, assemble and return the contracts
 | ||||
| 	shortVersion := versionRegexp.FindString(output.Version) | ||||
| 
 | ||||
| 	// 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] | ||||
| 
 | ||||
| 		// Parse the individual compilation results (code binary, ABI definitions, user and dev docs)
 | ||||
| 		var binary []byte | ||||
| 		binext := ".bin" | ||||
| 		if sol.legacy { | ||||
| 			binext = ".binary" | ||||
| 		} | ||||
| 		if binary, err = ioutil.ReadFile(filepath.Join(wd, base+binext)); err != nil { | ||||
| 			return nil, fmt.Errorf("solc: error reading compiler output for code: %v", err) | ||||
| 		} | ||||
| 
 | ||||
| 	for name, info := range output.Contracts { | ||||
| 		// Parse the individual compilation results.
 | ||||
| 		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) | ||||
| 		if err := json.Unmarshal([]byte(info.Abi), &abi); err != nil { | ||||
| 			return nil, fmt.Errorf("solc: error reading abi definition (%v)", err) | ||||
| 		} | ||||
| 
 | ||||
| 		var userdoc interface{} | ||||
| 		if blob, err := ioutil.ReadFile(filepath.Join(wd, base+".docuser")); err != nil { | ||||
| 		if err := json.Unmarshal([]byte(info.Userdoc), &userdoc); 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 devdoc interface{} | ||||
| 		if blob, err := ioutil.ReadFile(filepath.Join(wd, base+".docdev")); err != nil { | ||||
| 		if err := json.Unmarshal([]byte(info.Devdoc), &devdoc); 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), | ||||
| 		contracts[name] = &Contract{ | ||||
| 			Code: "0x" + info.Bin, | ||||
| 			Info: ContractInfo{ | ||||
| 				Source:          source, | ||||
| 				Language:        "Solidity", | ||||
| 				LanguageVersion: sol.version, | ||||
| 				CompilerVersion: sol.version, | ||||
| 				CompilerOptions: compilerOptions, | ||||
| 				LanguageVersion: shortVersion, | ||||
| 				CompilerVersion: shortVersion, | ||||
| 				CompilerOptions: strings.Join(solcParams, " "), | ||||
| 				AbiDefinition:   abi, | ||||
| 				UserDoc:         userdoc, | ||||
| 				DeveloperDoc:    devdoc, | ||||
| @ -214,12 +173,24 @@ func (sol *Solidity) Compile(source string) (map[string]*Contract, error) { | ||||
| 	return contracts, nil | ||||
| } | ||||
| 
 | ||||
| func SaveInfo(info *ContractInfo, filename string) (contenthash common.Hash, err error) { | ||||
| func slurpFiles(files []string) (string, error) { | ||||
| 	var concat bytes.Buffer | ||||
| 	for _, file := range files { | ||||
| 		content, err := ioutil.ReadFile(file) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		concat.Write(content) | ||||
| 	} | ||||
| 	return concat.String(), nil | ||||
| } | ||||
| 
 | ||||
| // SaveInfo serializes info to the given file and returns its Keccak256 hash.
 | ||||
| func SaveInfo(info *ContractInfo, filename string) (common.Hash, error) { | ||||
| 	infojson, err := json.Marshal(info) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 		return common.Hash{}, err | ||||
| 	} | ||||
| 	contenthash = common.BytesToHash(crypto.Keccak256(infojson)) | ||||
| 	err = ioutil.WriteFile(filename, infojson, 0600) | ||||
| 	return | ||||
| 	contenthash := common.BytesToHash(crypto.Keccak256(infojson)) | ||||
| 	return contenthash, ioutil.WriteFile(filename, infojson, 0600) | ||||
| } | ||||
|  | ||||
| @ -26,10 +26,9 @@ import ( | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| ) | ||||
| 
 | ||||
| const solcVersion = "0.1.1" | ||||
| 
 | ||||
| var ( | ||||
| 	source = ` | ||||
| const ( | ||||
| 	supportedSolcVersion = "0.3.5" | ||||
| 	testSource           = ` | ||||
| contract test { | ||||
|    /// @notice Will multiply ` + "`a`" + ` by 7.
 | ||||
|    function multiply(uint a) returns(uint d) { | ||||
| @ -37,61 +36,57 @@ contract test { | ||||
|    } | ||||
| } | ||||
| ` | ||||
| 	code = "0x6060604052606d8060116000396000f30060606040526000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa1146037576035565b005b6046600480359060200150605c565b6040518082815260200191505060405180910390f35b60006007820290506068565b91905056" | ||||
| 	info = `{"source":"\ncontract test {\n   /// @notice Will multiply ` + "`a`" + ` by 7.\n   function multiply(uint a) returns(uint d) {\n       return a * 7;\n   }\n}\n","language":"Solidity","languageVersion":"0.1.1","compilerVersion":"0.1.1","compilerOptions":"--binary file --json-abi file --natspec-user file --natspec-dev file --add-std 1","abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}},"developerDoc":{"methods":{}}}` | ||||
| 
 | ||||
| 	infohash = common.HexToHash("0x9f3803735e7f16120c5a140ab3f02121fd3533a9655c69b33a10e78752cc49b0") | ||||
| 	testCode = "0x6060604052602a8060106000396000f3606060405260e060020a6000350463c6888fa18114601a575b005b6007600435026060908152602090f3" | ||||
| 	testInfo = `{"source":"\ncontract test {\n   /// @notice Will multiply ` + "`a`" + ` by 7.\n   function multiply(uint a) returns(uint d) {\n       return a * 7;\n   }\n}\n","language":"Solidity","languageVersion":"0.1.1","compilerVersion":"0.1.1","compilerOptions":"--binary file --json-abi file --natspec-user file --natspec-dev file --add-std 1","abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}},"developerDoc":{"methods":{}}}` | ||||
| ) | ||||
| 
 | ||||
| func TestCompiler(t *testing.T) { | ||||
| 	sol, err := New("") | ||||
| func skipUnsupported(t *testing.T) { | ||||
| 	sol, err := SolidityVersion("") | ||||
| 	if err != nil { | ||||
| 		t.Skipf("solc not found: %v", err) | ||||
| 	} else if sol.Version() != solcVersion { | ||||
| 		t.Skipf("WARNING: a newer version of solc found (%v, expect %v)", sol.Version(), solcVersion) | ||||
| 	} | ||||
| 	contracts, err := sol.Compile(source) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("error compiling source. result %v: %v", contracts, err) | ||||
| 		t.Skip(err) | ||||
| 		return | ||||
| 	} | ||||
| 	if sol.Version != supportedSolcVersion { | ||||
| 		t.Skipf("unsupported version of solc found (%v, expect %v)", sol.Version, supportedSolcVersion) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestCompiler(t *testing.T) { | ||||
| 	skipUnsupported(t) | ||||
| 	contracts, err := CompileSolidityString("", testSource) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("error compiling source. result %v: %v", contracts, err) | ||||
| 	} | ||||
| 	if len(contracts) != 1 { | ||||
| 		t.Errorf("one contract expected, got %d", len(contracts)) | ||||
| 	} | ||||
| 
 | ||||
| 	if contracts["test"].Code != code { | ||||
| 		t.Errorf("wrong code, expected\n%s, got\n%s", code, contracts["test"].Code) | ||||
| 	c, ok := contracts["test"] | ||||
| 	if !ok { | ||||
| 		t.Fatal("info for contract 'test' not present in result") | ||||
| 	} | ||||
| 	if c.Code != testCode { | ||||
| 		t.Errorf("wrong code: expected\n%s, got\n%s", testCode, c.Code) | ||||
| 	} | ||||
| 	if c.Info.Source != testSource { | ||||
| 		t.Error("wrong source") | ||||
| 	} | ||||
| 	if c.Info.CompilerVersion != supportedSolcVersion { | ||||
| 		t.Errorf("wrong version: expected %q, got %q", supportedSolcVersion, c.Info.CompilerVersion) | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| func TestCompileError(t *testing.T) { | ||||
| 	sol, err := New("") | ||||
| 	if err != nil || sol.version != solcVersion { | ||||
| 		t.Skip("solc not found: skip") | ||||
| 	} else if sol.Version() != solcVersion { | ||||
| 		t.Skip("WARNING: skipping due to a newer version of solc found (%v, expect %v)", sol.Version(), solcVersion) | ||||
| 	} | ||||
| 	contracts, err := sol.Compile(source[2:]) | ||||
| 	skipUnsupported(t) | ||||
| 	contracts, err := CompileSolidityString("", testSource[4:]) | ||||
| 	if err == nil { | ||||
| 		t.Errorf("error expected compiling source. got none. result %v", contracts) | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestNoCompiler(t *testing.T) { | ||||
| 	_, err := New("/path/to/solc") | ||||
| 	if err != nil { | ||||
| 		t.Logf("solidity quits with error: %v", err) | ||||
| 	} else { | ||||
| 		t.Errorf("no solc installed, but got no error") | ||||
| 	} | ||||
| 	t.Logf("error: %v", err) | ||||
| } | ||||
| 
 | ||||
| func TestSaveInfo(t *testing.T) { | ||||
| 	var cinfo ContractInfo | ||||
| 	err := json.Unmarshal([]byte(info), &cinfo) | ||||
| 	err := json.Unmarshal([]byte(testInfo), &cinfo) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("%v", err) | ||||
| 	} | ||||
| @ -105,10 +100,11 @@ func TestSaveInfo(t *testing.T) { | ||||
| 	if err != nil { | ||||
| 		t.Errorf("error reading '%v': %v", filename, err) | ||||
| 	} | ||||
| 	if string(got) != info { | ||||
| 		t.Errorf("incorrect info.json extracted, expected:\n%s\ngot\n%s", info, string(got)) | ||||
| 	if string(got) != testInfo { | ||||
| 		t.Errorf("incorrect info.json extracted, expected:\n%s\ngot\n%s", testInfo, string(got)) | ||||
| 	} | ||||
| 	if cinfohash != infohash { | ||||
| 		t.Errorf("content hash for info is incorrect. expected %v, got %v", infohash.Hex(), cinfohash.Hex()) | ||||
| 	wantHash := common.HexToHash("0x9f3803735e7f16120c5a140ab3f02121fd3533a9655c69b33a10e78752cc49b0") | ||||
| 	if cinfohash != wantHash { | ||||
| 		t.Errorf("content hash for info is incorrect. expected %v, got %v", wantHash.Hex(), cinfohash.Hex()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -31,7 +31,6 @@ import ( | ||||
| 	"github.com/ethereum/ethash" | ||||
| 	"github.com/ethereum/go-ethereum/accounts" | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/common/compiler" | ||||
| 	"github.com/ethereum/go-ethereum/common/httpclient" | ||||
| 	"github.com/ethereum/go-ethereum/common/registrar/ethreg" | ||||
| 	"github.com/ethereum/go-ethereum/core" | ||||
| @ -130,7 +129,6 @@ type Ethereum struct { | ||||
| 	autodagquit  chan bool | ||||
| 	etherbase    common.Address | ||||
| 	solcPath     string | ||||
| 	solc         *compiler.Solidity | ||||
| 
 | ||||
| 	NatSpec       bool | ||||
| 	PowTest       bool | ||||
| @ -291,7 +289,7 @@ func CreatePoW(config *Config) (*ethash.Ethash, error) { | ||||
| // APIs returns the collection of RPC services the ethereum package offers.
 | ||||
| // NOTE, some of these services probably need to be moved to somewhere else.
 | ||||
| func (s *Ethereum) APIs() []rpc.API { | ||||
| 	return append(ethapi.GetAPIs(s.apiBackend, &s.solcPath, &s.solc), []rpc.API{ | ||||
| 	return append(ethapi.GetAPIs(s.apiBackend, s.solcPath), []rpc.API{ | ||||
| 		{ | ||||
| 			Namespace: "eth", | ||||
| 			Version:   "1.0", | ||||
|  | ||||
| @ -44,7 +44,7 @@ type ContractBackend struct { | ||||
| // Etheruem object.
 | ||||
| func NewContractBackend(eth *Ethereum) *ContractBackend { | ||||
| 	return &ContractBackend{ | ||||
| 		eapi:  ethapi.NewPublicEthereumAPI(eth.apiBackend, nil, nil), | ||||
| 		eapi:  ethapi.NewPublicEthereumAPI(eth.apiBackend), | ||||
| 		bcapi: ethapi.NewPublicBlockChainAPI(eth.apiBackend), | ||||
| 		txapi: ethapi.NewPublicTransactionPoolAPI(eth.apiBackend), | ||||
| 	} | ||||
|  | ||||
| @ -20,7 +20,6 @@ import ( | ||||
| 	"bytes" | ||||
| 	"encoding/hex" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"math/big" | ||||
| 	"strings" | ||||
| @ -30,7 +29,6 @@ import ( | ||||
| 	"github.com/ethereum/ethash" | ||||
| 	"github.com/ethereum/go-ethereum/accounts" | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/common/compiler" | ||||
| 	"github.com/ethereum/go-ethereum/core" | ||||
| 	"github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/core/vm" | ||||
| @ -51,13 +49,11 @@ const defaultGas = uint64(90000) | ||||
| // It offers only methods that operate on public data that is freely available to anyone.
 | ||||
| type PublicEthereumAPI struct { | ||||
| 	b Backend | ||||
| 	solcPath *string | ||||
| 	solc     **compiler.Solidity | ||||
| } | ||||
| 
 | ||||
| // NewPublicEthereumAPI creates a new Etheruem protocol API.
 | ||||
| func NewPublicEthereumAPI(b Backend, solcPath *string, solc **compiler.Solidity) *PublicEthereumAPI { | ||||
| 	return &PublicEthereumAPI{b, solcPath, solc} | ||||
| func NewPublicEthereumAPI(b Backend) *PublicEthereumAPI { | ||||
| 	return &PublicEthereumAPI{b} | ||||
| } | ||||
| 
 | ||||
| // GasPrice returns a suggestion for a gas price.
 | ||||
| @ -65,39 +61,6 @@ func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*big.Int, error) { | ||||
| 	return s.b.SuggestPrice(ctx) | ||||
| } | ||||
| 
 | ||||
| func (s *PublicEthereumAPI) getSolc() (*compiler.Solidity, error) { | ||||
| 	var err error | ||||
| 	solc := *s.solc | ||||
| 	if solc == nil { | ||||
| 		solc, err = compiler.New(*s.solcPath) | ||||
| 	} | ||||
| 	return solc, err | ||||
| } | ||||
| 
 | ||||
| // GetCompilers returns the collection of available smart contract compilers
 | ||||
| func (s *PublicEthereumAPI) GetCompilers() ([]string, error) { | ||||
| 	solc, err := s.getSolc() | ||||
| 	if err == nil && solc != nil { | ||||
| 		return []string{"Solidity"}, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return []string{}, nil | ||||
| } | ||||
| 
 | ||||
| // CompileSolidity compiles the given solidity source
 | ||||
| func (s *PublicEthereumAPI) CompileSolidity(source string) (map[string]*compiler.Contract, error) { | ||||
| 	solc, err := s.getSolc() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if solc == nil { | ||||
| 		return nil, errors.New("solc (solidity compiler) not found") | ||||
| 	} | ||||
| 
 | ||||
| 	return solc.Compile(source) | ||||
| } | ||||
| 
 | ||||
| // ProtocolVersion returns the current Ethereum protocol version this node supports
 | ||||
| func (s *PublicEthereumAPI) ProtocolVersion() *rpc.HexNumber { | ||||
| 	return rpc.NewHexNumber(s.b.ProtocolVersion()) | ||||
| @ -1416,31 +1379,6 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx *Tx, gasPrice, | ||||
| 	return common.Hash{}, fmt.Errorf("Transaction %#x not found", tx.Hash) | ||||
| } | ||||
| 
 | ||||
| // PrivateAdminAPI is the collection of Etheruem APIs exposed over the private
 | ||||
| // admin endpoint.
 | ||||
| type PrivateAdminAPI struct { | ||||
| 	b        Backend | ||||
| 	solcPath *string | ||||
| 	solc     **compiler.Solidity | ||||
| } | ||||
| 
 | ||||
| // NewPrivateAdminAPI creates a new API definition for the private admin methods
 | ||||
| // of the Ethereum service.
 | ||||
| func NewPrivateAdminAPI(b Backend, solcPath *string, solc **compiler.Solidity) *PrivateAdminAPI { | ||||
| 	return &PrivateAdminAPI{b, solcPath, solc} | ||||
| } | ||||
| 
 | ||||
| // SetSolc sets the Solidity compiler path to be used by the node.
 | ||||
| func (api *PrivateAdminAPI) SetSolc(path string) (string, error) { | ||||
| 	var err error | ||||
| 	*api.solcPath = path | ||||
| 	*api.solc, err = compiler.New(path) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return (*api.solc).Info(), nil | ||||
| } | ||||
| 
 | ||||
| // PublicDebugAPI is the collection of Etheruem APIs exposed over the public
 | ||||
| // debugging endpoint.
 | ||||
| type PublicDebugAPI struct { | ||||
|  | ||||
| @ -22,7 +22,6 @@ import ( | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/accounts" | ||||
| 	"github.com/ethereum/go-ethereum/common" | ||||
| 	"github.com/ethereum/go-ethereum/common/compiler" | ||||
| 	"github.com/ethereum/go-ethereum/core" | ||||
| 	"github.com/ethereum/go-ethereum/core/types" | ||||
| 	"github.com/ethereum/go-ethereum/core/vm" | ||||
| @ -69,12 +68,13 @@ type State interface { | ||||
| 	GetNonce(ctx context.Context, addr common.Address) (uint64, error) | ||||
| } | ||||
| 
 | ||||
| func GetAPIs(apiBackend Backend, solcPath *string, solc **compiler.Solidity) []rpc.API { | ||||
| 	return []rpc.API{ | ||||
| func GetAPIs(apiBackend Backend, solcPath string) []rpc.API { | ||||
| 	compiler := makeCompilerAPIs(solcPath) | ||||
| 	all := []rpc.API{ | ||||
| 		{ | ||||
| 			Namespace: "eth", | ||||
| 			Version:   "1.0", | ||||
| 			Service:   NewPublicEthereumAPI(apiBackend, solcPath, solc), | ||||
| 			Service:   NewPublicEthereumAPI(apiBackend), | ||||
| 			Public:    true, | ||||
| 		}, { | ||||
| 			Namespace: "eth", | ||||
| @ -91,10 +91,6 @@ func GetAPIs(apiBackend Backend, solcPath *string, solc **compiler.Solidity) []r | ||||
| 			Version:   "1.0", | ||||
| 			Service:   NewPublicTxPoolAPI(apiBackend), | ||||
| 			Public:    true, | ||||
| 		}, { | ||||
| 			Namespace: "admin", | ||||
| 			Version:   "1.0", | ||||
| 			Service:   NewPrivateAdminAPI(apiBackend, solcPath, solc), | ||||
| 		}, { | ||||
| 			Namespace: "debug", | ||||
| 			Version:   "1.0", | ||||
| @ -116,4 +112,5 @@ func GetAPIs(apiBackend Backend, solcPath *string, solc **compiler.Solidity) []r | ||||
| 			Public:    false, | ||||
| 		}, | ||||
| 	} | ||||
| 	return append(compiler, all...) | ||||
| } | ||||
|  | ||||
							
								
								
									
										82
									
								
								internal/ethapi/solc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								internal/ethapi/solc.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,82 @@ | ||||
| // Copyright 2016 The go-ethereum Authors
 | ||||
| // This file is part of the go-ethereum library.
 | ||||
| //
 | ||||
| // The go-ethereum library is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU Lesser General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| //
 | ||||
| // The go-ethereum library is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||
| // GNU Lesser General Public License for more details.
 | ||||
| //
 | ||||
| // You should have received a copy of the GNU Lesser General Public License
 | ||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| package ethapi | ||||
| 
 | ||||
| import ( | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/ethereum/go-ethereum/common/compiler" | ||||
| 	"github.com/ethereum/go-ethereum/rpc" | ||||
| ) | ||||
| 
 | ||||
| func makeCompilerAPIs(solcPath string) []rpc.API { | ||||
| 	c := &compilerAPI{solc: solcPath} | ||||
| 	return []rpc.API{ | ||||
| 		{ | ||||
| 			Namespace: "eth", | ||||
| 			Version:   "1.0", | ||||
| 			Service:   (*PublicCompilerAPI)(c), | ||||
| 			Public:    true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Namespace: "admin", | ||||
| 			Version:   "1.0", | ||||
| 			Service:   (*CompilerAdminAPI)(c), | ||||
| 			Public:    true, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type compilerAPI struct { | ||||
| 	// This lock guards the solc path set through the API.
 | ||||
| 	// It also ensures that only one solc process is used at
 | ||||
| 	// any time.
 | ||||
| 	mu   sync.Mutex | ||||
| 	solc string | ||||
| } | ||||
| 
 | ||||
| type CompilerAdminAPI compilerAPI | ||||
| 
 | ||||
| // SetSolc sets the Solidity compiler path to be used by the node.
 | ||||
| func (api *CompilerAdminAPI) SetSolc(path string) (string, error) { | ||||
| 	api.mu.Lock() | ||||
| 	defer api.mu.Unlock() | ||||
| 	info, err := compiler.SolidityVersion(path) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	api.solc = path | ||||
| 	return info.FullVersion, nil | ||||
| } | ||||
| 
 | ||||
| type PublicCompilerAPI compilerAPI | ||||
| 
 | ||||
| // CompileSolidity compiles the given solidity source.
 | ||||
| func (api *PublicCompilerAPI) CompileSolidity(source string) (map[string]*compiler.Contract, error) { | ||||
| 	api.mu.Lock() | ||||
| 	defer api.mu.Unlock() | ||||
| 	return compiler.CompileSolidityString(api.solc, source) | ||||
| } | ||||
| 
 | ||||
| func (api *PublicCompilerAPI) GetCompilers() ([]string, error) { | ||||
| 	api.mu.Lock() | ||||
| 	defer api.mu.Unlock() | ||||
| 	if _, err := compiler.SolidityVersion(api.solc); err == nil { | ||||
| 		return []string{"Solidity"}, nil | ||||
| 	} | ||||
| 	return []string{}, nil | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user