Browse Source

Merge pull request #965 from debris/libnatspec

natspec separated to it's own module. tests
cl-refactor
Gav Wood 10 years ago
parent
commit
0ed0e86b58
  1. 1
      CMakeLists.txt
  2. 1
      alethzero/CMakeLists.txt
  3. 30
      alethzero/OurWebThreeStubServer.cpp
  4. 16
      alethzero/OurWebThreeStubServer.h
  5. 1
      libjsqrc/js.qrc
  6. 35
      libnatspec/CMakeLists.txt
  7. 59
      libnatspec/NatspecExpressionEvaluator.cpp
  8. 49
      libnatspec/NatspecExpressionEvaluator.h
  9. 69
      libnatspec/natspec.js
  10. 5
      libnatspec/natspec.qrc
  11. 1
      test/CMakeLists.txt
  12. 112
      test/natspec.cpp

1
CMakeLists.txt

@ -168,6 +168,7 @@ endif ()
if (NOT HEADLESS) if (NOT HEADLESS)
add_subdirectory(libnatspec)
add_subdirectory(libjsqrc) add_subdirectory(libjsqrc)
add_subdirectory(libqwebthree) add_subdirectory(libqwebthree)
add_subdirectory(alethzero) add_subdirectory(alethzero)

1
alethzero/CMakeLists.txt

@ -49,6 +49,7 @@ target_link_libraries(${EXECUTABLE} evmcore)
target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} web3jsonrpc) target_link_libraries(${EXECUTABLE} web3jsonrpc)
target_link_libraries(${EXECUTABLE} jsqrc) target_link_libraries(${EXECUTABLE} jsqrc)
target_link_libraries(${EXECUTABLE} natspec)
# eth_install_executable is defined in cmake/EthExecutableHelper.cmake # eth_install_executable is defined in cmake/EthExecutableHelper.cmake
eth_install_executable(${EXECUTABLE}) eth_install_executable(${EXECUTABLE})

30
alethzero/OurWebThreeStubServer.cpp

@ -24,6 +24,7 @@
#include <QMessageBox> #include <QMessageBox>
#include <QAbstractButton> #include <QAbstractButton>
#include <libwebthree/WebThree.h> #include <libwebthree/WebThree.h>
#include <libnatspec/NatspecExpressionEvaluator.h>
#include "MainWin.h" #include "MainWin.h"
@ -84,36 +85,9 @@ bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t)
return showAuthenticationPopup("Unverified Pending Transaction", return showAuthenticationPopup("Unverified Pending Transaction",
"An undocumented transaction is about to be executed."); "An undocumented transaction is about to be executed.");
QNatspecExpressionEvaluator evaluator(this, m_main); NatspecExpressionEvaluator evaluator;
userNotice = evaluator.evalExpression(QString::fromStdString(userNotice)).toStdString(); userNotice = evaluator.evalExpression(QString::fromStdString(userNotice)).toStdString();
// otherwise it's a transaction to a contract for which we have the natspec // otherwise it's a transaction to a contract for which we have the natspec
return showAuthenticationPopup("Pending Transaction", userNotice); return showAuthenticationPopup("Pending Transaction", userNotice);
} }
QNatspecExpressionEvaluator::QNatspecExpressionEvaluator(OurWebThreeStubServer* _server, Main* _main)
: m_server(_server), m_main(_main)
{}
QNatspecExpressionEvaluator::~QNatspecExpressionEvaluator()
{}
QString QNatspecExpressionEvaluator::evalExpression(QString const& _expression) const
{
// load natspec.js only when we need it for natspec evaluation
m_main->evalRaw(contentsOfQResource(":/js/natspec.js"));
QVariant result = m_main->evalRaw("evaluateExpression('" + _expression + "')");
if (result.type() == QVariant::Invalid)
{
cerr << "Could not evaluate natspec expression: \"" << _expression.toStdString() << "\"" << endl;
// return the expression unevaluated
return _expression;
}
return result.toString();
}

16
alethzero/OurWebThreeStubServer.h

@ -47,19 +47,3 @@ private:
dev::WebThreeDirect* m_web3; dev::WebThreeDirect* m_web3;
Main* m_main; Main* m_main;
}; };
class QNatspecExpressionEvaluator: public QObject
{
Q_OBJECT
public:
QNatspecExpressionEvaluator(OurWebThreeStubServer* _server, Main* _main);
virtual ~QNatspecExpressionEvaluator();
QString evalExpression(QString const& _expression) const;
private:
OurWebThreeStubServer* m_server;
Main* m_main;
};

1
libjsqrc/js.qrc

@ -3,6 +3,5 @@
<file>bignumber.min.js</file> <file>bignumber.min.js</file>
<file>setup.js</file> <file>setup.js</file>
<file alias="webthree.js">ethereumjs/dist/ethereum.js</file> <file alias="webthree.js">ethereumjs/dist/ethereum.js</file>
<file>natspec.js</file>
</qresource> </qresource>
</RCC> </RCC>

35
libnatspec/CMakeLists.txt

@ -0,0 +1,35 @@
cmake_policy(SET CMP0015 NEW)
# let cmake autolink dependencies on windows
cmake_policy(SET CMP0020 NEW)
# this policy was introduced in cmake 3.0
# remove if, once 3.0 will be used on unix
if (${CMAKE_MAJOR_VERSION} GREATER 2)
# old policy do not use MACOSX_RPATH
cmake_policy(SET CMP0042 OLD)
cmake_policy(SET CMP0043 OLD)
endif()
set(CMAKE_AUTOMOC OFF)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
aux_source_directory(. SRC_LIST)
include_directories(..)
set(EXECUTABLE natspec)
file(GLOB HEADERS "*.h")
qt5_add_resources(NATSPECQRC natspec.qrc)
if (ETH_STATIC)
add_library(${EXECUTABLE} STATIC ${RESOURCE_ADDED} ${SRC_LIST} ${HEADERS} ${NATSPECQRC})
else()
add_library(${EXECUTABLE} SHARED ${RESOURCE_ADDED} ${SRC_LIST} ${HEADERS} ${NATSPECQRC})
endif()
target_link_libraries(${EXECUTABLE} Qt5::Core)
target_link_libraries(${EXECUTABLE} Qt5::Qml)
target_link_libraries(${EXECUTABLE} devcore)
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib )
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} )

59
libnatspec/NatspecExpressionEvaluator.cpp

@ -0,0 +1,59 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file NatspecExpressionEvaluator.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h>
#include "NatspecExpressionEvaluator.h"
using namespace std;
using namespace dev;
static QString contentsOfQResource(string const& _res)
{
QFile file(QString::fromStdString(_res));
if (!file.open(QFile::ReadOnly))
BOOST_THROW_EXCEPTION(FileError());
QTextStream in(&file);
return in.readAll();
}
NatspecExpressionEvaluator::NatspecExpressionEvaluator(QString const& _abi, QString const& _method, QString const& _params)
{
Q_INIT_RESOURCE(natspec);
QJSValue result = m_engine.evaluate(contentsOfQResource(":/natspec/natspec.js"));
if (result.isError())
BOOST_THROW_EXCEPTION(FileError());
m_engine.evaluate("globals.abi = " + _abi);
m_engine.evaluate("globals.method = " + _method);
m_engine.evaluate("globals.params = " + _params);
}
QString NatspecExpressionEvaluator::evalExpression(QString const& _expression)
{
QJSValue result = m_engine.evaluate("evaluateExpression(\"" + _expression + "\")");
if (result.isError())
{
cerr << "Could not evaluate expression: \"" << _expression.toStdString() << "\"" << endl;
return _expression;
}
return result.toString();
}

49
libnatspec/NatspecExpressionEvaluator.h

@ -0,0 +1,49 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file NatspecExpressionEvaluator.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <QtCore/QObject>
#include <QtCore/QtCore>
#include <QtQml/QJSEngine>
/**
* Should be used to evaluate natspec expression.
* @see test/natspec.cpp for natspec expression examples
*/
class NatspecExpressionEvaluator
{
public:
/// Construct natspec expression evaluator
/// @params abi - contract's abi in json format, passed as string
/// @params method - name of the contract's method for which we evaluate the natspec.
/// If we want to use raw string, it should be passed with quotation marks eg. "\"helloWorld\""
/// If we pass string "helloWorld", the value of the object with name "helloWorld" will be used
/// @params params - array of method input params, passed as string, objects in array should be
/// javascript valid objects
NatspecExpressionEvaluator(QString const& _abi = "[]", QString const& _method = "", QString const& _params = "[]");
/// Should be called to evaluate natspec expression
/// @params expression - natspec expression
/// @returns evaluated natspec expression if it was valid, otherwise original expression
QString evalExpression(QString const& _expression);
private:
QJSEngine m_engine;
};

69
libjsqrc/natspec.js → libnatspec/natspec.js

@ -2,13 +2,19 @@
/** /**
* This plugin exposes 'evaluateExpression' method which should be used * This plugin exposes 'evaluateExpression' method which should be used
* to evaluate natspec description * to evaluate natspec description
* It should be reloaded each time we want to evaluate set of expressions
* Just because of security reasons
* TODO: make use of sync api (once it's finished) and remove unnecessary
* code from 'getContractMethods'
* TODO: unify method signature creation with abi.js (and make a separate method from it)
*/ */
/// Object which should be used by NatspecExpressionEvaluator
/// abi - abi of the contract that will be used
/// method - name of the method that is called
/// params - input params of the method that will be called
var globals = {
abi: [],
method: "",
params: []
};
/// Helper method
/// Should be called to copy values from object to global context /// Should be called to copy values from object to global context
var copyToContext = function (obj, context) { var copyToContext = function (obj, context) {
var keys = Object.keys(obj); var keys = Object.keys(obj);
@ -17,32 +23,38 @@ var copyToContext = function (obj, context) {
}); });
} }
/// Helper method
/// Should be called to get method with given name from the abi
/// @param contract's abi
/// @param name of the method that we are looking for
var getMethodWithName = function(abi, name) {
for (var i = 0; i < abi.length; i++) {
if (abi[i].name === name) {
return abi[i];
}
}
//console.warn('could not find method with name: ' + name);
return undefined;
};
/// Function called to get all contract's storage values /// Function called to get all contract's storage values
/// @returns hashmap with contract properties which are used /// @returns hashmap with contract properties which are used
/// TODO: check if this function will be used
var getContractProperties = function (address, abi) { var getContractProperties = function (address, abi) {
return {}; return {};
}; };
/// Function called to get all contract's methods /// Function called to get all contract's methods
/// @returns hashmap with used contract's methods /// @returns hashmap with used contract's methods
/// TODO: check if this function will be used
var getContractMethods = function (address, abi) { var getContractMethods = function (address, abi) {
return web3.eth.contract(address, abi); //return web3.eth.contract(address, abi); // commented out web3 usage
}; return {};
var getMethodWithName = function(abi, name) {
for (var i = 0; i < abi.length; i++) {
if (abi[i].name === name) {
return abi[i];
}
}
console.warn('could not find method with name: ' + name);
return undefined;
}; };
/// 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 getContractInputParams = function (abi, methodName, params) { var getMethodInputParams = function (method, params) {
var method = getMethodWithName(abi, methodName);
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;
@ -55,18 +67,15 @@ var getContractInputParams = function (abi, methodName, params) {
var evaluateExpression = function (expression) { var evaluateExpression = function (expression) {
var self = this; var self = this;
var abi = web3._currentContractAbi;
var address = web3._currentContractAddress; //var storage = getContractProperties(address, abi);
var methodName = web3._currentContractMethodName; //var methods = getContractMethods(address, abi);
var params = web3._currentContractMethodParams;
var method = getMethodWithName(globals.abi, globals.method);
var storage = getContractProperties(address, abi); if (method) {
var methods = getContractMethods(address, abi); var input = getMethodInputParams(method, globals.params);
var inputParams = getContractInputParams(abi, methodName, params); copyToContext(input, self);
}
copyToContext(storage, self);
copyToContext(methods, self);
copyToContext(inputParams, self);
// TODO: test if it is safe // TODO: test if it is safe
var evaluatedExpression = ""; var evaluatedExpression = "";

5
libnatspec/natspec.qrc

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/natspec">
<file>natspec.js</file>
</qresource>
</RCC>

1
test/CMakeLists.txt

@ -22,6 +22,7 @@ target_link_libraries(testeth ethcore)
target_link_libraries(testeth secp256k1) target_link_libraries(testeth secp256k1)
target_link_libraries(testeth solidity) target_link_libraries(testeth solidity)
target_link_libraries(testeth webthree) target_link_libraries(testeth webthree)
target_link_libraries(testeth natspec)
if (JSONRPC) if (JSONRPC)
target_link_libraries(testeth web3jsonrpc) target_link_libraries(testeth web3jsonrpc)

112
test/natspec.cpp

@ -0,0 +1,112 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file natspec.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <boost/test/unit_test.hpp>
#include <libdevcore/Log.h>
#include <libnatspec/NatspecExpressionEvaluator.h>
using namespace std;
BOOST_AUTO_TEST_SUITE(natspec)
BOOST_AUTO_TEST_CASE(natspec_eval_function_exists)
{
// given
NatspecExpressionEvaluator e;
// when
string result = e.evalExpression("`typeof evaluateExpression`").toStdString();
// then
BOOST_CHECK_EQUAL(result, "function");
}
BOOST_AUTO_TEST_CASE(natspec_js_eval)
{
// given
NatspecExpressionEvaluator e;
// when
string result = e.evalExpression("`1 + 2`").toStdString();
// then
BOOST_CHECK_EQUAL(result, "3");
}
BOOST_AUTO_TEST_CASE(natspec_create_custom_function)
{
// given
NatspecExpressionEvaluator e;
// when
auto x = e.evalExpression("`test = function (x) { return x + 'ok'; }`"); // ommit var, make it global
string result = e.evalExpression("`test(5)`").toStdString();
string result2 = e.evalExpression("`typeof test`").toStdString();
// then
BOOST_CHECK_EQUAL(result, "5ok");
BOOST_CHECK_EQUAL(result2, "function");
}
BOOST_AUTO_TEST_CASE(natspec_js_eval_separated_expressions)
{
// given
NatspecExpressionEvaluator e;
// when
string result = e.evalExpression("`x = 1` + `y = 2` will be equal `x + y`").toStdString();
// then
BOOST_CHECK_EQUAL(result, "1 + 2 will be equal 3");
}
BOOST_AUTO_TEST_CASE(natspec_js_eval_input_params)
{
// given
char const* abi = R"([
{
"name": "f",
"constant": false,
"type": "function",
"inputs": [
{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}
])";
NatspecExpressionEvaluator e(abi, "'f'", "[4]");
// when
string result = e.evalExpression("Will multiply `a` by 7 and return `a * 7`.").toStdString();
// then
BOOST_CHECK_EQUAL(result, "Will multiply 4 by 7 and return 28.");
}
BOOST_AUTO_TEST_CASE(natspec_js_eval_error)
{
// given
NatspecExpressionEvaluator e;
// when
string result = e.evalExpression("`test(`").toStdString();
// then
BOOST_CHECK_EQUAL(result, "`test(`");
}
BOOST_AUTO_TEST_SUITE_END()
Loading…
Cancel
Save