From e1571472538e276ad9d9da3f2169dbd50a3bedfe Mon Sep 17 00:00:00 2001 From: Fefe Date: Fri, 6 Mar 2015 18:54:26 +0100 Subject: [PATCH] Now using github.com/obscuren/otto, no need for an Ethereum object (got rid of some messy code in test) --- ethutil/natspec/natspec.go | 28 +++---- ethutil/natspec/natspec.js | 127 ++++++++++++-------------------- ethutil/natspec/natspec_test.go | 114 +--------------------------- 3 files changed, 62 insertions(+), 207 deletions(-) diff --git a/ethutil/natspec/natspec.go b/ethutil/natspec/natspec.go index 33c072d4f..00e6f8720 100644 --- a/ethutil/natspec/natspec.go +++ b/ethutil/natspec/natspec.go @@ -1,66 +1,62 @@ package natspec import ( - // "encoding/json" - // "fmt" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/javascript" + "github.com/obscuren/otto" "io/ioutil" ) type NatSpec struct { - jsre *javascript.JSRE + jsvm *otto.Otto } -func NewNATSpec(ethereum *eth.Ethereum, transaction string) (self *NatSpec, err error) { +func NewNATSpec(transaction string) (self *NatSpec, err error) { self = new(NatSpec) - self.jsre = javascript.NewJSRE(ethereum) - //self.jsre.LoadExtFile("/home/fefe/go-ethereum/ethutil/natspec/natspec.js") + self.jsvm = otto.New() code, err := ioutil.ReadFile("natspec.js") if err != nil { return } - _, err = self.jsre.Run(string(code)) + _, err = self.jsvm.Run(string(code)) if err != nil { return } - _, err = self.jsre.Run("var natspec = require('natspec');") + _, err = self.jsvm.Run("var natspec = require('natspec');") if err != nil { return } - self.jsre.Run("var transaction = " + transaction + ";") + self.jsvm.Run("var transaction = " + transaction + ";") return } func (self *NatSpec) SetDescription(desc string) (err error) { - _, err = self.jsre.Run("var expression = \"" + desc + "\";") + _, err = self.jsvm.Run("var expression = \"" + desc + "\";") return } func (self *NatSpec) SetABI(abi string) (err error) { - _, err = self.jsre.Run("var abi = " + abi + ";") + _, err = self.jsvm.Run("var abi = " + abi + ";") return } func (self *NatSpec) SetMethod(method string) (err error) { - _, err = self.jsre.Run("var method = '" + method + "';") + _, err = self.jsvm.Run("var method = '" + method + "';") return } func (self *NatSpec) Parse() string { - self.jsre.Run("var call = {method: method,abi: abi,transaction: transaction};") - value, err := self.jsre.Run("natspec.evaluateExpression(expression, call);") + self.jsvm.Run("var call = {method: method,abi: abi,transaction: transaction};") + value, err := self.jsvm.Run("natspec.evaluateExpression(expression, call);") if err != nil { return err.Error() } diff --git a/ethutil/natspec/natspec.js b/ethutil/natspec/natspec.js index 4a71cd080..419ccd5c9 100644 --- a/ethutil/natspec/natspec.js +++ b/ethutil/natspec/natspec.js @@ -1824,10 +1824,6 @@ module.exports = { // Handle values that fail the validity test in BigNumber. - - // Zsolt Felfoldi 15/03/06 - // modified regexps in order to compile with go JSRE - parseNumeric = (function () { // var basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i, var basePrefix = /^(-?)0([xbo])/i, @@ -1838,7 +1834,6 @@ module.exports = { whitespaceOrPlus = /^\s*\+[\w.]|^\s+|\s+$/g; return function ( x, str, num, b ) { - var base, s = num ? str : str.replace( whitespaceOrPlus, '' ); @@ -3387,7 +3382,6 @@ module.exports = { })(this); },{"crypto":1}],"natspec":[function(require,module,exports){ -(function (global){ /* This file is part of natspec.js. @@ -3418,31 +3412,18 @@ var abi = require('./node_modules/ethereum.js/lib/abi.js'); */ var natspec = (function () { /// Helper method - /// Modifications by Zsolt Felfoldi, 15/03/06 - /// eval() under go JSRE is unable to reach variables that - /// are added to the global context runtime, so now we - /// create a variable assignment code for each param - /// and run in an isolated function(context) - /// variable assignment code is returned by copyToContext - + /// Should be called to copy values from object to global context var copyToContext = function (obj, context) { - var code = ""; - var keys = Object.keys(obj); - keys.forEach(function (key) { + Object.keys(obj).forEach(function (key) { context[key] = obj[key]; - code = code + "var "+key+" = context['"+key+"'];\n"; }); - return code; } - - /// this function will not be used in 'production' natspec evaluation - /// it's only used to enable tests in node environment - /// it copies all functions from current context to nodejs global context - var copyToNodeGlobal = function (obj) { - if (typeof global === 'undefined') { - return; - } - copyToContext(obj, global); + + /// generate codes, which will be evaluated + var generateCode = function (obj) { + return Object.keys(obj).reduce(function (acc, key) { + return acc + "var " + key + " = context['" + key + "'];\n"; + }, ""); }; /// Helper method @@ -3455,52 +3436,20 @@ var natspec = (function () { })[0]; }; - /// Function called to get all contract's storage values - /// @returns hashmap with contract properties which are used - /// TODO: check if this function will be used - var getContractProperties = function (address, abi) { - return {}; - }; - /// Function called to get all contract method input variables /// @returns hashmap with all contract's method input variables var getMethodInputParams = function (method, transaction) { // do it with output formatter (cause we have to decode) - var params = abi.formatOutput(method.inputs, '0x' + transaction.params[0].data.slice(10)); - + return method.inputs.reduce(function (acc, current, index) { acc[current.name] = params[index]; return acc; }, {}); - }; - /// Should be called to evaluate single expression - /// Is internally using javascript's 'eval' method - /// @param expression which should be evaluated - /// @param [call] object containing contract abi, transaction, called method - /// TODO: separate evaluation from getting input params, so as not to spoil 'evaluateExpression' function - var evaluateExpression = function (expression, call) { - - var self = this; - var code = ""; - var context = []; - - if (!!call) { - try { - var method = getMethodWithName(call.abi, call.method); - var params = getMethodInputParams(method, call.transaction); - code = copyToContext(params, context); // see copyToContext comments - } - catch (err) { - return "Natspec evaluation failed, wrong input params"; - } - } - - // used only for tests - copyToNodeGlobal(context); - + /// Should be called to evaluate expression + var mapExpressionsToEvaluate = function (expression, cb) { var evaluatedExpression = ""; // match everything in `` quotes @@ -3509,27 +3458,50 @@ var natspec = (function () { var lastIndex = 0; while ((match = pattern.exec(expression)) !== null) { var startIndex = pattern.lastIndex - match[0].length; - var toEval = match[0].slice(1, match[0].length - 1); - evaluatedExpression += expression.slice(lastIndex, startIndex); - - var evaluatedPart; - try { - var fn = new Function("context", code + "return "+toEval+";"); - evaluatedPart = fn(context).toString(); // see copyToContext comments -// evaluatedPart = eval(toEval).toString(); - } - catch (err) { - evaluatedPart = 'undefined'; - } - + var evaluatedPart = cb(toEval); evaluatedExpression += evaluatedPart; lastIndex = pattern.lastIndex; } - - evaluatedExpression += expression.slice(lastIndex); + evaluatedExpression += expression.slice(lastIndex); + + return evaluatedExpression; + }; + + /// Should be called to evaluate single expression + /// Is internally using javascript's 'eval' method + /// @param expression which should be evaluated + /// @param [call] object containing contract abi, transaction, called method + /// TODO: separate evaluation from getting input params, so as not to spoil 'evaluateExpression' function + var evaluateExpression = function (expression, call) { + //var self = this; + var context = {}; + + if (!!call) { + try { + var method = getMethodWithName(call.abi, call.method); + var params = getMethodInputParams(method, call.transaction); + copyToContext(params, context); + } + catch (err) { + return "Natspec evaluation failed, wrong input params"; + } + } + + var code = generateCode(context); + + var evaluatedExpression = mapExpressionsToEvaluate(expression, function (toEval) { + try { + var fn = new Function("context", code + "return " + toEval + ";"); + return fn(context).toString(); + } + catch (err) { + return 'undefined'; + } + }); + return evaluatedExpression; }; @@ -3542,5 +3514,4 @@ var natspec = (function () { module.exports = natspec; -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./node_modules/ethereum.js/lib/abi.js":3}]},{},[]); diff --git a/ethutil/natspec/natspec_test.go b/ethutil/natspec/natspec_test.go index 85e0b687e..48a9cb25c 100644 --- a/ethutil/natspec/natspec_test.go +++ b/ethutil/natspec/natspec_test.go @@ -1,124 +1,12 @@ package natspec import ( - "flag" - // "crypto/rand" - // "io/ioutil" - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/eth" "testing" ) -const ( - ClientIdentifier = "Ethereum(G)" - Version = "0.8.1" -) - -var ( - Identifier string - KeyRing string - DiffTool bool - DiffType string - KeyStore string - StartRpc bool - StartWebSockets bool - RpcPort int - NatType string - PMPGateway string - OutboundPort string - ShowGenesis bool - AddPeer string - MaxPeer int - GenAddr bool - UseSeed bool - SecretFile string - ExportDir string - NonInteractive bool - Datadir string - LogFile string - ConfigFile string - DebugFile string - LogLevel int - Dump bool - DumpHash string - DumpNumber int - VmType int - ImportChain string - SHH bool - Dial bool - PrintVersion bool -) - -func Init() { - /* flag.Usage = func() { - fmt.Fprintf(os.Stderr, "%s [options] [filename]:\noptions precedence: default < config file < environment variables < command line\n", os.Args[0]) - flag.PrintDefaults() - }*/ - - flag.IntVar(&VmType, "vm", 0, "Virtual Machine type: 0-1: standard, debug") - flag.StringVar(&Identifier, "id", "", "Custom client identifier") - flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use") - flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file (db)") - flag.StringVar(&OutboundPort, "port", "30303", "listening port") - flag.StringVar(&NatType, "nat", "", "NAT support (UPNP|PMP) (none)") - flag.StringVar(&PMPGateway, "pmp", "", "Gateway IP for PMP") - flag.IntVar(&MaxPeer, "maxpeer", 30, "maximum desired peers") - flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on") - flag.BoolVar(&StartRpc, "rpc", false, "start rpc server") - flag.BoolVar(&StartWebSockets, "ws", false, "start websocket server") - flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)") - flag.BoolVar(&UseSeed, "seed", true, "seed peers") - flag.BoolVar(&SHH, "shh", true, "whisper protocol (on)") - flag.BoolVar(&Dial, "dial", true, "dial out connections (on)") - flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") - flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)") - flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given") - flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)") - flag.StringVar(&Datadir, "datadir", "", "specifies the datadir to use") - flag.StringVar(&ConfigFile, "conf", "", "config file") - flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)") - flag.IntVar(&LogLevel, "loglevel", 0, "loglevel: 0-5: silent,error,warn,info,debug,debug detail)") - flag.BoolVar(&DiffTool, "difftool", false, "creates output for diff'ing. Sets LogLevel=0") - flag.StringVar(&DiffType, "diff", "all", "sets the level of diff output [vm, all]. Has no effect if difftool=false") - flag.BoolVar(&ShowGenesis, "genesis", false, "Dump the genesis block") - flag.StringVar(&ImportChain, "chain", "", "Imports given chain") - - flag.BoolVar(&Dump, "dump", false, "output the ethereum state in JSON format. Sub args [number, hash]") - flag.StringVar(&DumpHash, "hash", "", "specify arg in hex") - flag.IntVar(&DumpNumber, "number", -1, "specify arg in number") - - /* flag.BoolVar(&StartMining, "mine", false, "start dagger mining") - flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console") - flag.BoolVar(&PrintVersion, "version", false, "prints version number")*/ - - flag.Parse() - -} - func TestNotice(t *testing.T) { - Init() - - utils.InitConfig(VmType, ConfigFile, Datadir, "ETH") - - ethereum, _ := eth.New(ð.Config{ - Name: ClientIdentifier, - Version: Version, - KeyStore: KeyStore, - DataDir: Datadir, - LogFile: LogFile, - LogLevel: LogLevel, - Identifier: Identifier, - MaxPeers: MaxPeer, - Port: OutboundPort, - NATType: PMPGateway, - PMPGateway: PMPGateway, - KeyRing: KeyRing, - Shh: SHH, - Dial: Dial, - }) - - ns, err := NewNATSpec(ethereum, ` + ns, err := NewNATSpec(` { "jsonrpc": "2.0", "method": "eth_call",