Browse Source

Merge branch 'develop' of https://github.com/ethereum/cpp-ethereum into mix_tx

cl-refactor
arkpar 10 years ago
parent
commit
db66a7366f
  1. 2
      alethzero/MainWin.cpp
  2. 53
      alethzero/OurWebThreeStubServer.cpp
  3. 11
      alethzero/OurWebThreeStubServer.h
  4. 10
      libdevcore/Common.h
  5. 2
      libdevcore/CommonJS.h
  6. 5
      libethereum/LogFilter.cpp
  7. 966
      libjsqrc/es6-promise-2.0.0.js
  8. 15
      libjsqrc/ethereumjs/README.md
  9. 3
      libjsqrc/ethereumjs/bower.json
  10. 64
      libjsqrc/ethereumjs/dist/ethereum.js
  11. 14
      libjsqrc/ethereumjs/dist/ethereum.js.map
  12. 2
      libjsqrc/ethereumjs/dist/ethereum.min.js
  13. 1
      libjsqrc/ethereumjs/example/balance.html
  14. 5
      libjsqrc/ethereumjs/example/contract.html
  15. 2
      libjsqrc/ethereumjs/example/natspec_contract.html
  16. 18
      libjsqrc/ethereumjs/example/node-app.js
  17. 34
      libjsqrc/ethereumjs/lib/abi.js
  18. 8
      libjsqrc/ethereumjs/lib/contract.js
  19. 6
      libjsqrc/ethereumjs/lib/filter.js
  20. 4
      libjsqrc/ethereumjs/lib/httpsync.js
  21. 18
      libjsqrc/ethereumjs/lib/local.js
  22. 10
      libjsqrc/ethereumjs/lib/providermanager.js
  23. 2
      libjsqrc/ethereumjs/lib/web3.js
  24. 3
      libjsqrc/ethereumjs/package.json
  25. 1
      libjsqrc/ethereumjs/test/db.methods.js
  26. 2
      libjsqrc/ethereumjs/test/eth.methods.js
  27. 2
      libjsqrc/ethereumjs/test/shh.methods.js
  28. 2
      libjsqrc/ethereumjs/test/web3.methods.js
  29. 1
      libjsqrc/js.qrc
  30. 14
      libjsqrc/natspec.js
  31. 4
      libjsqrc/setup.js
  32. 1
      libqwebthree/QWebThree.h
  33. 131
      libsolidity/AST.cpp
  34. 143
      libsolidity/AST.h
  35. 5
      libsolidity/ASTForward.h
  36. 3
      libsolidity/ASTJsonConverter.cpp
  37. 36
      libsolidity/ASTPrinter.cpp
  38. 6
      libsolidity/ASTPrinter.h
  39. 12
      libsolidity/ASTVisitor.h
  40. 56
      libsolidity/AST_accept.h
  41. 35
      libsolidity/CallGraph.cpp
  42. 15
      libsolidity/CallGraph.h
  43. 107
      libsolidity/Compiler.cpp
  44. 16
      libsolidity/Compiler.h
  45. 28
      libsolidity/CompilerContext.cpp
  46. 13
      libsolidity/CompilerContext.h
  47. 3
      libsolidity/CompilerStack.cpp
  48. 75
      libsolidity/ExpressionCompiler.cpp
  49. 21
      libsolidity/NameAndTypeResolver.cpp
  50. 4
      libsolidity/NameAndTypeResolver.h
  51. 79
      libsolidity/Parser.cpp
  52. 4
      libsolidity/Parser.h
  53. 1
      libsolidity/Token.h
  54. 48
      libsolidity/Types.cpp
  55. 26
      libsolidity/Types.h
  56. 6
      libsolidity/grammar.txt
  57. 1
      mix/qml/html/WebContainer.html
  58. 78
      standard.js
  59. 212
      test/SolidityEndToEndTest.cpp
  60. 5
      test/SolidityExpressionCompiler.cpp
  61. 94
      test/SolidityNameAndTypeResolution.cpp
  62. 37
      test/SolidityParser.cpp
  63. 2
      test/whisperTopic.cpp

2
alethzero/MainWin.cpp

@ -1700,7 +1700,7 @@ void Main::on_data_textChanged()
// compiler.addSources(dev::solidity::StandardSources);
m_data = compiler.compile(src, m_enableOptimizer);
solidity = "<h4>Solidity</h4>";
solidity += "<pre>var " + QString::fromStdString(compiler.getContractNames().back()) + " = web3.eth.contractFromAbi(" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + ");</pre>";
solidity += "<pre>var " + QString::fromStdString(compiler.getContractNames().front()) + " = web3.eth.contractFromAbi(" + QString::fromStdString(compiler.getInterface()).replace(QRegExp("\\s"), "").toHtmlEscaped() + ");</pre>";
solidity += "<pre>" + QString::fromStdString(compiler.getSolidityInterface()).toHtmlEscaped() + "</pre>";
solidity += "<pre>" + QString::fromStdString(getFunctionHashes(compiler)).toHtmlEscaped() + "</pre>";
}

53
alethzero/OurWebThreeStubServer.cpp

@ -31,19 +31,19 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3,
std::vector<dev::KeyPair> const& _accounts, Main* main):
OurWebThreeStubServer::OurWebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3,
vector<KeyPair> const& _accounts, Main* main):
WebThreeStubServer(_conn, _web3, _accounts), m_web3(&_web3), m_main(main)
{}
std::string OurWebThreeStubServer::shh_newIdentity()
string OurWebThreeStubServer::shh_newIdentity()
{
dev::KeyPair kp = dev::KeyPair::create();
KeyPair kp = dev::KeyPair::create();
emit onNewId(QString::fromStdString(toJS(kp.sec())));
return toJS(kp.pub());
}
bool OurWebThreeStubServer::showAuthenticationPopup(std::string const& _title, std::string const& _text) const
bool OurWebThreeStubServer::showAuthenticationPopup(string const& _title, string const& _text) const
{
QMessageBox userInput;
userInput.setText(QString::fromStdString(_title));
@ -55,16 +55,31 @@ bool OurWebThreeStubServer::showAuthenticationPopup(std::string const& _title, s
return userInput.exec() == QMessageBox::Ok;
}
bool OurWebThreeStubServer::authenticate(dev::TransactionSkeleton const& _t)
void OurWebThreeStubServer::showBasicValueTransferNotice(u256 _value) const
{
QMessageBox notice;
notice.setText("Basic Value Transfer Transaction");
notice.setInformativeText(QString::fromStdString("Value is " + toString(_value)));
notice.setStandardButtons(QMessageBox::Ok);
notice.exec();
}
bool OurWebThreeStubServer::authenticate(TransactionSkeleton const& _t)
{
h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to);
if (contractCodeHash == EmptySHA3)
// recipient has no code - nothing special about this transaction.
// TODO: show basic message for value transfer.
// contract creation
return true;
std::string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, _t.data);
if (false) //TODO: When is is just a value transfer?
{
// recipient has no code - nothing special about this transaction, show basic value transfer info
showBasicValueTransferNotice(_t.value);
return true;
}
string userNotice = m_main->lookupNatSpecUserNotice(contractCodeHash, _t.data);
if (userNotice.empty())
return showAuthenticationPopup("Unverified Pending Transaction",
"An undocumented transaction is about to be executed.");
@ -83,17 +98,17 @@ QNatspecExpressionEvaluator::QNatspecExpressionEvaluator(OurWebThreeStubServer*
QNatspecExpressionEvaluator::~QNatspecExpressionEvaluator()
{}
QString QNatspecExpressionEvaluator::evalExpression(QString const& _expression)
QString QNatspecExpressionEvaluator::evalExpression(QString const& _expression) const
{
// evaluate the natspec
// load natspec.js only when we need it for natspec evaluation
m_main->evalRaw(contentsOfQResource(":/js/natspec.js"));
// _expression should be in the format like this
// auto toEval = QString::fromStdString("the result of calling multiply(4) is `multiply(4)`");
auto toEval = _expression;
auto result = m_main->evalRaw("evaluateExpression('" + toEval + "')");
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();
}

11
alethzero/OurWebThreeStubServer.h

@ -42,6 +42,7 @@ signals:
private:
bool showAuthenticationPopup(std::string const& _title, std::string const& _text) const;
void showBasicValueTransferNotice(dev::u256 _value) const;
dev::WebThreeDirect* m_web3;
Main* m_main;
@ -51,14 +52,14 @@ private:
class QNatspecExpressionEvaluator: public QObject
{
Q_OBJECT
public:
QNatspecExpressionEvaluator(OurWebThreeStubServer* _server, Main* _main);
virtual ~QNatspecExpressionEvaluator();
QString evalExpression(QString const& _expression);
QString evalExpression(QString const& _expression) const;
private:
OurWebThreeStubServer* m_server;
Main* m_main;
};
};

10
libdevcore/Common.h

@ -36,6 +36,7 @@
#include <map>
#include <vector>
#include <set>
#include <functional>
#pragma warning(push)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
@ -117,6 +118,15 @@ inline unsigned int toLog2(u256 _x)
return ret;
}
/// RAII utility class whose destructor calls a given function.
class ScopeGuard {
public:
ScopeGuard(std::function<void(void)> _f): m_f(_f) {}
~ScopeGuard() { m_f(); }
private:
std::function<void(void)> m_f;
};
// Assertions...
#if defined(_MSC_VER)

2
libdevcore/CommonJS.h

@ -65,7 +65,7 @@ template <unsigned N> FixedHash<N> jsToFixed(std::string const& _s)
{
if (_s.substr(0, 2) == "0x")
// Hex
return FixedHash<N>(_s.substr(2 + std::max<unsigned>(40, _s.size() - 2) - 40));
return FixedHash<N>(_s.substr(2 + std::max<unsigned>(N * 2, _s.size() - 2) - N * 2));
else if (_s.find_first_not_of("0123456789") == std::string::npos)
// Decimal
return (typename FixedHash<N>::Arith)(_s);

5
libethereum/LogFilter.cpp

@ -72,11 +72,12 @@ LogEntries LogFilter::matches(TransactionReceipt const& _m) const
for (LogEntry const& e: _m.log())
{
if (!m_addresses.empty() && !m_addresses.count(e.address))
continue;
goto continue2;
for (auto const& t: m_topics)
if (!std::count(e.topics.begin(), e.topics.end(), t))
continue;
goto continue2;
ret.push_back(e);
continue2:;
}
return ret;
}

966
libjsqrc/es6-promise-2.0.0.js

@ -1,966 +0,0 @@
/*!
* @overview es6-promise - a tiny implementation of Promises/A+.
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
* @license Licensed under MIT license
* See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE
* @version 2.0.0
*/
(function() {
"use strict";
function $$utils$$objectOrFunction(x) {
return typeof x === 'function' || (typeof x === 'object' && x !== null);
}
function $$utils$$isFunction(x) {
return typeof x === 'function';
}
function $$utils$$isMaybeThenable(x) {
return typeof x === 'object' && x !== null;
}
var $$utils$$_isArray;
if (!Array.isArray) {
$$utils$$_isArray = function (x) {
return Object.prototype.toString.call(x) === '[object Array]';
};
} else {
$$utils$$_isArray = Array.isArray;
}
var $$utils$$isArray = $$utils$$_isArray;
var $$utils$$now = Date.now || function() { return new Date().getTime(); };
function $$utils$$F() { }
var $$utils$$o_create = (Object.create || function (o) {
if (arguments.length > 1) {
throw new Error('Second argument not supported');
}
if (typeof o !== 'object') {
throw new TypeError('Argument must be an object');
}
$$utils$$F.prototype = o;
return new $$utils$$F();
});
var $$asap$$len = 0;
var $$asap$$default = function asap(callback, arg) {
$$asap$$queue[$$asap$$len] = callback;
$$asap$$queue[$$asap$$len + 1] = arg;
$$asap$$len += 2;
if ($$asap$$len === 2) {
// If len is 1, that means that we need to schedule an async flush.
// If additional callbacks are queued before the queue is flushed, they
// will be processed by this flush that we are scheduling.
$$asap$$scheduleFlush();
}
};
var $$asap$$browserGlobal = (typeof window !== 'undefined') ? window : {};
var $$asap$$BrowserMutationObserver = $$asap$$browserGlobal.MutationObserver || $$asap$$browserGlobal.WebKitMutationObserver;
// test for web worker but not in IE10
var $$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' &&
typeof importScripts !== 'undefined' &&
typeof MessageChannel !== 'undefined';
// node
function $$asap$$useNextTick() {
return function() {
process.nextTick($$asap$$flush);
};
}
function $$asap$$useMutationObserver() {
var iterations = 0;
var observer = new $$asap$$BrowserMutationObserver($$asap$$flush);
var node = document.createTextNode('');
observer.observe(node, { characterData: true });
return function() {
node.data = (iterations = ++iterations % 2);
};
}
// web worker
function $$asap$$useMessageChannel() {
var channel = new MessageChannel();
channel.port1.onmessage = $$asap$$flush;
return function () {
channel.port2.postMessage(0);
};
}
function $$asap$$useSetTimeout() {
return function() {
setTimeout($$asap$$flush, 1);
};
}
var $$asap$$queue = new Array(1000);
function $$asap$$flush() {
for (var i = 0; i < $$asap$$len; i+=2) {
var callback = $$asap$$queue[i];
var arg = $$asap$$queue[i+1];
callback(arg);
$$asap$$queue[i] = undefined;
$$asap$$queue[i+1] = undefined;
}
$$asap$$len = 0;
}
var $$asap$$scheduleFlush;
// Decide what async method to use to triggering processing of queued callbacks:
if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
$$asap$$scheduleFlush = $$asap$$useNextTick();
} else if ($$asap$$BrowserMutationObserver) {
$$asap$$scheduleFlush = $$asap$$useMutationObserver();
} else if ($$asap$$isWorker) {
$$asap$$scheduleFlush = $$asap$$useMessageChannel();
} else {
$$asap$$scheduleFlush = $$asap$$useSetTimeout();
}
function $$$internal$$noop() {}
var $$$internal$$PENDING = void 0;
var $$$internal$$FULFILLED = 1;
var $$$internal$$REJECTED = 2;
var $$$internal$$GET_THEN_ERROR = new $$$internal$$ErrorObject();
function $$$internal$$selfFullfillment() {
return new TypeError("You cannot resolve a promise with itself");
}
function $$$internal$$cannotReturnOwn() {
return new TypeError('A promises callback cannot return that same promise.')
}
function $$$internal$$getThen(promise) {
try {
return promise.then;
} catch(error) {
$$$internal$$GET_THEN_ERROR.error = error;
return $$$internal$$GET_THEN_ERROR;
}
}
function $$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) {
try {
then.call(value, fulfillmentHandler, rejectionHandler);
} catch(e) {
return e;
}
}
function $$$internal$$handleForeignThenable(promise, thenable, then) {
$$asap$$default(function(promise) {
var sealed = false;
var error = $$$internal$$tryThen(then, thenable, function(value) {
if (sealed) { return; }
sealed = true;
if (thenable !== value) {
$$$internal$$resolve(promise, value);
} else {
$$$internal$$fulfill(promise, value);
}
}, function(reason) {
if (sealed) { return; }
sealed = true;
$$$internal$$reject(promise, reason);
}, 'Settle: ' + (promise._label || ' unknown promise'));
if (!sealed && error) {
sealed = true;
$$$internal$$reject(promise, error);
}
}, promise);
}
function $$$internal$$handleOwnThenable(promise, thenable) {
if (thenable._state === $$$internal$$FULFILLED) {
$$$internal$$fulfill(promise, thenable._result);
} else if (promise._state === $$$internal$$REJECTED) {
$$$internal$$reject(promise, thenable._result);
} else {
$$$internal$$subscribe(thenable, undefined, function(value) {
$$$internal$$resolve(promise, value);
}, function(reason) {
$$$internal$$reject(promise, reason);
});
}
}
function $$$internal$$handleMaybeThenable(promise, maybeThenable) {
if (maybeThenable.constructor === promise.constructor) {
$$$internal$$handleOwnThenable(promise, maybeThenable);
} else {
var then = $$$internal$$getThen(maybeThenable);
if (then === $$$internal$$GET_THEN_ERROR) {
$$$internal$$reject(promise, $$$internal$$GET_THEN_ERROR.error);
} else if (then === undefined) {
$$$internal$$fulfill(promise, maybeThenable);
} else if ($$utils$$isFunction(then)) {
$$$internal$$handleForeignThenable(promise, maybeThenable, then);
} else {
$$$internal$$fulfill(promise, maybeThenable);
}
}
}
function $$$internal$$resolve(promise, value) {
if (promise === value) {
$$$internal$$reject(promise, $$$internal$$selfFullfillment());
} else if ($$utils$$objectOrFunction(value)) {
$$$internal$$handleMaybeThenable(promise, value);
} else {
$$$internal$$fulfill(promise, value);
}
}
function $$$internal$$publishRejection(promise) {
if (promise._onerror) {
promise._onerror(promise._result);
}
$$$internal$$publish(promise);
}
function $$$internal$$fulfill(promise, value) {
if (promise._state !== $$$internal$$PENDING) { return; }
promise._result = value;
promise._state = $$$internal$$FULFILLED;
if (promise._subscribers.length === 0) {
} else {
$$asap$$default($$$internal$$publish, promise);
}
}
function $$$internal$$reject(promise, reason) {
if (promise._state !== $$$internal$$PENDING) { return; }
promise._state = $$$internal$$REJECTED;
promise._result = reason;
$$asap$$default($$$internal$$publishRejection, promise);
}
function $$$internal$$subscribe(parent, child, onFulfillment, onRejection) {
var subscribers = parent._subscribers;
var length = subscribers.length;
parent._onerror = null;
subscribers[length] = child;
subscribers[length + $$$internal$$FULFILLED] = onFulfillment;
subscribers[length + $$$internal$$REJECTED] = onRejection;
if (length === 0 && parent._state) {
$$asap$$default($$$internal$$publish, parent);
}
}
function $$$internal$$publish(promise) {
var subscribers = promise._subscribers;
var settled = promise._state;
if (subscribers.length === 0) { return; }
var child, callback, detail = promise._result;
for (var i = 0; i < subscribers.length; i += 3) {
child = subscribers[i];
callback = subscribers[i + settled];
if (child) {
$$$internal$$invokeCallback(settled, child, callback, detail);
} else {
callback(detail);
}
}
promise._subscribers.length = 0;
}
function $$$internal$$ErrorObject() {
this.error = null;
}
var $$$internal$$TRY_CATCH_ERROR = new $$$internal$$ErrorObject();
function $$$internal$$tryCatch(callback, detail) {
try {
return callback(detail);
} catch(e) {
$$$internal$$TRY_CATCH_ERROR.error = e;
return $$$internal$$TRY_CATCH_ERROR;
}
}
function $$$internal$$invokeCallback(settled, promise, callback, detail) {
var hasCallback = $$utils$$isFunction(callback),
value, error, succeeded, failed;
if (hasCallback) {
value = $$$internal$$tryCatch(callback, detail);
if (value === $$$internal$$TRY_CATCH_ERROR) {
failed = true;
error = value.error;
value = null;
} else {
succeeded = true;
}
if (promise === value) {
$$$internal$$reject(promise, $$$internal$$cannotReturnOwn());
return;
}
} else {
value = detail;
succeeded = true;
}
if (promise._state !== $$$internal$$PENDING) {
// noop
} else if (hasCallback && succeeded) {
$$$internal$$resolve(promise, value);
} else if (failed) {
$$$internal$$reject(promise, error);
} else if (settled === $$$internal$$FULFILLED) {
$$$internal$$fulfill(promise, value);
} else if (settled === $$$internal$$REJECTED) {
$$$internal$$reject(promise, value);
}
}
function $$$internal$$initializePromise(promise, resolver) {
try {
resolver(function resolvePromise(value){
$$$internal$$resolve(promise, value);
}, function rejectPromise(reason) {
$$$internal$$reject(promise, reason);
});
} catch(e) {
$$$internal$$reject(promise, e);
}
}
function $$$enumerator$$makeSettledResult(state, position, value) {
if (state === $$$internal$$FULFILLED) {
return {
state: 'fulfilled',
value: value
};
} else {
return {
state: 'rejected',
reason: value
};
}
}
function $$$enumerator$$Enumerator(Constructor, input, abortOnReject, label) {
this._instanceConstructor = Constructor;
this.promise = new Constructor($$$internal$$noop, label);
this._abortOnReject = abortOnReject;
if (this._validateInput(input)) {
this._input = input;
this.length = input.length;
this._remaining = input.length;
this._init();
if (this.length === 0) {
$$$internal$$fulfill(this.promise, this._result);
} else {
this.length = this.length || 0;
this._enumerate();
if (this._remaining === 0) {
$$$internal$$fulfill(this.promise, this._result);
}
}
} else {
$$$internal$$reject(this.promise, this._validationError());
}
}
$$$enumerator$$Enumerator.prototype._validateInput = function(input) {
return $$utils$$isArray(input);
};
$$$enumerator$$Enumerator.prototype._validationError = function() {
return new Error('Array Methods must be provided an Array');
};
$$$enumerator$$Enumerator.prototype._init = function() {
this._result = new Array(this.length);
};
var $$$enumerator$$default = $$$enumerator$$Enumerator;
$$$enumerator$$Enumerator.prototype._enumerate = function() {
var length = this.length;
var promise = this.promise;
var input = this._input;
for (var i = 0; promise._state === $$$internal$$PENDING && i < length; i++) {
this._eachEntry(input[i], i);
}
};
$$$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) {
var c = this._instanceConstructor;
if ($$utils$$isMaybeThenable(entry)) {
if (entry.constructor === c && entry._state !== $$$internal$$PENDING) {
entry._onerror = null;
this._settledAt(entry._state, i, entry._result);
} else {
this._willSettleAt(c.resolve(entry), i);
}
} else {
this._remaining--;
this._result[i] = this._makeResult($$$internal$$FULFILLED, i, entry);
}
};
$$$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) {
var promise = this.promise;
if (promise._state === $$$internal$$PENDING) {
this._remaining--;
if (this._abortOnReject && state === $$$internal$$REJECTED) {
$$$internal$$reject(promise, value);
} else {
this._result[i] = this._makeResult(state, i, value);
}
}
if (this._remaining === 0) {
$$$internal$$fulfill(promise, this._result);
}
};
$$$enumerator$$Enumerator.prototype._makeResult = function(state, i, value) {
return value;
};
$$$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) {
var enumerator = this;
$$$internal$$subscribe(promise, undefined, function(value) {
enumerator._settledAt($$$internal$$FULFILLED, i, value);
}, function(reason) {
enumerator._settledAt($$$internal$$REJECTED, i, reason);
});
};
var $$promise$all$$default = function all(entries, label) {
return new $$$enumerator$$default(this, entries, true /* abort on reject */, label).promise;
};
var $$promise$race$$default = function race(entries, label) {
/*jshint validthis:true */
var Constructor = this;
var promise = new Constructor($$$internal$$noop, label);
if (!$$utils$$isArray(entries)) {
$$$internal$$reject(promise, new TypeError('You must pass an array to race.'));
return promise;
}
var length = entries.length;
function onFulfillment(value) {
$$$internal$$resolve(promise, value);
}
function onRejection(reason) {
$$$internal$$reject(promise, reason);
}
for (var i = 0; promise._state === $$$internal$$PENDING && i < length; i++) {
$$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection);
}
return promise;
};
var $$promise$resolve$$default = function resolve(object, label) {
/*jshint validthis:true */
var Constructor = this;
if (object && typeof object === 'object' && object.constructor === Constructor) {
return object;
}
var promise = new Constructor($$$internal$$noop, label);
$$$internal$$resolve(promise, object);
return promise;
};
var $$promise$reject$$default = function reject(reason, label) {
/*jshint validthis:true */
var Constructor = this;
var promise = new Constructor($$$internal$$noop, label);
$$$internal$$reject(promise, reason);
return promise;
};
var $$es6$promise$promise$$counter = 0;
function $$es6$promise$promise$$needsResolver() {
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
}
function $$es6$promise$promise$$needsNew() {
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
}
var $$es6$promise$promise$$default = $$es6$promise$promise$$Promise;
/**
Promise objects represent the eventual result of an asynchronous operation. The
primary way of interacting with a promise is through its `then` method, which
registers callbacks to receive either a promises eventual value or the reason
why the promise cannot be fulfilled.
Terminology
-----------
- `promise` is an object or function with a `then` method whose behavior conforms to this specification.
- `thenable` is an object or function that defines a `then` method.
- `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
- `exception` is a value that is thrown using the throw statement.
- `reason` is a value that indicates why a promise was rejected.
- `settled` the final resting state of a promise, fulfilled or rejected.
A promise can be in one of three states: pending, fulfilled, or rejected.
Promises that are fulfilled have a fulfillment value and are in the fulfilled
state. Promises that are rejected have a rejection reason and are in the
rejected state. A fulfillment value is never a thenable.
Promises can also be said to *resolve* a value. If this value is also a
promise, then the original promise's settled state will match the value's
settled state. So a promise that *resolves* a promise that rejects will
itself reject, and a promise that *resolves* a promise that fulfills will
itself fulfill.
Basic Usage:
------------
```js
var promise = new Promise(function(resolve, reject) {
// on success
resolve(value);
// on failure
reject(reason);
});
promise.then(function(value) {
// on fulfillment
}, function(reason) {
// on rejection
});
```
Advanced Usage:
---------------
Promises shine when abstracting away asynchronous interactions such as
`XMLHttpRequest`s.
```js
function getJSON(url) {
return new Promise(function(resolve, reject){
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onreadystatechange = handler;
xhr.responseType = 'json';
xhr.setRequestHeader('Accept', 'application/json');
xhr.send();
function handler() {
if (this.readyState === this.DONE) {
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
}
}
};
});
}
getJSON('/posts.json').then(function(json) {
// on fulfillment
}, function(reason) {
// on rejection
});
```
Unlike callbacks, promises are great composable primitives.
```js
Promise.all([
getJSON('/posts'),
getJSON('/comments')
]).then(function(values){
values[0] // => postsJSON
values[1] // => commentsJSON
return values;
});
```
@class Promise
@param {function} resolver
@param {String} label optional string for labeling the promise.
Useful for tooling.
@constructor
*/
function $$es6$promise$promise$$Promise(resolver, label) {
this._id = $$es6$promise$promise$$counter++;
this._label = label;
this._state = undefined;
this._result = undefined;
this._subscribers = [];
if ($$$internal$$noop !== resolver) {
if (!$$utils$$isFunction(resolver)) {
$$es6$promise$promise$$needsResolver();
}
if (!(this instanceof $$es6$promise$promise$$Promise)) {
$$es6$promise$promise$$needsNew();
}
$$$internal$$initializePromise(this, resolver);
}
}
$$es6$promise$promise$$Promise.all = $$promise$all$$default;
$$es6$promise$promise$$Promise.race = $$promise$race$$default;
$$es6$promise$promise$$Promise.resolve = $$promise$resolve$$default;
$$es6$promise$promise$$Promise.reject = $$promise$reject$$default;
$$es6$promise$promise$$Promise.prototype = {
constructor: $$es6$promise$promise$$Promise,
/**
The primary way of interacting with a promise is through its `then` method,
which registers callbacks to receive either a promise's eventual value or the
reason why the promise cannot be fulfilled.
```js
findUser().then(function(user){
// user is available
}, function(reason){
// user is unavailable, and you are given the reason why
});
```
Chaining
--------
The return value of `then` is itself a promise. This second, 'downstream'
promise is resolved with the return value of the first promise's fulfillment
or rejection handler, or rejected if the handler throws an exception.
```js
findUser().then(function (user) {
return user.name;
}, function (reason) {
return 'default name';
}).then(function (userName) {
// If `findUser` fulfilled, `userName` will be the user's name, otherwise it
// will be `'default name'`
});
findUser().then(function (user) {
throw new Error('Found user, but still unhappy');
}, function (reason) {
throw new Error('`findUser` rejected and we're unhappy');
}).then(function (value) {
// never reached
}, function (reason) {
// if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
// If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
});
```
If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
```js
findUser().then(function (user) {
throw new PedagogicalException('Upstream error');
}).then(function (value) {
// never reached
}).then(function (value) {
// never reached
}, function (reason) {
// The `PedgagocialException` is propagated all the way down to here
});
```
Assimilation
------------
Sometimes the value you want to propagate to a downstream promise can only be
retrieved asynchronously. This can be achieved by returning a promise in the
fulfillment or rejection handler. The downstream promise will then be pending
until the returned promise is settled. This is called *assimilation*.
```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// The user's comments are now available
});
```
If the assimliated promise rejects, then the downstream promise will also reject.
```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// If `findCommentsByAuthor` fulfills, we'll have the value here
}, function (reason) {
// If `findCommentsByAuthor` rejects, we'll have the reason here
});
```
Simple Example
--------------
Synchronous Example
```javascript
var result;
try {
result = findResult();
// success
} catch(reason) {
// failure
}
```
Errback Example
```js
findResult(function(result, err){
if (err) {
// failure
} else {
// success
}
});
```
Promise Example;
```javascript
findResult().then(function(result){
// success
}, function(reason){
// failure
});
```
Advanced Example
--------------
Synchronous Example
```javascript
var author, books;
try {
author = findAuthor();
books = findBooksByAuthor(author);
// success
} catch(reason) {
// failure
}
```
Errback Example
```js
function foundBooks(books) {
}
function failure(reason) {
}
findAuthor(function(author, err){
if (err) {
failure(err);
// failure
} else {
try {
findBoooksByAuthor(author, function(books, err) {
if (err) {
failure(err);
} else {
try {
foundBooks(books);
} catch(reason) {
failure(reason);
}
}
});
} catch(error) {
failure(err);
}
// success
}
});
```
Promise Example;
```javascript
findAuthor().
then(findBooksByAuthor).
then(function(books){
// found books
}).catch(function(reason){
// something went wrong
});
```
@method then
@param {Function} onFulfilled
@param {Function} onRejected
@param {String} label optional string for labeling the promise.
Useful for tooling.
@return {Promise}
*/
then: function(onFulfillment, onRejection, label) {
var parent = this;
var state = parent._state;
if (state === $$$internal$$FULFILLED && !onFulfillment || state === $$$internal$$REJECTED && !onRejection) {
return this;
}
parent._onerror = null;
var child = new this.constructor($$$internal$$noop, label);
var result = parent._result;
if (state) {
var callback = arguments[state - 1];
$$asap$$default(function(){
$$$internal$$invokeCallback(state, child, callback, result);
});
} else {
$$$internal$$subscribe(parent, child, onFulfillment, onRejection);
}
return child;
},
/**
`catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
as the catch block of a try/catch statement.
```js
function findAuthor(){
throw new Error('couldn't find that author');
}
// synchronous
try {
findAuthor();
} catch(reason) {
// something went wrong
}
// async with promises
findAuthor().catch(function(reason){
// something went wrong
});
```
@method catch
@param {Function} onRejection
@param {String} label optional string for labeling the promise.
Useful for tooling.
@return {Promise}
*/
'catch': function(onRejection, label) {
return this.then(null, onRejection, label);
}
};
var $$es6$promise$polyfill$$default = function polyfill() {
var local;
if (typeof global !== 'undefined') {
local = global;
} else if (typeof window !== 'undefined' && window.document) {
local = window;
} else {
local = self;
}
var es6PromiseSupport =
"Promise" in local &&
// Some of these methods are missing from
// Firefox/Chrome experimental implementations
"resolve" in local.Promise &&
"reject" in local.Promise &&
"all" in local.Promise &&
"race" in local.Promise &&
// Older version of the spec had a resolver object
// as the arg rather than a function
(function() {
var resolve;
new local.Promise(function(r) { resolve = r; });
return $$utils$$isFunction(resolve);
}());
if (!es6PromiseSupport) {
local.Promise = $$es6$promise$promise$$default;
}
};
var es6$promise$umd$$ES6Promise = {
Promise: $$es6$promise$promise$$default,
polyfill: $$es6$promise$polyfill$$default
};
/* global define:true module:true window: true */
if (typeof define === 'function' && define['amd']) {
define(function() { return es6$promise$umd$$ES6Promise; });
} else if (typeof module !== 'undefined' && module['exports']) {
module['exports'] = es6$promise$umd$$ES6Promise;
} else if (typeof this !== 'undefined') {
this['ES6Promise'] = es6$promise$umd$$ES6Promise;
}
}).call(this);

15
libjsqrc/ethereumjs/README.md

@ -1,6 +1,6 @@
# Ethereum JavaScript API
This is the Ethereum compatible JavaScript API using `Promise`s
This is the Ethereum compatible [JavaScript API](https://github.com/ethereum/wiki/wiki/JavaScript-API)
which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec. It's available on npm as a node module and also for bower and component as an embeddable js
[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url]
@ -23,7 +23,7 @@ Component
component install ethereum/ethereum.js
* Include `ethereum.min.js` in your html file.
* Include [es6-promise](https://github.com/jakearchibald/es6-promise) or another ES6-Shim if your browser doesn't support ECMAScript 6.
* Include [bignumber.js](https://github.com/MikeMcl/bignumber.js/)
## Usage
Require the library:
@ -37,14 +37,8 @@ Set a provider (QtProvider, WebSocketProvider, HttpRpcProvider)
There you go, now you can use it:
```
web3.eth.coinbase.then(function(result){
console.log(result);
return web3.eth.balanceAt(result);
}).then(function(balance){
console.log(web3.toDecimal(balance));
}).catch(function(err){
console.log(err);
});
var coinbase = web3.eth.coinbase;
var balance = web3.eth.balanceAt(coinbase);
```
@ -99,3 +93,4 @@ ethereum -ws -loglevel=4
[dep-url]: https://david-dm.org/ethereum/ethereum.js
[dep-dev-image]: https://david-dm.org/ethereum/ethereum.js/dev-status.svg
[dep-dev-url]: https://david-dm.org/ethereum/ethereum.js#info=devDependencies

3
libjsqrc/ethereumjs/bower.json

@ -1,11 +1,10 @@
{
"name": "ethereum.js",
"namespace": "ethereum",
"version": "0.0.8",
"version": "0.0.10",
"description": "Ethereum Compatible JavaScript API",
"main": ["./dist/ethereum.js", "./dist/ethereum.min.js"],
"dependencies": {
"es6-promise": "#master",
"bignumber.js": ">=2.0.0"
},
"repository": {

64
libjsqrc/ethereumjs/dist/ethereum.js

@ -56,6 +56,16 @@ var findMethodIndex = function (json, methodName) {
});
};
/// @returns method with given method name
var getMethodWithName = function (json, methodName) {
var index = findMethodIndex(json, methodName);
if (index === -1) {
console.error('method ' + methodName + ' not found in the abi');
return undefined;
}
return json[index];
};
/// @param string string to be padded
/// @param number of characters that result string should have
/// @param sign, by default 0
@ -129,7 +139,7 @@ var formatInputReal = function (value) {
var dynamicTypeBytes = function (type, value) {
// TODO: decide what to do with array of strings
if (arrayType(type) || type == 'string') // only string itself that is dynamic; stringX is static length.
if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.
return formatInputInt(value.length);
return "";
};
@ -159,13 +169,8 @@ var inputTypes = setupInputTypes();
/// @returns bytes representation of input params
var toAbiInput = function (json, methodName, params) {
var bytes = "";
var index = findMethodIndex(json, methodName);
if (index === -1) {
return;
}
var method = json[index];
var method = getMethodWithName(json, methodName);
var padding = ETH_PADDING * 2;
/// first we iterate in search for dynamic
@ -252,7 +257,7 @@ var formatOutputAddress = function (value) {
};
var dynamicBytesLength = function (type) {
if (arrayType(type) || type == 'string') // only string itself that is dynamic; stringX is static length.
if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.
return ETH_PADDING * 2;
return 0;
};
@ -281,16 +286,10 @@ var outputTypes = setupOutputTypes();
/// @param bytes representtion of output
/// @returns array of output params
var fromAbiOutput = function (json, methodName, output) {
var index = findMethodIndex(json, methodName);
if (index === -1) {
return;
}
output = output.slice(2);
var result = [];
var method = json[index];
var method = getMethodWithName(json, methodName);
var padding = ETH_PADDING * 2;
var dynamicPartLength = method.outputs.reduce(function (acc, curr) {
@ -404,7 +403,8 @@ module.exports = {
outputParser: outputParser,
methodSignature: methodSignature,
methodDisplayName: methodDisplayName,
methodTypeName: methodTypeName
methodTypeName: methodTypeName,
getMethodWithName: getMethodWithName
};
@ -464,7 +464,7 @@ var contract = function (address, desc) {
// prototype, so we make it so as a workaround.
if (method.name.indexOf('(') === -1) {
var displayName = method.name;
var typeName = method.inputs.map(function(i){return i.type}).join();
var typeName = method.inputs.map(function(i){return i.type; }).join();
method.name = displayName + '(' + typeName + ')';
}
});
@ -521,6 +521,8 @@ var contract = function (address, desc) {
// TODO: figure out better way to solve this
web3._currentContractAbi = desc;
web3._currentContractAddress = address;
web3._currentContractMethodName = method.name;
web3._currentContractMethodParams = params;
// transactions do not have any output, cause we do not know, when they will be processed
web3.eth.transact(options);
@ -531,9 +533,9 @@ var contract = function (address, desc) {
var ret = outputParser[displayName][typeName](output);
if (collapse)
{
if (ret.length == 1)
if (ret.length === 1)
ret = ret[0];
else if (ret.length == 0)
else if (ret.length === 0)
ret = null;
}
return ret;
@ -603,8 +605,10 @@ Filter.prototype.changed = function(callback) {
/// trigger calling new message from people
Filter.prototype.trigger = function(messages) {
for(var i = 0; i < this.callbacks.length; i++) {
this.callbacks[i].call(this, messages);
for (var i = 0; i < this.callbacks.length; i++) {
for (var j = 0; j < messages; j++) {
this.callbacks[i].call(this, messages[j]);
}
}
};
@ -650,6 +654,10 @@ module.exports = Filter;
* @date 2014
*/
if ("build" !== 'build') {/*
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
*/}
var HttpSyncProvider = function (host) {
this.handlers = [];
this.host = host || 'http://localhost:8080';
@ -746,15 +754,15 @@ var ProviderManager = function() {
result = JSON.parse(result);
// dont call the callback if result is an error, empty array or false
if (result.error || (result.result instanceof Array ? result.result.length === 0 : !result.result)) {
// dont call the callback if result is not an array, or empty one
if (result.error || !(result.result instanceof Array) || result.result.length === 0) {
return;
}
data.callback(result);
data.callback(result.result);
});
}
setTimeout(poll, 12000);
setTimeout(poll, 1000);
};
poll();
};
@ -767,7 +775,7 @@ ProviderManager.prototype.send = function(data) {
if (this.provider === undefined) {
console.error('provider is not set');
return undefined;
return null;
}
//TODO: handle error here?
@ -982,7 +990,7 @@ var shhWatchMethods = function () {
return [
{ name: 'newFilter', call: 'shh_newFilter' },
{ name: 'uninstallFilter', call: 'shh_uninstallFilter' },
{ name: 'getMessage', call: 'shh_getMessages' }
{ name: 'getMessages', call: 'shh_getMessages' }
];
};

14
libjsqrc/ethereumjs/dist/ethereum.js.map

File diff suppressed because one or more lines are too long

2
libjsqrc/ethereumjs/dist/ethereum.min.js

File diff suppressed because one or more lines are too long

1
libjsqrc/ethereumjs/example/balance.html

@ -2,7 +2,6 @@
<html>
<head>
<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript">

5
libjsqrc/ethereumjs/example/contract.html

@ -2,7 +2,6 @@
<html>
<head>
<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript">
@ -53,8 +52,8 @@
var param = parseInt(document.getElementById('value').value);
// call the contract
var res = contract.multiply(param);
document.getElementById('result').innerText = res[0];
var res = contract.call().multiply(param);
document.getElementById('result').innerText = res.toString(10);
}
</script>

2
libjsqrc/ethereumjs/example/natspec_contract.html

@ -2,10 +2,8 @@
<html>
<head>
<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
<script type="text/javascript" src="js/bignumber.js/bignumber.min.js"></script>
<script type="text/javascript" src="../dist/ethereum.js"></script>
<script type="text/javascript" src="../../natspec.js"></script>
<script type="text/javascript">
var web3 = require('web3');

18
libjsqrc/ethereumjs/example/node-app.js

@ -1,16 +1,12 @@
#!/usr/bin/env node
require('es6-promise').polyfill();
var web3 = require("../index.js");
web3.setProvider(new web3.providers.HttpRpcProvider('http://localhost:8080'));
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8080'));
var coinbase = web3.eth.coinbase;
console.log(coinbase);
var balance = web3.eth.balanceAt(coinbase);
console.log(balance);
web3.eth.coinbase.then(function(result){
console.log(result);
return web3.eth.balanceAt(result);
}).then(function(balance){
console.log(web3.toDecimal(balance));
}).catch(function(err){
console.log(err);
});

34
libjsqrc/ethereumjs/lib/abi.js

@ -55,6 +55,16 @@ var findMethodIndex = function (json, methodName) {
});
};
/// @returns method with given method name
var getMethodWithName = function (json, methodName) {
var index = findMethodIndex(json, methodName);
if (index === -1) {
console.error('method ' + methodName + ' not found in the abi');
return undefined;
}
return json[index];
};
/// @param string string to be padded
/// @param number of characters that result string should have
/// @param sign, by default 0
@ -128,7 +138,7 @@ var formatInputReal = function (value) {
var dynamicTypeBytes = function (type, value) {
// TODO: decide what to do with array of strings
if (arrayType(type) || type == 'string') // only string itself that is dynamic; stringX is static length.
if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.
return formatInputInt(value.length);
return "";
};
@ -158,13 +168,8 @@ var inputTypes = setupInputTypes();
/// @returns bytes representation of input params
var toAbiInput = function (json, methodName, params) {
var bytes = "";
var index = findMethodIndex(json, methodName);
if (index === -1) {
return;
}
var method = json[index];
var method = getMethodWithName(json, methodName);
var padding = ETH_PADDING * 2;
/// first we iterate in search for dynamic
@ -251,7 +256,7 @@ var formatOutputAddress = function (value) {
};
var dynamicBytesLength = function (type) {
if (arrayType(type) || type == 'string') // only string itself that is dynamic; stringX is static length.
if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.
return ETH_PADDING * 2;
return 0;
};
@ -280,16 +285,10 @@ var outputTypes = setupOutputTypes();
/// @param bytes representtion of output
/// @returns array of output params
var fromAbiOutput = function (json, methodName, output) {
var index = findMethodIndex(json, methodName);
if (index === -1) {
return;
}
output = output.slice(2);
var result = [];
var method = json[index];
var method = getMethodWithName(json, methodName);
var padding = ETH_PADDING * 2;
var dynamicPartLength = method.outputs.reduce(function (acc, curr) {
@ -403,6 +402,7 @@ module.exports = {
outputParser: outputParser,
methodSignature: methodSignature,
methodDisplayName: methodDisplayName,
methodTypeName: methodTypeName
methodTypeName: methodTypeName,
getMethodWithName: getMethodWithName
};

8
libjsqrc/ethereumjs/lib/contract.js

@ -53,7 +53,7 @@ var contract = function (address, desc) {
// prototype, so we make it so as a workaround.
if (method.name.indexOf('(') === -1) {
var displayName = method.name;
var typeName = method.inputs.map(function(i){return i.type}).join();
var typeName = method.inputs.map(function(i){return i.type; }).join();
method.name = displayName + '(' + typeName + ')';
}
});
@ -110,6 +110,8 @@ var contract = function (address, desc) {
// TODO: figure out better way to solve this
web3._currentContractAbi = desc;
web3._currentContractAddress = address;
web3._currentContractMethodName = method.name;
web3._currentContractMethodParams = params;
// transactions do not have any output, cause we do not know, when they will be processed
web3.eth.transact(options);
@ -120,9 +122,9 @@ var contract = function (address, desc) {
var ret = outputParser[displayName][typeName](output);
if (collapse)
{
if (ret.length == 1)
if (ret.length === 1)
ret = ret[0];
else if (ret.length == 0)
else if (ret.length === 0)
ret = null;
}
return ret;

6
libjsqrc/ethereumjs/lib/filter.js

@ -47,8 +47,10 @@ Filter.prototype.changed = function(callback) {
/// trigger calling new message from people
Filter.prototype.trigger = function(messages) {
for(var i = 0; i < this.callbacks.length; i++) {
this.callbacks[i].call(this, messages);
for (var i = 0; i < this.callbacks.length; i++) {
for (var j = 0; j < messages; j++) {
this.callbacks[i].call(this, messages[j]);
}
}
};

4
libjsqrc/ethereumjs/lib/httpsync.js

@ -21,6 +21,10 @@
* @date 2014
*/
if (process.env.NODE_ENV !== 'build') {
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line
}
var HttpSyncProvider = function (host) {
this.handlers = [];
this.host = host || 'http://localhost:8080';

18
libjsqrc/ethereumjs/lib/local.js

@ -0,0 +1,18 @@
var addressName = {"0x12378912345789": "Gav", "0x57835893478594739854": "Jeff"};
var nameAddress = {};
for (var prop in addressName) {
if (addressName.hasOwnProperty(prop)) {
nameAddress[addressName[prop]] = prop;
}
}
var local = {
addressBook:{
byName: addressName,
byAddress: nameAddress
}
};
if (typeof(module) !== "undefined")
module.exports = local;

10
libjsqrc/ethereumjs/lib/providermanager.js

@ -49,15 +49,15 @@ var ProviderManager = function() {
result = JSON.parse(result);
// dont call the callback if result is an error, empty array or false
if (result.error || (result.result instanceof Array ? result.result.length === 0 : !result.result)) {
// dont call the callback if result is not an array, or empty one
if (result.error || !(result.result instanceof Array) || result.result.length === 0) {
return;
}
data.callback(result);
data.callback(result.result);
});
}
setTimeout(poll, 12000);
setTimeout(poll, 1000);
};
poll();
};
@ -70,7 +70,7 @@ ProviderManager.prototype.send = function(data) {
if (this.provider === undefined) {
console.error('provider is not set');
return undefined;
return null;
}
//TODO: handle error here?

2
libjsqrc/ethereumjs/lib/web3.js

@ -145,7 +145,7 @@ var shhWatchMethods = function () {
return [
{ name: 'newFilter', call: 'shh_newFilter' },
{ name: 'uninstallFilter', call: 'shh_uninstallFilter' },
{ name: 'getMessage', call: 'shh_getMessages' }
{ name: 'getMessages', call: 'shh_getMessages' }
];
};

3
libjsqrc/ethereumjs/package.json

@ -1,14 +1,13 @@
{
"name": "ethereum.js",
"namespace": "ethereum",
"version": "0.0.8",
"version": "0.0.10",
"description": "Ethereum Compatible JavaScript API",
"main": "./index.js",
"directories": {
"lib": "./lib"
},
"dependencies": {
"es6-promise": "*",
"ws": "*",
"xmlhttprequest": "*",
"bignumber.js": ">=2.0.0"

1
libjsqrc/ethereumjs/test/db.methods.js

@ -1,4 +1,3 @@
require('es6-promise').polyfill();
var assert = require('assert');
var web3 = require('../index.js');

2
libjsqrc/ethereumjs/test/eth.methods.js

@ -1,5 +1,3 @@
require('es6-promise').polyfill();
var assert = require('assert');
var web3 = require('../index.js');
var u = require('./utils.js');

2
libjsqrc/ethereumjs/test/shh.methods.js

@ -1,5 +1,3 @@
require('es6-promise').polyfill();
var assert = require('assert');
var web3 = require('../index.js');
var u = require('./utils.js');

2
libjsqrc/ethereumjs/test/web3.methods.js

@ -1,5 +1,3 @@
require('es6-promise').polyfill();
var assert = require('assert');
var web3 = require('../index.js');
var u = require('./utils.js');

1
libjsqrc/js.qrc

@ -1,6 +1,5 @@
<RCC>
<qresource prefix="/js">
<file>es6-promise-2.0.0.js</file>
<file>bignumber.min.js</file>
<file>setup.js</file>
<file alias="webthree.js">ethereumjs/dist/ethereum.js</file>

14
libjsqrc/natspec.js

@ -29,6 +29,16 @@ var getContractMethods = function (address, abi) {
return web3.eth.contract(address, abi);
};
/// Function called to get all contract method input variables
/// @returns hashmap with all contract's method input variables
var getContractInputParams = function (abi, methodName, params) {
var method = web3.abi.getMethodWithName(abi, methodName);
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
/// Should be checked if it is safe
@ -37,12 +47,16 @@ var evaluateExpression = function (expression) {
var self = this;
var abi = web3._currentContractAbi;
var address = web3._currentContractAddress;
var methodName = web3._currentContractMethodName;
var params = web3._currentContractMethodParams;
var storage = getContractProperties(address, abi);
var methods = getContractMethods(address, abi);
var inputParams = getContractInputParams(abi, methodName, params);
copyToContext(storage, self);
copyToContext(methods, self);
copyToContext(inputParams, self);
// TODO: test if it is safe
var evaluatedExpression = "";

4
libjsqrc/setup.js

@ -22,10 +22,6 @@
navigator.qt = _web3;
if (window.Promise === undefined) {
window.Promise = ES6Promise.Promise;
}
var web3 = require('web3');
web3.setProvider(new web3.providers.QtSyncProvider());

1
libqwebthree/QWebThree.h

@ -81,7 +81,6 @@ private:
_frame->disconnect(); \
_frame->addToJavaScriptWindowObject("_web3", qweb, QWebFrame::ScriptOwnership); \
_frame->addToJavaScriptWindowObject("env", _env, QWebFrame::QtOwnership); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/es6-promise-2.0.0.js")); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/bignumber.min.js")); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/webthree.js")); \
_frame->evaluateJavaScript(contentsOfQResource(":/js/setup.js")); \

131
libsolidity/AST.cpp

@ -41,10 +41,15 @@ TypeError ASTNode::createTypeError(string const& _description) const
return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description);
}
TypePointer ContractDefinition::getType(ContractDefinition const* _currentContract) const
{
return make_shared<TypeType>(make_shared<ContractType>(*this), _currentContract);
}
void ContractDefinition::checkTypeRequirements()
{
for (ASTPointer<InheritanceSpecifier> const& base: getBaseContracts())
base->checkTypeRequirements();
for (ASTPointer<InheritanceSpecifier> const& baseSpecifier: getBaseContracts())
baseSpecifier->checkTypeRequirements();
checkIllegalOverrides();
@ -53,6 +58,9 @@ void ContractDefinition::checkTypeRequirements()
BOOST_THROW_EXCEPTION(constructor->getReturnParameterList()->createTypeError(
"Non-empty \"returns\" directive for constructor."));
for (ASTPointer<ModifierDefinition> const& modifier: getFunctionModifiers())
modifier->checkTypeRequirements();
for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions())
function->checkTypeRequirements();
@ -89,15 +97,22 @@ FunctionDefinition const* ContractDefinition::getConstructor() const
void ContractDefinition::checkIllegalOverrides() const
{
// TODO unify this at a later point. for this we need to put the constness and the access specifier
// into the types
map<string, FunctionDefinition const*> functions;
map<string, ModifierDefinition const*> modifiers;
// We search from derived to base, so the stored item causes the error.
for (ContractDefinition const* contract: getLinearizedBaseContracts())
{
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
{
if (function->isConstructor())
continue; // constructors can neither be overriden nor override anything
FunctionDefinition const*& override = functions[function->getName()];
continue; // constructors can neither be overridden nor override anything
string const& name = function->getName();
if (modifiers.count(name))
BOOST_THROW_EXCEPTION(modifiers[name]->createTypeError("Override changes function to modifier."));
FunctionDefinition const*& override = functions[name];
if (!override)
override = function.get();
else if (override->isPublic() != function->isPublic() ||
@ -105,6 +120,18 @@ void ContractDefinition::checkIllegalOverrides() const
FunctionType(*override) != FunctionType(*function))
BOOST_THROW_EXCEPTION(override->createTypeError("Override changes extended function signature."));
}
for (ASTPointer<ModifierDefinition> const& modifier: contract->getFunctionModifiers())
{
string const& name = modifier->getName();
if (functions.count(name))
BOOST_THROW_EXCEPTION(functions[name]->createTypeError("Override changes modifier to function."));
ModifierDefinition const*& override = modifiers[name];
if (!override)
override = modifier.get();
else if (ModifierType(*override) != ModifierType(*modifier))
BOOST_THROW_EXCEPTION(override->createTypeError("Override changes modifier signature."));
}
}
}
vector<pair<FixedHash<4>, FunctionDefinition const*>> const& ContractDefinition::getInterfaceFunctionList() const
@ -141,6 +168,11 @@ void InheritanceSpecifier::checkTypeRequirements()
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in constructer call."));
}
TypePointer StructDefinition::getType(ContractDefinition const*) const
{
return make_shared<TypeType>(make_shared<StructType>(*this));
}
void StructDefinition::checkMemberTypes() const
{
for (ASTPointer<VariableDeclaration> const& member: getMembers())
@ -169,11 +201,18 @@ void StructDefinition::checkRecursion() const
}
}
TypePointer FunctionDefinition::getType(ContractDefinition const*) const
{
return make_shared<FunctionType>(*this);
}
void FunctionDefinition::checkTypeRequirements()
{
for (ASTPointer<VariableDeclaration> const& var: getParameters() + getReturnParameters())
if (!var->getType()->canLiveOutsideStorage())
BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage."));
for (ASTPointer<ModifierInvocation> const& modifier: m_functionModifiers)
modifier->checkTypeRequirements();
m_body->checkTypeRequirements();
}
@ -183,6 +222,40 @@ string FunctionDefinition::getCanonicalSignature() const
return getName() + FunctionType(*this).getCanonicalSignature();
}
Declaration::LValueType VariableDeclaration::getLValueType() const
{
if (dynamic_cast<FunctionDefinition const*>(getScope()) || dynamic_cast<ModifierDefinition const*>(getScope()))
return Declaration::LValueType::LOCAL;
else
return Declaration::LValueType::STORAGE;
}
TypePointer ModifierDefinition::getType(ContractDefinition const*) const
{
return make_shared<ModifierType>(*this);
}
void ModifierDefinition::checkTypeRequirements()
{
m_body->checkTypeRequirements();
}
void ModifierInvocation::checkTypeRequirements()
{
m_modifierName->checkTypeRequirements();
for (ASTPointer<Expression> const& argument: m_arguments)
argument->checkTypeRequirements();
ModifierDefinition const* modifier = dynamic_cast<ModifierDefinition const*>(m_modifierName->getReferencedDeclaration());
solAssert(modifier, "Function modifier not found.");
vector<ASTPointer<VariableDeclaration>> const& parameters = modifier->getParameters();
if (parameters.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for modifier invocation."));
for (size_t i = 0; i < m_arguments.size(); ++i)
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType()))
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in modifier invocation."));
}
void Block::checkTypeRequirements()
{
for (shared_ptr<Statement> const& statement: m_statements)
@ -218,7 +291,8 @@ void Return::checkTypeRequirements()
{
if (!m_expression)
return;
solAssert(m_returnParameters, "Return parameters not assigned.");
if (!m_returnParameters)
BOOST_THROW_EXCEPTION(createTypeError("Return arguments not allowed."));
if (m_returnParameters->getParameters().size() != 1)
BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement "
"than in returns declaration."));
@ -394,7 +468,7 @@ void MemberAccess::checkTypeRequirements()
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not "
"visible in " + type.toString()));
//@todo later, this will not always be STORAGE
m_lvalue = type.getCategory() == Type::Category::STRUCT ? LValueType::STORAGE : LValueType::NONE;
m_lvalue = type.getCategory() == Type::Category::STRUCT ? Declaration::LValueType::STORAGE : Declaration::LValueType::NONE;
}
void IndexAccess::checkTypeRequirements()
@ -406,52 +480,17 @@ void IndexAccess::checkTypeRequirements()
MappingType const& type = dynamic_cast<MappingType const&>(*m_base->getType());
m_index->expectType(*type.getKeyType());
m_type = type.getValueType();
m_lvalue = LValueType::STORAGE;
m_lvalue = Declaration::LValueType::STORAGE;
}
void Identifier::checkTypeRequirements()
{
solAssert(m_referencedDeclaration, "Identifier not resolved.");
VariableDeclaration const* variable = dynamic_cast<VariableDeclaration const*>(m_referencedDeclaration);
if (variable)
{
if (!variable->getType())
BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined."));
m_type = variable->getType();
m_lvalue = variable->isLocalVariable() ? LValueType::LOCAL : LValueType::STORAGE;
return;
}
//@todo can we unify these with TypeName::toType()?
StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(m_referencedDeclaration);
if (structDef)
{
// note that we do not have a struct type here
m_type = make_shared<TypeType>(make_shared<StructType>(*structDef));
return;
}
FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(m_referencedDeclaration);
if (functionDef)
{
// a function reference is not a TypeType, because calling a TypeType converts to the type.
// Calling a function (e.g. function(12), otherContract.function(34)) does not do a type
// conversion.
m_type = make_shared<FunctionType>(*functionDef);
return;
}
ContractDefinition const* contractDef = dynamic_cast<ContractDefinition const*>(m_referencedDeclaration);
if (contractDef)
{
m_type = make_shared<TypeType>(make_shared<ContractType>(*contractDef), m_currentContract);
return;
}
MagicVariableDeclaration const* magicVariable = dynamic_cast<MagicVariableDeclaration const*>(m_referencedDeclaration);
if (magicVariable)
{
m_type = magicVariable->getType();
return;
}
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Declaration reference of unknown/forbidden type."));
m_lvalue = m_referencedDeclaration->getLValueType();
m_type = m_referencedDeclaration->getType(m_currentContract);
if (!m_type)
BOOST_THROW_EXCEPTION(createTypeError("Declaration referenced before type could be determined."));
}
void ElementaryTypeNameExpression::checkTypeRequirements()

143
libsolidity/AST.h

@ -132,6 +132,8 @@ private:
class Declaration: public ASTNode
{
public:
enum class LValueType { NONE, LOCAL, STORAGE };
Declaration(Location const& _location, ASTPointer<ASTString> const& _name):
ASTNode(_location), m_name(_name), m_scope(nullptr) {}
@ -142,6 +144,13 @@ public:
Declaration const* getScope() const { return m_scope; }
void setScope(Declaration const* _scope) { m_scope = _scope; }
/// @returns the type of expressions referencing this declaration.
/// The current contract has to be given since this context can change the type, especially of
/// contract types.
virtual TypePointer getType(ContractDefinition const* m_currentContract = nullptr) const = 0;
/// @returns the lvalue type of expressions referencing this declaration
virtual LValueType getLValueType() const { return LValueType::NONE; }
private:
ASTPointer<ASTString> m_name;
Declaration const* m_scope;
@ -161,12 +170,14 @@ public:
std::vector<ASTPointer<InheritanceSpecifier>> const& _baseContracts,
std::vector<ASTPointer<StructDefinition>> const& _definedStructs,
std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables,
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions):
std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions,
std::vector<ASTPointer<ModifierDefinition>> const& _functionModifiers):
Declaration(_location, _name),
m_baseContracts(_baseContracts),
m_definedStructs(_definedStructs),
m_stateVariables(_stateVariables),
m_definedFunctions(_definedFunctions),
m_functionModifiers(_functionModifiers),
m_documentation(_documentation)
{}
@ -176,8 +187,11 @@ public:
std::vector<ASTPointer<InheritanceSpecifier>> const& getBaseContracts() const { return m_baseContracts; }
std::vector<ASTPointer<StructDefinition>> const& getDefinedStructs() const { return m_definedStructs; }
std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() const { return m_stateVariables; }
std::vector<ASTPointer<ModifierDefinition>> const& getFunctionModifiers() const { return m_functionModifiers; }
std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() const { return m_definedFunctions; }
virtual TypePointer getType(ContractDefinition const* m_currentContract) const override;
/// Checks that there are no illegal overrides, that the constructor does not have a "returns"
/// and calls checkTypeRequirements on all its functions.
void checkTypeRequirements();
@ -207,6 +221,7 @@ private:
std::vector<ASTPointer<StructDefinition>> m_definedStructs;
std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;
std::vector<ASTPointer<FunctionDefinition>> m_definedFunctions;
std::vector<ASTPointer<ModifierDefinition>> m_functionModifiers;
ASTPointer<ASTString> m_documentation;
std::vector<ContractDefinition const*> m_linearizedBaseContracts;
@ -245,6 +260,8 @@ public:
std::vector<ASTPointer<VariableDeclaration>> const& getMembers() const { return m_members; }
virtual TypePointer getType(ContractDefinition const*) const override;
/// Checks that the members do not include any recursive structs and have valid types
/// (e.g. no functions).
void checkValidityOfMembers() const;
@ -276,7 +293,20 @@ private:
std::vector<ASTPointer<VariableDeclaration>> m_parameters;
};
class FunctionDefinition: public Declaration
/**
* Abstract class that is added to each AST node that can store local variables.
*/
class VariableScope
{
public:
void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); }
std::vector<VariableDeclaration const*> const& getLocalVariables() const { return m_localVariables; }
private:
std::vector<VariableDeclaration const*> m_localVariables;
};
class FunctionDefinition: public Declaration, public VariableScope
{
public:
FunctionDefinition(Location const& _location, ASTPointer<ASTString> const& _name,
@ -285,11 +315,13 @@ public:
ASTPointer<ASTString> const& _documentation,
ASTPointer<ParameterList> const& _parameters,
bool _isDeclaredConst,
std::vector<ASTPointer<ModifierInvocation>> const& _modifiers,
ASTPointer<ParameterList> const& _returnParameters,
ASTPointer<Block> const& _body):
Declaration(_location, _name), m_isPublic(_isPublic), m_isConstructor(_isConstructor),
m_parameters(_parameters),
m_isDeclaredConst(_isDeclaredConst),
m_functionModifiers(_modifiers),
m_returnParameters(_returnParameters),
m_body(_body),
m_documentation(_documentation)
@ -301,6 +333,7 @@ public:
bool isPublic() const { return m_isPublic; }
bool isConstructor() const { return m_isConstructor; }
bool isDeclaredConst() const { return m_isDeclaredConst; }
std::vector<ASTPointer<ModifierInvocation>> const& getModifiers() const { return m_functionModifiers; }
std::vector<ASTPointer<VariableDeclaration>> const& getParameters() const { return m_parameters->getParameters(); }
ParameterList const& getParameterList() const { return *m_parameters; }
std::vector<ASTPointer<VariableDeclaration>> const& getReturnParameters() const { return m_returnParameters->getParameters(); }
@ -310,8 +343,7 @@ public:
/// Can contain a nullptr in which case indicates absence of documentation
ASTPointer<ASTString> const& getDocumentation() const { return m_documentation; }
void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); }
std::vector<VariableDeclaration const*> const& getLocalVariables() const { return m_localVariables; }
virtual TypePointer getType(ContractDefinition const*) const override;
/// Checks that all parameters have allowed types and calls checkTypeRequirements on the body.
void checkTypeRequirements();
@ -326,11 +358,10 @@ private:
bool m_isConstructor;
ASTPointer<ParameterList> m_parameters;
bool m_isDeclaredConst;
std::vector<ASTPointer<ModifierInvocation>> m_functionModifiers;
ASTPointer<ParameterList> m_returnParameters;
ASTPointer<Block> m_body;
ASTPointer<ASTString> m_documentation;
std::vector<VariableDeclaration const*> m_localVariables;
};
/**
@ -350,10 +381,10 @@ public:
/// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly
/// declared and there is no assignment to the variable that fixes the type.
std::shared_ptr<Type const> const& getType() const { return m_type; }
TypePointer getType(ContractDefinition const* = nullptr) const { return m_type; }
void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); }
virtual LValueType getLValueType() const override;
private:
ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
@ -361,6 +392,64 @@ private:
std::shared_ptr<Type const> m_type; ///< derived type, initially empty
};
/**
* Definition of a function modifier.
*/
class ModifierDefinition: public Declaration, public VariableScope
{
public:
ModifierDefinition(Location const& _location,
ASTPointer<ASTString> const& _name,
ASTPointer<ASTString> const& _documentation,
ASTPointer<ParameterList> const& _parameters,
ASTPointer<Block> const& _body):
Declaration(_location, _name), m_documentation(_documentation),
m_parameters(_parameters), m_body(_body) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<VariableDeclaration>> const& getParameters() const { return m_parameters->getParameters(); }
ParameterList const& getParameterList() const { return *m_parameters; }
Block const& getBody() const { return *m_body; }
virtual TypePointer getType(ContractDefinition const* = nullptr) const override;
/// @return A shared pointer of an ASTString.
/// Can contain a nullptr in which case indicates absence of documentation
ASTPointer<ASTString> const& getDocumentation() const { return m_documentation; }
void checkTypeRequirements();
private:
ASTPointer<ASTString> m_documentation;
ASTPointer<ParameterList> m_parameters;
ASTPointer<Block> m_body;
};
/**
* Invocation/usage of a modifier in a function header.
*/
class ModifierInvocation: public ASTNode
{
public:
ModifierInvocation(Location const& _location, ASTPointer<Identifier> const& _name,
std::vector<ASTPointer<Expression>> _arguments):
ASTNode(_location), m_modifierName(_name), m_arguments(_arguments) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
ASTPointer<Identifier> const& getName() const { return m_modifierName; }
std::vector<ASTPointer<Expression>> const& getArguments() const { return m_arguments; }
void checkTypeRequirements();
private:
ASTPointer<Identifier> m_modifierName;
std::vector<ASTPointer<Expression>> m_arguments;
};
/**
* Pseudo AST node that is used as declaration for "this", "msg", "tx", "block" and the global
* functions when such an identifier is encountered. Will never have a valid location in the source code.
@ -375,7 +464,7 @@ public:
virtual void accept(ASTConstVisitor&) const override { BOOST_THROW_EXCEPTION(InternalCompilerError()
<< errinfo_comment("MagicVariableDeclaration used inside real AST.")); }
std::shared_ptr<Type const> const& getType() const { return m_type; }
virtual TypePointer getType(ContractDefinition const* = nullptr) const override { return m_type; }
private:
std::shared_ptr<Type const> m_type;
@ -502,6 +591,21 @@ private:
std::vector<ASTPointer<Statement>> m_statements;
};
/**
* Special placeholder statement denoted by "_" used in function modifiers. This is replaced by
* the original function when the modifier is applied.
*/
class PlaceholderStatement: public Statement
{
public:
PlaceholderStatement(Location const& _location): Statement(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override { }
};
/**
* If-statement with an optional "else" part. Note that "else if" is modeled by having a new
* if-statement as the false (else) body.
@ -618,12 +722,8 @@ public:
virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
void setFunctionReturnParameters(ParameterList const& _parameters) { m_returnParameters = &_parameters; }
ParameterList const& getFunctionReturnParameters() const
{
solAssert(m_returnParameters, "");
return *m_returnParameters;
}
void setFunctionReturnParameters(ParameterList const* _parameters) { m_returnParameters = _parameters; }
ParameterList const* getFunctionReturnParameters() const { return m_returnParameters; }
Expression const* getExpression() const { return m_expression.get(); }
private:
@ -686,16 +786,13 @@ private:
*/
class Expression: public ASTNode
{
protected:
enum class LValueType { NONE, LOCAL, STORAGE };
public:
Expression(Location const& _location): ASTNode(_location), m_lvalue(LValueType::NONE), m_lvalueRequested(false) {}
Expression(Location const& _location): ASTNode(_location) {}
virtual void checkTypeRequirements() = 0;
std::shared_ptr<Type const> const& getType() const { return m_type; }
bool isLValue() const { return m_lvalue != LValueType::NONE; }
bool isLocalLValue() const { return m_lvalue == LValueType::LOCAL; }
bool isLValue() const { return m_lvalue != Declaration::LValueType::NONE; }
bool isLocalLValue() const { return m_lvalue == Declaration::LValueType::LOCAL; }
/// Helper function, infer the type via @ref checkTypeRequirements and then check that it
/// is implicitly convertible to @a _expectedType. If not, throw exception.
@ -712,9 +809,9 @@ protected:
std::shared_ptr<Type const> m_type;
//! If this expression is an lvalue (i.e. something that can be assigned to) and is stored
//! locally or in storage. This is set during calls to @a checkTypeRequirements()
LValueType m_lvalue;
Declaration::LValueType m_lvalue = Declaration::LValueType::NONE;
//! Whether the outer expression requested the address (true) or the value (false) of this expression.
bool m_lvalueRequested;
bool m_lvalueRequested = false;
};
/// Assignment, can also be a compound assignment.

5
libsolidity/ASTForward.h

@ -43,6 +43,8 @@ class StructDefinition;
class ParameterList;
class FunctionDefinition;
class VariableDeclaration;
class ModifierDefinition;
class ModifierInvocation;
class MagicVariableDeclaration;
class TypeName;
class ElementaryTypeName;
@ -50,6 +52,7 @@ class UserDefinedTypeName;
class Mapping;
class Statement;
class Block;
class PlaceholderStatement;
class IfStatement;
class BreakableStatement;
class WhileStatement;
@ -72,6 +75,8 @@ class Identifier;
class ElementaryTypeNameExpression;
class Literal;
class VariableScope;
// Used as pointers to AST nodes, to be replaced by more clever pointers, e.g. pointers which do
// not do reference counting but point to a special memory area that is completely released
// explicitly.

3
libsolidity/ASTJsonConverter.cpp

@ -118,9 +118,10 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node)
bool ASTJsonConverter::visit(VariableDeclaration const& _node)
{
bool isLocalVariable = (_node.getLValueType() == VariableDeclaration::LValueType::LOCAL);
addJsonNode("VariableDeclaration",
{ make_pair("name", _node.getName()),
make_pair("local", boost::lexical_cast<std::string>(_node.isLocalVariable()))},
make_pair("local", boost::lexical_cast<std::string>(isLocalVariable))},
true);
return true;
}

36
libsolidity/ASTPrinter.cpp

@ -87,6 +87,20 @@ bool ASTPrinter::visit(VariableDeclaration const& _node)
return goDeeper();
}
bool ASTPrinter::visit(ModifierDefinition const& _node)
{
writeLine("ModifierDefinition \"" + _node.getName() + "\"");
printSourcePart(_node);
return goDeeper();
}
bool ASTPrinter::visit(ModifierInvocation const& _node)
{
writeLine("ModifierInvocation \"" + _node.getName()->getName() + "\"");
printSourcePart(_node);
return goDeeper();
}
bool ASTPrinter::visit(TypeName const& _node)
{
writeLine("TypeName");
@ -129,6 +143,13 @@ bool ASTPrinter::visit(Block const& _node)
return goDeeper();
}
bool ASTPrinter::visit(PlaceholderStatement const& _node)
{
writeLine("PlaceholderStatement");
printSourcePart(_node);
return goDeeper();
}
bool ASTPrinter::visit(IfStatement const& _node)
{
writeLine("IfStatement");
@ -322,6 +343,16 @@ void ASTPrinter::endVisit(VariableDeclaration const&)
m_indentation--;
}
void ASTPrinter::endVisit(ModifierDefinition const&)
{
m_indentation--;
}
void ASTPrinter::endVisit(ModifierInvocation const&)
{
m_indentation--;
}
void ASTPrinter::endVisit(TypeName const&)
{
m_indentation--;
@ -352,6 +383,11 @@ void ASTPrinter::endVisit(Block const&)
m_indentation--;
}
void ASTPrinter::endVisit(PlaceholderStatement const&)
{
m_indentation--;
}
void ASTPrinter::endVisit(IfStatement const&)
{
m_indentation--;

6
libsolidity/ASTPrinter.h

@ -48,12 +48,15 @@ public:
bool visit(ParameterList const& _node) override;
bool visit(FunctionDefinition const& _node) override;
bool visit(VariableDeclaration const& _node) override;
bool visit(ModifierDefinition const& _node) override;
bool visit(ModifierInvocation const& _node) override;
bool visit(TypeName const& _node) override;
bool visit(ElementaryTypeName const& _node) override;
bool visit(UserDefinedTypeName const& _node) override;
bool visit(Mapping const& _node) override;
bool visit(Statement const& _node) override;
bool visit(Block const& _node) override;
bool visit(PlaceholderStatement const& _node) override;
bool visit(IfStatement const& _node) override;
bool visit(BreakableStatement const& _node) override;
bool visit(WhileStatement const& _node) override;
@ -82,12 +85,15 @@ public:
void endVisit(ParameterList const&) override;
void endVisit(FunctionDefinition const&) override;
void endVisit(VariableDeclaration const&) override;
void endVisit(ModifierDefinition const&) override;
void endVisit(ModifierInvocation const&) override;
void endVisit(TypeName const&) override;
void endVisit(ElementaryTypeName const&) override;
void endVisit(UserDefinedTypeName const&) override;
void endVisit(Mapping const&) override;
void endVisit(Statement const&) override;
void endVisit(Block const&) override;
void endVisit(PlaceholderStatement const&) override;
void endVisit(IfStatement const&) override;
void endVisit(BreakableStatement const&) override;
void endVisit(WhileStatement const&) override;

12
libsolidity/ASTVisitor.h

@ -49,12 +49,15 @@ public:
virtual bool visit(ParameterList&) { return true; }
virtual bool visit(FunctionDefinition&) { return true; }
virtual bool visit(VariableDeclaration&) { return true; }
virtual bool visit(ModifierDefinition&) { return true; }
virtual bool visit(ModifierInvocation&) { return true; }
virtual bool visit(TypeName&) { return true; }
virtual bool visit(ElementaryTypeName&) { return true; }
virtual bool visit(UserDefinedTypeName&) { return true; }
virtual bool visit(Mapping&) { return true; }
virtual bool visit(Statement&) { return true; }
virtual bool visit(Block&) { return true; }
virtual bool visit(PlaceholderStatement&) { return true; }
virtual bool visit(IfStatement&) { return true; }
virtual bool visit(BreakableStatement&) { return true; }
virtual bool visit(WhileStatement&) { return true; }
@ -85,12 +88,15 @@ public:
virtual void endVisit(ParameterList&) { }
virtual void endVisit(FunctionDefinition&) { }
virtual void endVisit(VariableDeclaration&) { }
virtual void endVisit(ModifierDefinition&) { }
virtual void endVisit(ModifierInvocation&) { }
virtual void endVisit(TypeName&) { }
virtual void endVisit(ElementaryTypeName&) { }
virtual void endVisit(UserDefinedTypeName&) { }
virtual void endVisit(Mapping&) { }
virtual void endVisit(Statement&) { }
virtual void endVisit(Block&) { }
virtual void endVisit(PlaceholderStatement&) { }
virtual void endVisit(IfStatement&) { }
virtual void endVisit(BreakableStatement&) { }
virtual void endVisit(WhileStatement&) { }
@ -125,12 +131,15 @@ public:
virtual bool visit(ParameterList const&) { return true; }
virtual bool visit(FunctionDefinition const&) { return true; }
virtual bool visit(VariableDeclaration const&) { return true; }
virtual bool visit(ModifierDefinition const&) { return true; }
virtual bool visit(ModifierInvocation const&) { return true; }
virtual bool visit(TypeName const&) { return true; }
virtual bool visit(ElementaryTypeName const&) { return true; }
virtual bool visit(UserDefinedTypeName const&) { return true; }
virtual bool visit(Mapping const&) { return true; }
virtual bool visit(Statement const&) { return true; }
virtual bool visit(Block const&) { return true; }
virtual bool visit(PlaceholderStatement const&) { return true; }
virtual bool visit(IfStatement const&) { return true; }
virtual bool visit(BreakableStatement const&) { return true; }
virtual bool visit(WhileStatement const&) { return true; }
@ -161,12 +170,15 @@ public:
virtual void endVisit(ParameterList const&) { }
virtual void endVisit(FunctionDefinition const&) { }
virtual void endVisit(VariableDeclaration const&) { }
virtual void endVisit(ModifierDefinition const&) { }
virtual void endVisit(ModifierInvocation const&) { }
virtual void endVisit(TypeName const&) { }
virtual void endVisit(ElementaryTypeName const&) { }
virtual void endVisit(UserDefinedTypeName const&) { }
virtual void endVisit(Mapping const&) { }
virtual void endVisit(Statement const&) { }
virtual void endVisit(Block const&) { }
virtual void endVisit(PlaceholderStatement const&) { }
virtual void endVisit(IfStatement const&) { }
virtual void endVisit(BreakableStatement const&) { }
virtual void endVisit(WhileStatement const&) { }

56
libsolidity/AST_accept.h

@ -65,6 +65,7 @@ void ContractDefinition::accept(ASTVisitor& _visitor)
listAccept(m_definedStructs, _visitor);
listAccept(m_stateVariables, _visitor);
listAccept(m_definedFunctions, _visitor);
listAccept(m_functionModifiers, _visitor);
}
_visitor.endVisit(*this);
}
@ -77,6 +78,7 @@ void ContractDefinition::accept(ASTConstVisitor& _visitor) const
listAccept(m_definedStructs, _visitor);
listAccept(m_stateVariables, _visitor);
listAccept(m_definedFunctions, _visitor);
listAccept(m_functionModifiers, _visitor);
}
_visitor.endVisit(*this);
}
@ -142,6 +144,7 @@ void FunctionDefinition::accept(ASTVisitor& _visitor)
m_parameters->accept(_visitor);
if (m_returnParameters)
m_returnParameters->accept(_visitor);
listAccept(m_functionModifiers, _visitor);
m_body->accept(_visitor);
}
_visitor.endVisit(*this);
@ -154,6 +157,7 @@ void FunctionDefinition::accept(ASTConstVisitor& _visitor) const
m_parameters->accept(_visitor);
if (m_returnParameters)
m_returnParameters->accept(_visitor);
listAccept(m_functionModifiers, _visitor);
m_body->accept(_visitor);
}
_visitor.endVisit(*this);
@ -175,6 +179,46 @@ void VariableDeclaration::accept(ASTConstVisitor& _visitor) const
_visitor.endVisit(*this);
}
void ModifierDefinition::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
{
m_parameters->accept(_visitor);
m_body->accept(_visitor);
}
_visitor.endVisit(*this);
}
void ModifierDefinition::accept(ASTConstVisitor& _visitor) const
{
if (_visitor.visit(*this))
{
m_parameters->accept(_visitor);
m_body->accept(_visitor);
}
_visitor.endVisit(*this);
}
void ModifierInvocation::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
{
m_modifierName->accept(_visitor);
listAccept(m_arguments, _visitor);
}
_visitor.endVisit(*this);
}
void ModifierInvocation::accept(ASTConstVisitor& _visitor) const
{
if (_visitor.visit(*this))
{
m_modifierName->accept(_visitor);
listAccept(m_arguments, _visitor);
}
_visitor.endVisit(*this);
}
void TypeName::accept(ASTVisitor& _visitor)
{
_visitor.visit(*this);
@ -245,6 +289,18 @@ void Block::accept(ASTConstVisitor& _visitor) const
_visitor.endVisit(*this);
}
void PlaceholderStatement::accept(ASTVisitor& _visitor)
{
_visitor.visit(*this);
_visitor.endVisit(*this);
}
void PlaceholderStatement::accept(ASTConstVisitor& _visitor) const
{
_visitor.visit(*this);
_visitor.endVisit(*this);
}
void IfStatement::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))

35
libsolidity/CallGraph.cpp

@ -33,7 +33,11 @@ namespace solidity
void CallGraph::addNode(ASTNode const& _node)
{
_node.accept(*this);
if (!m_nodesSeen.count(&_node))
{
m_workQueue.push(&_node);
m_nodesSeen.insert(&_node);
}
}
set<FunctionDefinition const*> const& CallGraph::getCalls()
@ -53,20 +57,26 @@ void CallGraph::computeCallGraph()
bool CallGraph::visit(Identifier const& _identifier)
{
FunctionDefinition const* fun = dynamic_cast<FunctionDefinition const*>(_identifier.getReferencedDeclaration());
if (fun)
if (auto fun = dynamic_cast<FunctionDefinition const*>(_identifier.getReferencedDeclaration()))
{
if (m_overrideResolver)
fun = (*m_overrideResolver)(fun->getName());
if (m_functionOverrideResolver)
fun = (*m_functionOverrideResolver)(fun->getName());
solAssert(fun, "Error finding override for function " + fun->getName());
addFunction(*fun);
addNode(*fun);
}
if (auto modifier = dynamic_cast<ModifierDefinition const*>(_identifier.getReferencedDeclaration()))
{
if (m_modifierOverrideResolver)
modifier = (*m_modifierOverrideResolver)(modifier->getName());
solAssert(modifier, "Error finding override for modifier " + modifier->getName());
addNode(*modifier);
}
return true;
}
bool CallGraph::visit(FunctionDefinition const& _function)
{
addFunction(_function);
m_functionsSeen.insert(&_function);
return true;
}
@ -83,7 +93,7 @@ bool CallGraph::visit(MemberAccess const& _memberAccess)
for (ASTPointer<FunctionDefinition> const& function: contract.getDefinedFunctions())
if (function->getName() == _memberAccess.getMemberName())
{
addFunction(*function);
addNode(*function);
return true;
}
}
@ -91,14 +101,5 @@ bool CallGraph::visit(MemberAccess const& _memberAccess)
return true;
}
void CallGraph::addFunction(FunctionDefinition const& _function)
{
if (!m_functionsSeen.count(&_function))
{
m_functionsSeen.insert(&_function);
m_workQueue.push(&_function);
}
}
}
}

15
libsolidity/CallGraph.h

@ -39,9 +39,13 @@ namespace solidity
class CallGraph: private ASTConstVisitor
{
public:
using OverrideResolver = std::function<FunctionDefinition const*(std::string const&)>;
using FunctionOverrideResolver = std::function<FunctionDefinition const*(std::string const&)>;
using ModifierOverrideResolver = std::function<ModifierDefinition const*(std::string const&)>;
CallGraph(OverrideResolver const& _overrideResolver): m_overrideResolver(&_overrideResolver) {}
CallGraph(FunctionOverrideResolver const& _functionOverrideResolver,
ModifierOverrideResolver const& _modifierOverrideResolver):
m_functionOverrideResolver(&_functionOverrideResolver),
m_modifierOverrideResolver(&_modifierOverrideResolver) {}
void addNode(ASTNode const& _node);
@ -53,11 +57,12 @@ private:
virtual bool visit(MemberAccess const& _memberAccess) override;
void computeCallGraph();
void addFunction(FunctionDefinition const& _function);
OverrideResolver const* m_overrideResolver;
FunctionOverrideResolver const* m_functionOverrideResolver;
ModifierOverrideResolver const* m_modifierOverrideResolver;
std::set<ASTNode const*> m_nodesSeen;
std::set<FunctionDefinition const*> m_functionsSeen;
std::queue<FunctionDefinition const*> m_workQueue;
std::queue<ASTNode const*> m_workQueue;
};
}

107
libsolidity/Compiler.cpp

@ -42,9 +42,13 @@ void Compiler::compileContract(ContractDefinition const& _contract,
initializeContext(_contract, _contracts);
for (ContractDefinition const* contract: _contract.getLinearizedBaseContracts())
{
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
if (!function->isConstructor())
m_context.addFunction(*function);
for (ASTPointer<ModifierDefinition> const& modifier: contract->getFunctionModifiers())
m_context.addModifier(*modifier);
}
appendFunctionSelector(_contract);
for (ContractDefinition const* contract: _contract.getLinearizedBaseContracts())
@ -67,6 +71,13 @@ void Compiler::initializeContext(ContractDefinition const& _contract,
void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext)
{
std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts();
// Make all modifiers known to the context.
for (ContractDefinition const* contract: bases)
for (ASTPointer<ModifierDefinition> const& modifier: contract->getFunctionModifiers())
m_context.addModifier(*modifier);
// arguments for base constructors, filled in derived-to-base order
map<ContractDefinition const*, vector<ASTPointer<Expression>> const*> baseArguments;
set<FunctionDefinition const*> neededFunctions;
@ -74,7 +85,6 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
// Determine the arguments that are used for the base constructors and also which functions
// are needed at compile time.
std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts();
for (ContractDefinition const* contract: bases)
{
if (FunctionDefinition const* constructor = contract->getConstructor())
@ -93,7 +103,7 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
}
}
auto overrideResolver = [&](string const& _name) -> FunctionDefinition const*
auto functionOverrideResolver = [&](string const& _name) -> FunctionDefinition const*
{
for (ContractDefinition const* contract: bases)
for (ASTPointer<FunctionDefinition> const& function: contract->getDefinedFunctions())
@ -101,21 +111,26 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
return function.get();
return nullptr;
};
auto modifierOverrideResolver = [&](string const& _name) -> ModifierDefinition const*
{
return &m_context.getFunctionModifier(_name);
};
neededFunctions = getFunctionsCalled(nodesUsedInConstructors, overrideResolver);
neededFunctions = getFunctionsCalled(nodesUsedInConstructors, functionOverrideResolver,
modifierOverrideResolver);
// First add all overrides (or the functions themselves if there is no override)
for (FunctionDefinition const* fun: neededFunctions)
{
FunctionDefinition const* override = nullptr;
if (!fun->isConstructor())
override = overrideResolver(fun->getName());
override = functionOverrideResolver(fun->getName());
if (!!override && neededFunctions.count(override))
m_context.addFunction(*override);
}
// now add the rest
for (FunctionDefinition const* fun: neededFunctions)
if (fun->isConstructor() || overrideResolver(fun->getName()) != fun)
if (fun->isConstructor() || functionOverrideResolver(fun->getName()) != fun)
m_context.addFunction(*fun);
// Call constructors in base-to-derived order.
@ -150,11 +165,7 @@ void Compiler::appendBaseConstructorCall(FunctionDefinition const& _constructor,
FunctionType constructorType(_constructor);
eth::AssemblyItem returnLabel = m_context.pushNewTag();
for (unsigned i = 0; i < _arguments.size(); ++i)
{
compileExpression(*_arguments[i]);
ExpressionCompiler::appendTypeConversion(m_context, *_arguments[i]->getType(),
*constructorType.getParameterTypes()[i]);
}
compileExpression(*_arguments[i], constructorType.getParameterTypes()[i]);
m_context.appendJumpTo(m_context.getFunctionEntryLabel(_constructor));
m_context << returnLabel;
}
@ -179,9 +190,10 @@ void Compiler::appendConstructorCall(FunctionDefinition const& _constructor)
}
set<FunctionDefinition const*> Compiler::getFunctionsCalled(set<ASTNode const*> const& _nodes,
function<FunctionDefinition const*(string const&)> const& _resolveOverrides)
function<FunctionDefinition const*(string const&)> const& _resolveFunctionOverrides,
function<ModifierDefinition const*(string const&)> const& _resolveModifierOverrides)
{
CallGraph callgraph(_resolveOverrides);
CallGraph callgraph(_resolveFunctionOverrides, _resolveModifierOverrides);
for (ASTNode const* node: _nodes)
callgraph.addNode(*node);
return callgraph.getCalls();
@ -280,20 +292,28 @@ bool Compiler::visit(FunctionDefinition const& _function)
m_returnTag = m_context.newTag();
m_breakTags.clear();
m_continueTags.clear();
m_stackCleanupForReturn = 0;
m_currentFunction = &_function;
m_modifierDepth = 0;
m_context << m_context.getFunctionEntryLabel(_function);
// stack upon entry: [return address] [arg0] [arg1] ... [argn]
// reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp]
unsigned parametersSize = CompilerUtils::getSizeOnStack(_function.getParameters());
m_context.adjustStackOffset(parametersSize);
for (ASTPointer<VariableDeclaration const> const& variable: _function.getParameters())
m_context.addVariable(*variable);
{
m_context.addVariable(*variable, parametersSize);
parametersSize -= variable->getType()->getSizeOnStack();
}
for (ASTPointer<VariableDeclaration const> const& variable: _function.getReturnParameters())
m_context.addAndInitializeVariable(*variable);
for (VariableDeclaration const* localVariable: _function.getLocalVariables())
m_context.addAndInitializeVariable(*localVariable);
_function.getBody().accept(*this);
appendModifierOrFunctionCode();
m_context << m_returnTag;
@ -420,13 +440,15 @@ bool Compiler::visit(Return const& _return)
//@todo modifications are needed to make this work with functions returning multiple values
if (Expression const* expression = _return.getExpression())
{
compileExpression(*expression);
VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front();
ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *firstVariable.getType());
solAssert(_return.getFunctionReturnParameters(), "Invalid return parameters pointer.");
VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters()->getParameters().front();
compileExpression(*expression, firstVariable.getType());
CompilerUtils(m_context).moveToStackVariable(firstVariable);
}
for (unsigned i = 0; i < m_stackCleanupForReturn; ++i)
m_context << eth::Instruction::POP;
m_context.appendJumpTo(m_returnTag);
m_context.adjustStackOffset(m_stackCleanupForReturn);
return false;
}
@ -434,10 +456,7 @@ bool Compiler::visit(VariableDefinition const& _variableDefinition)
{
if (Expression const* expression = _variableDefinition.getExpression())
{
compileExpression(*expression);
ExpressionCompiler::appendTypeConversion(m_context,
*expression->getType(),
*_variableDefinition.getDeclaration().getType());
compileExpression(*expression, _variableDefinition.getDeclaration().getType());
CompilerUtils(m_context).moveToStackVariable(_variableDefinition.getDeclaration());
}
return false;
@ -451,9 +470,51 @@ bool Compiler::visit(ExpressionStatement const& _expressionStatement)
return false;
}
void Compiler::compileExpression(Expression const& _expression)
bool Compiler::visit(PlaceholderStatement const&)
{
++m_modifierDepth;
appendModifierOrFunctionCode();
--m_modifierDepth;
return true;
}
void Compiler::appendModifierOrFunctionCode()
{
solAssert(m_currentFunction, "");
if (m_modifierDepth >= m_currentFunction->getModifiers().size())
m_currentFunction->getBody().accept(*this);
else
{
ASTPointer<ModifierInvocation> const& modifierInvocation = m_currentFunction->getModifiers()[m_modifierDepth];
ModifierDefinition const& modifier = m_context.getFunctionModifier(modifierInvocation->getName()->getName());
solAssert(modifier.getParameters().size() == modifierInvocation->getArguments().size(), "");
for (unsigned i = 0; i < modifier.getParameters().size(); ++i)
{
m_context.addVariable(*modifier.getParameters()[i]);
compileExpression(*modifierInvocation->getArguments()[i],
modifier.getParameters()[i]->getType());
}
for (VariableDeclaration const* localVariable: modifier.getLocalVariables())
m_context.addAndInitializeVariable(*localVariable);
unsigned const c_stackSurplus = CompilerUtils::getSizeOnStack(modifier.getParameters()) +
CompilerUtils::getSizeOnStack(modifier.getLocalVariables());
m_stackCleanupForReturn += c_stackSurplus;
modifier.getBody().accept(*this);
for (unsigned i = 0; i < c_stackSurplus; ++i)
m_context << eth::Instruction::POP;
m_stackCleanupForReturn -= c_stackSurplus;
}
}
void Compiler::compileExpression(Expression const& _expression, TypePointer const& _targetType)
{
ExpressionCompiler::compileExpression(m_context, _expression, m_optimize);
if (_targetType)
ExpressionCompiler::appendTypeConversion(m_context, *_expression.getType(), *_targetType);
}
}

16
libsolidity/Compiler.h

@ -31,7 +31,8 @@ namespace solidity {
class Compiler: private ASTConstVisitor
{
public:
explicit Compiler(bool _optimize = false): m_optimize(_optimize), m_context(), m_returnTag(m_context.newTag()) {}
explicit Compiler(bool _optimize = false): m_optimize(_optimize), m_context(),
m_returnTag(m_context.newTag()) {}
void compileContract(ContractDefinition const& _contract,
std::map<ContractDefinition const*, bytes const*> const& _contracts);
@ -52,7 +53,8 @@ private:
/// Recursively searches the call graph and returns all functions referenced inside _nodes.
/// _resolveOverride is called to resolve virtual function overrides.
std::set<FunctionDefinition const*> getFunctionsCalled(std::set<ASTNode const*> const& _nodes,
std::function<FunctionDefinition const*(std::string const&)> const& _resolveOverride);
std::function<FunctionDefinition const*(std::string const&)> const& _resolveFunctionOverride,
std::function<ModifierDefinition const*(std::string const&)> const& _resolveModifierOverride);
void appendFunctionSelector(ContractDefinition const& _contract);
/// Creates code that unpacks the arguments for the given function, from memory if
/// @a _fromMemory is true, otherwise from call data. @returns the size of the data in bytes.
@ -70,8 +72,13 @@ private:
virtual bool visit(Return const& _return) override;
virtual bool visit(VariableDefinition const& _variableDefinition) override;
virtual bool visit(ExpressionStatement const& _expressionStatement) override;
virtual bool visit(PlaceholderStatement const&) override;
void compileExpression(Expression const& _expression);
/// Appends one layer of function modifier code of the current function, or the function
/// body itself if the last modifier was reached.
void appendModifierOrFunctionCode();
void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer());
bool const m_optimize;
CompilerContext m_context;
@ -79,6 +86,9 @@ private:
std::vector<eth::AssemblyItem> m_breakTags; ///< tag to jump to for a "break" statement
std::vector<eth::AssemblyItem> m_continueTags; ///< tag to jump to for a "continue" statement
eth::AssemblyItem m_returnTag; ///< tag to jump to for a "return" statement
unsigned m_modifierDepth = 0;
FunctionDefinition const* m_currentFunction;
unsigned m_stackCleanupForReturn; ///< this number of stack elements need to be removed before jump to m_returnTag
};
}

28
libsolidity/CompilerContext.cpp

@ -43,10 +43,11 @@ void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
m_stateVariablesSize += _declaration.getType()->getStorageSize();
}
void CompilerContext::addVariable(VariableDeclaration const& _declaration)
void CompilerContext::addVariable(VariableDeclaration const& _declaration,
unsigned _offsetToCurrent)
{
m_localVariables[&_declaration] = m_localVariablesSize;
m_localVariablesSize += _declaration.getType()->getSizeOnStack();
solAssert(m_asm.deposit() >= 0 && unsigned(m_asm.deposit()) >= _offsetToCurrent, "");
m_localVariables[&_declaration] = unsigned(m_asm.deposit()) - _offsetToCurrent;
}
void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration)
@ -56,7 +57,6 @@ void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _decla
int const size = _declaration.getType()->getSizeOnStack();
for (int i = 0; i < size; ++i)
*this << u256(0);
m_asm.adjustDeposit(-size);
}
void CompilerContext::addFunction(FunctionDefinition const& _function)
@ -66,6 +66,11 @@ void CompilerContext::addFunction(FunctionDefinition const& _function)
m_virtualFunctionEntryLabels.insert(make_pair(_function.getName(), tag));
}
void CompilerContext::addModifier(ModifierDefinition const& _modifier)
{
m_functionModifiers.insert(make_pair(_modifier.getName(), &_modifier));
}
bytes const& CompilerContext::getCompiledContract(const ContractDefinition& _contract) const
{
auto ret = m_compiledContracts.find(&_contract);
@ -75,7 +80,7 @@ bytes const& CompilerContext::getCompiledContract(const ContractDefinition& _con
bool CompilerContext::isLocalVariable(Declaration const* _declaration) const
{
return m_localVariables.count(_declaration) > 0;
return m_localVariables.count(_declaration);
}
eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const
@ -92,21 +97,28 @@ eth::AssemblyItem CompilerContext::getVirtualFunctionEntryLabel(FunctionDefiniti
return res->second.tag();
}
ModifierDefinition const& CompilerContext::getFunctionModifier(string const& _name) const
{
auto res = m_functionModifiers.find(_name);
solAssert(res != m_functionModifiers.end(), "Function modifier override not found.");
return *res->second;
}
unsigned CompilerContext::getBaseStackOffsetOfVariable(Declaration const& _declaration) const
{
auto res = m_localVariables.find(&_declaration);
solAssert(res != m_localVariables.end(), "Variable not found on stack.");
return m_localVariablesSize - res->second - 1;
return res->second;
}
unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
{
return _baseOffset + m_asm.deposit();
return m_asm.deposit() - _baseOffset - 1;
}
unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
{
return -baseToCurrentStackOffset(-_offset);
return m_asm.deposit() - _offset - 1;
}
u256 CompilerContext::getStorageLocationOfVariable(const Declaration& _declaration) const

13
libsolidity/CompilerContext.h

@ -42,9 +42,11 @@ public:
void addMagicGlobal(MagicVariableDeclaration const& _declaration);
void addStateVariable(VariableDeclaration const& _declaration);
void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); }
void addVariable(VariableDeclaration const& _declaration);
void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0);
void addAndInitializeVariable(VariableDeclaration const& _declaration);
void addFunction(FunctionDefinition const& _function);
/// Adds the given modifier to the list by name if the name is not present already.
void addModifier(ModifierDefinition const& _modifier);
void setCompiledContracts(std::map<ContractDefinition const*, bytes const*> const& _contracts) { m_compiledContracts = _contracts; }
bytes const& getCompiledContract(ContractDefinition const& _contract) const;
@ -59,7 +61,8 @@ public:
eth::AssemblyItem getFunctionEntryLabel(FunctionDefinition const& _function) const;
/// @returns the entry label of the given function and takes overrides into account.
eth::AssemblyItem getVirtualFunctionEntryLabel(FunctionDefinition const& _function) const;
/// Returns the distance of the given local variable from the top of the local variable stack.
ModifierDefinition const& getFunctionModifier(std::string const& _name) const;
/// Returns the distance of the given local variable from the bottom of the stack (of the current function).
unsigned getBaseStackOffsetOfVariable(Declaration const& _declaration) const;
/// If supplied by a value returned by @ref getBaseStackOffsetOfVariable(variable), returns
/// the distance of that variable from the current top of the stack.
@ -112,14 +115,14 @@ private:
u256 m_stateVariablesSize = 0;
/// Storage offsets of state variables
std::map<Declaration const*, u256> m_stateVariables;
/// Offsets of local variables on the stack (relative to stack base).
/// Positions of local variables on the stack.
std::map<Declaration const*, unsigned> m_localVariables;
/// Sum of stack sizes of local variables
unsigned m_localVariablesSize;
/// Labels pointing to the entry points of funcitons.
std::map<Declaration const*, eth::AssemblyItem> m_functionEntryLabels;
/// Labels pointing to the entry points of function overrides.
std::map<std::string, eth::AssemblyItem> m_virtualFunctionEntryLabels;
/// Mapping to obtain function modifiers by name. Should be filled from derived to base.
std::map<std::string, ModifierDefinition const*> m_functionModifiers;
};
}

3
libsolidity/CompilerStack.cpp

@ -141,6 +141,9 @@ string CompilerStack::expanded(string const& _sourceCode)
{
const map<string, string> c_standardSources = map<string, string>{
{ "Config", "contract Config{function lookup(uint256 service)constant returns(address a){}function kill(){}function unregister(uint256 id){}function register(uint256 id,address service){}}" },
{ "Coin", "contract Coin{function isApprovedFor(address _target,address _proxy)constant returns(bool _r){}function isApproved(address _proxy)constant returns(bool _r){}function sendCoinFrom(address _from,uint256 _val,address _to){}function coinBalanceOf(address _a)constant returns(uint256 _r){}function sendCoin(uint256 _val,address _to){}function coinBalance()constant returns(uint256 _r){}function approve(address _a){}}"},
{ "CoinReg", "contract CoinReg{function count()constant returns(uint256 r){}function info(uint256 i)constant returns(address addr,string3 name,uint256 denom){}function register(string3 name,uint256 denom){}function unregister(){}}" },
{ "coin", "#require CoinReg\ncontract coin {function coin(string3 name, uint denom) {CoinReg(Config().lookup(3)).register(name, denom);}}" },
{ "service", "#require Config\ncontract service{function service(uint _n){Config().register(_n, this);}}" },
{ "owned", "contract owned{function owned(){owner = msg.sender;}address owner;}" },
{ "mortal", "#require owned\ncontract mortal is owned {function kill() { if (msg.sender == owner) suicide(owner); }}" },

75
libsolidity/ExpressionCompiler.cpp

@ -628,38 +628,65 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
return;
Type::Category stackTypeCategory = _typeOnStack.getCategory();
Type::Category targetTypeCategory = _targetType.getCategory();
if (stackTypeCategory == Type::Category::INTEGER || stackTypeCategory == Type::Category::CONTRACT ||
stackTypeCategory == Type::Category::INTEGER_CONSTANT)
if (stackTypeCategory == Type::Category::STRING)
{
solAssert(targetTypeCategory == Type::Category::INTEGER || targetTypeCategory == Type::Category::CONTRACT, "");
IntegerType addressType(0, IntegerType::Modifier::ADDRESS);
IntegerType const& targetType = targetTypeCategory == Type::Category::INTEGER
? dynamic_cast<IntegerType const&>(_targetType) : addressType;
if (stackTypeCategory == Type::Category::INTEGER_CONSTANT)
if (targetTypeCategory == Type::Category::INTEGER)
{
IntegerConstantType const& constType = dynamic_cast<IntegerConstantType const&>(_typeOnStack);
// We know that the stack is clean, we only have to clean for a narrowing conversion
// where cleanup is forced.
if (targetType.getNumBits() < constType.getIntegerType()->getNumBits() && _cleanupNeeded)
appendHighBitsCleanup(targetType);
// conversion from string to hash. no need to clean the high bit
// only to shift right because of opposite alignment
IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType);
StaticStringType const& typeOnStack = dynamic_cast<StaticStringType const&>(_typeOnStack);
solAssert(targetIntegerType.isHash(), "Only conversion between String and Hash is allowed.");
solAssert(targetIntegerType.getNumBits() == typeOnStack.getNumBytes() * 8, "The size should be the same.");
m_context << (u256(1) << (256 - typeOnStack.getNumBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
}
else
{
IntegerType const& typeOnStack = stackTypeCategory == Type::Category::INTEGER
? dynamic_cast<IntegerType const&>(_typeOnStack) : addressType;
// Widening: clean up according to source type width
// Non-widening and force: clean up according to target type bits
if (targetType.getNumBits() > typeOnStack.getNumBits())
appendHighBitsCleanup(typeOnStack);
else if (_cleanupNeeded)
appendHighBitsCleanup(targetType);
solAssert(targetTypeCategory == Type::Category::STRING, "Invalid type conversion requested.");
// nothing to do, strings are high-order-bit-aligned
//@todo clear lower-order bytes if we allow explicit conversion to shorter strings
}
}
else if (stackTypeCategory == Type::Category::STRING)
else if (stackTypeCategory == Type::Category::INTEGER || stackTypeCategory == Type::Category::CONTRACT ||
stackTypeCategory == Type::Category::INTEGER_CONSTANT)
{
solAssert(targetTypeCategory == Type::Category::STRING, "");
// nothing to do, strings are high-order-bit-aligned
//@todo clear lower-order bytes if we allow explicit conversion to shorter strings
if (targetTypeCategory == Type::Category::STRING && stackTypeCategory == Type::Category::INTEGER)
{
// conversion from hash to string. no need to clean the high bit
// only to shift left because of opposite alignment
StaticStringType const& targetStringType = dynamic_cast<StaticStringType const&>(_targetType);
IntegerType const& typeOnStack = dynamic_cast<IntegerType const&>(_typeOnStack);
solAssert(typeOnStack.isHash(), "Only conversion between String and Hash is allowed.");
solAssert(typeOnStack.getNumBits() == targetStringType.getNumBytes() * 8, "The size should be the same.");
m_context << (u256(1) << (256 - typeOnStack.getNumBits())) << eth::Instruction::MUL;
}
else
{
solAssert(targetTypeCategory == Type::Category::INTEGER || targetTypeCategory == Type::Category::CONTRACT, "");
IntegerType addressType(0, IntegerType::Modifier::ADDRESS);
IntegerType const& targetType = targetTypeCategory == Type::Category::INTEGER
? dynamic_cast<IntegerType const&>(_targetType) : addressType;
if (stackTypeCategory == Type::Category::INTEGER_CONSTANT)
{
IntegerConstantType const& constType = dynamic_cast<IntegerConstantType const&>(_typeOnStack);
// We know that the stack is clean, we only have to clean for a narrowing conversion
// where cleanup is forced.
if (targetType.getNumBits() < constType.getIntegerType()->getNumBits() && _cleanupNeeded)
appendHighBitsCleanup(targetType);
}
else
{
IntegerType const& typeOnStack = stackTypeCategory == Type::Category::INTEGER
? dynamic_cast<IntegerType const&>(_typeOnStack) : addressType;
// Widening: clean up according to source type width
// Non-widening and force: clean up according to target type bits
if (targetType.getNumBits() > typeOnStack.getNumBits())
appendHighBitsCleanup(typeOnStack);
else if (_cleanupNeeded)
appendHighBitsCleanup(targetType);
}
}
}
else if (_typeOnStack != _targetType)
// All other types should not be convertible to non-equal types.

21
libsolidity/NameAndTypeResolver.cpp

@ -60,6 +60,11 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
ReferencesResolver resolver(*structDef, *this, &_contract, nullptr);
for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables())
ReferencesResolver resolver(*variable, *this, &_contract, nullptr);
for (ASTPointer<ModifierDefinition> const& modifier: _contract.getFunctionModifiers())
{
m_currentScope = &m_scopes[modifier.get()];
ReferencesResolver resolver(*modifier, *this, &_contract, nullptr);
}
for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
{
m_currentScope = &m_scopes[function.get()];
@ -227,6 +232,19 @@ void DeclarationRegistrationHelper::endVisit(FunctionDefinition&)
closeCurrentScope();
}
bool DeclarationRegistrationHelper::visit(ModifierDefinition& _modifier)
{
registerDeclaration(_modifier, true);
m_currentFunction = &_modifier;
return true;
}
void DeclarationRegistrationHelper::endVisit(ModifierDefinition&)
{
m_currentFunction = nullptr;
closeCurrentScope();
}
void DeclarationRegistrationHelper::endVisit(VariableDefinition& _variableDefinition)
{
// Register the local variables with the function
@ -293,8 +311,7 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable)
bool ReferencesResolver::visit(Return& _return)
{
solAssert(m_returnParameters, "Return parameters not set.");
_return.setFunctionReturnParameters(*m_returnParameters);
_return.setFunctionReturnParameters(m_returnParameters);
return true;
}

4
libsolidity/NameAndTypeResolver.h

@ -100,6 +100,8 @@ private:
void endVisit(StructDefinition& _struct);
bool visit(FunctionDefinition& _function);
void endVisit(FunctionDefinition& _function);
bool visit(ModifierDefinition& _modifier);
void endVisit(ModifierDefinition& _modifier);
void endVisit(VariableDefinition& _variableDefinition);
bool visit(VariableDeclaration& _declaration);
@ -109,7 +111,7 @@ private:
std::map<ASTNode const*, DeclarationContainer>& m_scopes;
Declaration const* m_currentScope;
FunctionDefinition* m_currentFunction;
VariableScope* m_currentFunction;
};
/**

79
libsolidity/Parser.cpp

@ -121,6 +121,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
vector<ASTPointer<StructDefinition>> structs;
vector<ASTPointer<VariableDeclaration>> stateVariables;
vector<ASTPointer<FunctionDefinition>> functions;
vector<ASTPointer<ModifierDefinition>> modifiers;
if (m_scanner->getCurrentToken() == Token::IS)
do
{
@ -152,13 +153,15 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
stateVariables.push_back(parseVariableDeclaration(allowVar));
expectToken(Token::SEMICOLON);
}
else if (currentToken == Token::MODIFIER)
modifiers.push_back(parseModifierDefinition());
else
BOOST_THROW_EXCEPTION(createParserError("Function, variable or struct declaration expected."));
BOOST_THROW_EXCEPTION(createParserError("Function, variable, struct or modifier declaration expected."));
}
nodeFactory.markEndPosition();
expectToken(Token::RBRACE);
return nodeFactory.createNode<ContractDefinition>(name, docString, baseContracts, structs,
stateVariables, functions);
stateVariables, functions, modifiers);
}
ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
@ -189,10 +192,18 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic, A
ASTPointer<ASTString> name(expectIdentifierToken());
ASTPointer<ParameterList> parameters(parseParameterList());
bool isDeclaredConst = false;
if (m_scanner->getCurrentToken() == Token::CONST)
vector<ASTPointer<ModifierInvocation>> modifiers;
while (true)
{
isDeclaredConst = true;
m_scanner->next();
if (m_scanner->getCurrentToken() == Token::CONST)
{
isDeclaredConst = true;
m_scanner->next();
}
else if (m_scanner->getCurrentToken() == Token::IDENTIFIER)
modifiers.push_back(parseModifierInvocation());
else
break;
}
ASTPointer<ParameterList> returnParameters;
if (m_scanner->getCurrentToken() == Token::RETURNS)
@ -212,8 +223,8 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic, A
nodeFactory.setEndPositionFromNode(block);
bool const c_isConstructor = (_contractName && *name == *_contractName);
return nodeFactory.createNode<FunctionDefinition>(name, _isPublic, c_isConstructor, docstring,
parameters,
isDeclaredConst, returnParameters, block);
parameters, isDeclaredConst, modifiers,
returnParameters, block);
}
ASTPointer<StructDefinition> Parser::parseStructDefinition()
@ -242,6 +253,50 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(bool _allowVar)
return nodeFactory.createNode<VariableDeclaration>(type, expectIdentifierToken());
}
ASTPointer<ModifierDefinition> Parser::parseModifierDefinition()
{
ScopeGuard resetModifierFlag([this]() { m_insideModifier = false; });
m_insideModifier = true;
ASTNodeFactory nodeFactory(*this);
ASTPointer<ASTString> docstring;
if (m_scanner->getCurrentCommentLiteral() != "")
docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral());
expectToken(Token::MODIFIER);
ASTPointer<ASTString> name(expectIdentifierToken());
ASTPointer<ParameterList> parameters;
if (m_scanner->getCurrentToken() == Token::LPAREN)
parameters = parseParameterList();
else
{
// create an empty parameter list at a zero-length location
ASTNodeFactory nodeFactory(*this);
nodeFactory.setLocationEmpty();
parameters = nodeFactory.createNode<ParameterList>(vector<ASTPointer<VariableDeclaration>>());
}
ASTPointer<Block> block = parseBlock();
nodeFactory.setEndPositionFromNode(block);
return nodeFactory.createNode<ModifierDefinition>(name, docstring, parameters, block);
}
ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()
{
ASTNodeFactory nodeFactory(*this);
ASTPointer<Identifier> name = ASTNodeFactory(*this).createNode<Identifier>(expectIdentifierToken());
vector<ASTPointer<Expression>> arguments;
if (m_scanner->getCurrentToken() == Token::LPAREN)
{
m_scanner->next();
arguments = parseFunctionCallArguments();
nodeFactory.markEndPosition();
expectToken(Token::RPAREN);
}
else
nodeFactory.setEndPositionFromNode(name);
return nodeFactory.createNode<ModifierInvocation>(name, arguments);
}
ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
{
ASTPointer<TypeName> type;
@ -354,8 +409,16 @@ ASTPointer<Statement> Parser::parseStatement()
nodeFactory.setEndPositionFromNode(expression);
}
statement = nodeFactory.createNode<Return>(expression);
break;
}
break;
case Token::IDENTIFIER:
if (m_insideModifier && m_scanner->getCurrentLiteral() == "_")
{
statement = ASTNodeFactory(*this).createNode<PlaceholderStatement>();
m_scanner->next();
return statement;
}
// fall-through
default:
statement = parseVarDefOrExprStmt();
}

4
libsolidity/Parser.h

@ -53,6 +53,8 @@ private:
ASTPointer<FunctionDefinition> parseFunctionDefinition(bool _isPublic, ASTString const* _contractName);
ASTPointer<StructDefinition> parseStructDefinition();
ASTPointer<VariableDeclaration> parseVariableDeclaration(bool _allowVar);
ASTPointer<ModifierDefinition> parseModifierDefinition();
ASTPointer<ModifierInvocation> parseModifierInvocation();
ASTPointer<TypeName> parseTypeName(bool _allowVar);
ASTPointer<Mapping> parseMapping();
ASTPointer<ParameterList> parseParameterList(bool _allowEmpty = true);
@ -90,6 +92,8 @@ private:
ParserError createParserError(std::string const& _description) const;
std::shared_ptr<Scanner> m_scanner;
/// Flag that signifies whether '_' is parsed as a PlaceholderStatement or a regular identifier.
bool m_insideModifier = false;
};
}

1
libsolidity/Token.h

@ -159,6 +159,7 @@ namespace solidity
K(IF, "if", 0) \
K(IMPORT, "import", 0) \
K(MAPPING, "mapping", 0) \
K(MODIFIER, "modifier", 0) \
K(NEW, "new", 0) \
K(PUBLIC, "public", 0) \
K(PRIVATE, "private", 0) \

48
libsolidity/Types.cpp

@ -140,6 +140,11 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
if (_convertTo.getCategory() == Category::STRING)
{
StaticStringType const& convertTo = dynamic_cast<StaticStringType const&>(_convertTo);
return isHash() && (m_bits == convertTo.getNumBytes() * 8);
}
return _convertTo.getCategory() == getCategory() || _convertTo.getCategory() == Category::CONTRACT;
}
@ -367,6 +372,17 @@ bool StaticStringType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return convertTo.m_bytes >= m_bytes;
}
bool StaticStringType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
if (_convertTo.getCategory() == Category::INTEGER)
{
IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
if (convertTo.isHash() && (m_bytes * 8 == convertTo.getNumBits()))
return true;
}
return isImplicitlyConvertibleTo(_convertTo);
}
bool StaticStringType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())
@ -724,6 +740,38 @@ MemberList const& TypeType::getMembers() const
return *m_members;
}
ModifierType::ModifierType(const ModifierDefinition& _modifier)
{
TypePointers params;
params.reserve(_modifier.getParameters().size());
for (ASTPointer<VariableDeclaration> const& var: _modifier.getParameters())
params.push_back(var->getType());
swap(params, m_parameterTypes);
}
bool ModifierType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())
return false;
ModifierType const& other = dynamic_cast<ModifierType const&>(_other);
if (m_parameterTypes.size() != other.m_parameterTypes.size())
return false;
auto typeCompare = [](TypePointer const& _a, TypePointer const& _b) -> bool { return *_a == *_b; };
if (!equal(m_parameterTypes.cbegin(), m_parameterTypes.cend(),
other.m_parameterTypes.cbegin(), typeCompare))
return false;
return true;
}
string ModifierType::toString() const
{
string name = "modifier (";
for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
name += (*it)->toString() + (it + 1 == m_parameterTypes.end() ? "" : ",");
return name + ")";
}
MagicType::MagicType(MagicType::Kind _kind):
m_kind(_kind)

26
libsolidity/Types.h

@ -75,7 +75,7 @@ class Type: private boost::noncopyable, public std::enable_shared_from_this<Type
public:
enum class Category
{
INTEGER, INTEGER_CONSTANT, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE, MAGIC
INTEGER, INTEGER_CONSTANT, BOOL, REAL, STRING, CONTRACT, STRUCT, FUNCTION, MAPPING, VOID, TYPE, MODIFIER, MAGIC
};
///@{
@ -233,9 +233,10 @@ public:
/// if no type fits.
static std::shared_ptr<StaticStringType> smallestTypeForLiteral(std::string const& _literal);
StaticStringType(int _bytes);
explicit StaticStringType(int _bytes);
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool operator==(Type const& _other) const override;
virtual unsigned getCalldataEncodedSize() const override { return m_bytes; }
@ -463,6 +464,27 @@ private:
};
/**
* The type of a function modifier. Not used for anything for now.
*/
class ModifierType: public Type
{
public:
virtual Category getCategory() const override { return Category::MODIFIER; }
explicit ModifierType(ModifierDefinition const& _modifier);
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
virtual bool canBeStored() const override { return false; }
virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); }
virtual bool canLiveOutsideStorage() const override { return false; }
virtual bool operator==(Type const& _other) const override;
virtual std::string toString() const override;
private:
TypePointers m_parameterTypes;
};
/**
* Special type for magic variables (block, msg, tx), similar to a struct but without any reference
* (it always references a global singleton by name).

6
libsolidity/grammar.txt

@ -1,14 +1,14 @@
ContractDefinition = 'contract' Identifier
( 'is' InheritanceSpecifier (',' InheritanceSpecifier )* )?
'{' ContractPart* '}'
ContractPart = VariableDeclaration ';' | StructDefinition |
ContractPart = VariableDeclaration ';' | StructDefinition | ModifierDefinition |
FunctionDefinition | 'public:' | 'private:'
InheritanceSpecifier = Identifier ( '(' Expression ( ',' Expression )* ')' )?
StructDefinition = 'struct' Identifier '{'
( VariableDeclaration (';' VariableDeclaration)* )? '}
FunctionDefinition = 'function' Identifier ParameterList 'const'?
ModifierDefinition = 'modifier' Identifier ParameterList? Block
FunctionDefinition = 'function' Identifier ParameterList ( Identifier | 'constant' )*
( 'returns' ParameterList )? Block
ParameterList = '(' ( VariableDeclaration (',' VariableDeclaration)* )? ')'
// semantic restriction: mappings and structs (recursively) containing mappings

1
mix/qml/html/WebContainer.html

@ -1,7 +1,6 @@
<!doctype html>
<html>
<head>
<script src="qrc:///js/es6-promise-2.0.0.js"></script>
<script src="qrc:///js/bignumber.min.js"></script>
<script src="qrc:///js/webthree.js"></script>
<script>

78
standard.js

@ -1,5 +1,3 @@
///TODO
var compile = function(name) { return web3.eth.solidity(env.contents("/home/gav/Eth/dapp-bin/" + name + "/" + name + ".sol")); web3.eth.flush(); };
var create = function(code) { return web3.eth.transact({ 'code': code }); web3.eth.flush(); };
var createVal = function(code, val) { return web3.eth.transact(val ? { 'code': code, 'value': val } : { 'code': code }); web3.eth.flush(); };
@ -11,6 +9,8 @@ var addrConfig = create(compile("config"));
var addrNameReg = initService("namereg");
var addrGavsino = initServiceVal("gavmble", "1000000000000000000");
var addrCoinReg = initService("coins");
var addrGavCoin = initService("coin");
var addrRegistrar = initService("registrar");
var abiNameReg = [{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"getName","outputs":[{"name":"o_name","type":"string32"}]},{"constant":false,"inputs":[{"name":"name","type":"string32"}],"name":"register","outputs":[]},{"constant":true,"inputs":[{"name":"name","type":"string32"}],"name":"addressOf","outputs":[{"name":"addr","type":"address"}]},{"constant":true,"inputs":[{"name":"_name","type":"string32"}],"name":"getAddress","outputs":[{"name":"o_owner","type":"address"}]},{"constant":false,"inputs":[],"name":"unregister","outputs":[]},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"nameOf","outputs":[{"name":"name","type":"string32"}]}];
var regName = function(account, name) { return web3.eth.contract(addrNameReg, abiNameReg).transact({'from': account, 'gas': 10000}).register(name); };
@ -19,71 +19,11 @@ send(web3.eth.accounts[0], '100000000000000000000', web3.eth.accounts[1]);
regName(web3.eth.accounts[0], 'Gav');
regName(web3.eth.accounts[1], 'Gav Would');
/*
// ASYNC API
var compile = function(name) { return web3.eth.solidity(env.contents("/home/gav/Eth/dapp-bin/" + name + "/" + name + ".sol")); };
var create = function(code) { return web3.eth.transact({ 'code': code }); };
var createVal = function(code, val) { return web3.eth.transact(val ? { 'code': code, 'value': val } : { 'code': code }); };
var send = function(from, val, to) { return web3.eth.transact({ 'from': from, 'value': val, 'to': to }); };
var initService = function(name, dep) { return dep.then(function(){ return compile(name).then(create); }); };
var initServiceVal = function(name, dep, val) { return dep.then(function(){ return compile(name).then(function(c) { createVal(c, val); }); }); };
var addrConfig = compile("config").then(create);
var addrNameReg = initService("namereg", addrConfig);
var addrGavsino = initServiceVal("gavmble", addrNameReg, "1000000000000000000");
var abiNameReg = [{"constant":true,"inputs":[{"name":"name","type":"string32"}],"name":"addressOf","outputs":[{"name":"addr","type":"address"}]},{"constant":false,"inputs":[],"name":"kill","outputs":[]},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"nameOf","outputs":[{"name":"name","type":"string32"}]},{"constant":false,"inputs":[{"name":"name","type":"string32"}],"name":"register","outputs":[]},{"constant":false,"inputs":[],"name":"unregister","outputs":[]}];
var regName = function(account, name) { return web3.contract(addrNameReg, abiNameReg).register(name).transact({'from': account, 'gas': 10000}); };
//var coins = initService("coins", 1, nameReg);
//var coin = initService("coin", 2, coins);
//var approve = function(account, approvedAddress) { web3.eth.transact({ 'from': account, 'to': coin, 'gas': '10000', 'data': [ web3.fromAscii('approve'), approvedAddress ] }); };
//var exchange = initService("exchange", 3, coin);
//var offer = function(account, haveCoin, haveVal, wantCoin, wantVal) { web3.eth.transact({ 'from': account, 'to': exchange, 'gas': '10000', 'data': [web3.fromAscii('new'), haveCoin, haveVal, wantCoin, wantVal] }); };
addrConfig.then(function() {
env.note("config ready");
web3.eth.accounts.then(function(accounts)
{
env.note("accounts ready");
var funded = send(accounts[0], '100000000000000000000', accounts[1]);
funded.then(function(){
env.note("second account funded");
regName(accounts[1], 'Gav Would');
});
regName(accounts[0], 'Gav');
// TODO: once we have the exchange.
// approve(accounts[0], exchange).then(function(){ offer(accounts[0], coin, '5000', '0', '5000000000000000000'); });
// funded.then(function(){ approve(accounts[1], exchange); });
// TODO: once we have a new implementation of DNSReg.
// env.note('Register gav.eth...')
// eth.transact({ 'to': dnsReg, 'data': [web3.fromAscii('register'), web3.fromAscii('gav'), web3.fromAscii('opensecrecy.com')] });
});
});
*/
// TODO
/*
var nameRegJeff;
env.note('Create NameRegJeff...')
eth.transact({ 'code': nameRegCode }, function(a) { nameRegJeff = a; });
env.note('Register NameRegJeff...')
eth.transact({ 'to': config, 'data': ['4', nameRegJeff] });
var dnsRegCode = '0x60006000546000600053602001546000600053604001546020604060206020600073661005d2720d855f1d9976f88bb10c1a3398c77f6103e8f17f7265676973746572000000000000000000000000000000000000000000000000600053606001600060200201547f446e735265670000000000000000000000000000000000000000000000000000600053606001600160200201546000600060006000604060606000600053604001536103e8f1327f6f776e65720000000000000000000000000000000000000000000000000000005761011663000000e46000396101166000f20060006000547f72656769737465720000000000000000000000000000000000000000000000006000602002350e0f630000006d596000600160200235560e0f630000006c59600032560e0f0f6300000057596000325657600260200235600160200235576001602002353257007f64657265676973746572000000000000000000000000000000000000000000006000602002350e0f63000000b95960016020023532560e0f63000000b959600032576000600160200235577f6b696c6c000000000000000000000000000000000000000000000000000000006000602002350e0f630000011559327f6f776e6572000000000000000000000000000000000000000000000000000000560e0f63000001155932ff00';
var dnsReg;
env.note('Create DnsReg...')
eth.transact({ 'code': dnsRegCode }, function(a) { dnsReg = a; });
env.note('DnsReg at address ' + dnsReg)
env.note('Register DnsReg...')
eth.transact({ 'to': config, 'data': ['4', dnsReg] });
*/
// TODO: once we have the exchange.
// var offer = function(account, haveCoin, haveVal, wantCoin, wantVal) { web3.eth.transact({ 'from': account, 'to': exchange, 'gas': '10000', 'data': [web3.fromAscii('new'), haveCoin, haveVal, wantCoin, wantVal] }); };
// approve(accounts[0], exchange).then(function(){ offer(accounts[0], coin, '5000', '0', '5000000000000000000'); });
// funded.then(function(){ approve(accounts[1], exchange); });
// env.load('/home/gav/Eth/cpp-ethereum/stdserv.js')
// TODO: once we have a new implementation of DNSReg.
// env.note('Register gav.eth...')
// eth.transact({ 'to': dnsReg, 'data': [web3.fromAscii('register'), web3.fromAscii('gav'), web3.fromAscii('opensecrecy.com')] });

212
test/SolidityEndToEndTest.cpp

@ -940,6 +940,97 @@ BOOST_AUTO_TEST_CASE(type_conversions_cleanup)
0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22}));
}
BOOST_AUTO_TEST_CASE(convert_string_to_string)
{
char const* sourceCode = R"(
contract Test {
function pipeTrough(string3 input) returns (string3 ret) {
return string3(input);
}
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("pipeTrough(string3)", "abc") == encodeArgs("abc"));
}
BOOST_AUTO_TEST_CASE(convert_hash_to_string_same_size)
{
char const* sourceCode = R"(
contract Test {
function hashToString(hash h) returns (string32 s) {
return string32(h);
}
})";
compileAndRun(sourceCode);
u256 a("0x6162630000000000000000000000000000000000000000000000000000000000");
BOOST_CHECK(callContractFunction("hashToString(hash256)", a) == encodeArgs(a));
}
BOOST_AUTO_TEST_CASE(convert_hash_to_string_different_size)
{
char const* sourceCode = R"(
contract Test {
function hashToString(hash160 h) returns (string20 s) {
return string20(h);
}
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("hashToString(hash160)", u160("0x6161626361626361626361616263616263616263")) ==
encodeArgs(string("aabcabcabcaabcabcabc")));
}
BOOST_AUTO_TEST_CASE(convert_string_to_hash_same_size)
{
char const* sourceCode = R"(
contract Test {
function stringToHash(string32 s) returns (hash h) {
return hash(s);
}
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("stringToHash(string32)", string("abc2")) ==
encodeArgs(u256("0x6162633200000000000000000000000000000000000000000000000000000000")));
}
BOOST_AUTO_TEST_CASE(convert_string_to_hash_different_size)
{
char const* sourceCode = R"(
contract Test {
function stringToHash(string20 s) returns (hash160 h) {
return hash160(s);
}
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("stringToHash(string20)", string("aabcabcabcaabcabcabc")) ==
encodeArgs(u160("0x6161626361626361626361616263616263616263")));
}
BOOST_AUTO_TEST_CASE(convert_string_to_hash_different_min_size)
{
char const* sourceCode = R"(
contract Test {
function stringToHash(string1 s) returns (hash8 h) {
return hash8(s);
}
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("stringToHash(string1)", string("a")) ==
encodeArgs(u256("0x61")));
}
BOOST_AUTO_TEST_CASE(convert_hash_to_string_different_min_size)
{
char const* sourceCode = R"(
contract Test {
function HashToString(hash8 h) returns (string1 s) {
return string1(h);
}
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("HashToString(hash8)", u256("0x61")) ==
encodeArgs(string("a")));
}
BOOST_AUTO_TEST_CASE(send_ether)
{
@ -1650,6 +1741,127 @@ BOOST_AUTO_TEST_CASE(constructor_argument_overriding)
BOOST_CHECK(callContractFunction("getA()") == encodeArgs(3));
}
BOOST_AUTO_TEST_CASE(function_modifier)
{
char const* sourceCode = R"(
contract C {
function getOne() nonFree returns (uint r) { return 1; }
modifier nonFree { if (msg.value > 0) _ }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("getOne()") == encodeArgs(0));
BOOST_CHECK(callContractFunctionWithValue("getOne()", 1) == encodeArgs(1));
}
BOOST_AUTO_TEST_CASE(function_modifier_local_variables)
{
char const* sourceCode = R"(
contract C {
modifier mod1 { var a = 1; var b = 2; _ }
modifier mod2(bool a) { if (a) return; else _ }
function f(bool a) mod1 mod2(a) returns (uint r) { return 3; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(0));
BOOST_CHECK(callContractFunction("f(bool)", false) == encodeArgs(3));
}
BOOST_AUTO_TEST_CASE(function_modifier_loop)
{
char const* sourceCode = R"(
contract C {
modifier repeat(uint count) { for (var i = 0; i < count; ++i) _ }
function f() repeat(10) returns (uint r) { r += 1; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("f()") == encodeArgs(10));
}
BOOST_AUTO_TEST_CASE(function_modifier_multi_invocation)
{
char const* sourceCode = R"(
contract C {
modifier repeat(bool twice) { if (twice) _ _ }
function f(bool twice) repeat(twice) returns (uint r) { r += 1; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("f(bool)", false) == encodeArgs(1));
BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(2));
}
BOOST_AUTO_TEST_CASE(function_modifier_multi_with_return)
{
// Here, the explicit return prevents the second execution
char const* sourceCode = R"(
contract C {
modifier repeat(bool twice) { if (twice) _ _ }
function f(bool twice) repeat(twice) returns (uint r) { r += 1; return r; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("f(bool)", false) == encodeArgs(1));
BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(1));
}
BOOST_AUTO_TEST_CASE(function_modifier_overriding)
{
char const* sourceCode = R"(
contract A {
function f() mod returns (bool r) { return true; }
modifier mod { _ }
}
contract C is A {
modifier mod { }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("f()") == encodeArgs(false));
}
BOOST_AUTO_TEST_CASE(function_modifier_calling_functions_in_creation_context)
{
char const* sourceCode = R"(
contract A {
uint data;
function A() mod1 { f1(); }
function f1() mod2 { data |= 0x1; }
function f2() { data |= 0x20; }
function f3() { }
modifier mod1 { f2(); _ }
modifier mod2 { f3(); }
function getData() returns (uint r) { return data; }
}
contract C is A {
modifier mod1 { f4(); _ }
function f3() { data |= 0x300; }
function f4() { data |= 0x4000; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("getData()") == encodeArgs(0x4300));
}
BOOST_AUTO_TEST_CASE(function_modifier_for_constructor)
{
char const* sourceCode = R"(
contract A {
uint data;
function A() mod1 { data |= 2; }
modifier mod1 { data |= 1; _ }
function getData() returns (uint r) { return data; }
}
contract C is A {
modifier mod1 { data |= 4; _ }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("getData()") == encodeArgs(4 | 2));
}
BOOST_AUTO_TEST_SUITE_END()
}

5
test/SolidityExpressionCompiler.cpp

@ -118,8 +118,11 @@ bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _
CompilerContext context;
for (vector<string> const& function: _functions)
context.addFunction(dynamic_cast<FunctionDefinition const&>(resolveDeclaration(function, resolver)));
unsigned parametersSize = _localVariables.size(); // assume they are all one slot on the stack
context.adjustStackOffset(parametersSize);
for (vector<string> const& variable: _localVariables)
context.addVariable(dynamic_cast<VariableDeclaration const&>(resolveDeclaration(variable, resolver)));
context.addVariable(dynamic_cast<VariableDeclaration const&>(resolveDeclaration(variable, resolver)),
parametersSize--);
ExpressionCompiler::compileExpression(context, *extractor.getExpression());

94
test/SolidityNameAndTypeResolution.cpp

@ -479,6 +479,7 @@ BOOST_AUTO_TEST_CASE(implicit_derived_to_base_conversion)
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(implicit_base_to_derived_conversion)
{
char const* text = R"(
@ -490,6 +491,99 @@ BOOST_AUTO_TEST_CASE(implicit_base_to_derived_conversion)
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(function_modifier_invocation)
{
char const* text = R"(
contract B {
function f() mod1(2, true) mod2("0123456") { }
modifier mod1(uint a, bool b) { if (b) _ }
modifier mod2(string7 a) { while (a == "1234567") _ }
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(invalid_function_modifier_type)
{
char const* text = R"(
contract B {
function f() mod1(true) { }
modifier mod1(uint a) { if (a > 0) _ }
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(function_modifier_invocation_parameters)
{
char const* text = R"(
contract B {
function f(uint8 a) mod1(a, true) mod2(r) returns (string7 r) { }
modifier mod1(uint a, bool b) { if (b) _ }
modifier mod2(string7 a) { while (a == "1234567") _ }
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables)
{
char const* text = R"(
contract B {
function f() mod(x) { uint x = 7; }
modifier mod(uint a) { if (a > 0) _ }
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(legal_modifier_override)
{
char const* text = R"(
contract A { modifier mod(uint a) {} }
contract B is A { modifier mod(uint a) {} }
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(illegal_modifier_override)
{
char const* text = R"(
contract A { modifier mod(uint a) {} }
contract B is A { modifier mod(uint8 a) {} }
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(modifier_overrides_function)
{
char const* text = R"(
contract A { modifier mod(uint a) {} }
contract B is A { function mod(uint a) {} }
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(function_overrides_modifier)
{
char const* text = R"(
contract A { function mod(uint a) {} }
contract B is A { modifier mod(uint a) {} }
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(modifier_returns_value)
{
char const* text = R"(
contract A {
function f(uint a) mod(2) returns (uint r) {}
modifier mod(uint a) { return 7; }
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_SUITE_END()
}

37
test/SolidityParser.cpp

@ -540,6 +540,43 @@ BOOST_AUTO_TEST_CASE(contract_multiple_inheritance_with_arguments)
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(placeholder_in_function_context)
{
char const* text = "contract c {\n"
" function fun() returns (uint r) {\n"
" var _ = 8;\n"
" return _ + 1;"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(modifier)
{
char const* text = "contract c {\n"
" modifier mod { if (msg.sender == 0) _ }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(modifier_arguments)
{
char const* text = "contract c {\n"
" modifier mod(uint a) { if (msg.sender == a) _ }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(modifier_invocation)
{
char const* text = "contract c {\n"
" modifier mod1(uint a) { if (msg.sender == a) _ }\n"
" modifier mod2 { if (msg.sender == 2) _ }\n"
" function f() mod1(7) mod2 { }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_SUITE_END()
}

2
test/whisperTopic.cpp

@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE(topic)
this_thread::sleep_for(chrono::milliseconds(50));
Host ph("Test", NetworkPreferences(50300, "", false, true));
auto wh = ph.registerCapability(new WhisperHost());
shared_ptr<WhisperHost> wh = ph.registerCapability(new WhisperHost());
this_thread::sleep_for(chrono::milliseconds(500));
ph.start();
this_thread::sleep_for(chrono::milliseconds(500));

Loading…
Cancel
Save