Now using github.com/obscuren/otto, no need for an Ethereum object

(got rid of some messy code in test)
This commit is contained in:
Fefe 2015-03-06 18:54:26 +01:00
parent b67ded9f27
commit e157147253
3 changed files with 62 additions and 207 deletions

View File

@ -1,66 +1,62 @@
package natspec package natspec
import ( import (
// "encoding/json" "github.com/obscuren/otto"
// "fmt"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/javascript"
"io/ioutil" "io/ioutil"
) )
type NatSpec struct { 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 = new(NatSpec)
self.jsre = javascript.NewJSRE(ethereum) self.jsvm = otto.New()
//self.jsre.LoadExtFile("/home/fefe/go-ethereum/ethutil/natspec/natspec.js")
code, err := ioutil.ReadFile("natspec.js") code, err := ioutil.ReadFile("natspec.js")
if err != nil { if err != nil {
return return
} }
_, err = self.jsre.Run(string(code)) _, err = self.jsvm.Run(string(code))
if err != nil { if err != nil {
return return
} }
_, err = self.jsre.Run("var natspec = require('natspec');") _, err = self.jsvm.Run("var natspec = require('natspec');")
if err != nil { if err != nil {
return return
} }
self.jsre.Run("var transaction = " + transaction + ";") self.jsvm.Run("var transaction = " + transaction + ";")
return return
} }
func (self *NatSpec) SetDescription(desc string) (err error) { func (self *NatSpec) SetDescription(desc string) (err error) {
_, err = self.jsre.Run("var expression = \"" + desc + "\";") _, err = self.jsvm.Run("var expression = \"" + desc + "\";")
return return
} }
func (self *NatSpec) SetABI(abi string) (err error) { func (self *NatSpec) SetABI(abi string) (err error) {
_, err = self.jsre.Run("var abi = " + abi + ";") _, err = self.jsvm.Run("var abi = " + abi + ";")
return return
} }
func (self *NatSpec) SetMethod(method string) (err error) { func (self *NatSpec) SetMethod(method string) (err error) {
_, err = self.jsre.Run("var method = '" + method + "';") _, err = self.jsvm.Run("var method = '" + method + "';")
return return
} }
func (self *NatSpec) Parse() string { func (self *NatSpec) Parse() string {
self.jsre.Run("var call = {method: method,abi: abi,transaction: transaction};") self.jsvm.Run("var call = {method: method,abi: abi,transaction: transaction};")
value, err := self.jsre.Run("natspec.evaluateExpression(expression, call);") value, err := self.jsvm.Run("natspec.evaluateExpression(expression, call);")
if err != nil { if err != nil {
return err.Error() return err.Error()
} }

View File

@ -1824,10 +1824,6 @@ module.exports = {
// Handle values that fail the validity test in BigNumber. // 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 () { parseNumeric = (function () {
// var basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i, // var basePrefix = /^(-?)0([xbo])(?=\w[\w.]*$)/i,
var basePrefix = /^(-?)0([xbo])/i, var basePrefix = /^(-?)0([xbo])/i,
@ -1838,7 +1834,6 @@ module.exports = {
whitespaceOrPlus = /^\s*\+[\w.]|^\s+|\s+$/g; whitespaceOrPlus = /^\s*\+[\w.]|^\s+|\s+$/g;
return function ( x, str, num, b ) { return function ( x, str, num, b ) {
var base, var base,
s = num ? str : str.replace( whitespaceOrPlus, '' ); s = num ? str : str.replace( whitespaceOrPlus, '' );
@ -3387,7 +3382,6 @@ module.exports = {
})(this); })(this);
},{"crypto":1}],"natspec":[function(require,module,exports){ },{"crypto":1}],"natspec":[function(require,module,exports){
(function (global){
/* /*
This file is part of natspec.js. This file is part of natspec.js.
@ -3418,31 +3412,18 @@ var abi = require('./node_modules/ethereum.js/lib/abi.js');
*/ */
var natspec = (function () { var natspec = (function () {
/// Helper method /// Helper method
/// Modifications by Zsolt Felfoldi, 15/03/06 /// Should be called to copy values from object to global context
/// 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
var copyToContext = function (obj, context) { var copyToContext = function (obj, context) {
var code = ""; Object.keys(obj).forEach(function (key) {
var keys = Object.keys(obj);
keys.forEach(function (key) {
context[key] = obj[key]; context[key] = obj[key];
code = code + "var "+key+" = context['"+key+"'];\n";
}); });
return code;
} }
/// this function will not be used in 'production' natspec evaluation /// generate codes, which will be evaluated
/// it's only used to enable tests in node environment var generateCode = function (obj) {
/// it copies all functions from current context to nodejs global context return Object.keys(obj).reduce(function (acc, key) {
var copyToNodeGlobal = function (obj) { return acc + "var " + key + " = context['" + key + "'];\n";
if (typeof global === 'undefined') { }, "");
return;
}
copyToContext(obj, global);
}; };
/// Helper method /// Helper method
@ -3455,52 +3436,20 @@ var natspec = (function () {
})[0]; })[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 /// Function called to get all contract method input variables
/// @returns hashmap with all contract's method input variables /// @returns hashmap with all contract's method input variables
var getMethodInputParams = function (method, transaction) { var getMethodInputParams = function (method, transaction) {
// do it with output formatter (cause we have to decode) // do it with output formatter (cause we have to decode)
var params = abi.formatOutput(method.inputs, '0x' + transaction.params[0].data.slice(10)); var params = abi.formatOutput(method.inputs, '0x' + transaction.params[0].data.slice(10));
return method.inputs.reduce(function (acc, current, index) { return method.inputs.reduce(function (acc, current, index) {
acc[current.name] = params[index]; acc[current.name] = params[index];
return acc; return acc;
}, {}); }, {});
}; };
/// Should be called to evaluate single expression /// Should be called to evaluate expression
/// Is internally using javascript's 'eval' method var mapExpressionsToEvaluate = function (expression, cb) {
/// @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);
var evaluatedExpression = ""; var evaluatedExpression = "";
// match everything in `` quotes // match everything in `` quotes
@ -3509,27 +3458,50 @@ var natspec = (function () {
var lastIndex = 0; var lastIndex = 0;
while ((match = pattern.exec(expression)) !== null) { while ((match = pattern.exec(expression)) !== null) {
var startIndex = pattern.lastIndex - match[0].length; var startIndex = pattern.lastIndex - match[0].length;
var toEval = match[0].slice(1, match[0].length - 1); var toEval = match[0].slice(1, match[0].length - 1);
evaluatedExpression += expression.slice(lastIndex, startIndex); evaluatedExpression += expression.slice(lastIndex, startIndex);
var evaluatedPart = cb(toEval);
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';
}
evaluatedExpression += evaluatedPart; evaluatedExpression += evaluatedPart;
lastIndex = pattern.lastIndex; 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; return evaluatedExpression;
}; };
@ -3542,5 +3514,4 @@ var natspec = (function () {
module.exports = natspec; 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}]},{},[]); },{"./node_modules/ethereum.js/lib/abi.js":3}]},{},[]);

View File

@ -1,124 +1,12 @@
package natspec package natspec
import ( import (
"flag"
// "crypto/rand"
// "io/ioutil"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/eth"
"testing" "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) { func TestNotice(t *testing.T) {
Init() ns, err := NewNATSpec(`
utils.InitConfig(VmType, ConfigFile, Datadir, "ETH")
ethereum, _ := eth.New(&eth.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, `
{ {
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "eth_call", "method": "eth_call",