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
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()
}

View File

@ -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}]},{},[]);

View File

@ -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(&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, `
ns, err := NewNATSpec(`
{
"jsonrpc": "2.0",
"method": "eth_call",