Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
08d396fd
Commit
08d396fd
authored
Mar 10, 2015
by
Jeffrey Wilcke
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #437 from ethersphere/poc9/natspec
[WIP] Poc9/natspec
parents
0d64163f
0743d68d
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
150 additions
and
103 deletions
+150
-103
natspec.go
ethutil/natspec/natspec.go
+28
-30
natspec_js.go
ethutil/natspec/natspec_js.go
+47
-44
natspec_test.go
ethutil/natspec/natspec_test.go
+75
-29
No files found.
ethutil/natspec/natspec.go
View file @
08d396fd
package
natspec
import
(
"fmt"
"github.com/obscuren/otto"
"io/ioutil"
)
type
NatSpec
struct
{
jsvm
*
otto
.
Otto
}
func
NewNATSpec
(
transaction
string
)
(
self
*
NatSpec
,
err
error
)
{
// TODO: should initialise with abi and userdoc jsons
func
New
()
(
self
*
NatSpec
,
err
error
)
{
self
=
new
(
NatSpec
)
self
.
jsvm
=
otto
.
New
()
code
,
err
:=
ioutil
.
ReadFile
(
"natspec.js"
)
if
err
!=
nil
{
return
}
_
,
err
=
self
.
jsvm
.
Run
(
string
(
code
)
)
_
,
err
=
self
.
jsvm
.
Run
(
natspecJS
)
if
err
!=
nil
{
return
}
...
...
@@ -27,39 +24,40 @@ func NewNATSpec(transaction string) (self *NatSpec, err error) {
return
}
self
.
jsvm
.
Run
(
"var transaction = "
+
transaction
+
";"
)
return
}
func
(
self
*
NatSpec
)
SetDescription
(
desc
string
)
(
err
error
)
{
_
,
err
=
self
.
jsvm
.
Run
(
"var expression =
\"
"
+
desc
+
"
\"
;"
)
return
}
func
(
self
*
NatSpec
)
SetABI
(
abi
string
)
(
err
error
)
{
_
,
err
=
self
.
jsvm
.
Run
(
"var abi = "
+
abi
+
";"
)
return
}
func
(
self
*
NatSpec
)
SetMethod
(
method
string
)
(
err
error
)
{
func
(
self
*
NatSpec
)
Notice
(
transaction
,
abi
,
method
,
expression
string
)
(
string
,
error
)
{
var
err
error
if
_
,
err
=
self
.
jsvm
.
Run
(
"var transaction = "
+
transaction
+
";"
);
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"natspec.js error setting transaction: %v"
,
err
)
}
_
,
err
=
self
.
jsvm
.
Run
(
"var method = '"
+
method
+
"';"
)
return
if
_
,
err
=
self
.
jsvm
.
Run
(
"var abi = "
+
abi
+
";"
);
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"natspec.js error setting abi: %v"
,
err
)
}
}
if
_
,
err
=
self
.
jsvm
.
Run
(
"var method = '"
+
method
+
"';"
);
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"natspec.js error setting method: %v"
,
err
)
}
func
(
self
*
NatSpec
)
Parse
()
string
{
if
_
,
err
=
self
.
jsvm
.
Run
(
"var expression =
\"
"
+
expression
+
"
\"
;"
);
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"natspec.js error setting expression: %v"
,
err
)
}
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
()
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
)
}
return
value
.
String
()
if
len
(
value
.
String
())
==
0
{
return
""
,
fmt
.
Errorf
(
"natspec.js error evaluating expression"
)
}
return
value
.
String
(),
nil
}
ethutil/natspec/natspec
.js
→
ethutil/natspec/natspec
_js.go
View file @
08d396fd
require
=
(
function
e
(
t
,
n
,
r
){
function
s
(
o
,
u
){
if
(
!
n
[
o
]){
if
(
!
t
[
o
]){
var
a
=
typeof
require
==
"function"
&&
require
;
if
(
!
u
&&
a
)
return
a
(
o
,
!
0
);
if
(
i
)
return
i
(
o
,
!
0
);
var
f
=
new
Error
(
"Cannot find module '"
+
o
+
"'"
);
throw
f
.
code
=
"MODULE_NOT_FOUND"
,
f
}
var
l
=
n
[
o
]
=
{
exports
:{}};
t
[
o
][
0
].
call
(
l
.
exports
,
function
(
e
){
var
n
=
t
[
o
][
1
][
e
];
return
s
(
n
?
n
:
e
)},
l
,
l
.
exports
,
e
,
t
,
n
,
r
)}
return
n
[
o
].
exports
}
var
i
=
typeof
require
==
"function"
&&
require
;
for
(
var
o
=
0
;
o
<
r
.
length
;
o
++
)
s
(
r
[
o
]);
return
s
})({
1
:[
function
(
require
,
module
,
exports
){
package
natspec
const
natspecJS
=
`require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
},{}],2:[function(require,module,exports){
// shim for using process in browser
...
...
@@ -291,26 +293,26 @@ if (process.env.NODE_ENV !== 'build') {
var BigNumber = require('bignumber.js'); // jshint ignore:line
}
var
ETH_UNITS
=
[
'wei'
,
'Kwei'
,
'Mwei'
,
'Gwei'
,
'szabo'
,
'finney'
,
'ether'
,
'grand'
,
'Mether'
,
'Gether'
,
'Tether'
,
'Pether'
,
'Eether'
,
'Zether'
,
'Yether'
,
'Nether'
,
'Dether'
,
'Vether'
,
'Uether'
var ETH_UNITS = [
'wei',
'Kwei',
'Mwei',
'Gwei',
'szabo',
'finney',
'ether',
'grand',
'Mether',
'Gether',
'Tether',
'Pether',
'Eether',
'Zether',
'Yether',
'Nether',
'Dether',
'Vether',
'Uether'
];
module.exports = {
...
...
@@ -375,7 +377,7 @@ var formatInputInt = function (value) {
BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);
value = value.round();
if
(
value
.
lessThan
(
0
))
if (value.lessThan(0))
value = new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(value).plus(1);
value = value.toString(16);
}
...
...
@@ -404,7 +406,7 @@ var formatInputBool = function (value) {
/// Values are multiplied by 2^m and encoded as integers
/// @returns byte representation of real
var formatInputReal = function (value) {
return
formatInputInt
(
new
BigNumber
(
value
).
times
(
new
BigNumber
(
2
).
pow
(
128
)));
return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128)));
};
...
...
@@ -436,12 +438,12 @@ var formatOutputUInt = function (value) {
/// @returns input bytes formatted to real
var formatOutputReal = function (value) {
return
formatOutputInt
(
value
).
dividedBy
(
new
BigNumber
(
2
).
pow
(
128
));
return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128));
};
/// @returns input bytes formatted to ureal
var formatOutputUReal = function (value) {
return
formatOutputUInt
(
value
).
dividedBy
(
new
BigNumber
(
2
).
pow
(
128
));
return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128));
};
/// @returns right-aligned input bytes formatted to hex
...
...
@@ -524,14 +526,14 @@ var namedType = function (name) {
};
/// Setups input formatters for solidity types
/// @returns an array of input formatters
/// @returns an array of input formatters
var inputTypes = function () {
return [
{ type: prefixedType('uint'), format: f.formatInputInt },
{ type: prefixedType('int'), format: f.formatInputInt },
{ type: prefixedType('hash'), format: f.formatInputInt },
{
type
:
prefixedType
(
'string'
),
format
:
f
.
formatInputString
},
{ type: prefixedType('string'), format: f.formatInputString },
{ type: prefixedType('real'), format: f.formatInputReal },
{ type: prefixedType('ureal'), format: f.formatInputReal },
{ type: namedType('address'), format: f.formatInputInt },
...
...
@@ -620,7 +622,7 @@ var toAscii = function(hex) {
return str;
};
var toHex = function(str) {
var hex = "";
for(var i = 0; i < str.length; i++) {
...
...
@@ -642,7 +644,7 @@ var fromAscii = function(str, pad) {
/// @returns display name for function/event eg. multiply(uint256) -> multiply
var extractDisplayName = function (name) {
var
length
=
name
.
indexOf
(
'('
);
var length = name.indexOf('(');
return length !== -1 ? name.substr(0, length) : name;
};
...
...
@@ -657,8 +659,8 @@ var extractTypeName = function (name) {
/// @returns abi array with filtered objects of type 'function'
var filterFunctions = function (json) {
return json.filter(function (current) {
return
current
.
type
===
'function'
;
});
return current.type === 'function';
});
};
/// Filters all events form input abi
...
...
@@ -3404,7 +3406,7 @@ module.exports = {
* @date 2015
*/
var
abi
=
require
(
'./node_modules/ethereum.js/lib/abi.js'
);
var abi = require('./node_modules/ethereum.js/lib/abi.js');
/**
* This object should be used to evaluate natspec expression
...
...
@@ -3418,7 +3420,7 @@ var natspec = (function () {
context[key] = obj[key];
});
}
/// generate codes, which will be evaluated
var generateCode = function (obj) {
return Object.keys(obj).reduce(function (acc, key) {
...
...
@@ -3440,20 +3442,20 @@ var natspec = (function () {
/// @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
));
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 expression
var mapExpressionsToEvaluate = function (expression, cb) {
var evaluatedExpression = "";
// match everything in
`` quotes
var
pattern
=
/
\`
(?:\\
.|
[^
`
\\])
*
\
`
/gim
// match everything in
backtick
var pattern = /\`
+
"`"
+
`(?:\\.|[^`
+
"`"
+
`\\])*\`
+
"`"
+
`/gim
var match;
var lastIndex = 0;
while ((match = pattern.exec(expression)) !== null) {
...
...
@@ -3464,9 +3466,9 @@ var natspec = (function () {
evaluatedExpression += evaluatedPart;
lastIndex = pattern.lastIndex;
}
evaluatedExpression += expression.slice(lastIndex);
return evaluatedExpression;
};
...
...
@@ -3478,11 +3480,11 @@ var natspec = (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
);
var params = getMethodInputParams(method, call.transaction);
copyToContext(params, context);
}
catch (err) {
...
...
@@ -3498,7 +3500,7 @@ var natspec = (function () {
return fn(context).toString();
}
catch (err) {
return
'undefined'
;
return 'undefined';
}
});
...
...
@@ -3511,7 +3513,8 @@ var natspec = (function () {
})();
module
.
exports
=
natspec
;
module.exports = natspec;
},{"./node_modules/ethereum.js/lib/abi.js":3}]},{},[]);
`
ethutil/natspec/natspec_test.go
View file @
08d396fd
...
...
@@ -6,41 +6,48 @@ import (
func
TestNotice
(
t
*
testing
.
T
)
{
ns
,
err
:=
NewNATSpec
(
`
tx
:=
`
{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [{
"to": "0x8521742d3f456bd237e312d6e30724960f72517a",
"data": "0xc6888fa1000000000000000000000000000000000000000000000000000000000000007a"
}],
"id": 6
}
`
)
"jsonrpc": "2.0",
"method": "eth_call",
"params": [{
"to": "0x8521742d3f456bd237e312d6e30724960f72517a",
"data": "0xc6888fa1000000000000000000000000000000000000000000000000000000000000007a"
}],
"id": 6
}
`
abi
:=
`
[{
"name": "multiply",
"constant": false,
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
}],
"outputs": [{
"name": "d",
"type": "uint256"
}]
}]
`
desc
:=
"Will multiply `a` by 7 and return `a * 7`."
method
:=
"multiply"
ns
,
err
:=
New
()
if
err
!=
nil
{
t
.
Errorf
(
"NewNATSpec error %v"
,
err
)
}
ns
.
SetABI
(
`
[{
"name": "multiply",
"constant": false,
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
}],
"outputs": [{
"name": "d",
"type": "uint256"
}]
}]
`
)
ns
.
SetDescription
(
"Will multiply `a` by 7 and return `a * 7`."
)
ns
.
SetMethod
(
"multiply"
)
notice
:=
ns
.
Parse
()
notice
,
err
:=
ns
.
Notice
(
tx
,
abi
,
method
,
desc
)
if
err
!=
nil
{
t
.
Errorf
(
"expected no error got %v"
,
err
)
}
expected
:=
"Will multiply 122 by 7 and return 854."
if
notice
!=
expected
{
...
...
@@ -48,4 +55,43 @@ func TestNotice(t *testing.T) {
}
else
{
t
.
Logf
(
"returned notice
\"
%v
\"
"
,
notice
)
}
notice
,
err
=
ns
.
Notice
(
tx
,
abi
,
method
,
"Will multiply 122 by
\"
7
\"
and return 854."
)
expected
=
"natspec.js error setting expression: (anonymous): Line 1:41 Unexpected number"
if
err
==
nil
{
t
.
Errorf
(
"expected error, got nothing (notice: '%v')"
,
err
,
notice
)
}
else
{
if
err
.
Error
()
!=
expected
{
t
.
Errorf
(
"expected error '%s' got '%v' (notice: '%v')"
,
expected
,
err
,
notice
)
}
}
// https://github.com/ethereum/natspec.js/issues/1
// badDesc := "Will multiply `e` by 7 and return `a * 7`."
// notice, err = ns.Notice(tx, abi, method, badDesc)
// expected = "natspec.js error evaluating expression: wrong input param in expression ''"
// if err == nil {
// t.Errorf("expected error, got nothing (notice: '%v')", notice)
// } else {
// if err.Error() != expected {
// t.Errorf("expected error '%s' got '%v' (notice: '%v')", expected, err, notice)
// }
// }
notice
,
err
=
ns
.
Notice
(
tx
,
abi
,
"missing_method"
,
desc
)
expected
=
"natspec.js error evaluating expression: wrong input params in expression 'Will multiply `a` by 7 and return `a * 7`.'"
if
err
==
nil
{
t
.
Errorf
(
"expected error, got nothing (notice: '%v')"
,
notice
)
}
else
{
if
err
.
Error
()
!=
expected
{
t
.
Errorf
(
"expected error '%s' got '%v' (notice: '%v')"
,
expected
,
err
,
notice
)
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment