Browse Source

Merge branch 'develop' into mixonosx

cl-refactor
Marek Kotewicz 10 years ago
parent
commit
86796b5acd
  1. 12
      libethereum/CanonBlockChain.cpp
  2. 12
      libethereum/CanonBlockChain.h
  3. 2
      libethereum/State.cpp
  4. 2
      libjsqrc/ethereumjs/bower.json
  5. 377
      libjsqrc/ethereumjs/dist/ethereum.js
  6. 22
      libjsqrc/ethereumjs/dist/ethereum.js.map
  7. 2
      libjsqrc/ethereumjs/dist/ethereum.min.js
  8. 66
      libjsqrc/ethereumjs/example/event_inc.html
  9. 23
      libjsqrc/ethereumjs/lib/const.js
  10. 11
      libjsqrc/ethereumjs/lib/contract.js
  11. 72
      libjsqrc/ethereumjs/lib/event.js
  12. 7
      libjsqrc/ethereumjs/lib/filter.js
  13. 32
      libjsqrc/ethereumjs/lib/httpsync.js
  14. 65
      libjsqrc/ethereumjs/lib/jsonrpc.js
  15. 45
      libjsqrc/ethereumjs/lib/providermanager.js
  16. 3
      libjsqrc/ethereumjs/lib/qtsync.js
  17. 33
      libjsqrc/ethereumjs/lib/utils.js
  18. 62
      libjsqrc/ethereumjs/lib/web3.js
  19. 2
      libjsqrc/ethereumjs/package.json
  20. 438
      libjsqrc/ethereumjs/test/abi.inputParser.js
  21. 461
      libjsqrc/ethereumjs/test/abi.outputParser.js
  22. 2
      libjsqrc/ethereumjs/test/db.methods.js
  23. 2
      libjsqrc/ethereumjs/test/eth.methods.js
  24. 125
      libjsqrc/ethereumjs/test/event.inputParser.js
  25. 124
      libjsqrc/ethereumjs/test/event.js
  26. 81
      libjsqrc/ethereumjs/test/event.outputParser.js
  27. 128
      libjsqrc/ethereumjs/test/jsonrpc.isValidResponse.js
  28. 47
      libjsqrc/ethereumjs/test/jsonrpc.toBatchPayload.js
  29. 40
      libjsqrc/ethereumjs/test/jsonrpc.toPayload.js
  30. 2
      libjsqrc/ethereumjs/test/shh.methods.js
  31. 0
      libjsqrc/ethereumjs/test/test.utils.js
  32. 42
      libjsqrc/ethereumjs/test/utils.extractDisplayName.js
  33. 55
      libjsqrc/ethereumjs/test/utils.extractTypeName.js
  34. 2
      libjsqrc/ethereumjs/test/web3.methods.js
  35. 13
      libqwebthree/QWebThree.cpp
  36. 45
      libsolidity/AST.cpp
  37. 41
      libsolidity/AST.h
  38. 4
      libsolidity/Compiler.cpp
  39. 72
      libsolidity/ExpressionCompiler.cpp
  40. 4
      libsolidity/ExpressionCompiler.h
  41. 89
      libsolidity/Parser.cpp
  42. 7
      libsolidity/Parser.h
  43. 2
      libsolidity/Token.h
  44. 23
      libsolidity/Types.cpp
  45. 7
      libsolidity/grammar.txt
  46. 4
      mix/qml/StateDialog.qml
  47. 1
      mix/qml/StateList.qml
  48. 52
      mix/qml/StateListModel.qml
  49. 17
      mix/qml/main.qml
  50. 45
      test/SolidityEndToEndTest.cpp
  51. 98
      test/SolidityNameAndTypeResolution.cpp
  52. 31
      test/SolidityParser.cpp

12
libethereum/CanonBlockChain.cpp

@ -0,0 +1,12 @@
#include "CanonBlockChain.h"
CanonBlockChain::CanonBlockChain()
{
}
CanonBlockChain::~CanonBlockChain()
{
}

12
libethereum/CanonBlockChain.h

@ -0,0 +1,12 @@
#ifndef CANONBLOCKCHAIN_H
#define CANONBLOCKCHAIN_H
class CanonBlockChain
{
public:
CanonBlockChain();
~CanonBlockChain();
};
#endif // CANONBLOCKCHAIN_H

2
libethereum/State.cpp

@ -800,7 +800,7 @@ void State::completeMine()
ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentTxs);
ret.appendRaw(m_currentUncles); ret.appendRaw(m_currentUncles);
ret.swapOut(m_currentBytes); ret.swapOut(m_currentBytes);
m_currentBlock.hash = sha3(m_currentBytes); m_currentBlock.hash = sha3(RLP(m_currentBytes)[0].data());
cnote << "Mined " << m_currentBlock.hash.abridged() << "(parent: " << m_currentBlock.parentHash.abridged() << ")"; cnote << "Mined " << m_currentBlock.hash.abridged() << "(parent: " << m_currentBlock.parentHash.abridged() << ")";
// Quickly reset the transactions. // Quickly reset the transactions.

2
libjsqrc/ethereumjs/bower.json

@ -1,7 +1,7 @@
{ {
"name": "ethereum.js", "name": "ethereum.js",
"namespace": "ethereum", "namespace": "ethereum",
"version": "0.0.11", "version": "0.0.13",
"description": "Ethereum Compatible JavaScript API", "description": "Ethereum Compatible JavaScript API",
"main": ["./dist/ethereum.js", "./dist/ethereum.min.js"], "main": ["./dist/ethereum.js", "./dist/ethereum.min.js"],
"dependencies": { "dependencies": {

377
libjsqrc/ethereumjs/dist/ethereum.js

@ -210,7 +210,7 @@ module.exports = {
}; };
},{"./const":2,"./formatters":6,"./types":10,"./utils":11,"./web3":12}],2:[function(require,module,exports){ },{"./const":2,"./formatters":6,"./types":11,"./utils":12,"./web3":13}],2:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -238,9 +238,32 @@ if ("build" !== 'build') {/*
var BigNumber = require('bignumber.js'); // jshint ignore:line var BigNumber = require('bignumber.js'); // jshint ignore:line
*/} */}
var ETH_UNITS = [
'wei',
'Kwei',
'Mwei',
'Gwei',
'szabo',
'finney',
'ether',
'grand',
'Mether',
'Gether',
'Tether',
'Pether',
'Eether',
'Zether',
'Yether',
'Nether',
'Dether',
'Vether',
'Uether'
];
module.exports = { module.exports = {
ETH_PADDING: 32, ETH_PADDING: 32,
ETH_SIGNATURE_LENGTH: 4, ETH_SIGNATURE_LENGTH: 4,
ETH_UNITS: ETH_UNITS,
ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN } ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }
}; };
@ -368,6 +391,11 @@ var addFunctionsToContract = function (contract, desc, address) {
var addEventRelatedPropertiesToContract = function (contract, desc, address) { var addEventRelatedPropertiesToContract = function (contract, desc, address) {
contract.address = address; contract.address = address;
contract._onWatchEventResult = function (data) {
var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc));
var parser = eventImpl.outputParser(matchingEvent);
return parser(data);
};
Object.defineProperty(contract, 'topic', { Object.defineProperty(contract, 'topic', {
get: function() { get: function() {
@ -386,8 +414,12 @@ var addEventsToContract = function (contract, desc, address) {
var impl = function () { var impl = function () {
var params = Array.prototype.slice.call(arguments); var params = Array.prototype.slice.call(arguments);
var signature = abi.eventSignatureFromAscii(e.name); var signature = abi.eventSignatureFromAscii(e.name);
var event = eventImpl(address, signature, e); var event = eventImpl.inputParser(address, signature, e);
var o = event.apply(null, params); var o = event.apply(null, params);
o._onWatchEventResult = function (data) {
var parser = eventImpl.outputParser(e);
return parser(data);
};
return web3.eth.watch(o); return web3.eth.watch(o);
}; };
@ -455,7 +487,7 @@ var contract = function (address, desc) {
module.exports = contract; module.exports = contract;
},{"./abi":1,"./event":4,"./utils":11,"./web3":12}],4:[function(require,module,exports){ },{"./abi":1,"./event":4,"./utils":12,"./web3":13}],4:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -481,6 +513,16 @@ module.exports = contract;
var abi = require('./abi'); var abi = require('./abi');
var utils = require('./utils'); var utils = require('./utils');
/// filter inputs array && returns only indexed (or not) inputs
/// @param inputs array
/// @param bool if result should be an array of indexed params on not
/// @returns array of (not?) indexed params
var filterInputs = function (inputs, indexed) {
return inputs.filter(function (current) {
return current.indexed === indexed;
});
};
var inputWithName = function (inputs, name) { var inputWithName = function (inputs, name) {
var index = utils.findIndex(inputs, function (input) { var index = utils.findIndex(inputs, function (input) {
return input.name === name; return input.name === name;
@ -496,7 +538,7 @@ var inputWithName = function (inputs, name) {
var indexedParamsToTopics = function (event, indexed) { var indexedParamsToTopics = function (event, indexed) {
// sort keys? // sort keys?
return Object.keys(indexed).map(function (key) { return Object.keys(indexed).map(function (key) {
var inputs = [inputWithName(event.inputs, key)]; var inputs = [inputWithName(filterInputs(event.inputs, true), key)];
var value = indexed[key]; var value = indexed[key];
if (value instanceof Array) { if (value instanceof Array) {
@ -508,7 +550,7 @@ var indexedParamsToTopics = function (event, indexed) {
}); });
}; };
var implementationOfEvent = function (address, signature, event) { var inputParser = function (address, signature, event) {
// valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch' // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'
return function (indexed, options) { return function (indexed, options) {
@ -523,10 +565,66 @@ var implementationOfEvent = function (address, signature, event) {
}; };
}; };
module.exports = implementationOfEvent; var getArgumentsObject = function (inputs, indexed, notIndexed) {
var indexedCopy = indexed.slice();
var notIndexedCopy = notIndexed.slice();
return inputs.reduce(function (acc, current) {
var value;
if (current.indexed)
value = indexed.splice(0, 1)[0];
else
value = notIndexed.splice(0, 1)[0];
acc[current.name] = value;
return acc;
}, {});
};
var outputParser = function (event) {
return function (output) {
var result = {
event: utils.extractDisplayName(event.name),
number: output.number,
args: {}
};
if (!output.topic) {
return result;
}
var indexedOutputs = filterInputs(event.inputs, true);
var indexedData = "0x" + output.topic.slice(1, output.topic.length).map(function (topic) { return topic.slice(2); }).join("");
var indexedRes = abi.formatOutput(indexedOutputs, indexedData);
var notIndexedOutputs = filterInputs(event.inputs, false);
var notIndexedRes = abi.formatOutput(notIndexedOutputs, output.data);
result.args = getArgumentsObject(event.inputs, indexedRes, notIndexedRes);
return result;
};
};
var getMatchingEvent = function (events, payload) {
for (var i = 0; i < events.length; i++) {
var signature = abi.eventSignatureFromAscii(events[i].name);
if (signature === payload.topic[0]) {
return events[i];
}
}
return undefined;
};
module.exports = {
inputParser: inputParser,
outputParser: outputParser,
getMatchingEvent: getMatchingEvent
};
},{"./abi":1,"./utils":11}],5:[function(require,module,exports){ },{"./abi":1,"./utils":12}],5:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -565,6 +663,8 @@ var Filter = function(options, impl) {
if (options.topics) { if (options.topics) {
console.warn('"topics" is deprecated, use "topic" instead'); console.warn('"topics" is deprecated, use "topic" instead');
} }
this._onWatchResult = options._onWatchEventResult;
// evaluate lazy properties // evaluate lazy properties
options = { options = {
@ -583,7 +683,7 @@ var Filter = function(options, impl) {
this.callbacks = []; this.callbacks = [];
this.id = impl.newFilter(options); this.id = impl.newFilter(options);
web3.provider.startPolling({call: impl.changed, args: [this.id]}, this.id, this.trigger.bind(this)); web3.provider.startPolling({method: impl.changed, params: [this.id]}, this.id, this.trigger.bind(this));
}; };
/// alias for changed* /// alias for changed*
@ -603,7 +703,8 @@ Filter.prototype.changed = function(callback) {
Filter.prototype.trigger = function(messages) { Filter.prototype.trigger = function(messages) {
for (var i = 0; i < this.callbacks.length; i++) { for (var i = 0; i < this.callbacks.length; i++) {
for (var j = 0; j < messages.length; j++) { for (var j = 0; j < messages.length; j++) {
this.callbacks[i].call(this, messages[j]); var message = this._onWatchResult ? this._onWatchResult(messages[j]) : messages[j];
this.callbacks[i].call(this, message);
} }
} }
}; };
@ -626,7 +727,7 @@ Filter.prototype.logs = function () {
module.exports = Filter; module.exports = Filter;
},{"./web3":12}],6:[function(require,module,exports){ },{"./web3":13}],6:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -782,7 +883,7 @@ module.exports = {
}; };
},{"./const":2,"./utils":11}],7:[function(require,module,exports){ },{"./const":2,"./utils":12}],7:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -815,40 +916,16 @@ var HttpSyncProvider = function (host) {
this.host = host || 'http://localhost:8080'; this.host = host || 'http://localhost:8080';
}; };
/// Transforms inner message to proper jsonrpc object
/// @param inner message object
/// @returns jsonrpc object
function formatJsonRpcObject(object) {
return {
jsonrpc: '2.0',
method: object.call,
params: object.args,
id: object._id
};
}
/// Transforms jsonrpc object to inner message
/// @param incoming jsonrpc message
/// @returns inner message object
function formatJsonRpcMessage(message) {
var object = JSON.parse(message);
return {
_id: object.id,
data: object.result,
error: object.error
};
}
HttpSyncProvider.prototype.send = function (payload) { HttpSyncProvider.prototype.send = function (payload) {
var data = formatJsonRpcObject(payload); //var data = formatJsonRpcObject(payload);
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('POST', this.host, false); request.open('POST', this.host, false);
request.send(JSON.stringify(data)); request.send(JSON.stringify(payload));
// check request.status // check request.status
return request.responseText; var result = request.responseText;
return JSON.parse(result);
}; };
module.exports = HttpSyncProvider; module.exports = HttpSyncProvider;
@ -871,6 +948,73 @@ module.exports = HttpSyncProvider;
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>. along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file jsonrpc.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var messageId = 1;
/// Should be called to valid json create payload object
/// @param method of jsonrpc call, required
/// @param params, an array of method params, optional
/// @returns valid jsonrpc payload object
var toPayload = function (method, params) {
if (!method)
console.error('jsonrpc method should be specified!');
return {
jsonrpc: '2.0',
method: method,
params: params || [],
id: messageId++
};
};
/// Should be called to check if jsonrpc response is valid
/// @returns true if response is valid, otherwise false
var isValidResponse = function (response) {
return !!response &&
!response.error &&
response.jsonrpc === '2.0' &&
typeof response.id === 'number' &&
(!!response.result || typeof response.result === 'boolean');
};
/// Should be called to create batch payload object
/// @param messages, an array of objects with method (required) and params (optional) fields
var toBatchPayload = function (messages) {
return messages.map(function (message) {
return toPayload(message.method, message.params);
});
};
module.exports = {
toPayload: toPayload,
isValidResponse: isValidResponse,
toBatchPayload: toBatchPayload
};
},{}],9:[function(require,module,exports){
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file providermanager.js /** @file providermanager.js
* @authors: * @authors:
* Jeffrey Wilcke <jeff@ethdev.com> * Jeffrey Wilcke <jeff@ethdev.com>
@ -880,7 +1024,9 @@ module.exports = HttpSyncProvider;
* @date 2014 * @date 2014
*/ */
var web3 = require('./web3'); // jshint ignore:line var web3 = require('./web3');
var jsonrpc = require('./jsonrpc');
/** /**
* Provider manager object prototype * Provider manager object prototype
@ -894,25 +1040,35 @@ var web3 = require('./web3'); // jshint ignore:line
var ProviderManager = function() { var ProviderManager = function() {
this.polls = []; this.polls = [];
this.provider = undefined; this.provider = undefined;
this.id = 1;
var self = this; var self = this;
var poll = function () { var poll = function () {
if (self.provider) { if (self.provider) {
self.polls.forEach(function (data) { var pollsBatch = self.polls.map(function (data) {
data.data._id = self.id; return data.data;
self.id++; });
var result = self.provider.send(data.data);
var payload = jsonrpc.toBatchPayload(pollsBatch);
result = JSON.parse(result); var results = self.provider.send(payload);
self.polls.forEach(function (data, index) {
var result = results[index];
if (!jsonrpc.isValidResponse(result)) {
console.log(result);
return;
}
result = result.result;
// dont call the callback if result is not an array, or empty one // dont call the callback if result is not an array, or empty one
if (result.error || !(result.result instanceof Array) || result.result.length === 0) { if (!(result instanceof Array) || result.length === 0) {
return; return;
} }
data.callback(result.result); data.callback(result);
}); });
} }
setTimeout(poll, 1000); setTimeout(poll, 1000);
}; };
@ -920,22 +1076,19 @@ var ProviderManager = function() {
}; };
/// sends outgoing requests /// sends outgoing requests
/// @params data - an object with at least 'method' property
ProviderManager.prototype.send = function(data) { ProviderManager.prototype.send = function(data) {
var payload = jsonrpc.toPayload(data.method, data.params);
data.args = data.args || [];
data._id = this.id++;
if (this.provider === undefined) { if (this.provider === undefined) {
console.error('provider is not set'); console.error('provider is not set');
return null; return null;
} }
//TODO: handle error here? var result = this.provider.send(payload);
var result = this.provider.send(data);
result = JSON.parse(result);
if (result.error) { if (!jsonrpc.isValidResponse(result)) {
console.log(result.error); console.log(result);
return null; return null;
} }
@ -966,7 +1119,7 @@ ProviderManager.prototype.stopPolling = function (pollId) {
module.exports = ProviderManager; module.exports = ProviderManager;
},{"./web3":12}],9:[function(require,module,exports){ },{"./jsonrpc":8,"./web3":13}],10:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -994,13 +1147,14 @@ var QtSyncProvider = function () {
}; };
QtSyncProvider.prototype.send = function (payload) { QtSyncProvider.prototype.send = function (payload) {
return navigator.qt.callMethod(JSON.stringify(payload)); var result = navigator.qt.callMethod(JSON.stringify(payload));
return JSON.parse(result);
}; };
module.exports = QtSyncProvider; module.exports = QtSyncProvider;
},{}],10:[function(require,module,exports){ },{}],11:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -1081,7 +1235,7 @@ module.exports = {
}; };
},{"./formatters":6}],11:[function(require,module,exports){ },{"./formatters":6}],12:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -1104,6 +1258,8 @@ module.exports = {
* @date 2015 * @date 2015
*/ */
var c = require('./const');
/// Finds first index of array element matching pattern /// Finds first index of array element matching pattern
/// @param array /// @param array
/// @param callback pattern /// @param callback pattern
@ -1166,7 +1322,7 @@ var extractDisplayName = function (name) {
var extractTypeName = function (name) { var extractTypeName = function (name) {
/// TODO: make it invulnerable /// TODO: make it invulnerable
var length = name.indexOf('('); var length = name.indexOf('(');
return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)) : ""; return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : "";
}; };
/// Filters all function from input abi /// Filters all function from input abi
@ -1185,6 +1341,32 @@ var filterEvents = function (json) {
}); });
}; };
/// used to transform value/string to eth string
/// TODO: use BigNumber.js to parse int
/// TODO: add tests for it!
var toEth = function (str) {
var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
var unit = 0;
var units = c.ETH_UNITS;
while (val > 3000 && unit < units.length - 1)
{
val /= 1000;
unit++;
}
var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);
var replaceFunction = function($0, $1, $2) {
return $1 + ',' + $2;
};
while (true) {
var o = s;
s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction);
if (o === s)
break;
}
return s + ' ' + units[unit];
};
module.exports = { module.exports = {
findIndex: findIndex, findIndex: findIndex,
toAscii: toAscii, toAscii: toAscii,
@ -1192,11 +1374,12 @@ module.exports = {
extractDisplayName: extractDisplayName, extractDisplayName: extractDisplayName,
extractTypeName: extractTypeName, extractTypeName: extractTypeName,
filterFunctions: filterFunctions, filterFunctions: filterFunctions,
filterEvents: filterEvents filterEvents: filterEvents,
toEth: toEth
}; };
},{}],12:[function(require,module,exports){ },{"./const":2}],13:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -1228,28 +1411,6 @@ if ("build" !== 'build') {/*
var utils = require('./utils'); var utils = require('./utils');
var ETH_UNITS = [
'wei',
'Kwei',
'Mwei',
'Gwei',
'szabo',
'finney',
'ether',
'grand',
'Mether',
'Gether',
'Tether',
'Pether',
'Eether',
'Zether',
'Yether',
'Nether',
'Dether',
'Vether',
'Uether'
];
/// @returns an array of objects describing web3 api methods /// @returns an array of objects describing web3 api methods
var web3Methods = function () { var web3Methods = function () {
return [ return [
@ -1357,8 +1518,8 @@ var setupMethods = function (obj, methods) {
var args = Array.prototype.slice.call(arguments); var args = Array.prototype.slice.call(arguments);
var call = typeof method.call === 'function' ? method.call(args) : method.call; var call = typeof method.call === 'function' ? method.call(args) : method.call;
return web3.provider.send({ return web3.provider.send({
call: call, method: call,
args: args params: args
}); });
}; };
}); });
@ -1371,15 +1532,15 @@ var setupProperties = function (obj, properties) {
var proto = {}; var proto = {};
proto.get = function () { proto.get = function () {
return web3.provider.send({ return web3.provider.send({
call: property.getter method: property.getter
}); });
}; };
if (property.setter) { if (property.setter) {
proto.set = function (val) { proto.set = function (val) {
return web3.provider.send({ return web3.provider.send({
call: property.setter, method: property.setter,
args: [val] params: [val]
}); });
}; };
} }
@ -1412,29 +1573,7 @@ var web3 = {
}, },
/// used to transform value/string to eth string /// used to transform value/string to eth string
/// TODO: use BigNumber.js to parse int toEth: utils.toEth,
toEth: function(str) {
var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
var unit = 0;
var units = ETH_UNITS;
while (val > 3000 && unit < units.length - 1)
{
val /= 1000;
unit++;
}
var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);
var replaceFunction = function($0, $1, $2) {
return $1 + ',' + $2;
};
while (true) {
var o = s;
s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction);
if (o === s)
break;
}
return s + ' ' + units[unit];
},
/// eth object prototype /// eth object prototype
eth: { eth: {
@ -1470,11 +1609,6 @@ var web3 = {
return new web3.filter(filter, shhWatch); return new web3.filter(filter, shhWatch);
} }
}, },
/// @returns true if provider is installed
haveProvider: function() {
return !!web3.provider.provider;
}
}; };
/// setups all api methods /// setups all api methods
@ -1497,14 +1631,13 @@ var shhWatch = {
setupMethods(shhWatch, shhWatchMethods()); setupMethods(shhWatch, shhWatchMethods());
web3.setProvider = function(provider) { web3.setProvider = function(provider) {
//provider.onmessage = messageHandler; // there will be no async calls, to remove
web3.provider.set(provider); web3.provider.set(provider);
}; };
module.exports = web3; module.exports = web3;
},{"./utils":11}],"web3":[function(require,module,exports){ },{"./utils":12}],"web3":[function(require,module,exports){
var web3 = require('./lib/web3'); var web3 = require('./lib/web3');
var ProviderManager = require('./lib/providermanager'); var ProviderManager = require('./lib/providermanager');
web3.provider = new ProviderManager(); web3.provider = new ProviderManager();
@ -1517,7 +1650,7 @@ web3.abi = require('./lib/abi');
module.exports = web3; module.exports = web3;
},{"./lib/abi":1,"./lib/contract":3,"./lib/filter":5,"./lib/httpsync":7,"./lib/providermanager":8,"./lib/qtsync":9,"./lib/web3":12}]},{},["web3"]) },{"./lib/abi":1,"./lib/contract":3,"./lib/filter":5,"./lib/httpsync":7,"./lib/providermanager":9,"./lib/qtsync":10,"./lib/web3":13}]},{},["web3"])
//# sourceMappingURL=ethereum.js.map //# sourceMappingURL=ethereum.js.map

22
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

66
libjsqrc/ethereumjs/example/event_inc.html

@ -0,0 +1,66 @@
<!doctype>
<html>
<head>
<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">
var web3 = require('web3');
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8080'));
var source = "" +
"contract Contract { " +
" event Incremented(bool indexed odd, uint x); " +
" function Contract() { " +
" x = 69; " +
" } " +
" function inc() { " +
" ++x; " +
" Incremented(x % 2 == 1, x); " +
" } " +
" uint x; " +
"}";
var desc = [{
"type":"event",
"name":"Incremented",
"inputs": [{"name":"odd","type":"bool","indexed":true},{"name":"x","type":"uint","indexed":false}],
}, {
"type":"function",
"name":"inc",
"inputs": [],
"outputs": []
}];
var address;
var contract;
var update = function (x) {
document.getElementById('result').innerText = JSON.stringify(x);
};
var createContract = function () {
address = web3.eth.transact({code: web3.eth.solidity(source)});
contract = web3.eth.contract(address, desc);
contract.Incremented({odd: true}).changed(update);
};
var callContract = function () {
contract.call().inc();
};
</script>
</head>
<body>
<div>
<button type="button" onClick="createContract();">create contract</button>
</div>
<div>
<button type="button" onClick="callContract();">test1</button>
</div>
<div id="result">
</div>
</body>
</html>

23
libjsqrc/ethereumjs/lib/const.js

@ -25,9 +25,32 @@ if (process.env.NODE_ENV !== 'build') {
var BigNumber = require('bignumber.js'); // jshint ignore:line var BigNumber = require('bignumber.js'); // jshint ignore:line
} }
var ETH_UNITS = [
'wei',
'Kwei',
'Mwei',
'Gwei',
'szabo',
'finney',
'ether',
'grand',
'Mether',
'Gether',
'Tether',
'Pether',
'Eether',
'Zether',
'Yether',
'Nether',
'Dether',
'Vether',
'Uether'
];
module.exports = { module.exports = {
ETH_PADDING: 32, ETH_PADDING: 32,
ETH_SIGNATURE_LENGTH: 4, ETH_SIGNATURE_LENGTH: 4,
ETH_UNITS: ETH_UNITS,
ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN } ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }
}; };

11
libjsqrc/ethereumjs/lib/contract.js

@ -120,6 +120,11 @@ var addFunctionsToContract = function (contract, desc, address) {
var addEventRelatedPropertiesToContract = function (contract, desc, address) { var addEventRelatedPropertiesToContract = function (contract, desc, address) {
contract.address = address; contract.address = address;
contract._onWatchEventResult = function (data) {
var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc));
var parser = eventImpl.outputParser(matchingEvent);
return parser(data);
};
Object.defineProperty(contract, 'topic', { Object.defineProperty(contract, 'topic', {
get: function() { get: function() {
@ -138,8 +143,12 @@ var addEventsToContract = function (contract, desc, address) {
var impl = function () { var impl = function () {
var params = Array.prototype.slice.call(arguments); var params = Array.prototype.slice.call(arguments);
var signature = abi.eventSignatureFromAscii(e.name); var signature = abi.eventSignatureFromAscii(e.name);
var event = eventImpl(address, signature, e); var event = eventImpl.inputParser(address, signature, e);
var o = event.apply(null, params); var o = event.apply(null, params);
o._onWatchEventResult = function (data) {
var parser = eventImpl.outputParser(e);
return parser(data);
};
return web3.eth.watch(o); return web3.eth.watch(o);
}; };

72
libjsqrc/ethereumjs/lib/event.js

@ -23,6 +23,16 @@
var abi = require('./abi'); var abi = require('./abi');
var utils = require('./utils'); var utils = require('./utils');
/// filter inputs array && returns only indexed (or not) inputs
/// @param inputs array
/// @param bool if result should be an array of indexed params on not
/// @returns array of (not?) indexed params
var filterInputs = function (inputs, indexed) {
return inputs.filter(function (current) {
return current.indexed === indexed;
});
};
var inputWithName = function (inputs, name) { var inputWithName = function (inputs, name) {
var index = utils.findIndex(inputs, function (input) { var index = utils.findIndex(inputs, function (input) {
return input.name === name; return input.name === name;
@ -38,7 +48,7 @@ var inputWithName = function (inputs, name) {
var indexedParamsToTopics = function (event, indexed) { var indexedParamsToTopics = function (event, indexed) {
// sort keys? // sort keys?
return Object.keys(indexed).map(function (key) { return Object.keys(indexed).map(function (key) {
var inputs = [inputWithName(event.inputs, key)]; var inputs = [inputWithName(filterInputs(event.inputs, true), key)];
var value = indexed[key]; var value = indexed[key];
if (value instanceof Array) { if (value instanceof Array) {
@ -50,7 +60,7 @@ var indexedParamsToTopics = function (event, indexed) {
}); });
}; };
var implementationOfEvent = function (address, signature, event) { var inputParser = function (address, signature, event) {
// valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch' // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch'
return function (indexed, options) { return function (indexed, options) {
@ -65,5 +75,61 @@ var implementationOfEvent = function (address, signature, event) {
}; };
}; };
module.exports = implementationOfEvent; var getArgumentsObject = function (inputs, indexed, notIndexed) {
var indexedCopy = indexed.slice();
var notIndexedCopy = notIndexed.slice();
return inputs.reduce(function (acc, current) {
var value;
if (current.indexed)
value = indexed.splice(0, 1)[0];
else
value = notIndexed.splice(0, 1)[0];
acc[current.name] = value;
return acc;
}, {});
};
var outputParser = function (event) {
return function (output) {
var result = {
event: utils.extractDisplayName(event.name),
number: output.number,
args: {}
};
if (!output.topic) {
return result;
}
var indexedOutputs = filterInputs(event.inputs, true);
var indexedData = "0x" + output.topic.slice(1, output.topic.length).map(function (topic) { return topic.slice(2); }).join("");
var indexedRes = abi.formatOutput(indexedOutputs, indexedData);
var notIndexedOutputs = filterInputs(event.inputs, false);
var notIndexedRes = abi.formatOutput(notIndexedOutputs, output.data);
result.args = getArgumentsObject(event.inputs, indexedRes, notIndexedRes);
return result;
};
};
var getMatchingEvent = function (events, payload) {
for (var i = 0; i < events.length; i++) {
var signature = abi.eventSignatureFromAscii(events[i].name);
if (signature === payload.topic[0]) {
return events[i];
}
}
return undefined;
};
module.exports = {
inputParser: inputParser,
outputParser: outputParser,
getMatchingEvent: getMatchingEvent
};

7
libjsqrc/ethereumjs/lib/filter.js

@ -36,6 +36,8 @@ var Filter = function(options, impl) {
if (options.topics) { if (options.topics) {
console.warn('"topics" is deprecated, use "topic" instead'); console.warn('"topics" is deprecated, use "topic" instead');
} }
this._onWatchResult = options._onWatchEventResult;
// evaluate lazy properties // evaluate lazy properties
options = { options = {
@ -54,7 +56,7 @@ var Filter = function(options, impl) {
this.callbacks = []; this.callbacks = [];
this.id = impl.newFilter(options); this.id = impl.newFilter(options);
web3.provider.startPolling({call: impl.changed, args: [this.id]}, this.id, this.trigger.bind(this)); web3.provider.startPolling({method: impl.changed, params: [this.id]}, this.id, this.trigger.bind(this));
}; };
/// alias for changed* /// alias for changed*
@ -74,7 +76,8 @@ Filter.prototype.changed = function(callback) {
Filter.prototype.trigger = function(messages) { Filter.prototype.trigger = function(messages) {
for (var i = 0; i < this.callbacks.length; i++) { for (var i = 0; i < this.callbacks.length; i++) {
for (var j = 0; j < messages.length; j++) { for (var j = 0; j < messages.length; j++) {
this.callbacks[i].call(this, messages[j]); var message = this._onWatchResult ? this._onWatchResult(messages[j]) : messages[j];
this.callbacks[i].call(this, message);
} }
} }
}; };

32
libjsqrc/ethereumjs/lib/httpsync.js

@ -30,40 +30,16 @@ var HttpSyncProvider = function (host) {
this.host = host || 'http://localhost:8080'; this.host = host || 'http://localhost:8080';
}; };
/// Transforms inner message to proper jsonrpc object
/// @param inner message object
/// @returns jsonrpc object
function formatJsonRpcObject(object) {
return {
jsonrpc: '2.0',
method: object.call,
params: object.args,
id: object._id
};
}
/// Transforms jsonrpc object to inner message
/// @param incoming jsonrpc message
/// @returns inner message object
function formatJsonRpcMessage(message) {
var object = JSON.parse(message);
return {
_id: object.id,
data: object.result,
error: object.error
};
}
HttpSyncProvider.prototype.send = function (payload) { HttpSyncProvider.prototype.send = function (payload) {
var data = formatJsonRpcObject(payload); //var data = formatJsonRpcObject(payload);
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('POST', this.host, false); request.open('POST', this.host, false);
request.send(JSON.stringify(data)); request.send(JSON.stringify(payload));
// check request.status // check request.status
return request.responseText; var result = request.responseText;
return JSON.parse(result);
}; };
module.exports = HttpSyncProvider; module.exports = HttpSyncProvider;

65
libjsqrc/ethereumjs/lib/jsonrpc.js

@ -0,0 +1,65 @@
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file jsonrpc.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
var messageId = 1;
/// Should be called to valid json create payload object
/// @param method of jsonrpc call, required
/// @param params, an array of method params, optional
/// @returns valid jsonrpc payload object
var toPayload = function (method, params) {
if (!method)
console.error('jsonrpc method should be specified!');
return {
jsonrpc: '2.0',
method: method,
params: params || [],
id: messageId++
};
};
/// Should be called to check if jsonrpc response is valid
/// @returns true if response is valid, otherwise false
var isValidResponse = function (response) {
return !!response &&
!response.error &&
response.jsonrpc === '2.0' &&
typeof response.id === 'number' &&
(!!response.result || typeof response.result === 'boolean');
};
/// Should be called to create batch payload object
/// @param messages, an array of objects with method (required) and params (optional) fields
var toBatchPayload = function (messages) {
return messages.map(function (message) {
return toPayload(message.method, message.params);
});
};
module.exports = {
toPayload: toPayload,
isValidResponse: isValidResponse,
toBatchPayload: toBatchPayload
};

45
libjsqrc/ethereumjs/lib/providermanager.js

@ -23,7 +23,9 @@
* @date 2014 * @date 2014
*/ */
var web3 = require('./web3'); // jshint ignore:line var web3 = require('./web3');
var jsonrpc = require('./jsonrpc');
/** /**
* Provider manager object prototype * Provider manager object prototype
@ -37,25 +39,35 @@ var web3 = require('./web3'); // jshint ignore:line
var ProviderManager = function() { var ProviderManager = function() {
this.polls = []; this.polls = [];
this.provider = undefined; this.provider = undefined;
this.id = 1;
var self = this; var self = this;
var poll = function () { var poll = function () {
if (self.provider) { if (self.provider) {
self.polls.forEach(function (data) { var pollsBatch = self.polls.map(function (data) {
data.data._id = self.id; return data.data;
self.id++; });
var result = self.provider.send(data.data);
var payload = jsonrpc.toBatchPayload(pollsBatch);
result = JSON.parse(result); var results = self.provider.send(payload);
self.polls.forEach(function (data, index) {
var result = results[index];
if (!jsonrpc.isValidResponse(result)) {
console.log(result);
return;
}
result = result.result;
// dont call the callback if result is not an array, or empty one // dont call the callback if result is not an array, or empty one
if (result.error || !(result.result instanceof Array) || result.result.length === 0) { if (!(result instanceof Array) || result.length === 0) {
return; return;
} }
data.callback(result.result); data.callback(result);
}); });
} }
setTimeout(poll, 1000); setTimeout(poll, 1000);
}; };
@ -63,22 +75,19 @@ var ProviderManager = function() {
}; };
/// sends outgoing requests /// sends outgoing requests
/// @params data - an object with at least 'method' property
ProviderManager.prototype.send = function(data) { ProviderManager.prototype.send = function(data) {
var payload = jsonrpc.toPayload(data.method, data.params);
data.args = data.args || [];
data._id = this.id++;
if (this.provider === undefined) { if (this.provider === undefined) {
console.error('provider is not set'); console.error('provider is not set');
return null; return null;
} }
//TODO: handle error here? var result = this.provider.send(payload);
var result = this.provider.send(data);
result = JSON.parse(result);
if (result.error) { if (!jsonrpc.isValidResponse(result)) {
console.log(result.error); console.log(result);
return null; return null;
} }

3
libjsqrc/ethereumjs/lib/qtsync.js

@ -25,7 +25,8 @@ var QtSyncProvider = function () {
}; };
QtSyncProvider.prototype.send = function (payload) { QtSyncProvider.prototype.send = function (payload) {
return navigator.qt.callMethod(JSON.stringify(payload)); var result = navigator.qt.callMethod(JSON.stringify(payload));
return JSON.parse(result);
}; };
module.exports = QtSyncProvider; module.exports = QtSyncProvider;

33
libjsqrc/ethereumjs/lib/utils.js

@ -20,6 +20,8 @@
* @date 2015 * @date 2015
*/ */
var c = require('./const');
/// Finds first index of array element matching pattern /// Finds first index of array element matching pattern
/// @param array /// @param array
/// @param callback pattern /// @param callback pattern
@ -82,7 +84,7 @@ var extractDisplayName = function (name) {
var extractTypeName = function (name) { var extractTypeName = function (name) {
/// TODO: make it invulnerable /// TODO: make it invulnerable
var length = name.indexOf('('); var length = name.indexOf('(');
return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)) : ""; return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : "";
}; };
/// Filters all function from input abi /// Filters all function from input abi
@ -101,6 +103,32 @@ var filterEvents = function (json) {
}); });
}; };
/// used to transform value/string to eth string
/// TODO: use BigNumber.js to parse int
/// TODO: add tests for it!
var toEth = function (str) {
var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
var unit = 0;
var units = c.ETH_UNITS;
while (val > 3000 && unit < units.length - 1)
{
val /= 1000;
unit++;
}
var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);
var replaceFunction = function($0, $1, $2) {
return $1 + ',' + $2;
};
while (true) {
var o = s;
s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction);
if (o === s)
break;
}
return s + ' ' + units[unit];
};
module.exports = { module.exports = {
findIndex: findIndex, findIndex: findIndex,
toAscii: toAscii, toAscii: toAscii,
@ -108,6 +136,7 @@ module.exports = {
extractDisplayName: extractDisplayName, extractDisplayName: extractDisplayName,
extractTypeName: extractTypeName, extractTypeName: extractTypeName,
filterFunctions: filterFunctions, filterFunctions: filterFunctions,
filterEvents: filterEvents filterEvents: filterEvents,
toEth: toEth
}; };

62
libjsqrc/ethereumjs/lib/web3.js

@ -29,28 +29,6 @@ if (process.env.NODE_ENV !== 'build') {
var utils = require('./utils'); var utils = require('./utils');
var ETH_UNITS = [
'wei',
'Kwei',
'Mwei',
'Gwei',
'szabo',
'finney',
'ether',
'grand',
'Mether',
'Gether',
'Tether',
'Pether',
'Eether',
'Zether',
'Yether',
'Nether',
'Dether',
'Vether',
'Uether'
];
/// @returns an array of objects describing web3 api methods /// @returns an array of objects describing web3 api methods
var web3Methods = function () { var web3Methods = function () {
return [ return [
@ -158,8 +136,8 @@ var setupMethods = function (obj, methods) {
var args = Array.prototype.slice.call(arguments); var args = Array.prototype.slice.call(arguments);
var call = typeof method.call === 'function' ? method.call(args) : method.call; var call = typeof method.call === 'function' ? method.call(args) : method.call;
return web3.provider.send({ return web3.provider.send({
call: call, method: call,
args: args params: args
}); });
}; };
}); });
@ -172,15 +150,15 @@ var setupProperties = function (obj, properties) {
var proto = {}; var proto = {};
proto.get = function () { proto.get = function () {
return web3.provider.send({ return web3.provider.send({
call: property.getter method: property.getter
}); });
}; };
if (property.setter) { if (property.setter) {
proto.set = function (val) { proto.set = function (val) {
return web3.provider.send({ return web3.provider.send({
call: property.setter, method: property.setter,
args: [val] params: [val]
}); });
}; };
} }
@ -213,29 +191,7 @@ var web3 = {
}, },
/// used to transform value/string to eth string /// used to transform value/string to eth string
/// TODO: use BigNumber.js to parse int toEth: utils.toEth,
toEth: function(str) {
var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
var unit = 0;
var units = ETH_UNITS;
while (val > 3000 && unit < units.length - 1)
{
val /= 1000;
unit++;
}
var s = val.toString().length < val.toFixed(2).length ? val.toString() : val.toFixed(2);
var replaceFunction = function($0, $1, $2) {
return $1 + ',' + $2;
};
while (true) {
var o = s;
s = s.replace(/(\d)(\d\d\d[\.\,])/, replaceFunction);
if (o === s)
break;
}
return s + ' ' + units[unit];
},
/// eth object prototype /// eth object prototype
eth: { eth: {
@ -271,11 +227,6 @@ var web3 = {
return new web3.filter(filter, shhWatch); return new web3.filter(filter, shhWatch);
} }
}, },
/// @returns true if provider is installed
haveProvider: function() {
return !!web3.provider.provider;
}
}; };
/// setups all api methods /// setups all api methods
@ -298,7 +249,6 @@ var shhWatch = {
setupMethods(shhWatch, shhWatchMethods()); setupMethods(shhWatch, shhWatchMethods());
web3.setProvider = function(provider) { web3.setProvider = function(provider) {
//provider.onmessage = messageHandler; // there will be no async calls, to remove
web3.provider.set(provider); web3.provider.set(provider);
}; };

2
libjsqrc/ethereumjs/package.json

@ -1,7 +1,7 @@
{ {
"name": "ethereum.js", "name": "ethereum.js",
"namespace": "ethereum", "namespace": "ethereum",
"version": "0.0.11", "version": "0.0.13",
"description": "Ethereum Compatible JavaScript API", "description": "Ethereum Compatible JavaScript API",
"main": "./index.js", "main": "./index.js",
"directories": { "directories": {

438
libjsqrc/ethereumjs/test/abi.parsers.js → libjsqrc/ethereumjs/test/abi.inputParser.js

@ -423,443 +423,5 @@ describe('abi', function() {
}); });
}); });
describe('outputParser', function() {
it('should parse output string', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: "string" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000")[0],
'hello'
);
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"776f726c64000000000000000000000000000000000000000000000000000000")[0],
'world'
);
});
it('should parse output uint', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
);
});
it('should parse output uint256', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint256' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
);
});
it('should parse output uint128', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint128' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
);
});
it('should parse output int', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
});
it('should parse output int256', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int256' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
});
it('should parse output int128', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int128' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
});
it('should parse output hash', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'hash' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"
);
});
it('should parse output hash256', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'hash256' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"
);
});
it('should parse output hash160', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'hash160' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"
);
// TODO shouldnt' the expected hash be shorter?
});
it('should parse output address', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'address' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x407d73d8a49eeb85d32cf465507dd71d507100c1"
);
});
it('should parse output bool', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'bool' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], true);
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000000")[0], false);
});
it('should parse output real', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'real' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000100000000000000000000000000000000")[0], 1);
assert.equal(parser.test("0x0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125);
assert.equal(parser.test("0x0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffff00000000000000000000000000000000")[0], -1);
});
it('should parse output ureal', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'ureal' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000100000000000000000000000000000000")[0], 1);
assert.equal(parser.test("0x0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125);
assert.equal(parser.test("0x0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5);
});
it('should parse multiple output strings', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: "string" },
{ type: "string" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000" +
"776f726c64000000000000000000000000000000000000000000000000000000")[0],
'hello'
);
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000" +
"776f726c64000000000000000000000000000000000000000000000000000000")[1],
'world'
);
});
it('should use proper method name', function () {
// given
var d = clone(description);
d[0].name = 'helloworld(int)';
d[0].outputs = [
{ type: "int" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.helloworld("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.helloworld['int']("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
});
it('should parse multiple methods', function () {
// given
var d = [{
name: "test",
type: "function",
inputs: [{ type: "int" }],
outputs: [{ type: "int" }]
},{
name: "test2",
type: "function",
inputs: [{ type: "string" }],
outputs: [{ type: "string" }]
}];
// when
var parser = abi.outputParser(d);
//then
assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test2("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000")[0],
"hello"
);
});
it('should parse output array', function () {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int[]' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006")[0][0],
5
);
assert.equal(parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006")[0][1],
6
);
});
it('should parse 0x value', function () {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x")[0], 0);
});
it('should parse 0x value', function () {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x")[0], 0);
});
});
}); });

461
libjsqrc/ethereumjs/test/abi.outputParser.js

@ -0,0 +1,461 @@
var assert = require('assert');
var BigNumber = require('bignumber.js');
var abi = require('../lib/abi.js');
var clone = function (object) { return JSON.parse(JSON.stringify(object)); };
var description = [{
"name": "test",
"type": "function",
"inputs": [{
"name": "a",
"type": "uint256"
}
],
"outputs": [
{
"name": "d",
"type": "uint256"
}
]
}];
describe('abi', function() {
describe('outputParser', function() {
it('should parse output string', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: "string" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000")[0],
'hello'
);
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"776f726c64000000000000000000000000000000000000000000000000000000")[0],
'world'
);
});
it('should parse output uint', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
);
});
it('should parse output uint256', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint256' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
);
});
it('should parse output uint128', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint128' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(
parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0].toString(10),
new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).toString(10)
);
assert.equal(
parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0].toString(10),
new BigNumber("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", 16).toString(10)
);
});
it('should parse output int', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
});
it('should parse output int256', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int256' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
});
it('should parse output int128', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int128' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test("0x000000000000000000000000000000000000000000000000000000000000000a")[0], 10);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[0], -1);
assert.equal(parser.test("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0")[0], -16);
});
it('should parse output hash', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'hash' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"
);
});
it('should parse output hash256', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'hash256' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"
);
});
it('should parse output hash160', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'hash160' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1"
);
// TODO shouldnt' the expected hash be shorter?
});
it('should parse output address', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'address' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x000000000000000000000000407d73d8a49eeb85d32cf465507dd71d507100c1")[0],
"0x407d73d8a49eeb85d32cf465507dd71d507100c1"
);
});
it('should parse output bool', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'bool' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000001")[0], true);
assert.equal(parser.test("0x0000000000000000000000000000000000000000000000000000000000000000")[0], false);
});
it('should parse output real', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'real' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000100000000000000000000000000000000")[0], 1);
assert.equal(parser.test("0x0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125);
assert.equal(parser.test("0x0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5);
assert.equal(parser.test("0xffffffffffffffffffffffffffffffff00000000000000000000000000000000")[0], -1);
});
it('should parse output ureal', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'ureal' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x0000000000000000000000000000000100000000000000000000000000000000")[0], 1);
assert.equal(parser.test("0x0000000000000000000000000000000220000000000000000000000000000000")[0], 2.125);
assert.equal(parser.test("0x0000000000000000000000000000000880000000000000000000000000000000")[0], 8.5);
});
it('should parse multiple output strings', function() {
// given
var d = clone(description);
d[0].outputs = [
{ type: "string" },
{ type: "string" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000" +
"776f726c64000000000000000000000000000000000000000000000000000000")[0],
'hello'
);
assert.equal(
parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000" +
"776f726c64000000000000000000000000000000000000000000000000000000")[1],
'world'
);
});
it('should use proper method name', function () {
// given
var d = clone(description);
d[0].name = 'helloworld(int)';
d[0].outputs = [
{ type: "int" }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.helloworld("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.helloworld['int']("0x0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
});
it('should parse multiple methods', function () {
// given
var d = [{
name: "test",
type: "function",
inputs: [{ type: "int" }],
outputs: [{ type: "int" }]
},{
name: "test2",
type: "function",
inputs: [{ type: "string" }],
outputs: [{ type: "string" }]
}];
// when
var parser = abi.outputParser(d);
//then
assert.equal(parser.test("0000000000000000000000000000000000000000000000000000000000000001")[0], 1);
assert.equal(parser.test2("0x" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"68656c6c6f000000000000000000000000000000000000000000000000000000")[0],
"hello"
);
});
it('should parse output array', function () {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int[]' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006")[0][0],
5
);
assert.equal(parser.test("0x" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"0000000000000000000000000000000000000000000000000000000000000005" +
"0000000000000000000000000000000000000000000000000000000000000006")[0][1],
6
);
});
it('should parse 0x value', function () {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'int' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x")[0], 0);
});
it('should parse 0x value', function () {
// given
var d = clone(description);
d[0].outputs = [
{ type: 'uint' }
];
// when
var parser = abi.outputParser(d);
// then
assert.equal(parser.test("0x")[0], 0);
});
});
});

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

@ -1,7 +1,7 @@
var assert = require('assert'); var assert = require('assert');
var web3 = require('../index.js'); var web3 = require('../index.js');
var u = require('./utils.js'); var u = require('./test.utils.js');
describe('web3', function() { describe('web3', function() {
describe('db', function() { describe('db', function() {

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

@ -1,6 +1,6 @@
var assert = require('assert'); var assert = require('assert');
var web3 = require('../index.js'); var web3 = require('../index.js');
var u = require('./utils.js'); var u = require('./test.utils.js');
describe('web3', function() { describe('web3', function() {
describe('eth', function() { describe('eth', function() {

125
libjsqrc/ethereumjs/test/event.inputParser.js

@ -0,0 +1,125 @@
var assert = require('assert');
var event = require('../lib/event.js');
var f = require('../lib/formatters.js');
describe('event', function () {
describe('inputParser', function () {
it('should create basic filter input object', function () {
// given
var address = '0x012345';
var signature = '0x987654';
var e = {
name: 'Event',
inputs: [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}]
};
// when
var impl = event.inputParser(address, signature, e);
var result = impl();
// then
assert.equal(result.address, address);
assert.equal(result.topic.length, 1);
assert.equal(result.topic[0], signature);
});
it('should create filter input object with options', function () {
// given
var address = '0x012345';
var signature = '0x987654';
var options = {
earliest: 1,
latest: 2,
offset: 3,
max: 4
};
var e = {
name: 'Event',
inputs: [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}]
};
// when
var impl = event.inputParser(address, signature, e);
var result = impl({}, options);
// then
assert.equal(result.address, address);
assert.equal(result.topic.length, 1);
assert.equal(result.topic[0], signature);
assert.equal(result.earliest, options.earliest);
assert.equal(result.latest, options.latest);
assert.equal(result.offset, options.offset);
assert.equal(result.max, options.max);
});
it('should create filter input object with indexed params', function () {
// given
var address = '0x012345';
var signature = '0x987654';
var options = {
earliest: 1,
latest: 2,
offset: 3,
max: 4
};
var e = {
name: 'Event',
inputs: [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}]
};
// when
var impl = event.inputParser(address, signature, e);
var result = impl({a: 4}, options);
// then
assert.equal(result.address, address);
assert.equal(result.topic.length, 2);
assert.equal(result.topic[0], signature);
assert.equal(result.topic[1], f.formatInputInt(4));
assert.equal(result.earliest, options.earliest);
assert.equal(result.latest, options.latest);
assert.equal(result.offset, options.offset);
assert.equal(result.max, options.max);
});
it('should create filter input object with an array of indexed params', function () {
// given
var address = '0x012345';
var signature = '0x987654';
var options = {
earliest: 1,
latest: 2,
offset: 3,
max: 4
};
var e = {
name: 'Event',
inputs: [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}]
};
// when
var impl = event.inputParser(address, signature, e);
var result = impl({a: [4, 69]}, options);
// then
assert.equal(result.address, address);
assert.equal(result.topic.length, 2);
assert.equal(result.topic[0], signature);
assert.equal(result.topic[1][0], f.formatInputInt(4));
assert.equal(result.topic[1][1], f.formatInputInt(69));
assert.equal(result.earliest, options.earliest);
assert.equal(result.latest, options.latest);
assert.equal(result.offset, options.offset);
assert.equal(result.max, options.max);
});
});
});

124
libjsqrc/ethereumjs/test/event.js

@ -1,124 +0,0 @@
var assert = require('assert');
var event = require('../lib/event.js');
var f = require('../lib/formatters.js');
describe('event', function () {
it('should create basic filter input object', function () {
// given
var address = '0x012345';
var signature = '0x987654';
var e = {
name: 'Event',
inputs: [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}]
};
// when
var impl = event(address, signature, e);
var result = impl();
// then
assert.equal(result.address, address);
assert.equal(result.topic.length, 1);
assert.equal(result.topic[0], signature);
});
it('should create filter input object with options', function () {
// given
var address = '0x012345';
var signature = '0x987654';
var options = {
earliest: 1,
latest: 2,
offset: 3,
max: 4
};
var e = {
name: 'Event',
inputs: [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}]
};
// when
var impl = event(address, signature, e);
var result = impl({}, options);
// then
assert.equal(result.address, address);
assert.equal(result.topic.length, 1);
assert.equal(result.topic[0], signature);
assert.equal(result.earliest, options.earliest);
assert.equal(result.latest, options.latest);
assert.equal(result.offset, options.offset);
assert.equal(result.max, options.max);
});
it('should create filter input object with indexed params', function () {
// given
var address = '0x012345';
var signature = '0x987654';
var options = {
earliest: 1,
latest: 2,
offset: 3,
max: 4
};
var e = {
name: 'Event',
inputs: [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}]
};
// when
var impl = event(address, signature, e);
var result = impl({a: 4}, options);
// then
assert.equal(result.address, address);
assert.equal(result.topic.length, 2);
assert.equal(result.topic[0], signature);
assert.equal(result.topic[1], f.formatInputInt(4));
assert.equal(result.earliest, options.earliest);
assert.equal(result.latest, options.latest);
assert.equal(result.offset, options.offset);
assert.equal(result.max, options.max);
});
it('should create filter input object with an array of indexed params', function () {
// given
var address = '0x012345';
var signature = '0x987654';
var options = {
earliest: 1,
latest: 2,
offset: 3,
max: 4
};
var e = {
name: 'Event',
inputs: [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"hash256","indexed":false}]
};
// when
var impl = event(address, signature, e);
var result = impl({a: [4, 69]}, options);
// then
assert.equal(result.address, address);
assert.equal(result.topic.length, 2);
assert.equal(result.topic[0], signature);
assert.equal(result.topic[1][0], f.formatInputInt(4));
assert.equal(result.topic[1][1], f.formatInputInt(69));
assert.equal(result.earliest, options.earliest);
assert.equal(result.latest, options.latest);
assert.equal(result.offset, options.offset);
assert.equal(result.max, options.max);
});
});

81
libjsqrc/ethereumjs/test/event.outputParser.js

@ -0,0 +1,81 @@
var assert = require('assert');
var event = require('../lib/event.js');
describe('event', function () {
describe('outputParser', function () {
it('should parse basic event output object', function () {
// given
var output = {
"address":"0x78dfc5983baecf65f73e3de3a96cee24e6b7981e",
"data":"0x000000000000000000000000000000000000000000000000000000000000004b",
"number":2,
"topic":[
"0x6e61ef44ac2747ff8b84d353a908eb8bd5c3fb118334d57698c5cfc7041196ad",
"0x0000000000000000000000000000000000000000000000000000000000000001"
]
};
var e = {
name: 'Event',
inputs: [{"name":"a","type":"bool","indexed":true},{"name":"b","type":"uint256","indexed":false}]
};
// when
var impl = event.outputParser(e);
var result = impl(output);
// then
assert.equal(result.event, 'Event');
assert.equal(result.number, 2);
assert.equal(Object.keys(result.args).length, 2);
assert.equal(result.args.a, true);
assert.equal(result.args.b, 75);
});
it('should parse event output object arguments in correct order', function () {
// given
var output = {
"address":"0x78dfc5983baecf65f73e3de3a96cee24e6b7981e",
"data": "0x" +
"000000000000000000000000000000000000000000000000000000000000004b" +
"000000000000000000000000000000000000000000000000000000000000004c" +
"0000000000000000000000000000000000000000000000000000000000000001",
"number":3,
"topic":[
"0x6e61ef44ac2747ff8b84d353a908eb8bd5c3fb118334d57698c5cfc7041196ad",
"0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000000000000000000000000000005"
]
};
var e = {
name: 'Event2',
inputs: [
{"name":"a","type":"bool","indexed":true},
{"name":"b","type":"int","indexed":false},
{"name":"c","type":"int","indexed":false},
{"name":"d","type":"int","indexed":true},
{"name":"e","type":"bool","indexed":false}
]
};
// when
var impl = event.outputParser(e);
var result = impl(output);
// then
assert.equal(result.event, 'Event2');
assert.equal(result.number, 3);
assert.equal(Object.keys(result.args).length, 5);
assert.equal(result.args.a, true);
assert.equal(result.args.b, 75);
assert.equal(result.args.c, 76);
assert.equal(result.args.d, 5);
assert.equal(result.args.e, true);
});
});
});

128
libjsqrc/ethereumjs/test/jsonrpc.isValidResponse.js

@ -0,0 +1,128 @@
var assert = require('assert');
var jsonrpc = require('../lib/jsonrpc');
describe('jsonrpc', function () {
describe('isValidResponse', function () {
it('should validate basic jsonrpc response', function () {
// given
var response = {
jsonrpc: '2.0',
id: 1,
result: []
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, true);
});
it('should validate basic undefined response', function () {
// given
var response = undefined;
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, false);
});
it('should validate jsonrpc response without jsonrpc field', function () {
// given
var response = {
id: 1,
result: []
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, false);
});
it('should validate jsonrpc response with wrong jsonrpc version', function () {
// given
var response = {
jsonrpc: '1.0',
id: 1,
result: []
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, false);
});
it('should validate jsonrpc response without id number', function () {
// given
var response = {
jsonrpc: '2.0',
result: []
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, false);
});
it('should validate jsonrpc response with wrong id field', function () {
// given
var response = {
jsonrpc: '2.0',
id: 'x',
result: []
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, false);
});
it('should validate jsonrpc response without result field', function () {
// given
var response = {
jsonrpc: '2.0',
id: 1
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, false);
});
it('should validate jsonrpc response with result field === false', function () {
// given
var response = {
jsonrpc: '2.0',
id: 1,
result: false
};
// when
var valid = jsonrpc.isValidResponse(response);
// then
assert.equal(valid, true);
});
});
});

47
libjsqrc/ethereumjs/test/jsonrpc.toBatchPayload.js

@ -0,0 +1,47 @@
var assert = require('assert');
var jsonrpc = require('../lib/jsonrpc');
describe('jsonrpc', function () {
describe('toBatchPayload', function () {
it('should create basic batch payload', function () {
// given
var messages = [{
method: 'helloworld'
}, {
method: 'test2',
params: [1]
}];
// when
var payload = jsonrpc.toBatchPayload(messages);
// then
assert.equal(payload instanceof Array, true);
assert.equal(payload.length, 2);
assert.equal(payload[0].jsonrpc, '2.0');
assert.equal(payload[1].jsonrpc, '2.0');
assert.equal(payload[0].method, 'helloworld');
assert.equal(payload[1].method, 'test2');
assert.equal(payload[0].params instanceof Array, true);
assert.equal(payload[1].params.length, 1);
assert.equal(payload[1].params[0], 1);
assert.equal(typeof payload[0].id, 'number');
assert.equal(typeof payload[1].id, 'number');
assert.equal(payload[0].id + 1, payload[1].id);
});
it('should create batch payload for empty input array', function () {
// given
var messages = [];
// when
var payload = jsonrpc.toBatchPayload(messages);
// then
assert.equal(payload instanceof Array, true);
assert.equal(payload.length, 0);
});
});
});

40
libjsqrc/ethereumjs/test/jsonrpc.toPayload.js

@ -0,0 +1,40 @@
var assert = require('assert');
var jsonrpc = require('../lib/jsonrpc');
describe('jsonrpc', function () {
describe('toPayload', function () {
it('should create basic payload', function () {
// given
var method = 'helloworld';
// when
var payload = jsonrpc.toPayload(method);
// then
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, method);
assert.equal(payload.params instanceof Array, true);
assert.equal(payload.params.length, 0);
assert.equal(typeof payload.id, 'number');
});
it('should create payload with params', function () {
// given
var method = 'helloworld1';
var params = [123, 'test'];
// when
var payload = jsonrpc.toPayload(method, params);
// then
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, method);
assert.equal(payload.params.length, 2);
assert.equal(payload.params[0], params[0]);
assert.equal(payload.params[1], params[1]);
assert.equal(typeof payload.id, 'number');
});
});
});

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

@ -1,6 +1,6 @@
var assert = require('assert'); var assert = require('assert');
var web3 = require('../index.js'); var web3 = require('../index.js');
var u = require('./utils.js'); var u = require('./test.utils.js');
describe('web3', function() { describe('web3', function() {
describe('shh', function() { describe('shh', function() {

0
libjsqrc/ethereumjs/test/utils.js → libjsqrc/ethereumjs/test/test.utils.js

42
libjsqrc/ethereumjs/test/utils.extractDisplayName.js

@ -0,0 +1,42 @@
var assert = require('assert');
var utils = require('../lib/utils.js');
describe('utils', function () {
describe('extractDisplayName', function () {
it('should extract display name from method with no params', function () {
// given
var test = 'helloworld()';
// when
var displayName = utils.extractDisplayName(test);
// then
assert.equal(displayName, 'helloworld');
});
it('should extract display name from method with one param' , function () {
// given
var test = 'helloworld1(int)';
// when
var displayName = utils.extractDisplayName(test);
// then
assert.equal(displayName, 'helloworld1');
});
it('should extract display name from method with two params' , function () {
// given
var test = 'helloworld2(int,string)';
// when
var displayName = utils.extractDisplayName(test);
// then
assert.equal(displayName, 'helloworld2');
});
});
});

55
libjsqrc/ethereumjs/test/utils.extractTypeName.js

@ -0,0 +1,55 @@
var assert = require('assert');
var utils = require('../lib/utils.js');
describe('utils', function () {
describe('extractTypeName', function () {
it('should extract type name from method with no params', function () {
// given
var test = 'helloworld()';
// when
var typeName = utils.extractTypeName(test);
// then
assert.equal(typeName, '');
});
it('should extract type name from method with one param', function () {
// given
var test = 'helloworld1(int)';
// when
var typeName = utils.extractTypeName(test);
// then
assert.equal(typeName, 'int');
});
it('should extract type name from method with two params', function () {
// given
var test = 'helloworld2(int,string)';
// when
var typeName = utils.extractTypeName(test);
// then
assert.equal(typeName, 'int,string');
});
it('should extract type name from method with spaces between params', function () {
// given
var test = 'helloworld3(int, string)';
// when
var typeName = utils.extractTypeName(test);
// then
assert.equal(typeName, 'int,string');
});
});
});

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

@ -1,6 +1,6 @@
var assert = require('assert'); var assert = require('assert');
var web3 = require('../index.js'); var web3 = require('../index.js');
var u = require('./utils.js'); var u = require('./test.utils.js');
describe('web3', function() { describe('web3', function() {
u.methodExists(web3, 'sha3'); u.methodExists(web3, 'sha3');

13
libqwebthree/QWebThree.cpp

@ -41,20 +41,9 @@ void QWebThree::clientDieing()
this->disconnect(); this->disconnect();
} }
static QString formatInput(QJsonObject const& _object)
{
QJsonObject res;
res["jsonrpc"] = QString::fromStdString("2.0");
res["method"] = _object["call"];
res["params"] = _object["args"];
res["id"] = _object["_id"];
return QString::fromUtf8(QJsonDocument(res).toJson());
}
QString QWebThree::callMethod(QString _json) QString QWebThree::callMethod(QString _json)
{ {
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); emit processData(_json, ""); // it's synchronous
emit processData(formatInput(f), ""); // it's synchronous
return m_response; return m_response;
} }

45
libsolidity/AST.cpp

@ -133,7 +133,7 @@ void ContractDefinition::checkIllegalOverrides() const
FunctionDefinition const*& override = functions[name]; FunctionDefinition const*& override = functions[name];
if (!override) if (!override)
override = function.get(); override = function.get();
else if (override->isPublic() != function->isPublic() || else if (override->getVisibility() != function->getVisibility() ||
override->isDeclaredConst() != function->isDeclaredConst() || override->isDeclaredConst() != function->isDeclaredConst() ||
FunctionType(*override) != FunctionType(*function)) FunctionType(*override) != FunctionType(*function))
BOOST_THROW_EXCEPTION(override->createTypeError("Override changes extended function signature.")); BOOST_THROW_EXCEPTION(override->createTypeError("Override changes extended function signature."));
@ -475,6 +475,8 @@ void FunctionCall::checkTypeRequirements()
// number of non-mapping members // number of non-mapping members
if (m_arguments.size() != 1) if (m_arguments.size() != 1)
BOOST_THROW_EXCEPTION(createTypeError("More than one argument for explicit type conversion.")); BOOST_THROW_EXCEPTION(createTypeError("More than one argument for explicit type conversion."));
if (!m_names.empty())
BOOST_THROW_EXCEPTION(createTypeError("Type conversion can't allow named arguments."));
if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type.getActualType())) if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type.getActualType()))
BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed.")); BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
m_type = type.getActualType(); m_type = type.getActualType();
@ -487,9 +489,44 @@ void FunctionCall::checkTypeRequirements()
TypePointers const& parameterTypes = functionType->getParameterTypes(); TypePointers const& parameterTypes = functionType->getParameterTypes();
if (parameterTypes.size() != m_arguments.size()) if (parameterTypes.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
for (size_t i = 0; i < m_arguments.size(); ++i)
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) if (m_names.empty())
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); {
for (size_t i = 0; i < m_arguments.size(); ++i)
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]))
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
}
else
{
auto const& parameterNames = functionType->getParameterNames();
if (parameterNames.size() != m_names.size())
BOOST_THROW_EXCEPTION(createTypeError("Some argument names are missing."));
// check duplicate names
for (size_t i = 0; i < m_names.size(); i++) {
for (size_t j = i + 1; j < m_names.size(); j++) {
if (m_names[i] == m_names[j])
BOOST_THROW_EXCEPTION(createTypeError("Duplicate named argument."));
}
}
for (size_t i = 0; i < m_names.size(); i++) {
bool found = false;
for (size_t j = 0; j < parameterNames.size(); j++) {
if (parameterNames[j] == *m_names[i]) {
// check type convertible
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[j]))
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
found = true;
break;
}
}
if (!found)
BOOST_THROW_EXCEPTION(createTypeError("Named argument doesn't match function declaration."));
}
}
// @todo actually the return type should be an anonymous struct, // @todo actually the return type should be an anonymous struct,
// but we change it to the type of the first return value until we have structs // but we change it to the type of the first return value until we have structs
if (functionType->getReturnParameterTypes().empty()) if (functionType->getReturnParameterTypes().empty())

41
libsolidity/AST.h

@ -133,12 +133,17 @@ class Declaration: public ASTNode
{ {
public: public:
enum class LValueType { NONE, LOCAL, STORAGE }; enum class LValueType { NONE, LOCAL, STORAGE };
enum class Visibility { DEFAULT, PUBLIC, PROTECTED, PRIVATE };
Declaration(Location const& _location, ASTPointer<ASTString> const& _name): Declaration(Location const& _location, ASTPointer<ASTString> const& _name,
ASTNode(_location), m_name(_name), m_scope(nullptr) {} Visibility _visibility = Visibility::DEFAULT):
ASTNode(_location), m_name(_name), m_visibility(_visibility), m_scope(nullptr) {}
/// @returns the declared name. /// @returns the declared name.
ASTString const& getName() const { return *m_name; } ASTString const& getName() const { return *m_name; }
Visibility getVisibility() const { return m_visibility == Visibility::DEFAULT ? getDefaultVisibility() : m_visibility; }
bool isPublic() const { return getVisibility() == Visibility::PUBLIC; }
/// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope.
/// Available only after name and type resolution step. /// Available only after name and type resolution step.
Declaration const* getScope() const { return m_scope; } Declaration const* getScope() const { return m_scope; }
@ -151,8 +156,12 @@ public:
/// @returns the lvalue type of expressions referencing this declaration /// @returns the lvalue type of expressions referencing this declaration
virtual LValueType getLValueType() const { return LValueType::NONE; } virtual LValueType getLValueType() const { return LValueType::NONE; }
protected:
virtual Visibility getDefaultVisibility() const { return Visibility::PUBLIC; }
private: private:
ASTPointer<ASTString> m_name; ASTPointer<ASTString> m_name;
Visibility m_visibility;
Declaration const* m_scope; Declaration const* m_scope;
}; };
@ -330,16 +339,15 @@ class FunctionDefinition: public Declaration, public VariableScope, public Docum
{ {
public: public:
FunctionDefinition(Location const& _location, ASTPointer<ASTString> const& _name, FunctionDefinition(Location const& _location, ASTPointer<ASTString> const& _name,
bool _isPublic, Declaration::Visibility _visibility, bool _isConstructor,
bool _isConstructor,
ASTPointer<ASTString> const& _documentation, ASTPointer<ASTString> const& _documentation,
ASTPointer<ParameterList> const& _parameters, ASTPointer<ParameterList> const& _parameters,
bool _isDeclaredConst, bool _isDeclaredConst,
std::vector<ASTPointer<ModifierInvocation>> const& _modifiers, std::vector<ASTPointer<ModifierInvocation>> const& _modifiers,
ASTPointer<ParameterList> const& _returnParameters, ASTPointer<ParameterList> const& _returnParameters,
ASTPointer<Block> const& _body): ASTPointer<Block> const& _body):
Declaration(_location, _name), Documented(_documentation), Declaration(_location, _name, _visibility), Documented(_documentation),
m_isPublic(_isPublic), m_isConstructor(_isConstructor), m_isConstructor(_isConstructor),
m_parameters(_parameters), m_parameters(_parameters),
m_isDeclaredConst(_isDeclaredConst), m_isDeclaredConst(_isDeclaredConst),
m_functionModifiers(_modifiers), m_functionModifiers(_modifiers),
@ -350,7 +358,6 @@ public:
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override; virtual void accept(ASTConstVisitor& _visitor) const override;
bool isPublic() const { return m_isPublic; }
bool isConstructor() const { return m_isConstructor; } bool isConstructor() const { return m_isConstructor; }
bool isDeclaredConst() const { return m_isDeclaredConst; } bool isDeclaredConst() const { return m_isDeclaredConst; }
std::vector<ASTPointer<ModifierInvocation>> const& getModifiers() const { return m_functionModifiers; } std::vector<ASTPointer<ModifierInvocation>> const& getModifiers() const { return m_functionModifiers; }
@ -371,7 +378,6 @@ public:
std::string getCanonicalSignature() const; std::string getCanonicalSignature() const;
private: private:
bool m_isPublic;
bool m_isConstructor; bool m_isConstructor;
ASTPointer<ParameterList> m_parameters; ASTPointer<ParameterList> m_parameters;
bool m_isDeclaredConst; bool m_isDeclaredConst;
@ -388,10 +394,10 @@ class VariableDeclaration: public Declaration
{ {
public: public:
VariableDeclaration(Location const& _location, ASTPointer<TypeName> const& _type, VariableDeclaration(Location const& _location, ASTPointer<TypeName> const& _type,
ASTPointer<ASTString> const& _name, bool _isPublic, bool _isStateVar = false, ASTPointer<ASTString> const& _name, Visibility _visibility,
bool _isIndexed = false): bool _isStateVar = false, bool _isIndexed = false):
Declaration(_location, _name), m_typeName(_type), Declaration(_location, _name, _visibility), m_typeName(_type),
m_isPublic(_isPublic), m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {} m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override; virtual void accept(ASTConstVisitor& _visitor) const override;
@ -404,13 +410,14 @@ public:
virtual LValueType getLValueType() const override; virtual LValueType getLValueType() const override;
bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); } bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); }
bool isPublic() const { return m_isPublic; }
bool isStateVariable() const { return m_isStateVariable; } bool isStateVariable() const { return m_isStateVariable; }
bool isIndexed() const { return m_isIndexed; } bool isIndexed() const { return m_isIndexed; }
protected:
Visibility getDefaultVisibility() const override { return Visibility::PROTECTED; }
private: private:
ASTPointer<TypeName> m_typeName; ///< can be empty ("var") ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
bool m_isPublic; ///< Whether there is an accessor for it or not
bool m_isStateVariable; ///< Whether or not this is a contract state variable bool m_isStateVariable; ///< Whether or not this is a contract state variable
bool m_isIndexed; ///< Whether this is an indexed variable (used by events). bool m_isIndexed; ///< Whether this is an indexed variable (used by events).
@ -956,14 +963,15 @@ class FunctionCall: public Expression
{ {
public: public:
FunctionCall(Location const& _location, ASTPointer<Expression> const& _expression, FunctionCall(Location const& _location, ASTPointer<Expression> const& _expression,
std::vector<ASTPointer<Expression>> const& _arguments): std::vector<ASTPointer<Expression>> const& _arguments, std::vector<ASTPointer<ASTString>> const& _names):
Expression(_location), m_expression(_expression), m_arguments(_arguments) {} Expression(_location), m_expression(_expression), m_arguments(_arguments), m_names(_names) {}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override; virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
Expression const& getExpression() const { return *m_expression; } Expression const& getExpression() const { return *m_expression; }
std::vector<ASTPointer<Expression const>> getArguments() const { return {m_arguments.begin(), m_arguments.end()}; } std::vector<ASTPointer<Expression const>> getArguments() const { return {m_arguments.begin(), m_arguments.end()}; }
std::vector<ASTPointer<ASTString>> const& getNames() const { return m_names; }
/// Returns true if this is not an actual function call, but an explicit type conversion /// Returns true if this is not an actual function call, but an explicit type conversion
/// or constructor call. /// or constructor call.
@ -972,6 +980,7 @@ public:
private: private:
ASTPointer<Expression> m_expression; ASTPointer<Expression> m_expression;
std::vector<ASTPointer<Expression>> m_arguments; std::vector<ASTPointer<Expression>> m_arguments;
std::vector<ASTPointer<ASTString>> m_names;
}; };
/** /**

4
libsolidity/Compiler.cpp

@ -240,10 +240,6 @@ bool Compiler::visit(VariableDeclaration const& _variableDeclaration)
m_context << m_context.getFunctionEntryLabel(_variableDeclaration); m_context << m_context.getFunctionEntryLabel(_variableDeclaration);
ExpressionCompiler::appendStateVariableAccessor(m_context, _variableDeclaration); ExpressionCompiler::appendStateVariableAccessor(m_context, _variableDeclaration);
unsigned sizeOnStack = _variableDeclaration.getType()->getSizeOnStack();
solAssert(sizeOnStack <= 15, "Stack too deep.");
m_context << eth::dupInstruction(sizeOnStack + 1) << eth::Instruction::JUMP;
return false; return false;
} }

72
libsolidity/ExpressionCompiler.cpp

@ -22,6 +22,7 @@
#include <utility> #include <utility>
#include <numeric> #include <numeric>
#include <boost/range/adaptor/reversed.hpp>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include <libsolidity/AST.h> #include <libsolidity/AST.h>
@ -194,6 +195,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{ {
//@todo struct construction //@todo struct construction
solAssert(_functionCall.getArguments().size() == 1, ""); solAssert(_functionCall.getArguments().size() == 1, "");
solAssert(_functionCall.getNames().empty(), "");
Expression const& firstArgument = *_functionCall.getArguments().front(); Expression const& firstArgument = *_functionCall.getArguments().front();
firstArgument.accept(*this); firstArgument.accept(*this);
appendTypeConversion(*firstArgument.getType(), *_functionCall.getType()); appendTypeConversion(*firstArgument.getType(), *_functionCall.getType());
@ -201,8 +203,26 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
else else
{ {
FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType()); FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType());
vector<ASTPointer<Expression const>> arguments = _functionCall.getArguments(); TypePointers const& parameterTypes = function.getParameterTypes();
solAssert(arguments.size() == function.getParameterTypes().size(), ""); vector<ASTPointer<Expression const>> const& callArguments = _functionCall.getArguments();
vector<ASTPointer<ASTString>> const& callArgumentNames = _functionCall.getNames();
solAssert(callArguments.size() == parameterTypes.size(), "");
vector<ASTPointer<Expression const>> arguments;
if (callArgumentNames.empty())
// normal arguments
arguments = callArguments;
else
// named arguments
for (auto const& parameterName: function.getParameterNames())
{
bool found = false;
for (size_t j = 0; j < callArgumentNames.size() && !found; j++)
if ((found = (parameterName == *callArgumentNames[j])))
// we found the actual parameter position
arguments.push_back(callArguments[j]);
solAssert(found, "");
}
switch (function.getLocation()) switch (function.getLocation())
{ {
@ -823,26 +843,58 @@ unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _typ
return length; return length;
} }
unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, unsigned ExpressionCompiler::appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type,
Expression const& _expression, unsigned _memoryOffset) Location const& _location, unsigned _memoryOffset)
{ {
_expression.accept(*this); appendTypeConversion(_type, _expectedType, true);
appendTypeConversion(*_expression.getType(), _expectedType, true);
unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize()); unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize());
if (c_numBytes == 0 || c_numBytes > 32) if (c_numBytes == 0 || c_numBytes > 32)
BOOST_THROW_EXCEPTION(CompilerError() BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(_expression.getLocation()) << errinfo_sourceLocation(_location)
<< errinfo_comment("Type " + _expectedType.toString() + " not yet supported.")); << errinfo_comment("Type " + _expectedType.toString() + " not yet supported."));
bool const c_leftAligned = _expectedType.getCategory() == Type::Category::STRING; bool const c_leftAligned = _expectedType.getCategory() == Type::Category::STRING;
bool const c_padToWords = true; bool const c_padToWords = true;
return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, c_padToWords); return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, c_padToWords);
} }
unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType,
Expression const& _expression,
unsigned _memoryOffset)
{
_expression.accept(*this);
return appendTypeConversionAndMoveToMemory(_expectedType, *_expression.getType(), _expression.getLocation(), _memoryOffset);
}
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
{ {
m_currentLValue.fromStateVariable(_varDecl, _varDecl.getType()); FunctionType thisType(_varDecl);
solAssert(m_currentLValue.isInStorage(), ""); solAssert(thisType.getReturnParameterTypes().size() == 1, "");
m_currentLValue.retrieveValue(_varDecl.getType(), Location(), true); TypePointer const& resultType = thisType.getReturnParameterTypes().front();
unsigned sizeOnStack;
unsigned length = 0;
TypePointers const& params = thisType.getParameterTypes();
// move arguments to memory
for (TypePointer const& param: boost::adaptors::reverse(params))
length += appendTypeConversionAndMoveToMemory(*param, *param, Location(), length);
// retrieve the position of the mapping
m_context << m_context.getStorageLocationOfVariable(_varDecl);
for (TypePointer const& param: params)
{
// move offset to memory
CompilerUtils(m_context).storeInMemory(length);
unsigned argLen = CompilerUtils::getPaddedSize(param->getCalldataEncodedSize());
length -= argLen;
m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3;
}
m_currentLValue = LValue(m_context, LValue::STORAGE, *resultType);
m_currentLValue.retrieveValue(resultType, Location(), true);
sizeOnStack = resultType->getSizeOnStack();
solAssert(sizeOnStack <= 15, "Stack too deep.");
m_context << eth::dupInstruction(sizeOnStack + 1) << eth::Instruction::JUMP;
} }
ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType, ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType,

4
libsolidity/ExpressionCompiler.h

@ -97,6 +97,10 @@ private:
unsigned appendArgumentCopyToMemory(TypePointers const& _types, unsigned appendArgumentCopyToMemory(TypePointers const& _types,
std::vector<ASTPointer<Expression const>> const& _arguments, std::vector<ASTPointer<Expression const>> const& _arguments,
unsigned _memoryOffset = 0); unsigned _memoryOffset = 0);
/// Appends code that copies a type to memory.
/// @returns the number of bytes copied to memory
unsigned appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type,
Location const& _location, unsigned _memoryOffset = 0);
/// Appends code that evaluates a single expression and copies it to memory (with optional offset). /// Appends code that evaluates a single expression and copies it to memory (with optional offset).
/// @returns the number of bytes copied to memory /// @returns the number of bytes copied to memory
unsigned appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression, unsigned appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression,

89
libsolidity/Parser.cpp

@ -131,27 +131,19 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
} }
while (m_scanner->getCurrentToken() == Token::COMMA); while (m_scanner->getCurrentToken() == Token::COMMA);
expectToken(Token::LBRACE); expectToken(Token::LBRACE);
bool visibilityIsPublic = true;
while (true) while (true)
{ {
Token::Value currentToken = m_scanner->getCurrentToken(); Token::Value currentToken = m_scanner->getCurrentToken();
if (currentToken == Token::RBRACE) if (currentToken == Token::RBRACE)
break; break;
else if (currentToken == Token::PUBLIC || currentToken == Token::PRIVATE)
{
visibilityIsPublic = (m_scanner->getCurrentToken() == Token::PUBLIC);
m_scanner->next();
expectToken(Token::COLON);
}
else if (currentToken == Token::FUNCTION) else if (currentToken == Token::FUNCTION)
functions.push_back(parseFunctionDefinition(visibilityIsPublic, name.get())); functions.push_back(parseFunctionDefinition(name.get()));
else if (currentToken == Token::STRUCT) else if (currentToken == Token::STRUCT)
structs.push_back(parseStructDefinition()); structs.push_back(parseStructDefinition());
else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING || else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING ||
Token::isElementaryTypeName(currentToken)) Token::isElementaryTypeName(currentToken))
{ {
VarDeclParserOptions options; VarDeclParserOptions options;
options.isPublic = visibilityIsPublic;
options.isStateVariable = true; options.isStateVariable = true;
stateVariables.push_back(parseVariableDeclaration(options)); stateVariables.push_back(parseVariableDeclaration(options));
expectToken(Token::SEMICOLON); expectToken(Token::SEMICOLON);
@ -177,7 +169,7 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
if (m_scanner->getCurrentToken() == Token::LPAREN) if (m_scanner->getCurrentToken() == Token::LPAREN)
{ {
m_scanner->next(); m_scanner->next();
arguments = parseFunctionCallArguments(); arguments = parseFunctionCallListArguments();
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
expectToken(Token::RPAREN); expectToken(Token::RPAREN);
} }
@ -186,7 +178,22 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
return nodeFactory.createNode<InheritanceSpecifier>(name, arguments); return nodeFactory.createNode<InheritanceSpecifier>(name, arguments);
} }
ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic, ASTString const* _contractName) Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token)
{
Declaration::Visibility visibility;
if (_token == Token::PUBLIC)
visibility = Declaration::Visibility::PUBLIC;
else if (_token == Token::PROTECTED)
visibility = Declaration::Visibility::PROTECTED;
else if (_token == Token::PRIVATE)
visibility = Declaration::Visibility::PRIVATE;
else
solAssert(false, "Invalid visibility specifier.");
m_scanner->next();
return visibility;
}
ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const* _contractName)
{ {
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
ASTPointer<ASTString> docstring; ASTPointer<ASTString> docstring;
@ -201,16 +208,24 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic, A
name = expectIdentifierToken(); name = expectIdentifierToken();
ASTPointer<ParameterList> parameters(parseParameterList()); ASTPointer<ParameterList> parameters(parseParameterList());
bool isDeclaredConst = false; bool isDeclaredConst = false;
Declaration::Visibility visibility(Declaration::Visibility::DEFAULT);
vector<ASTPointer<ModifierInvocation>> modifiers; vector<ASTPointer<ModifierInvocation>> modifiers;
while (true) while (true)
{ {
if (m_scanner->getCurrentToken() == Token::CONST) Token::Value token = m_scanner->getCurrentToken();
if (token == Token::CONST)
{ {
isDeclaredConst = true; isDeclaredConst = true;
m_scanner->next(); m_scanner->next();
} }
else if (m_scanner->getCurrentToken() == Token::IDENTIFIER) else if (token == Token::IDENTIFIER)
modifiers.push_back(parseModifierInvocation()); modifiers.push_back(parseModifierInvocation());
else if (Token::isVisibilitySpecifier(token))
{
if (visibility != Declaration::Visibility::DEFAULT)
BOOST_THROW_EXCEPTION(createParserError("Multiple visibility specifiers."));
visibility = parseVisibilitySpecifier(token);
}
else else
break; break;
} }
@ -226,7 +241,7 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic, A
ASTPointer<Block> block = parseBlock(); ASTPointer<Block> block = parseBlock();
nodeFactory.setEndPositionFromNode(block); nodeFactory.setEndPositionFromNode(block);
bool const c_isConstructor = (_contractName && *name == *_contractName); bool const c_isConstructor = (_contractName && *name == *_contractName);
return nodeFactory.createNode<FunctionDefinition>(name, _isPublic, c_isConstructor, docstring, return nodeFactory.createNode<FunctionDefinition>(name, visibility, c_isConstructor, docstring,
parameters, isDeclaredConst, modifiers, parameters, isDeclaredConst, modifiers,
returnParameters, block); returnParameters, block);
} }
@ -253,14 +268,18 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(VarDeclParserOp
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
ASTPointer<TypeName> type = parseTypeName(_options.allowVar); ASTPointer<TypeName> type = parseTypeName(_options.allowVar);
bool isIndexed = false; bool isIndexed = false;
if (_options.allowIndexed && m_scanner->getCurrentToken() == Token::INDEXED) Token::Value token = m_scanner->getCurrentToken();
if (_options.allowIndexed && token == Token::INDEXED)
{ {
isIndexed = true; isIndexed = true;
m_scanner->next(); m_scanner->next();
} }
Declaration::Visibility visibility(Declaration::Visibility::DEFAULT);
if (_options.isStateVariable && Token::isVisibilitySpecifier(token))
visibility = parseVisibilitySpecifier(token);
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
return nodeFactory.createNode<VariableDeclaration>(type, expectIdentifierToken(), return nodeFactory.createNode<VariableDeclaration>(type, expectIdentifierToken(),
_options.isPublic, _options.isStateVariable, visibility, _options.isStateVariable,
isIndexed); isIndexed);
} }
@ -313,7 +332,7 @@ ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()
if (m_scanner->getCurrentToken() == Token::LPAREN) if (m_scanner->getCurrentToken() == Token::LPAREN)
{ {
m_scanner->next(); m_scanner->next();
arguments = parseFunctionCallArguments(); arguments = parseFunctionCallListArguments();
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
expectToken(Token::RPAREN); expectToken(Token::RPAREN);
} }
@ -573,7 +592,6 @@ ASTPointer<Expression> Parser::parseBinaryExpression(int _minPrecedence)
ASTPointer<Expression> expression = parseUnaryExpression(); ASTPointer<Expression> expression = parseUnaryExpression();
int precedence = Token::precedence(m_scanner->getCurrentToken()); int precedence = Token::precedence(m_scanner->getCurrentToken());
for (; precedence >= _minPrecedence; --precedence) for (; precedence >= _minPrecedence; --precedence)
{
while (Token::precedence(m_scanner->getCurrentToken()) == precedence) while (Token::precedence(m_scanner->getCurrentToken()) == precedence)
{ {
Token::Value op = m_scanner->getCurrentToken(); Token::Value op = m_scanner->getCurrentToken();
@ -582,7 +600,6 @@ ASTPointer<Expression> Parser::parseBinaryExpression(int _minPrecedence)
nodeFactory.setEndPositionFromNode(right); nodeFactory.setEndPositionFromNode(right);
expression = nodeFactory.createNode<BinaryOperation>(expression, op, right); expression = nodeFactory.createNode<BinaryOperation>(expression, op, right);
} }
}
return expression; return expression;
} }
@ -648,10 +665,12 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression()
case Token::LPAREN: case Token::LPAREN:
{ {
m_scanner->next(); m_scanner->next();
vector<ASTPointer<Expression>> arguments = parseFunctionCallArguments(); vector<ASTPointer<Expression>> arguments;
vector<ASTPointer<ASTString>> names;
std::tie(arguments, names) = parseFunctionCallArguments();
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
expectToken(Token::RPAREN); expectToken(Token::RPAREN);
expression = nodeFactory.createNode<FunctionCall>(expression, arguments); expression = nodeFactory.createNode<FunctionCall>(expression, arguments, names);
} }
break; break;
default: default:
@ -704,7 +723,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
return expression; return expression;
} }
vector<ASTPointer<Expression>> Parser::parseFunctionCallArguments() vector<ASTPointer<Expression>> Parser::parseFunctionCallListArguments()
{ {
vector<ASTPointer<Expression>> arguments; vector<ASTPointer<Expression>> arguments;
if (m_scanner->getCurrentToken() != Token::RPAREN) if (m_scanner->getCurrentToken() != Token::RPAREN)
@ -719,6 +738,32 @@ vector<ASTPointer<Expression>> Parser::parseFunctionCallArguments()
return arguments; return arguments;
} }
pair<vector<ASTPointer<Expression>>, vector<ASTPointer<ASTString>>> Parser::parseFunctionCallArguments()
{
pair<vector<ASTPointer<Expression>>, vector<ASTPointer<ASTString>>> ret;
Token::Value token = m_scanner->getCurrentToken();
if (token == Token::LBRACE)
{
// call({arg1 : 1, arg2 : 2 })
expectToken(Token::LBRACE);
while (m_scanner->getCurrentToken() != Token::RBRACE)
{
ret.second.push_back(expectIdentifierToken());
expectToken(Token::COLON);
ret.first.push_back(parseExpression());
if (m_scanner->getCurrentToken() == Token::COMMA)
expectToken(Token::COMMA);
else
break;
}
expectToken(Token::RBRACE);
}
else
ret.first = parseFunctionCallListArguments();
return ret;
}
bool Parser::peekVariableDefinition() bool Parser::peekVariableDefinition()
{ {

7
libsolidity/Parser.h

@ -48,7 +48,6 @@ private:
struct VarDeclParserOptions { struct VarDeclParserOptions {
VarDeclParserOptions() {} VarDeclParserOptions() {}
bool allowVar = false; bool allowVar = false;
bool isPublic = false;
bool isStateVariable = false; bool isStateVariable = false;
bool allowIndexed = false; bool allowIndexed = false;
}; };
@ -58,7 +57,8 @@ private:
ASTPointer<ImportDirective> parseImportDirective(); ASTPointer<ImportDirective> parseImportDirective();
ASTPointer<ContractDefinition> parseContractDefinition(); ASTPointer<ContractDefinition> parseContractDefinition();
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier(); ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
ASTPointer<FunctionDefinition> parseFunctionDefinition(bool _isPublic, ASTString const* _contractName); Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
ASTPointer<StructDefinition> parseStructDefinition(); ASTPointer<StructDefinition> parseStructDefinition();
ASTPointer<VariableDeclaration> parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions()); ASTPointer<VariableDeclaration> parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions());
ASTPointer<ModifierDefinition> parseModifierDefinition(); ASTPointer<ModifierDefinition> parseModifierDefinition();
@ -81,7 +81,8 @@ private:
ASTPointer<Expression> parseUnaryExpression(); ASTPointer<Expression> parseUnaryExpression();
ASTPointer<Expression> parseLeftHandSideExpression(); ASTPointer<Expression> parseLeftHandSideExpression();
ASTPointer<Expression> parsePrimaryExpression(); ASTPointer<Expression> parsePrimaryExpression();
std::vector<ASTPointer<Expression>> parseFunctionCallArguments(); std::vector<ASTPointer<Expression>> parseFunctionCallListArguments();
std::pair<std::vector<ASTPointer<Expression>>, std::vector<ASTPointer<ASTString>>> parseFunctionCallArguments();
///@} ///@}
///@{ ///@{

2
libsolidity/Token.h

@ -165,6 +165,7 @@ namespace solidity
K(NEW, "new", 0) \ K(NEW, "new", 0) \
K(PUBLIC, "public", 0) \ K(PUBLIC, "public", 0) \
K(PRIVATE, "private", 0) \ K(PRIVATE, "private", 0) \
K(PROTECTED, "protected", 0) \
K(RETURN, "return", 0) \ K(RETURN, "return", 0) \
K(RETURNS, "returns", 0) \ K(RETURNS, "returns", 0) \
K(STRUCT, "struct", 0) \ K(STRUCT, "struct", 0) \
@ -376,6 +377,7 @@ public:
static bool isUnaryOp(Value op) { return (NOT <= op && op <= DELETE) || op == ADD || op == SUB; } static bool isUnaryOp(Value op) { return (NOT <= op && op <= DELETE) || op == ADD || op == SUB; }
static bool isCountOp(Value op) { return op == INC || op == DEC; } static bool isCountOp(Value op) { return op == INC || op == DEC; }
static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); }
static bool isVisibilitySpecifier(Value op) { return op == PUBLIC || op == PRIVATE || op == PROTECTED; }
// Returns a string corresponding to the JS token string // Returns a string corresponding to the JS token string
// (.e., "<" for the token LT) or NULL if the token doesn't // (.e., "<" for the token LT) or NULL if the token doesn't

23
libsolidity/Types.cpp

@ -621,11 +621,24 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal
FunctionType::FunctionType(VariableDeclaration const& _varDecl): FunctionType::FunctionType(VariableDeclaration const& _varDecl):
m_location(Location::EXTERNAL), m_isConstant(true), m_declaration(&_varDecl) m_location(Location::EXTERNAL), m_isConstant(true), m_declaration(&_varDecl)
{ {
TypePointers params({}); TypePointers params;
vector<string> paramNames({}); vector<string> paramNames;
TypePointers retParams({_varDecl.getType()}); TypePointers retParams;
vector<string> retParamNames({ _varDecl.getName()}); vector<string> retParamNames;
// for now, no input parameters LTODO: change for some things like mapping TypePointer varDeclType = _varDecl.getType();
auto mappingType = dynamic_cast<MappingType const*>(varDeclType.get());
auto returnType = varDeclType;
while (mappingType != nullptr)
{
params.push_back(mappingType->getKeyType());
paramNames.push_back("");
returnType = mappingType->getValueType();
mappingType = dynamic_cast<MappingType const*>(mappingType->getValueType().get());
}
retParams.push_back(returnType);
retParamNames.push_back("");
swap(params, m_parameterTypes); swap(params, m_parameterTypes);
swap(paramNames, m_parameterNames); swap(paramNames, m_parameterNames);

7
libsolidity/grammar.txt

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

4
mix/qml/StateDialog.qml

@ -33,9 +33,10 @@ Window {
transactionsModel.append(item.transactions[t]); transactionsModel.append(item.transactions[t]);
stateTransactions.push(item.transactions[t]); stateTransactions.push(item.transactions[t]);
} }
isDefault = setDefault;
visible = true; visible = true;
isDefault = setDefault;
titleField.focus = true; titleField.focus = true;
defaultCheckBox.enabled = !isDefault;
} }
function close() { function close() {
@ -167,6 +168,7 @@ Window {
onClicked: transactionsModel.editTransaction(index) onClicked: transactionsModel.editTransaction(index)
} }
ToolButton { ToolButton {
visible: index >= 0 ? !transactionsModel.get(index).executeConstructor : false
text: qsTr("Delete"); text: qsTr("Delete");
Layout.fillHeight: true Layout.fillHeight: true
onClicked: transactionsModel.deleteTransaction(index) onClicked: transactionsModel.deleteTransaction(index)

1
mix/qml/StateList.qml

@ -48,6 +48,7 @@ Rectangle {
onClicked: list.model.editState(index); onClicked: list.model.editState(index);
} }
ToolButton { ToolButton {
visible: list.model.count - 1 != index
text: qsTr("Delete"); text: qsTr("Delete");
Layout.fillHeight: true Layout.fillHeight: true
onClicked: list.model.deleteState(index); onClicked: list.model.deleteState(index);

52
mix/qml/StateListModel.qml

@ -8,7 +8,7 @@ import "js/QEtherHelper.js" as QEtherHelper
Item { Item {
property int defaultStateIndex: -1 property int defaultStateIndex: 0
property alias model: stateListModel property alias model: stateListModel
property var stateList: [] property var stateList: []
@ -105,20 +105,7 @@ Item {
stateListModel.clear(); stateListModel.clear();
stateList = []; stateList = [];
} }
onProjectLoading: { onProjectLoading: stateListModel.loadStatesFromProject(projectData);
if (!projectData.states)
projectData.states = [];
if (projectData.defaultStateIndex !== undefined)
defaultStateIndex = projectData.defaultStateIndex;
else
defaultStateIndex = -1;
var items = projectData.states;
for(var i = 0; i < items.length; i++) {
var item = fromPlainStateItem(items[i]);
stateListModel.append(item);
stateList.push(item);
}
}
onProjectSaving: { onProjectSaving: {
projectData.states = [] projectData.states = []
for(var i = 0; i < stateListModel.count; i++) { for(var i = 0; i < stateListModel.count; i++) {
@ -149,7 +136,8 @@ Item {
stateList.push(item); stateList.push(item);
stateListModel.append(item); stateListModel.append(item);
} }
if (stateDialog.isDefault)
stateListModel.defaultStateChanged();
stateListModel.save(); stateListModel.save();
} }
} }
@ -161,6 +149,9 @@ Item {
ListModel { ListModel {
id: stateListModel id: stateListModel
signal defaultStateChanged;
signal stateListModelReady;
function defaultTransactionItem() { function defaultTransactionItem() {
return { return {
value: QEtherHelper.createEther("100", QEther.Wei), value: QEtherHelper.createEther("100", QEther.Wei),
@ -199,7 +190,7 @@ Item {
function addState() { function addState() {
var item = createDefaultState(); var item = createDefaultState();
stateDialog.open(stateListModel.count, item, defaultStateIndex === -1); stateDialog.open(stateListModel.count, item, false);
} }
function editState(index) { function editState(index) {
@ -220,12 +211,37 @@ Item {
stateListModel.remove(index); stateListModel.remove(index);
stateList.splice(index, 1); stateList.splice(index, 1);
if (index === defaultStateIndex) if (index === defaultStateIndex)
defaultStateIndex = -1; {
defaultStateIndex = 0;
defaultStateChanged();
}
save(); save();
} }
function save() { function save() {
projectModel.saveProject(); projectModel.saveProject();
} }
function defaultStateName()
{
return stateList[defaultStateIndex].title;
}
function loadStatesFromProject(projectData)
{
if (!projectData.states)
projectData.states = [];
if (projectData.defaultStateIndex !== undefined)
defaultStateIndex = projectData.defaultStateIndex;
else
defaultStateIndex = 0;
var items = projectData.states;
for(var i = 0; i < items.length; i++) {
var item = fromPlainStateItem(items[i]);
stateListModel.append(item);
stateList.push(item);
}
stateListModelReady();
}
} }
} }

17
mix/qml/main.qml

@ -35,7 +35,7 @@ ApplicationWindow {
MenuItem { action: exitAppAction } MenuItem { action: exitAppAction }
} }
Menu { Menu {
title: qsTr("Debug") title: qsTr("Deploy")
MenuItem { action: debugRunAction } MenuItem { action: debugRunAction }
MenuItem { action: mineAction } MenuItem { action: mineAction }
MenuSeparator {} MenuSeparator {}
@ -90,9 +90,22 @@ ApplicationWindow {
onTriggered: clientModel.mine(); onTriggered: clientModel.mine();
enabled: codeModel.hasContract && !clientModel.running enabled: codeModel.hasContract && !clientModel.running
} }
Connections {
target: projectModel.stateListModel
function updateRunLabel()
{
debugRunAction.text = qsTr("Deploy") + " \"" + projectModel.stateListModel.defaultStateName() + "\"";
}
onDefaultStateChanged: updateRunLabel()
onStateListModelReady: updateRunLabel()
}
Action { Action {
id: debugRunAction id: debugRunAction
text: qsTr("Run") text: qsTr("Deploy")
shortcut: "F5" shortcut: "F5"
onTriggered: mainContent.startQuickDebugging() onTriggered: mainContent.startQuickDebugging()
enabled: codeModel.hasContract && !clientModel.running enabled: codeModel.hasContract && !clientModel.running

45
test/SolidityEndToEndTest.cpp

@ -92,6 +92,16 @@ BOOST_AUTO_TEST_CASE(multiple_functions)
BOOST_CHECK(callContractFunction("i_am_not_there()", bytes()) == bytes()); BOOST_CHECK(callContractFunction("i_am_not_there()", bytes()) == bytes());
} }
BOOST_AUTO_TEST_CASE(named_args)
{
char const* sourceCode = "contract test {\n"
" function a(uint a, uint b, uint c) returns (uint r) { r = a * 100 + b * 10 + c * 1; }\n"
" function b() returns (uint r) { r = a({a: 1, b: 2, c: 3}); }\n"
"}\n";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("b()", bytes()) == toBigEndian(u256(123)));
}
BOOST_AUTO_TEST_CASE(while_loop) BOOST_AUTO_TEST_CASE(while_loop)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
@ -885,7 +895,7 @@ BOOST_AUTO_TEST_CASE(constructor)
BOOST_AUTO_TEST_CASE(simple_accessor) BOOST_AUTO_TEST_CASE(simple_accessor)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
" uint256 data;\n" " uint256 public data;\n"
" function test() {\n" " function test() {\n"
" data = 8;\n" " data = 8;\n"
" }\n" " }\n"
@ -897,10 +907,10 @@ BOOST_AUTO_TEST_CASE(simple_accessor)
BOOST_AUTO_TEST_CASE(multiple_elementary_accessors) BOOST_AUTO_TEST_CASE(multiple_elementary_accessors)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
" uint256 data;\n" " uint256 public data;\n"
" string6 name;\n" " string6 public name;\n"
" hash a_hash;\n" " hash public a_hash;\n"
" address an_address;\n" " address public an_address;\n"
" function test() {\n" " function test() {\n"
" data = 8;\n" " data = 8;\n"
" name = \"Celina\";\n" " name = \"Celina\";\n"
@ -908,7 +918,6 @@ BOOST_AUTO_TEST_CASE(multiple_elementary_accessors)
" an_address = address(0x1337);\n" " an_address = address(0x1337);\n"
" super_secret_data = 42;\n" " super_secret_data = 42;\n"
" }\n" " }\n"
" private:"
" uint256 super_secret_data;" " uint256 super_secret_data;"
"}\n"; "}\n";
compileAndRun(sourceCode); compileAndRun(sourceCode);
@ -919,6 +928,27 @@ BOOST_AUTO_TEST_CASE(multiple_elementary_accessors)
BOOST_CHECK(callContractFunction("super_secret_data()") == bytes()); BOOST_CHECK(callContractFunction("super_secret_data()") == bytes());
} }
BOOST_AUTO_TEST_CASE(complex_accessors)
{
char const* sourceCode = "contract test {\n"
" mapping(uint256 => string4) public to_string_map;\n"
" mapping(uint256 => bool) public to_bool_map;\n"
" mapping(uint256 => uint256) public to_uint_map;\n"
" mapping(uint256 => mapping(uint256 => uint256)) public to_multiple_map;\n"
" function test() {\n"
" to_string_map[42] = \"24\";\n"
" to_bool_map[42] = false;\n"
" to_uint_map[42] = 12;\n"
" to_multiple_map[42][23] = 31;\n"
" }\n"
"}\n";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("to_string_map(uint256)", 42) == encodeArgs("24"));
BOOST_CHECK(callContractFunction("to_bool_map(uint256)", 42) == encodeArgs(false));
BOOST_CHECK(callContractFunction("to_uint_map(uint256)", 42) == encodeArgs(12));
BOOST_CHECK(callContractFunction("to_multiple_map(uint256,uint256)", 42, 23) == encodeArgs(31));
}
BOOST_AUTO_TEST_CASE(balance) BOOST_AUTO_TEST_CASE(balance)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
@ -1490,8 +1520,7 @@ BOOST_AUTO_TEST_CASE(functions_called_by_constructor)
setName("abc"); setName("abc");
} }
function getName() returns (string3 ret) { return name; } function getName() returns (string3 ret) { return name; }
private: function setName(string3 _name) private { name = _name; }
function setName(string3 _name) { name = _name; }
})"; })";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_REQUIRE(callContractFunction("getName()") == encodeArgs("abc")); BOOST_REQUIRE(callContractFunction("getName()") == encodeArgs("abc"));

98
test/SolidityNameAndTypeResolution.cpp

@ -467,6 +467,24 @@ BOOST_AUTO_TEST_CASE(illegal_override_indirect)
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
} }
BOOST_AUTO_TEST_CASE(illegal_override_visibility)
{
char const* text = R"(
contract B { function f() protected {} }
contract C is B { function f() public {} }
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(illegal_override_constness)
{
char const* text = R"(
contract B { function f() constant {} }
contract C is B { function f() {} }
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(complex_inheritance) BOOST_AUTO_TEST_CASE(complex_inheritance)
{ {
char const* text = R"( char const* text = R"(
@ -636,7 +654,9 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors)
" function fun() {\n" " function fun() {\n"
" uint64(2);\n" " uint64(2);\n"
" }\n" " }\n"
"uint256 foo;\n" "uint256 public foo;\n"
"mapping(uint=>string4) public map;\n"
"mapping(uint=>mapping(uint=>string4)) public multiple_map;\n"
"}\n"; "}\n";
ASTPointer<SourceUnit> source; ASTPointer<SourceUnit> source;
@ -644,10 +664,27 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors)
BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text)); BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text));
BOOST_REQUIRE((contract = retrieveContract(source, 0)) != nullptr); BOOST_REQUIRE((contract = retrieveContract(source, 0)) != nullptr);
FunctionTypePointer function = retrieveFunctionBySignature(contract, "foo()"); FunctionTypePointer function = retrieveFunctionBySignature(contract, "foo()");
BOOST_REQUIRE(function->hasDeclaration()); BOOST_REQUIRE(function && function->hasDeclaration());
auto returnParams = function->getReturnParameterTypeNames(); auto returnParams = function->getReturnParameterTypeNames();
BOOST_CHECK_EQUAL(returnParams.at(0), "uint256"); BOOST_CHECK_EQUAL(returnParams.at(0), "uint256");
BOOST_CHECK(function->isConstant()); BOOST_CHECK(function->isConstant());
function = retrieveFunctionBySignature(contract, "map(uint256)");
BOOST_REQUIRE(function && function->hasDeclaration());
auto params = function->getParameterTypeNames();
BOOST_CHECK_EQUAL(params.at(0), "uint256");
returnParams = function->getReturnParameterTypeNames();
BOOST_CHECK_EQUAL(returnParams.at(0), "string4");
BOOST_CHECK(function->isConstant());
function = retrieveFunctionBySignature(contract, "multiple_map(uint256,uint256)");
BOOST_REQUIRE(function && function->hasDeclaration());
params = function->getParameterTypeNames();
BOOST_CHECK_EQUAL(params.at(0), "uint256");
BOOST_CHECK_EQUAL(params.at(1), "uint256");
returnParams = function->getReturnParameterTypeNames();
BOOST_CHECK_EQUAL(returnParams.at(0), "string4");
BOOST_CHECK(function->isConstant());
} }
BOOST_AUTO_TEST_CASE(function_clash_with_state_variable_accessor) BOOST_AUTO_TEST_CASE(function_clash_with_state_variable_accessor)
@ -668,16 +705,19 @@ BOOST_AUTO_TEST_CASE(private_state_variable)
" function fun() {\n" " function fun() {\n"
" uint64(2);\n" " uint64(2);\n"
" }\n" " }\n"
"private:\n" "uint256 private foo;\n"
"uint256 foo;\n" "uint256 protected bar;\n"
"}\n"; "}\n";
ASTPointer<SourceUnit> source; ASTPointer<SourceUnit> source;
ContractDefinition const* contract; ContractDefinition const* contract;
BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text)); BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text));
BOOST_CHECK((contract = retrieveContract(source, 0)) != nullptr); BOOST_CHECK((contract = retrieveContract(source, 0)) != nullptr);
FunctionTypePointer function = retrieveFunctionBySignature(contract, "foo()"); FunctionTypePointer function;
function = retrieveFunctionBySignature(contract, "foo()");
BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a private variable should not exist"); BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a private variable should not exist");
function = retrieveFunctionBySignature(contract, "bar()");
BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a protected variable should not exist");
} }
BOOST_AUTO_TEST_CASE(fallback_function) BOOST_AUTO_TEST_CASE(fallback_function)
@ -780,6 +820,54 @@ BOOST_AUTO_TEST_CASE(multiple_events_argument_clash)
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
} }
BOOST_AUTO_TEST_CASE(access_to_default_function_visibility)
{
char const* text = R"(
contract c {
function f() {}
}
contract d {
function g() { c(0).f(); }
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(access_to_protected_function)
{
char const* text = R"(
contract c {
function f() protected {}
}
contract d {
function g() { c(0).f(); }
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(access_to_default_state_variable_visibility)
{
char const* text = R"(
contract c {
uint a;
}
contract d {
function g() { c(0).a(); }
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(access_to_protected_state_variable)
{
char const* text = R"(
contract c {
uint public a;
}
contract d {
function g() { c(0).a(); }
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

31
test/SolidityParser.cpp

@ -129,9 +129,7 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation)
ASTPointer<ContractDefinition> contract; ASTPointer<ContractDefinition> contract;
ASTPointer<FunctionDefinition> function; ASTPointer<FunctionDefinition> function;
char const* text = "contract test {\n" char const* text = "contract test {\n"
" private:\n" " uint256 stateVar;\n"
" uint256 stateVar;\n"
" public:\n"
" /// This is a test function\n" " /// This is a test function\n"
" function functionName(hash hashin) returns (hash hashout) {}\n" " function functionName(hash hashin) returns (hash hashout) {}\n"
"}\n"; "}\n";
@ -162,9 +160,7 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation)
ASTPointer<ContractDefinition> contract; ASTPointer<ContractDefinition> contract;
ASTPointer<FunctionDefinition> function; ASTPointer<FunctionDefinition> function;
char const* text = "contract test {\n" char const* text = "contract test {\n"
" private:\n"
" uint256 stateVar;\n" " uint256 stateVar;\n"
" public:\n"
" /// This is test function 1\n" " /// This is test function 1\n"
" function functionName1(hash hashin) returns (hash hashout) {}\n" " function functionName1(hash hashin) returns (hash hashout) {}\n"
" /// This is test function 2\n" " /// This is test function 2\n"
@ -621,6 +617,31 @@ BOOST_AUTO_TEST_CASE(event_arguments_indexed)
BOOST_CHECK_NO_THROW(parseText(text)); BOOST_CHECK_NO_THROW(parseText(text));
} }
BOOST_AUTO_TEST_CASE(visibility_specifiers)
{
char const* text = R"(
contract c {
uint private a;
uint protected b;
uint public c;
uint d;
function f() {}
function f_priv() private {}
function f_public() public {}
function f_protected() protected {}
})";
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers)
{
char const* text = R"(
contract c {
uint private protected a;
})";
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

Loading…
Cancel
Save