| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							|  |  |  | // go-ethereum 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. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | package natspec | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2015-03-08 20:09:13 +07:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:55 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common/docserver" | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common/registrar" | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/xeth" | 
					
						
							| 
									
										
										
										
											2015-07-07 05:10:49 +02:00
										 |  |  | 	"github.com/robertkrimen/otto" | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | type abi2method map[[8]byte]*method | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | type NatSpec struct { | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | 	jsvm       *otto.Otto | 
					
						
							|  |  |  | 	abiDocJson []byte | 
					
						
							|  |  |  | 	userDoc    userDoc | 
					
						
							|  |  |  | 	tx, data   string | 
					
						
							| 
									
										
										
										
											2015-04-08 12:35:02 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | // main entry point for to get natspec notice for a transaction | 
					
						
							|  |  |  | // the implementation is frontend friendly in that it always gives back | 
					
						
							|  |  |  | // a notice that is safe to display | 
					
						
							|  |  |  | // :FIXME: the second return value is an error, which can be used to fine-tune bahaviour | 
					
						
							| 
									
										
										
										
											2015-04-08 12:35:02 +02:00
										 |  |  | func GetNotice(xeth *xeth.XEth, tx string, http *docserver.DocServer) (notice string) { | 
					
						
							|  |  |  | 	ns, err := New(xeth, tx, http) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if ns == nil { | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | 			return getFallbackNotice(fmt.Sprintf("no NatSpec info found for contract: %v", err), tx) | 
					
						
							| 
									
										
										
										
											2015-04-08 12:35:02 +02:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | 			return getFallbackNotice(fmt.Sprintf("invalid NatSpec info: %v", err), tx) | 
					
						
							| 
									
										
										
										
											2015-04-08 12:35:02 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | 	notice, err = ns.Notice() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return getFallbackNotice(fmt.Sprintf("NatSpec notice error: %v", err), tx) | 
					
						
							| 
									
										
										
										
											2015-04-08 12:35:02 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-04-08 12:35:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | func getFallbackNotice(comment, tx string) string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("About to submit transaction (%s): %s", comment, tx) | 
					
						
							| 
									
										
										
										
											2015-04-08 12:35:02 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | type transaction struct { | 
					
						
							|  |  |  | 	To   string `json:"to"` | 
					
						
							|  |  |  | 	Data string `json:"data"` | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | type jsonTx struct { | 
					
						
							|  |  |  | 	Params []transaction `json:"params"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type contractInfo struct { | 
					
						
							|  |  |  | 	Source        string          `json:"source"` | 
					
						
							|  |  |  | 	Language      string          `json:"language"` | 
					
						
							|  |  |  | 	Version       string          `json:"compilerVersion"` | 
					
						
							|  |  |  | 	AbiDefinition json.RawMessage `json:"abiDefinition"` | 
					
						
							|  |  |  | 	UserDoc       userDoc         `json:"userDoc"` | 
					
						
							|  |  |  | 	DeveloperDoc  json.RawMessage `json:"developerDoc"` | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | func New(xeth *xeth.XEth, jsontx string, http *docserver.DocServer) (self *NatSpec, err error) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// extract contract address from tx | 
					
						
							|  |  |  | 	var tx jsonTx | 
					
						
							|  |  |  | 	err = json.Unmarshal([]byte(jsontx), &tx) | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | 	t := tx.Params[0] | 
					
						
							|  |  |  | 	contractAddress := t.To | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	content, err := FetchDocsForContract(contractAddress, xeth, http) | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | 	self, err = NewWithDocs(content, jsontx, t.Data) | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // also called by admin.contractInfo.get | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | func FetchDocsForContract(contractAddress string, xeth *xeth.XEth, ds *docserver.DocServer) (content []byte, err error) { | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 	// retrieve contract hash from state | 
					
						
							| 
									
										
										
										
											2015-04-07 11:50:17 +02:00
										 |  |  | 	codehex := xeth.CodeAt(contractAddress) | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | 	codeb := xeth.CodeAtBytes(contractAddress) | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | 	if codehex == "0x" { | 
					
						
							|  |  |  | 		err = fmt.Errorf("contract (%v) not found", contractAddress) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	codehash := common.BytesToHash(crypto.Sha3(codeb)) | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:55 +01:00
										 |  |  | 	// set up nameresolver with natspecreg + urlhint contract addresses | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	reg := registrar.New(xeth) | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-07 11:50:17 +02:00
										 |  |  | 	// resolve host via HashReg/UrlHint Resolver | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	hash, err := reg.HashToHash(codehash) | 
					
						
							| 
									
										
										
										
											2015-03-31 16:02:55 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	if ds.HasScheme("bzz") { | 
					
						
							|  |  |  | 		content, err = ds.Get("bzz://"+hash.Hex()[2:], "") | 
					
						
							|  |  |  | 		if err == nil { // non-fatal | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		err = nil | 
					
						
							|  |  |  | 		//falling back to urlhint | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	uri, err := reg.HashToUrl(hash) | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-23 15:48:33 +01:00
										 |  |  | 	// get content via http client and authenticate content using hash | 
					
						
							|  |  |  | 	content, err = ds.GetAuthContent(uri, hash) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 	return | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | func NewWithDocs(infoDoc []byte, tx string, data string) (self *NatSpec, err error) { | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | 	var contract contractInfo | 
					
						
							|  |  |  | 	err = json.Unmarshal(infoDoc, &contract) | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	self = &NatSpec{ | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | 		jsvm:       otto.New(), | 
					
						
							|  |  |  | 		abiDocJson: []byte(contract.AbiDefinition), | 
					
						
							|  |  |  | 		userDoc:    contract.UserDoc, | 
					
						
							|  |  |  | 		tx:         tx, | 
					
						
							|  |  |  | 		data:       data, | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-01 12:29:16 +01:00
										 |  |  | 	// load and require natspec js (but it is meant to be protected environment) | 
					
						
							| 
									
										
										
										
											2015-03-08 20:09:13 +07:00
										 |  |  | 	_, err = self.jsvm.Run(natspecJS) | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-06 18:54:26 +01:00
										 |  |  | 	_, err = self.jsvm.Run("var natspec = require('natspec');") | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // type abiDoc []method | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // type method struct { | 
					
						
							|  |  |  | // 	Name   string  `json:name` | 
					
						
							|  |  |  | // 	Inputs []input `json:inputs` | 
					
						
							|  |  |  | // 	abiKey [8]byte | 
					
						
							|  |  |  | // } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // type input struct { | 
					
						
							|  |  |  | // 	Name string `json:name` | 
					
						
							|  |  |  | // 	Type string `json:type` | 
					
						
							|  |  |  | // } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-01 12:29:16 +01:00
										 |  |  | // json skeleton for abi doc (contract method definitions) | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | type method struct { | 
					
						
							|  |  |  | 	Notice string `json:notice` | 
					
						
							|  |  |  | 	name   string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type userDoc struct { | 
					
						
							|  |  |  | 	Methods map[string]*method `json:methods` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (self *NatSpec) makeAbi2method(abiKey [8]byte) (meth *method) { | 
					
						
							|  |  |  | 	for signature, m := range self.userDoc.Methods { | 
					
						
							|  |  |  | 		name := strings.Split(signature, "(")[0] | 
					
						
							|  |  |  | 		hash := []byte(common.Bytes2Hex(crypto.Sha3([]byte(signature)))) | 
					
						
							|  |  |  | 		var key [8]byte | 
					
						
							|  |  |  | 		copy(key[:], hash[:8]) | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 		if bytes.Equal(key[:], abiKey[:]) { | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 			meth = m | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 			meth.name = name | 
					
						
							|  |  |  | 			return | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | func (self *NatSpec) Notice() (notice string, err error) { | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 	var abiKey [8]byte | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 	if len(self.data) < 10 { | 
					
						
							|  |  |  | 		err = fmt.Errorf("Invalid transaction data") | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	copy(abiKey[:], self.data[2:10]) | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 	meth := self.makeAbi2method(abiKey) | 
					
						
							| 
									
										
										
										
											2015-04-07 11:50:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 	if meth == nil { | 
					
						
							| 
									
										
										
										
											2015-04-19 19:24:46 +01:00
										 |  |  | 		err = fmt.Errorf("abi key does not match any method") | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-31 08:28:12 +02:00
										 |  |  | 	notice, err = self.noticeForMethod(self.tx, meth.name, meth.Notice) | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | func (self *NatSpec) noticeForMethod(tx string, name, expression string) (notice string, err error) { | 
					
						
							| 
									
										
										
										
											2015-04-07 11:50:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 	if _, err = self.jsvm.Run("var transaction = " + tx + ";"); err != nil { | 
					
						
							| 
									
										
										
										
											2015-03-08 20:09:13 +07:00
										 |  |  | 		return "", fmt.Errorf("natspec.js error setting transaction: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 	if _, err = self.jsvm.Run("var abi = " + string(self.abiDocJson) + ";"); err != nil { | 
					
						
							| 
									
										
										
										
											2015-03-08 20:09:13 +07:00
										 |  |  | 		return "", fmt.Errorf("natspec.js error setting abi: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-31 00:49:38 +01:00
										 |  |  | 	if _, err = self.jsvm.Run("var method = '" + name + "';"); err != nil { | 
					
						
							| 
									
										
										
										
											2015-03-08 20:09:13 +07:00
										 |  |  | 		return "", fmt.Errorf("natspec.js error setting method: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-08 20:09:13 +07:00
										 |  |  | 	if _, err = self.jsvm.Run("var expression = \"" + expression + "\";"); err != nil { | 
					
						
							|  |  |  | 		return "", fmt.Errorf("natspec.js error setting expression: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-06 18:54:26 +01:00
										 |  |  | 	self.jsvm.Run("var call = {method: method,abi: abi,transaction: transaction};") | 
					
						
							|  |  |  | 	value, err := self.jsvm.Run("natspec.evaluateExpression(expression, call);") | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-03-08 20:09:13 +07:00
										 |  |  | 		return "", fmt.Errorf("natspec.js error evaluating expression: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	evalError := "Natspec evaluation failed, wrong input params" | 
					
						
							|  |  |  | 	if value.String() == evalError { | 
					
						
							|  |  |  | 		return "", fmt.Errorf("natspec.js error evaluating expression: wrong input params in expression '%s'", expression) | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-08 20:09:13 +07:00
										 |  |  | 	if len(value.String()) == 0 { | 
					
						
							|  |  |  | 		return "", fmt.Errorf("natspec.js error evaluating expression") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return value.String(), nil | 
					
						
							| 
									
										
										
										
											2015-03-06 03:43:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | } |