From b0ae84aa0dae65f00492f981bb61887331def2a5 Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 20 May 2015 04:11:48 +0100 Subject: [PATCH] multiple contract source for solidity compiler: returns contract array if multiple contracts. fixes #1023 --- cmd/geth/js_test.go | 6 +- common/compiler/solidity.go | 99 ++++++++++++++++---------------- common/compiler/solidity_test.go | 16 ++++-- rpc/api.go | 5 +- rpc/api_test.go | 24 ++++---- xeth/xeth.go | 7 +++ 6 files changed, 87 insertions(+), 70 deletions(-) diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go index 8ffef49700..71c1fedb9e 100644 --- a/cmd/geth/js_test.go +++ b/cmd/geth/js_test.go @@ -234,7 +234,7 @@ func TestSignature(t *testing.T) { // This is a very preliminary test, lacking actual signature verification if err != nil { - t.Errorf("Error runnig js: %v", err) + t.Errorf("Error running js: %v", err) return } output := val.String() @@ -297,7 +297,7 @@ func TestContract(t *testing.T) { t.Errorf("%v", err) } } else { - checkEvalJSON(t, repl, `contract = eth.compile.solidity(source)`, string(contractInfo)) + checkEvalJSON(t, repl, `contract = eth.compile.solidity(source).test`, string(contractInfo)) } checkEvalJSON(t, repl, `contract.code`, `"0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056"`) @@ -310,7 +310,7 @@ func TestContract(t *testing.T) { callSetup := `abiDef = JSON.parse('[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]'); Multiply7 = eth.contract(abiDef); -multiply7 = new Multiply7(contractaddress); +multiply7 = Multiply7.at(contractaddress); ` // time.Sleep(1500 * time.Millisecond) _, err = repl.re.Run(callSetup) diff --git a/common/compiler/solidity.go b/common/compiler/solidity.go index 19d5849fb3..0cfd41c95c 100644 --- a/common/compiler/solidity.go +++ b/common/compiler/solidity.go @@ -92,7 +92,7 @@ func (sol *Solidity) Version() string { return sol.version } -func (sol *Solidity) Compile(source string) (contract *Contract, err error) { +func (sol *Solidity) Compile(source string) (contracts map[string]*Contract, err error) { if len(source) == 0 { err = fmt.Errorf("empty source") @@ -123,58 +123,61 @@ func (sol *Solidity) Compile(source string) (contract *Contract, err error) { err = fmt.Errorf("solc error: missing code output") return } - if len(matches) > 1 { - err = fmt.Errorf("multi-contract sources are not supported") - return - } - _, file := filepath.Split(matches[0]) - 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") + contracts = make(map[string]*Contract) + for _, path := range matches { + _, file := filepath.Split(path) + base := strings.Split(file, ".")[0] - 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) + codeFile := filepath.Join(wd, base+".binary") + abiDefinitionFile := filepath.Join(wd, base+".abi") + userDocFile := filepath.Join(wd, base+".docuser") + developerDocFile := filepath.Join(wd, base+".docdev") - userDocJson, err := ioutil.ReadFile(userDocFile) - if err != nil { - err = fmt.Errorf("error reading compiler output for userDoc: %v", err) - return - } - var userDoc interface{} - err = json.Unmarshal(userDocJson, &userDoc) + 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) - developerDocJson, err := ioutil.ReadFile(developerDocFile) - if err != nil { - err = fmt.Errorf("error reading compiler output for developerDoc: %v", err) - return - } - var developerDoc interface{} - err = json.Unmarshal(developerDocJson, &developerDoc) + userDocJson, err = ioutil.ReadFile(userDocFile) + if err != nil { + err = fmt.Errorf("error reading compiler output for userDoc: %v", err) + return + } + var userDoc interface{} + err = json.Unmarshal(userDocJson, &userDoc) - contract = &Contract{ - Code: "0x" + string(code), - Info: ContractInfo{ - Source: source, - Language: "Solidity", - LanguageVersion: languageVersion, - CompilerVersion: sol.version, - AbiDefinition: abiDefinition, - UserDoc: userDoc, - DeveloperDoc: developerDoc, - }, + developerDocJson, err = ioutil.ReadFile(developerDocFile) + if err != nil { + err = fmt.Errorf("error reading compiler output for developerDoc: %v", err) + return + } + var developerDoc interface{} + err = json.Unmarshal(developerDocJson, &developerDoc) + + contract := &Contract{ + Code: "0x" + string(code), + Info: ContractInfo{ + Source: source, + Language: "Solidity", + LanguageVersion: languageVersion, + CompilerVersion: sol.version, + AbiDefinition: abiDefinition, + UserDoc: userDoc, + DeveloperDoc: developerDoc, + }, + } + + contracts[base] = contract } return diff --git a/common/compiler/solidity_test.go b/common/compiler/solidity_test.go index 2b0ca148fe..46f733e59d 100644 --- a/common/compiler/solidity_test.go +++ b/common/compiler/solidity_test.go @@ -33,14 +33,18 @@ func TestCompiler(t *testing.T) { } else if sol.Version() != solcVersion { t.Logf("WARNING: a newer version of solc found (%v, expect %v)", sol.Version(), solcVersion) } - contract, err := sol.Compile(source) + contracts, err := sol.Compile(source) if err != nil { - t.Errorf("error compiling source. result %v: %v", contract, err) + t.Errorf("error compiling source. result %v: %v", contracts, err) return } - if contract.Code != code { - t.Errorf("wrong code, expected\n%s, got\n%s", code, contract.Code) + if len(contracts) != 1 { + t.Errorf("one contract expected, got\n%s", len(contracts)) + } + + if contracts["test"].Code != code { + t.Errorf("wrong code, expected\n%s, got\n%s", code, contracts["test"].Code) } } @@ -52,9 +56,9 @@ func TestCompileError(t *testing.T) { } else if sol.Version() != solcVersion { t.Logf("WARNING: a newer version of solc found (%v, expect %v)", sol.Version(), solcVersion) } - contract, err := sol.Compile(source[2:]) + contracts, err := sol.Compile(source[2:]) if err == nil { - t.Errorf("error expected compiling source. got none. result %v", contract) + t.Errorf("error expected compiling source. got none. result %v", contracts) return } } diff --git a/rpc/api.go b/rpc/api.go index 0c1409d71b..4b705c7812 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -355,12 +355,11 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err return err } - contract, err := solc.Compile(args.Source) + contracts, err := solc.Compile(args.Source) if err != nil { return err } - contract.Code = newHexData(contract.Code).String() - *reply = contract + *reply = contracts case "eth_newFilter": args := new(BlockFilterArgs) diff --git a/rpc/api_test.go b/rpc/api_test.go index 263e9666d7..d1dcad2667 100644 --- a/rpc/api_test.go +++ b/rpc/api_test.go @@ -2,14 +2,11 @@ package rpc import ( "encoding/json" - // "sync" - "testing" - // "time" - // "fmt" - "io/ioutil" "strconv" + "testing" "github.com/ethereum/go-ethereum/common/compiler" + "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/xeth" ) @@ -58,7 +55,7 @@ func TestCompileSolidity(t *testing.T) { expLanguageVersion := "0" expSource := source - api := NewEthereumApi(&xeth.XEth{}) + api := NewEthereumApi(xeth.NewTest(ð.Ethereum{}, nil)) var req RpcRequest json.Unmarshal([]byte(jsonstr), &req) @@ -73,12 +70,18 @@ func TestCompileSolidity(t *testing.T) { t.Errorf("expected no error, got %v", err) } - var contract = compiler.Contract{} - err = json.Unmarshal(respjson, &contract) + var contracts = make(map[string]*compiler.Contract) + err = json.Unmarshal(respjson, &contracts) if err != nil { t.Errorf("expected no error, got %v", err) } + if len(contracts) != 1 { + t.Errorf("expected one contract, got %v", len(contracts)) + } + + contract := contracts["test"] + if contract.Code != expCode { t.Errorf("Expected \n%s got \n%s", expCode, contract.Code) } @@ -86,12 +89,15 @@ func TestCompileSolidity(t *testing.T) { if strconv.Quote(contract.Info.Source) != `"`+expSource+`"` { t.Errorf("Expected \n'%s' got \n'%s'", expSource, strconv.Quote(contract.Info.Source)) } + if contract.Info.Language != expLanguage { t.Errorf("Expected %s got %s", expLanguage, contract.Info.Language) } + if contract.Info.LanguageVersion != expLanguageVersion { t.Errorf("Expected %s got %s", expLanguageVersion, contract.Info.LanguageVersion) } + if contract.Info.CompilerVersion != expCompilerVersion { t.Errorf("Expected %s got %s", expCompilerVersion, contract.Info.CompilerVersion) } @@ -114,8 +120,6 @@ func TestCompileSolidity(t *testing.T) { if string(abidef) != expAbiDefinition { t.Errorf("Expected \n'%s' got \n'%s'", expAbiDefinition, string(abidef)) } - ioutil.WriteFile("/tmp/abidef", []byte(string(abidef)), 0700) - ioutil.WriteFile("/tmp/expabidef", []byte(expAbiDefinition), 0700) if string(userdoc) != expUserDoc { t.Errorf("Expected \n'%s' got \n'%s'", expUserDoc, string(userdoc)) diff --git a/xeth/xeth.go b/xeth/xeth.go index 81197d3818..4925fe635b 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -69,6 +69,13 @@ type XEth struct { agent *miner.RemoteAgent } +func NewTest(eth *eth.Ethereum, frontend Frontend) *XEth { + return &XEth{ + backend: eth, + frontend: frontend, + } +} + // New creates an XEth that uses the given frontend. // If a nil Frontend is provided, a default frontend which // confirms all transactions will be used.