From 009b2216921b15962f2612687c1460a8342d49d6 Mon Sep 17 00:00:00 2001 From: zelig Date: Wed, 22 Apr 2015 23:11:11 +0100 Subject: solidity compiler and contract metadocs integration * common/compiler: solidity compiler + tests * rpc: eth_compilers, eth_compileSolidity + tests * fix natspec test using keystore API, notice exp dynamically changes addr, cleanup * resolver implements registrars and needs to create reg contract (temp) * xeth: solidity compiler. expose getter Solc() and paths setter SetSolc(solcPath) * ethereumApi: implement compiler related RPC calls using XEth - json struct tests * admin: make use of XEth.SetSolc to allow runtime setting of compiler paths * cli: command line flags solc to set custom solc bin path * js admin api with new features debug and contractInfo modules * wiki is the doc https://github.com/ethereum/go-ethereum/wiki/Contracts-and-Transactions --- rpc/api.go | 46 ++++++++++++++++++--------- rpc/api_test.go | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- rpc/args.go | 23 ++++++++++++++ rpc/args_test.go | 10 ++++++ 4 files changed, 160 insertions(+), 16 deletions(-) (limited to 'rpc') diff --git a/rpc/api.go b/rpc/api.go index b79a1306e..452116fb4 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -2,9 +2,8 @@ package rpc import ( "encoding/json" - "fmt" "math/big" - "sync" + // "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -14,8 +13,7 @@ import ( ) type EthereumApi struct { - eth *xeth.XEth - xethMu sync.RWMutex + eth *xeth.XEth } func NewEthereumApi(xeth *xeth.XEth) *EthereumApi { @@ -27,9 +25,6 @@ func NewEthereumApi(xeth *xeth.XEth) *EthereumApi { } func (api *EthereumApi) xeth() *xeth.XEth { - api.xethMu.RLock() - defer api.xethMu.RUnlock() - return api.eth } @@ -154,6 +149,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err } *reply = newHexNum(big.NewInt(int64(len(br.Uncles))).Bytes()) + case "eth_getData", "eth_getCode": args := new(GetDataArgs) if err := json.Unmarshal(req.Params, &args); err != nil { @@ -161,18 +157,13 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err } v := api.xethAtStateNum(args.BlockNumber).CodeAtBytes(args.Address) *reply = newHexData(v) + case "eth_sendTransaction", "eth_transact": args := new(NewTxArgs) if err := json.Unmarshal(req.Params, &args); err != nil { return err } - // call ConfirmTransaction first - tx, _ := json.Marshal(req) - if !api.xeth().ConfirmTransaction(string(tx)) { - return fmt.Errorf("Transaction not confirmed") - } - // nonce may be nil ("guess" mode) var nonce string if args.Nonce != nil { @@ -311,11 +302,36 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err } else { *reply = v.Uncles[args.Index] } + case "eth_getCompilers": - c := []string{""} + var lang string + if solc, _ := api.xeth().Solc(); solc != nil { + lang = "Solidity" + } + c := []string{lang} *reply = c - case "eth_compileSolidity", "eth_compileLLL", "eth_compileSerpent": + + case "eth_compileLLL", "eth_compileSerpent": return NewNotImplementedError(req.Method) + + case "eth_compileSolidity": + + solc, _ := api.xeth().Solc() + if solc == nil { + return NewNotImplementedError(req.Method) + } + + args := new(SourceArgs) + if err := json.Unmarshal(req.Params, &args); err != nil { + return err + } + + contract, err := solc.Compile(args.Source) + if err != nil { + return err + } + *reply = contract + case "eth_newFilter": args := new(BlockFilterArgs) if err := json.Unmarshal(req.Params, &args); err != nil { diff --git a/rpc/api_test.go b/rpc/api_test.go index ac9b67fac..c6489557c 100644 --- a/rpc/api_test.go +++ b/rpc/api_test.go @@ -5,8 +5,12 @@ import ( // "sync" "testing" // "time" + // "fmt" + "io/ioutil" + "strconv" - // "github.com/ethereum/go-ethereum/xeth" + "github.com/ethereum/go-ethereum/common/compiler" + "github.com/ethereum/go-ethereum/xeth" ) func TestWeb3Sha3(t *testing.T) { @@ -26,6 +30,97 @@ func TestWeb3Sha3(t *testing.T) { } } +func TestCompileSolidity(t *testing.T) { + + solc, err := compiler.New("") + if solc == nil { + t.Skip("no solidity compiler") + } + source := `contract test {\n` + + " /// @notice Will multiply `a` by 7." + `\n` + + ` function multiply(uint a) returns(uint d) {\n` + + ` return a * 7;\n` + + ` }\n` + + `}\n` + + jsonstr := `{"jsonrpc":"2.0","method":"eth_compileSolidity","params":["` + source + `"],"id":64}` + + expCode := "605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056" + expAbiDefinition := `[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]` + expUserDoc := `{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}}` + expDeveloperDoc := `{"methods":{}}` + expCompilerVersion := `0.9.13` + expLanguage := "Solidity" + expLanguageVersion := "0" + expSource := source + + api := NewEthereumApi(&xeth.XEth{}) + + var req RpcRequest + json.Unmarshal([]byte(jsonstr), &req) + + var response interface{} + err = api.GetRequestReply(&req, &response) + if err != nil { + t.Errorf("expected no error, got %v", err) + } + respjson, err := json.Marshal(response) + if err != nil { + t.Errorf("expected no error, got %v", err) + } + + var contract = compiler.Contract{} + err = json.Unmarshal(respjson, &contract) + if err != nil { + t.Errorf("expected no error, got %v", err) + } + + if contract.Code != expCode { + t.Errorf("Expected %s got %s", expCode, contract.Code) + } + 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) + } + + userdoc, err := json.Marshal(contract.Info.UserDoc) + if err != nil { + t.Errorf("expected no error, got %v", err) + } + + devdoc, err := json.Marshal(contract.Info.DeveloperDoc) + if err != nil { + t.Errorf("expected no error, got %v", err) + } + + abidef, err := json.Marshal(contract.Info.AbiDefinition) + if err != nil { + t.Errorf("expected no error, got %v", err) + } + + 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)) + } + + if string(devdoc) != expDeveloperDoc { + t.Errorf("Expected %s got %s", expDeveloperDoc, string(devdoc)) + } +} + // func TestDbStr(t *testing.T) { // jsonput := `{"jsonrpc":"2.0","method":"db_putString","params":["testDB","myKey","myString"],"id":64}` // jsonget := `{"jsonrpc":"2.0","method":"db_getString","params":["testDB","myKey"],"id":64}` diff --git a/rpc/args.go b/rpc/args.go index e61f28c4f..58a750415 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -1136,3 +1136,26 @@ func (args *SubmitWorkArgs) UnmarshalJSON(b []byte) (err error) { return nil } + +type SourceArgs struct { + Source string +} + +func (args *SourceArgs) UnmarshalJSON(b []byte) (err error) { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { + return NewDecodeParamError(err.Error()) + } + + if len(obj) < 1 { + return NewInsufficientParamsError(len(obj), 1) + } + + arg0, ok := obj[0].(string) + if !ok { + return NewInvalidTypeError("source code", "not a string") + } + args.Source = arg0 + + return nil +} diff --git a/rpc/args_test.go b/rpc/args_test.go index f5949b7a2..09ce12467 100644 --- a/rpc/args_test.go +++ b/rpc/args_test.go @@ -2494,3 +2494,13 @@ func TestBlockHeightFromJsonInvalid(t *testing.T) { t.Error(str) } } + +func TestSourceArgsEmpty(t *testing.T) { + input := `[]` + + args := new(SourceArgs) + str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) + if len(str) > 0 { + t.Error(str) + } +} -- cgit