Browse Source

Merge branch 'develop' into p2p

cl-refactor
subtly 10 years ago
parent
commit
c144fa329a
  1. 7
      alethzero/MainWin.cpp
  2. 13
      cmake/EthExecutableHelper.cmake
  3. 22
      libdevcore/CommonJS.cpp
  4. 8
      libdevcore/CommonJS.h
  5. 21
      libethcore/CommonEth.cpp
  6. 2
      libethcore/CommonEth.h
  7. 12
      libethereum/CanonBlockChain.cpp
  8. 12
      libethereum/CanonBlockChain.h
  9. 2
      libethereum/Client.cpp
  10. 4
      libethereum/State.cpp
  11. 5
      libethereum/State.h
  12. 2
      libjsqrc/ethereumjs/bower.json
  13. 380
      libjsqrc/ethereumjs/dist/ethereum.js
  14. 22
      libjsqrc/ethereumjs/dist/ethereum.js.map
  15. 2
      libjsqrc/ethereumjs/dist/ethereum.min.js
  16. 66
      libjsqrc/ethereumjs/example/event_inc.html
  17. 23
      libjsqrc/ethereumjs/lib/const.js
  18. 11
      libjsqrc/ethereumjs/lib/contract.js
  19. 72
      libjsqrc/ethereumjs/lib/event.js
  20. 10
      libjsqrc/ethereumjs/lib/filter.js
  21. 32
      libjsqrc/ethereumjs/lib/httpsync.js
  22. 65
      libjsqrc/ethereumjs/lib/jsonrpc.js
  23. 45
      libjsqrc/ethereumjs/lib/providermanager.js
  24. 3
      libjsqrc/ethereumjs/lib/qtsync.js
  25. 33
      libjsqrc/ethereumjs/lib/utils.js
  26. 62
      libjsqrc/ethereumjs/lib/web3.js
  27. 2
      libjsqrc/ethereumjs/package.json
  28. 438
      libjsqrc/ethereumjs/test/abi.inputParser.js
  29. 461
      libjsqrc/ethereumjs/test/abi.outputParser.js
  30. 2
      libjsqrc/ethereumjs/test/db.methods.js
  31. 2
      libjsqrc/ethereumjs/test/eth.methods.js
  32. 125
      libjsqrc/ethereumjs/test/event.inputParser.js
  33. 124
      libjsqrc/ethereumjs/test/event.js
  34. 81
      libjsqrc/ethereumjs/test/event.outputParser.js
  35. 143
      libjsqrc/ethereumjs/test/jsonrpc.isValidResponse.js
  36. 47
      libjsqrc/ethereumjs/test/jsonrpc.toBatchPayload.js
  37. 40
      libjsqrc/ethereumjs/test/jsonrpc.toPayload.js
  38. 2
      libjsqrc/ethereumjs/test/shh.methods.js
  39. 0
      libjsqrc/ethereumjs/test/test.utils.js
  40. 42
      libjsqrc/ethereumjs/test/utils.extractDisplayName.js
  41. 55
      libjsqrc/ethereumjs/test/utils.extractTypeName.js
  42. 2
      libjsqrc/ethereumjs/test/web3.methods.js
  43. 12
      libjsqrc/natspec.js
  44. 13
      libqwebthree/QWebThree.cpp
  45. 45
      libsolidity/AST.cpp
  46. 41
      libsolidity/AST.h
  47. 4
      libsolidity/Compiler.cpp
  48. 72
      libsolidity/ExpressionCompiler.cpp
  49. 4
      libsolidity/ExpressionCompiler.h
  50. 89
      libsolidity/Parser.cpp
  51. 7
      libsolidity/Parser.h
  52. 2
      libsolidity/Token.h
  53. 23
      libsolidity/Types.cpp
  54. 7
      libsolidity/grammar.txt
  55. 45
      macdeployfix.sh
  56. 13
      mix/AppContext.cpp
  57. 1
      mix/AssemblyDebuggerControl.cpp
  58. 2
      mix/CMakeLists.txt
  59. 50
      mix/ClientModel.cpp
  60. 6
      mix/ClientModel.h
  61. 22
      mix/CodeHighlighter.cpp
  62. 98
      mix/ContractCallDataEncoder.cpp
  63. 16
      mix/ContractCallDataEncoder.h
  64. 1
      mix/Exceptions.h
  65. 79
      mix/MachineStates.h
  66. 9
      mix/MixClient.cpp
  67. 41
      mix/MixClient.h
  68. 3
      mix/QBigInt.h
  69. 8
      mix/QVariableDeclaration.h
  70. 90
      mix/QVariableDefinition.cpp
  71. 90
      mix/QVariableDefinition.h
  72. 2
      mix/Web3Server.cpp
  73. 1
      mix/main.cpp
  74. 215
      mix/qml/MainContent.qml
  75. 3
      mix/qml/ProjectModel.qml
  76. 7
      mix/qml/QBoolType.qml
  77. 42
      mix/qml/QBoolTypeView.qml
  78. 7
      mix/qml/QHashType.qml
  79. 22
      mix/qml/QHashTypeView.qml
  80. 7
      mix/qml/QIntType.qml
  81. 24
      mix/qml/QIntTypeView.qml
  82. 7
      mix/qml/QRealType.qml
  83. 15
      mix/qml/QRealTypeView.qml
  84. 7
      mix/qml/QStringType.qml
  85. 25
      mix/qml/QStringTypeView.qml
  86. 7
      mix/qml/QVariableDeclaration.qml
  87. 13
      mix/qml/QVariableDefinition.qml
  88. 47
      mix/qml/Splitter.qml
  89. 4
      mix/qml/StateDialog.qml
  90. 1
      mix/qml/StateList.qml
  91. 99
      mix/qml/StateListModel.qml
  92. 155
      mix/qml/TransactionDialog.qml
  93. 2
      mix/qml/WebPreview.qml
  94. 1
      mix/qml/html/codeeditor.js
  95. 7
      mix/qml/js/ProjectModel.js
  96. 55
      mix/qml/main.qml
  97. 13
      mix/res.qrc
  98. 55
      test/SolidityEndToEndTest.cpp
  99. 98
      test/SolidityNameAndTypeResolution.cpp
  100. 49
      test/SolidityParser.cpp

7
alethzero/MainWin.cpp

@ -1206,8 +1206,9 @@ string Main::renderDiff(StateDiff const& _d) const
if (ad.balance)
{
s << "<br/>" << indent << "Balance " << dec << formatBalance(ad.balance.to());
s << " <b>" << showpos << (((dev::bigint)ad.balance.to()) - ((dev::bigint)ad.balance.from())) << noshowpos << "</b>";
s << "<br/>" << indent << "Balance " << dec << ad.balance.to() << " [=" << formatBalance(ad.balance.to()) << "]";
auto d = (((dev::bigint)ad.balance.to()) - ((dev::bigint)ad.balance.from()));
s << " <b>" << showpos << dec << d << " [=" << formatBalance(d) << "]" << noshowpos << "</b>";
}
if (ad.nonce)
{
@ -1216,7 +1217,7 @@ string Main::renderDiff(StateDiff const& _d) const
}
if (ad.code)
{
s << "<br/>" << indent << "Code " << hex << ad.code.to().size() << " bytes";
s << "<br/>" << indent << "Code " << dec << ad.code.to().size() << " bytes";
if (ad.code.from().size())
s << " (" << ad.code.from().size() << " bytes)";
}

13
cmake/EthExecutableHelper.cmake

@ -71,8 +71,9 @@ macro(eth_install_executable EXECUTABLE)
if (APPLE)
# First have qt5 install plugins and frameworks
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD
COMMAND ${MACDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.app ${eth_qml_dir}
COMMAND ${MACDEPLOYQT_APP} ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.app -executable=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.app/Contents/MacOS/${EXECUTABLE} ${eth_qml_dir}
WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
COMMAND sh ${CMAKE_SOURCE_DIR}/macdeployfix.sh ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${EXECUTABLE}.app/Contents
)
# This tool and next will inspect linked libraries in order to determine which dependencies are required
@ -82,19 +83,11 @@ macro(eth_install_executable EXECUTABLE)
set(APP_BUNDLE_PATH "${CMAKE_CURRENT_BINARY_DIR}/\$ENV{CONFIGURATION}/${EXECUTABLE}.app")
endif ()
# TODO check, how fixup_bundle works and if it is required
install(CODE "
include(BundleUtilities)
set(BU_CHMOD_BUNDLE_ITEMS 1)
fixup_bundle(\"${APP_BUNDLE_PATH}\" \"${BUNDLELIBS}\" \"../libqethereum ../libethereum ../secp256k1\")
verify_app(\"${APP_BUNDLE_PATH}\")
" COMPONENT RUNTIME )
# Cleanup duplicate libs from macdeployqt
install(CODE "
file(GLOB LINGER_RM \"${APP_BUNDLE_PATH}/Contents/Frameworks/*.dylib\")
if (LINGER_RM)
file(REMOVE \${LINGER_RM})
endif ()
")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# copy all dlls to executable directory

22
libdevcore/CommonJS.cpp

@ -45,6 +45,12 @@ bytes padded(bytes _b, unsigned _l)
return asBytes(asString(_b).substr(_b.size() - std::max(_l, _l)));
}
bytes paddedRight(bytes _b, unsigned _l)
{
_b.resize(_l);
return _b;
}
bytes unpadded(bytes _b)
{
auto p = asString(_b).find_last_not_of((char)0);
@ -52,12 +58,18 @@ bytes unpadded(bytes _b)
return _b;
}
std::string unpadLeft(std::string _b)
bytes unpadLeft(bytes _b)
{
auto p = _b.find_first_not_of('0');
if (p == std::string::npos)
return "0";
return _b.substr(p, _b.length() - 1);
unsigned int i = 0;
if (_b.size() == 0)
return _b;
while (i < _b.size() && _b[i] == byte(0))
i++;
if (i != 0)
_b.erase(_b.begin(), _b.begin() + i);
return _b;
}
std::string prettyU256(u256 _n)

8
libdevcore/CommonJS.h

@ -48,12 +48,14 @@ inline std::string toJS(dev::bytes const& _n)
/// Convert string to byte array. Input parameters can be hex or dec. Returns empty array if invalid input e.g neither dec or hex.
bytes jsToBytes(std::string const& _s);
/// Add '0' on the head of _b until _l.
/// Add '0' on the head of @a _b until @a _l.
bytes padded(bytes _b, unsigned _l);
/// Add '0' on the queue of @a _b until @a _l.
bytes paddedRight(bytes _b, unsigned _l);
/// Removing all trailing '0'. Returns empty array if input contains only '0' char.
bytes unpadded(bytes _s);
/// Remove all '0' on the head of _s. Returns 0 if _s contains only '0'.
std::string unpadLeft(std::string _s);
/// Remove all 0 byte on the head of @a _s.
bytes unpadLeft(bytes _s);
/// Convert u256 into user-readable string. Returns int/hex value of 64 bits int, hex of 160 bits FixedHash. As a fallback try to handle input as h256.
std::string prettyU256(u256 _n);
/// Convert h256 into user-readable string (by directly using std::string constructor).

21
libethcore/CommonEth.cpp

@ -63,22 +63,31 @@ vector<pair<u256, string>> const& units()
return g_units;
}
std::string formatBalance(u256 _b)
std::string formatBalance(bigint const& _b)
{
ostringstream ret;
if (_b > g_units[0].first * 10000)
u256 b;
if (_b < 0)
{
ret << (_b / g_units[0].first) << " " << g_units[0].second;
ret << "-";
b = (u256)-_b;
}
else
b = (u256)_b;
if (b > g_units[0].first * 10000)
{
ret << (b / g_units[0].first) << " " << g_units[0].second;
return ret.str();
}
ret << setprecision(5);
for (auto const& i: g_units)
if (i.first != 1 && _b >= i.first * 100)
if (i.first != 1 && b >= i.first * 100)
{
ret << (double(_b / (i.first / 1000)) / 1000.0) << " " << i.second;
ret << (double(b / (i.first / 1000)) / 1000.0) << " " << i.second;
return ret.str();
}
ret << _b << " wei";
ret << b << " wei";
return ret.str();
}

2
libethcore/CommonEth.h

@ -39,7 +39,7 @@ extern const unsigned c_protocolVersion;
extern const unsigned c_databaseVersion;
/// User-friendly string representation of the amount _b in wei.
std::string formatBalance(u256 _b);
std::string formatBalance(bigint const& _b);
/// Get information concerning the currency denominations.
std::vector<std::pair<u256, std::string>> const& units();

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/Client.cpp

@ -226,7 +226,7 @@ void Client::uninstallWatch(unsigned _i)
void Client::noteChanged(h256Set const& _filters)
{
Guard l(m_filterLock);
cnote << "noteChanged(" << _filters << ")";
// cnote << "noteChanged(" << _filters << ")";
// accrue all changes left in each filter into the watches.
for (auto& i: m_watches)
if (_filters.count(i.second.id))

4
libethereum/State.cpp

@ -682,8 +682,6 @@ LogBloom State::logBloom() const
return ret;
}
// @returns the block that represents the difference between m_previousBlock and m_currentBlock.
// (i.e. all the transactions we executed).
void State::commitToMine(BlockChain const& _bc)
{
uncommitToMine();
@ -802,7 +800,7 @@ void State::completeMine()
ret.appendRaw(m_currentTxs);
ret.appendRaw(m_currentUncles);
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() << ")";
// Quickly reset the transactions.

5
libethereum/State.h

@ -122,11 +122,14 @@ public:
/** Commit to DB and build the final block if the previous call to mine()'s result is completion.
* Typically looks like:
* @code
* while (notYetMined)
* {
* // lock
* commitToMine(blockchain);
* commitToMine(_blockChain); // will call uncommitToMine if a repeat.
* // unlock
* MineInfo info;
* for (info.complete = false; !info.complete; info = mine()) {}
* }
* // lock
* completeMine();
* // unlock

2
libjsqrc/ethereumjs/bower.json

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

380
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.
@ -238,9 +238,32 @@ if ("build" !== 'build') {/*
var BigNumber = require('bignumber.js'); // jshint ignore:line
*/}
var ETH_UNITS = [
'wei',
'Kwei',
'Mwei',
'Gwei',
'szabo',
'finney',
'ether',
'grand',
'Mether',
'Gether',
'Tether',
'Pether',
'Eether',
'Zether',
'Yether',
'Nether',
'Dether',
'Vether',
'Uether'
];
module.exports = {
ETH_PADDING: 32,
ETH_SIGNATURE_LENGTH: 4,
ETH_UNITS: ETH_UNITS,
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) {
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', {
get: function() {
@ -386,8 +414,12 @@ var addEventsToContract = function (contract, desc, address) {
var impl = function () {
var params = Array.prototype.slice.call(arguments);
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);
o._onWatchEventResult = function (data) {
var parser = eventImpl.outputParser(e);
return parser(data);
};
return web3.eth.watch(o);
};
@ -455,7 +487,7 @@ var contract = function (address, desc) {
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.
@ -481,6 +513,16 @@ module.exports = contract;
var abi = require('./abi');
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 index = utils.findIndex(inputs, function (input) {
return input.name === name;
@ -496,7 +538,7 @@ var inputWithName = function (inputs, name) {
var indexedParamsToTopics = function (event, indexed) {
// sort keys?
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];
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'
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);
},{"./abi":1,"./utils":11}],5:[function(require,module,exports){
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":12}],5:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -565,6 +663,8 @@ var Filter = function(options, impl) {
if (options.topics) {
console.warn('"topics" is deprecated, use "topic" instead');
}
this._onWatchResult = options._onWatchEventResult;
// evaluate lazy properties
options = {
@ -583,13 +683,16 @@ var Filter = function(options, impl) {
this.callbacks = [];
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*
Filter.prototype.arrived = function(callback) {
this.changed(callback);
};
Filter.prototype.happened = function(callback) {
this.changed(callback);
};
/// gets called when there is new eth/shh message
Filter.prototype.changed = function(callback) {
@ -600,7 +703,8 @@ Filter.prototype.changed = function(callback) {
Filter.prototype.trigger = function(messages) {
for (var i = 0; i < this.callbacks.length; i++) {
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);
}
}
};
@ -623,7 +727,7 @@ Filter.prototype.logs = function () {
module.exports = Filter;
},{"./web3":12}],6:[function(require,module,exports){
},{"./web3":13}],6:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -779,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.
@ -812,40 +916,16 @@ var HttpSyncProvider = function (host) {
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) {
var data = formatJsonRpcObject(payload);
//var data = formatJsonRpcObject(payload);
var request = new XMLHttpRequest();
request.open('POST', this.host, false);
request.send(JSON.stringify(data));
request.send(JSON.stringify(payload));
// check request.status
return request.responseText;
var result = request.responseText;
return JSON.parse(result);
};
module.exports = HttpSyncProvider;
@ -868,6 +948,73 @@ module.exports = HttpSyncProvider;
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 !== undefined; // only undefined is not valid json object
};
/// 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
* @authors:
* Jeffrey Wilcke <jeff@ethdev.com>
@ -877,7 +1024,9 @@ module.exports = HttpSyncProvider;
* @date 2014
*/
var web3 = require('./web3'); // jshint ignore:line
var web3 = require('./web3');
var jsonrpc = require('./jsonrpc');
/**
* Provider manager object prototype
@ -891,25 +1040,35 @@ var web3 = require('./web3'); // jshint ignore:line
var ProviderManager = function() {
this.polls = [];
this.provider = undefined;
this.id = 1;
var self = this;
var poll = function () {
if (self.provider) {
self.polls.forEach(function (data) {
data.data._id = self.id;
self.id++;
var result = self.provider.send(data.data);
result = JSON.parse(result);
var pollsBatch = self.polls.map(function (data) {
return data.data;
});
var payload = jsonrpc.toBatchPayload(pollsBatch);
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
if (result.error || !(result.result instanceof Array) || result.result.length === 0) {
if (!(result instanceof Array) || result.length === 0) {
return;
}
data.callback(result.result);
data.callback(result);
});
}
setTimeout(poll, 1000);
};
@ -917,22 +1076,19 @@ var ProviderManager = function() {
};
/// sends outgoing requests
/// @params data - an object with at least 'method' property
ProviderManager.prototype.send = function(data) {
data.args = data.args || [];
data._id = this.id++;
var payload = jsonrpc.toPayload(data.method, data.params);
if (this.provider === undefined) {
console.error('provider is not set');
return null;
}
//TODO: handle error here?
var result = this.provider.send(data);
result = JSON.parse(result);
var result = this.provider.send(payload);
if (result.error) {
console.log(result.error);
if (!jsonrpc.isValidResponse(result)) {
console.log(result);
return null;
}
@ -963,7 +1119,7 @@ ProviderManager.prototype.stopPolling = function (pollId) {
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.
@ -991,13 +1147,14 @@ var QtSyncProvider = function () {
};
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;
},{}],10:[function(require,module,exports){
},{}],11:[function(require,module,exports){
/*
This file is part of ethereum.js.
@ -1078,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.
@ -1101,6 +1258,8 @@ module.exports = {
* @date 2015
*/
var c = require('./const');
/// Finds first index of array element matching pattern
/// @param array
/// @param callback pattern
@ -1163,7 +1322,7 @@ var extractDisplayName = function (name) {
var extractTypeName = function (name) {
/// TODO: make it invulnerable
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
@ -1182,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 = {
findIndex: findIndex,
toAscii: toAscii,
@ -1189,11 +1374,12 @@ module.exports = {
extractDisplayName: extractDisplayName,
extractTypeName: extractTypeName,
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.
@ -1225,28 +1411,6 @@ if ("build" !== 'build') {/*
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
var web3Methods = function () {
return [
@ -1354,8 +1518,8 @@ var setupMethods = function (obj, methods) {
var args = Array.prototype.slice.call(arguments);
var call = typeof method.call === 'function' ? method.call(args) : method.call;
return web3.provider.send({
call: call,
args: args
method: call,
params: args
});
};
});
@ -1368,15 +1532,15 @@ var setupProperties = function (obj, properties) {
var proto = {};
proto.get = function () {
return web3.provider.send({
call: property.getter
method: property.getter
});
};
if (property.setter) {
proto.set = function (val) {
return web3.provider.send({
call: property.setter,
args: [val]
method: property.setter,
params: [val]
});
};
}
@ -1409,29 +1573,7 @@ var web3 = {
},
/// used to transform value/string to eth string
/// TODO: use BigNumber.js to parse int
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];
},
toEth: utils.toEth,
/// eth object prototype
eth: {
@ -1467,11 +1609,6 @@ var web3 = {
return new web3.filter(filter, shhWatch);
}
},
/// @returns true if provider is installed
haveProvider: function() {
return !!web3.provider.provider;
}
};
/// setups all api methods
@ -1494,14 +1631,13 @@ var shhWatch = {
setupMethods(shhWatch, shhWatchMethods());
web3.setProvider = function(provider) {
//provider.onmessage = messageHandler; // there will be no async calls, to remove
web3.provider.set(provider);
};
module.exports = web3;
},{"./utils":11}],"web3":[function(require,module,exports){
},{"./utils":12}],"web3":[function(require,module,exports){
var web3 = require('./lib/web3');
var ProviderManager = require('./lib/providermanager');
web3.provider = new ProviderManager();
@ -1514,7 +1650,7 @@ web3.abi = require('./lib/abi');
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

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 ETH_UNITS = [
'wei',
'Kwei',
'Mwei',
'Gwei',
'szabo',
'finney',
'ether',
'grand',
'Mether',
'Gether',
'Tether',
'Pether',
'Eether',
'Zether',
'Yether',
'Nether',
'Dether',
'Vether',
'Uether'
];
module.exports = {
ETH_PADDING: 32,
ETH_SIGNATURE_LENGTH: 4,
ETH_UNITS: ETH_UNITS,
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) {
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', {
get: function() {
@ -138,8 +143,12 @@ var addEventsToContract = function (contract, desc, address) {
var impl = function () {
var params = Array.prototype.slice.call(arguments);
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);
o._onWatchEventResult = function (data) {
var parser = eventImpl.outputParser(e);
return parser(data);
};
return web3.eth.watch(o);
};

72
libjsqrc/ethereumjs/lib/event.js

@ -23,6 +23,16 @@
var abi = require('./abi');
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 index = utils.findIndex(inputs, function (input) {
return input.name === name;
@ -38,7 +48,7 @@ var inputWithName = function (inputs, name) {
var indexedParamsToTopics = function (event, indexed) {
// sort keys?
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];
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'
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
};

10
libjsqrc/ethereumjs/lib/filter.js

@ -36,6 +36,8 @@ var Filter = function(options, impl) {
if (options.topics) {
console.warn('"topics" is deprecated, use "topic" instead');
}
this._onWatchResult = options._onWatchEventResult;
// evaluate lazy properties
options = {
@ -54,13 +56,16 @@ var Filter = function(options, impl) {
this.callbacks = [];
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*
Filter.prototype.arrived = function(callback) {
this.changed(callback);
};
Filter.prototype.happened = function(callback) {
this.changed(callback);
};
/// gets called when there is new eth/shh message
Filter.prototype.changed = function(callback) {
@ -71,7 +76,8 @@ Filter.prototype.changed = function(callback) {
Filter.prototype.trigger = function(messages) {
for (var i = 0; i < this.callbacks.length; i++) {
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';
};
/// 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) {
var data = formatJsonRpcObject(payload);
//var data = formatJsonRpcObject(payload);
var request = new XMLHttpRequest();
request.open('POST', this.host, false);
request.send(JSON.stringify(data));
request.send(JSON.stringify(payload));
// check request.status
return request.responseText;
var result = request.responseText;
return JSON.parse(result);
};
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 !== undefined; // only undefined is not valid json object
};
/// 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
*/
var web3 = require('./web3'); // jshint ignore:line
var web3 = require('./web3');
var jsonrpc = require('./jsonrpc');
/**
* Provider manager object prototype
@ -37,25 +39,35 @@ var web3 = require('./web3'); // jshint ignore:line
var ProviderManager = function() {
this.polls = [];
this.provider = undefined;
this.id = 1;
var self = this;
var poll = function () {
if (self.provider) {
self.polls.forEach(function (data) {
data.data._id = self.id;
self.id++;
var result = self.provider.send(data.data);
result = JSON.parse(result);
var pollsBatch = self.polls.map(function (data) {
return data.data;
});
var payload = jsonrpc.toBatchPayload(pollsBatch);
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
if (result.error || !(result.result instanceof Array) || result.result.length === 0) {
if (!(result instanceof Array) || result.length === 0) {
return;
}
data.callback(result.result);
data.callback(result);
});
}
setTimeout(poll, 1000);
};
@ -63,22 +75,19 @@ var ProviderManager = function() {
};
/// sends outgoing requests
/// @params data - an object with at least 'method' property
ProviderManager.prototype.send = function(data) {
data.args = data.args || [];
data._id = this.id++;
var payload = jsonrpc.toPayload(data.method, data.params);
if (this.provider === undefined) {
console.error('provider is not set');
return null;
}
//TODO: handle error here?
var result = this.provider.send(data);
result = JSON.parse(result);
var result = this.provider.send(payload);
if (result.error) {
console.log(result.error);
if (!jsonrpc.isValidResponse(result)) {
console.log(result);
return null;
}

3
libjsqrc/ethereumjs/lib/qtsync.js

@ -25,7 +25,8 @@ var QtSyncProvider = function () {
};
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;

33
libjsqrc/ethereumjs/lib/utils.js

@ -20,6 +20,8 @@
* @date 2015
*/
var c = require('./const');
/// Finds first index of array element matching pattern
/// @param array
/// @param callback pattern
@ -82,7 +84,7 @@ var extractDisplayName = function (name) {
var extractTypeName = function (name) {
/// TODO: make it invulnerable
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
@ -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 = {
findIndex: findIndex,
toAscii: toAscii,
@ -108,6 +136,7 @@ module.exports = {
extractDisplayName: extractDisplayName,
extractTypeName: extractTypeName,
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 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
var web3Methods = function () {
return [
@ -158,8 +136,8 @@ var setupMethods = function (obj, methods) {
var args = Array.prototype.slice.call(arguments);
var call = typeof method.call === 'function' ? method.call(args) : method.call;
return web3.provider.send({
call: call,
args: args
method: call,
params: args
});
};
});
@ -172,15 +150,15 @@ var setupProperties = function (obj, properties) {
var proto = {};
proto.get = function () {
return web3.provider.send({
call: property.getter
method: property.getter
});
};
if (property.setter) {
proto.set = function (val) {
return web3.provider.send({
call: property.setter,
args: [val]
method: property.setter,
params: [val]
});
};
}
@ -213,29 +191,7 @@ var web3 = {
},
/// used to transform value/string to eth string
/// TODO: use BigNumber.js to parse int
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];
},
toEth: utils.toEth,
/// eth object prototype
eth: {
@ -271,11 +227,6 @@ var web3 = {
return new web3.filter(filter, shhWatch);
}
},
/// @returns true if provider is installed
haveProvider: function() {
return !!web3.provider.provider;
}
};
/// setups all api methods
@ -298,7 +249,6 @@ var shhWatch = {
setupMethods(shhWatch, shhWatchMethods());
web3.setProvider = function(provider) {
//provider.onmessage = messageHandler; // there will be no async calls, to remove
web3.provider.set(provider);
};

2
libjsqrc/ethereumjs/package.json

@ -1,7 +1,7 @@
{
"name": "ethereum.js",
"namespace": "ethereum",
"version": "0.0.11",
"version": "0.0.13",
"description": "Ethereum Compatible JavaScript API",
"main": "./index.js",
"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 web3 = require('../index.js');
var u = require('./utils.js');
var u = require('./test.utils.js');
describe('web3', function() {
describe('db', function() {

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

@ -1,6 +1,6 @@
var assert = require('assert');
var web3 = require('../index.js');
var u = require('./utils.js');
var u = require('./test.utils.js');
describe('web3', 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);
});
});
});

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

@ -0,0 +1,143 @@
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);
});
it('should validate jsonrpc response with result field === 0', function () {
// given
var response = {
jsonrpc: '2.0',
id: 1,
result: 0
};
// 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 web3 = require('../index.js');
var u = require('./utils.js');
var u = require('./test.utils.js');
describe('web3', 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 web3 = require('../index.js');
var u = require('./utils.js');
var u = require('./test.utils.js');
describe('web3', function() {
u.methodExists(web3, 'sha3');

12
libjsqrc/natspec.js

@ -29,10 +29,20 @@ var getContractMethods = function (address, abi) {
return web3.eth.contract(address, abi);
};
var getMethodWithName = function(abi, name) {
for (var i = 0; i < abi.length; i++) {
if (abi[i].name === name) {
return abi[i];
}
}
console.warn('could not find method with name: ' + name);
return undefined;
};
/// Function called to get all contract method input variables
/// @returns hashmap with all contract's method input variables
var getContractInputParams = function (abi, methodName, params) {
var method = web3.abi.getMethodWithName(abi, methodName);
var method = getMethodWithName(abi, methodName);
return method.inputs.reduce(function (acc, current, index) {
acc[current.name] = params[index];
return acc;

13
libqwebthree/QWebThree.cpp

@ -41,20 +41,9 @@ void QWebThree::clientDieing()
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)
{
QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object();
emit processData(formatInput(f), ""); // it's synchronous
emit processData(_json, ""); // it's synchronous
return m_response;
}

45
libsolidity/AST.cpp

@ -133,7 +133,7 @@ void ContractDefinition::checkIllegalOverrides() const
FunctionDefinition const*& override = functions[name];
if (!override)
override = function.get();
else if (override->isPublic() != function->isPublic() ||
else if (override->getVisibility() != function->getVisibility() ||
override->isDeclaredConst() != function->isDeclaredConst() ||
FunctionType(*override) != FunctionType(*function))
BOOST_THROW_EXCEPTION(override->createTypeError("Override changes extended function signature."));
@ -475,6 +475,8 @@ void FunctionCall::checkTypeRequirements()
// number of non-mapping members
if (m_arguments.size() != 1)
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()))
BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
m_type = type.getActualType();
@ -487,9 +489,44 @@ void FunctionCall::checkTypeRequirements()
TypePointers const& parameterTypes = functionType->getParameterTypes();
if (parameterTypes.size() != m_arguments.size())
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]))
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
if (m_names.empty())
{
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,
// but we change it to the type of the first return value until we have structs
if (functionType->getReturnParameterTypes().empty())

41
libsolidity/AST.h

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

72
libsolidity/ExpressionCompiler.cpp

@ -22,6 +22,7 @@
#include <utility>
#include <numeric>
#include <boost/range/adaptor/reversed.hpp>
#include <libdevcore/Common.h>
#include <libdevcrypto/SHA3.h>
#include <libsolidity/AST.h>
@ -194,6 +195,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
//@todo struct construction
solAssert(_functionCall.getArguments().size() == 1, "");
solAssert(_functionCall.getNames().empty(), "");
Expression const& firstArgument = *_functionCall.getArguments().front();
firstArgument.accept(*this);
appendTypeConversion(*firstArgument.getType(), *_functionCall.getType());
@ -201,8 +203,26 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
else
{
FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType());
vector<ASTPointer<Expression const>> arguments = _functionCall.getArguments();
solAssert(arguments.size() == function.getParameterTypes().size(), "");
TypePointers const& parameterTypes = function.getParameterTypes();
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())
{
@ -823,26 +843,58 @@ unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _typ
return length;
}
unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType,
Expression const& _expression, unsigned _memoryOffset)
unsigned ExpressionCompiler::appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type,
Location const& _location, unsigned _memoryOffset)
{
_expression.accept(*this);
appendTypeConversion(*_expression.getType(), _expectedType, true);
appendTypeConversion(_type, _expectedType, true);
unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize());
if (c_numBytes == 0 || c_numBytes > 32)
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(_expression.getLocation())
<< errinfo_sourceLocation(_location)
<< errinfo_comment("Type " + _expectedType.toString() + " not yet supported."));
bool const c_leftAligned = _expectedType.getCategory() == Type::Category::STRING;
bool const c_padToWords = true;
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)
{
m_currentLValue.fromStateVariable(_varDecl, _varDecl.getType());
solAssert(m_currentLValue.isInStorage(), "");
m_currentLValue.retrieveValue(_varDecl.getType(), Location(), true);
FunctionType thisType(_varDecl);
solAssert(thisType.getReturnParameterTypes().size() == 1, "");
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,

4
libsolidity/ExpressionCompiler.h

@ -97,6 +97,10 @@ private:
unsigned appendArgumentCopyToMemory(TypePointers const& _types,
std::vector<ASTPointer<Expression const>> const& _arguments,
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).
/// @returns the number of bytes copied to memory
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);
expectToken(Token::LBRACE);
bool visibilityIsPublic = true;
while (true)
{
Token::Value currentToken = m_scanner->getCurrentToken();
if (currentToken == Token::RBRACE)
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)
functions.push_back(parseFunctionDefinition(visibilityIsPublic, name.get()));
functions.push_back(parseFunctionDefinition(name.get()));
else if (currentToken == Token::STRUCT)
structs.push_back(parseStructDefinition());
else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING ||
Token::isElementaryTypeName(currentToken))
{
VarDeclParserOptions options;
options.isPublic = visibilityIsPublic;
options.isStateVariable = true;
stateVariables.push_back(parseVariableDeclaration(options));
expectToken(Token::SEMICOLON);
@ -177,7 +169,7 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
if (m_scanner->getCurrentToken() == Token::LPAREN)
{
m_scanner->next();
arguments = parseFunctionCallArguments();
arguments = parseFunctionCallListArguments();
nodeFactory.markEndPosition();
expectToken(Token::RPAREN);
}
@ -186,7 +178,22 @@ ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier()
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);
ASTPointer<ASTString> docstring;
@ -201,16 +208,24 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic, A
name = expectIdentifierToken();
ASTPointer<ParameterList> parameters(parseParameterList());
bool isDeclaredConst = false;
Declaration::Visibility visibility(Declaration::Visibility::DEFAULT);
vector<ASTPointer<ModifierInvocation>> modifiers;
while (true)
{
if (m_scanner->getCurrentToken() == Token::CONST)
Token::Value token = m_scanner->getCurrentToken();
if (token == Token::CONST)
{
isDeclaredConst = true;
m_scanner->next();
}
else if (m_scanner->getCurrentToken() == Token::IDENTIFIER)
else if (token == Token::IDENTIFIER)
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
break;
}
@ -226,7 +241,7 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic, A
ASTPointer<Block> block = parseBlock();
nodeFactory.setEndPositionFromNode(block);
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,
returnParameters, block);
}
@ -253,14 +268,18 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(VarDeclParserOp
ASTNodeFactory nodeFactory(*this);
ASTPointer<TypeName> type = parseTypeName(_options.allowVar);
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;
m_scanner->next();
}
Declaration::Visibility visibility(Declaration::Visibility::DEFAULT);
if (_options.isStateVariable && Token::isVisibilitySpecifier(token))
visibility = parseVisibilitySpecifier(token);
nodeFactory.markEndPosition();
return nodeFactory.createNode<VariableDeclaration>(type, expectIdentifierToken(),
_options.isPublic, _options.isStateVariable,
visibility, _options.isStateVariable,
isIndexed);
}
@ -313,7 +332,7 @@ ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()
if (m_scanner->getCurrentToken() == Token::LPAREN)
{
m_scanner->next();
arguments = parseFunctionCallArguments();
arguments = parseFunctionCallListArguments();
nodeFactory.markEndPosition();
expectToken(Token::RPAREN);
}
@ -573,7 +592,6 @@ ASTPointer<Expression> Parser::parseBinaryExpression(int _minPrecedence)
ASTPointer<Expression> expression = parseUnaryExpression();
int precedence = Token::precedence(m_scanner->getCurrentToken());
for (; precedence >= _minPrecedence; --precedence)
{
while (Token::precedence(m_scanner->getCurrentToken()) == precedence)
{
Token::Value op = m_scanner->getCurrentToken();
@ -582,7 +600,6 @@ ASTPointer<Expression> Parser::parseBinaryExpression(int _minPrecedence)
nodeFactory.setEndPositionFromNode(right);
expression = nodeFactory.createNode<BinaryOperation>(expression, op, right);
}
}
return expression;
}
@ -648,10 +665,12 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression()
case Token::LPAREN:
{
m_scanner->next();
vector<ASTPointer<Expression>> arguments = parseFunctionCallArguments();
vector<ASTPointer<Expression>> arguments;
vector<ASTPointer<ASTString>> names;
std::tie(arguments, names) = parseFunctionCallArguments();
nodeFactory.markEndPosition();
expectToken(Token::RPAREN);
expression = nodeFactory.createNode<FunctionCall>(expression, arguments);
expression = nodeFactory.createNode<FunctionCall>(expression, arguments, names);
}
break;
default:
@ -704,7 +723,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
return expression;
}
vector<ASTPointer<Expression>> Parser::parseFunctionCallArguments()
vector<ASTPointer<Expression>> Parser::parseFunctionCallListArguments()
{
vector<ASTPointer<Expression>> arguments;
if (m_scanner->getCurrentToken() != Token::RPAREN)
@ -719,6 +738,32 @@ vector<ASTPointer<Expression>> Parser::parseFunctionCallArguments()
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()
{

7
libsolidity/Parser.h

@ -48,7 +48,6 @@ private:
struct VarDeclParserOptions {
VarDeclParserOptions() {}
bool allowVar = false;
bool isPublic = false;
bool isStateVariable = false;
bool allowIndexed = false;
};
@ -58,7 +57,8 @@ private:
ASTPointer<ImportDirective> parseImportDirective();
ASTPointer<ContractDefinition> parseContractDefinition();
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<VariableDeclaration> parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions());
ASTPointer<ModifierDefinition> parseModifierDefinition();
@ -81,7 +81,8 @@ private:
ASTPointer<Expression> parseUnaryExpression();
ASTPointer<Expression> parseLeftHandSideExpression();
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(PUBLIC, "public", 0) \
K(PRIVATE, "private", 0) \
K(PROTECTED, "protected", 0) \
K(RETURN, "return", 0) \
K(RETURNS, "returns", 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 isCountOp(Value op) { return op == INC || op == DEC; }
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
// (.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):
m_location(Location::EXTERNAL), m_isConstant(true), m_declaration(&_varDecl)
{
TypePointers params({});
vector<string> paramNames({});
TypePointers retParams({_varDecl.getType()});
vector<string> retParamNames({ _varDecl.getName()});
// for now, no input parameters LTODO: change for some things like mapping
TypePointers params;
vector<string> paramNames;
TypePointers retParams;
vector<string> retParamNames;
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(paramNames, m_parameterNames);

7
libsolidity/grammar.txt

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

45
macdeployfix.sh

@ -0,0 +1,45 @@
#!/bin/bash
# solves problem with macdeployqt on Qt 5.4 RC
# http://qt-project.org/forums/viewthread/50118
BUILD_FOLDER_PATH=$1
BUILD_QML_FOLDER_PATH="$BUILD_FOLDER_PATH/Resources/qml"
BUILD_PLUGINS_FOLDER_PATH="$BUILD_FOLDER_PATH/PlugIns"
if [ ! -d ${BUILD_QML_FOLDER_PATH} ]; then
# we are not using any qml files
# gracefully exit
exit 0
fi
declare -a BROKEN_FILES;
k=0;
for j in $(find ${BUILD_QML_FOLDER_PATH} -name *.dylib); do
BROKEN_FILES[${k}]=$j
((k=k+1))
done
for i in "${BROKEN_FILES[@]}"; do
REPLACE_STRING="$BUILD_FOLDER_PATH/"
APP_CONTENT_FILE=${i//$REPLACE_STRING/""}
IFS='/' read -a array <<< "$APP_CONTENT_FILE"
LENGTH=${#array[@]}
LAST_ITEM_INDEX=$((LENGTH-1))
FILE=${array[${LENGTH} - 1]}
ORIGINE_PATH=$(find ${BUILD_PLUGINS_FOLDER_PATH} -name ${FILE})
ORIGINE_PATH=${ORIGINE_PATH//$REPLACE_STRING/""}
s=""
for((l=0;l<${LAST_ITEM_INDEX};l++)) do
s=$s"../"
done
s=$s$ORIGINE_PATH
echo "s: $s"
REMOVE_BROKEN_ALIAS=$(rm -rf $i)
RESULT=$(ln -s $s $i)
done

13
mix/AppContext.cpp

@ -27,15 +27,16 @@
#include <QQmlComponent>
#include <QQmlContext>
#include <QQmlApplicationEngine>
#include <QQuickWindow>
#include <QWindow>
#include "CodeModel.h"
#include "FileIo.h"
#include "ClientModel.h"
#include "CodeEditorExtensionManager.h"
#include "Exceptions.h"
#include "AppContext.h"
#include "QEther.h"
#include "QVariableDefinition.h"
#include "HttpServer.h"
#include "AppContext.h"
using namespace dev;
using namespace dev::eth;
@ -63,6 +64,12 @@ void AppContext::load()
m_applicationEngine->rootContext()->setContextProperty("fileIo", m_fileIo.get());
qmlRegisterType<QEther>("org.ethereum.qml.QEther", 1, 0, "QEther");
qmlRegisterType<QBigInt>("org.ethereum.qml.QBigInt", 1, 0, "QBigInt");
qmlRegisterType<QIntType>("org.ethereum.qml.QIntType", 1, 0, "QIntType");
qmlRegisterType<QRealType>("org.ethereum.qml.QRealType", 1, 0, "QRealType");
qmlRegisterType<QStringType>("org.ethereum.qml.QStringType", 1, 0, "QStringType");
qmlRegisterType<QHashType>("org.ethereum.qml.QHashType", 1, 0, "QHashType");
qmlRegisterType<QBoolType>("org.ethereum.qml.QBoolType", 1, 0, "QBoolType");
qmlRegisterType<QVariableDeclaration>("org.ethereum.qml.QVariableDeclaration", 1, 0, "QVariableDeclaration");
QQmlComponent projectModelComponent(m_applicationEngine, QUrl("qrc:/qml/ProjectModel.qml"));
QObject* projectModel = projectModelComponent.create();
if (projectModelComponent.isError())
@ -76,7 +83,7 @@ void AppContext::load()
qmlRegisterType<CodeEditorExtensionManager>("CodeEditorExtensionManager", 1, 0, "CodeEditorExtensionManager");
qmlRegisterType<HttpServer>("HttpServer", 1, 0, "HttpServer");
m_applicationEngine->load(QUrl("qrc:/qml/main.qml"));
QQuickWindow *window = qobject_cast<QQuickWindow *>(m_applicationEngine->rootObjects().at(0));
QWindow *window = qobject_cast<QWindow *>(m_applicationEngine->rootObjects().at(0));
window->setIcon(QIcon(":/res/mix_256x256x32.png"));
appLoaded();
}

1
mix/AssemblyDebuggerControl.cpp

@ -20,7 +20,6 @@
#include <QDebug>
#include <QQmlContext>
#include <QQmlApplicationEngine>
#include "AppContext.h"
#include "ClientModel.h"
#include "AssemblyDebuggerControl.h"

2
mix/CMakeLists.txt

@ -26,6 +26,8 @@ else()
qt5_add_resources(UI_RESOURCES noweb.qrc)
endif()
add_definitions(-DQT_QML_DEBUG)
# eth_add_executable is defined in cmake/EthExecutableHelper.cmake
eth_add_executable(${EXECUTABLE}
ICON mix

50
mix/ClientModel.cpp

@ -30,6 +30,7 @@
#include "Exceptions.h"
#include "QContractDefinition.h"
#include "QVariableDeclaration.h"
#include "QVariableDefinition.h"
#include "ContractCallDataEncoder.h"
#include "CodeModel.h"
#include "ClientModel.h"
@ -66,6 +67,10 @@ ClientModel::ClientModel(AppContext* _context):
m_context(_context), m_running(false), m_rpcConnector(new RpcConnector()), m_contractAddress(Address())
{
qRegisterMetaType<QBigInt*>("QBigInt*");
qRegisterMetaType<QIntType*>("QIntType*");
qRegisterMetaType<QStringType*>("QStringType*");
qRegisterMetaType<QRealType*>("QRealType*");
qRegisterMetaType<QHashType*>("QHashType*");
qRegisterMetaType<QEther*>("QEther*");
qRegisterMetaType<QVariableDefinition*>("QVariableDefinition*");
qRegisterMetaType<QVariableDefinitionList*>("QVariableDefinitionList*");
@ -93,8 +98,16 @@ ClientModel::~ClientModel()
QString ClientModel::apiCall(QString const& _message)
{
m_rpcConnector->OnRequest(_message.toStdString(), nullptr);
return m_rpcConnector->response();
try
{
m_rpcConnector->OnRequest(_message.toStdString(), nullptr);
return m_rpcConnector->response();
}
catch (...)
{
std::cerr << boost::current_exception_diagnostic_information();
return QString();
}
}
void ClientModel::mine()
@ -138,13 +151,13 @@ void ClientModel::setupState(QVariantMap _state)
}
else
{
QVariantMap params = transaction.value("parameters").toMap();
QVariantList qParams = transaction.value("qType").toList();
TransactionSettings transactionSettings(functionId, value, gas, gasPrice);
for (auto p = params.cbegin(); p != params.cend(); ++p)
for (QVariant const& variant: qParams)
{
QBigInt* param = qvariant_cast<QBigInt*>(p.value());
transactionSettings.parameterValues.insert(std::make_pair(p.key(), boost::get<dev::u256>(param->internalValue())));
QVariableDefinition* param = qvariant_cast<QVariableDefinition*>(variant);
transactionSettings.parameterValues.push_back(param);
}
if (transaction.value("executeConstructor").toBool())
@ -204,14 +217,11 @@ void ClientModel::executeSequence(std::vector<TransactionSettings> const& _seque
BOOST_THROW_EXCEPTION(FunctionNotFoundException() << FunctionName(transaction.functionId.toStdString()));
encoder.encode(f);
for (int p = 0; p < f->parametersList().size(); p++)
for (int p = 0; p < transaction.parameterValues.size(); p++)
{
QVariableDeclaration* var = f->parametersList().at(p);
u256 value = 0;
auto v = transaction.parameterValues.find(var->name());
if (v != transaction.parameterValues.cend())
value = v->second;
encoder.encode(var, value);
if (f->parametersList().at(p)->type() != transaction.parameterValues.at(p)->declaration()->type())
BOOST_THROW_EXCEPTION(ParameterChangedException() << FunctionName(f->parametersList().at(p)->type().toStdString()));
encoder.push(transaction.parameterValues.at(p)->encodeValue());
}
if (transaction.functionId.isEmpty())
@ -322,11 +332,6 @@ void ClientModel::onNewTransaction()
bool creation = tr.contractAddress != 0;
if (creation)
returned = QString::fromStdString(toJS(tr.contractAddress));
else
returned = QString::fromStdString(toJS(tr.returnValue));
//TODO: handle value transfer
FixedHash<4> functionHash;
bool call = false;
@ -355,6 +360,9 @@ void ClientModel::onNewTransaction()
function = QObject::tr("<none>");
}
if (creation)
returned = QString::fromStdString(toJS(tr.contractAddress));
if (m_contractAddress != 0 && (tr.address == m_contractAddress || tr.contractAddress == m_contractAddress))
{
auto compilerRes = m_context->codeModel()->code();
@ -364,7 +372,13 @@ void ClientModel::onNewTransaction()
{
QFunctionDefinition* funcDef = def->getFunction(functionHash);
if (funcDef)
{
function = funcDef->name();
ContractCallDataEncoder encoder;
QList<QVariableDefinition*> returnValues = encoder.decode(funcDef->returnParameters(), tr.returnValue);
for (auto const& var: returnValues)
returned += var->value() + " | ";
}
}
}

6
mix/ClientModel.h

@ -26,7 +26,7 @@
#include <atomic>
#include <map>
#include <QString>
#include "MixClient.h"
#include "MachineStates.h"
namespace dev
{
@ -38,6 +38,8 @@ class Web3Server;
class RpcConnector;
class QEther;
class QDebugData;
class MixClient;
class QVariableDefinition;
/// Backend transaction config class
struct TransactionSettings
@ -59,7 +61,7 @@ struct TransactionSettings
/// Gas price
u256 gasPrice;
/// Mapping from contract function parameter name to value
std::map<QString, u256> parameterValues;
QList<QVariableDefinition*> parameterValues;
/// Standard contract url
QString stdContractUrl;
};

22
mix/CodeHighlighter.cpp

@ -1,18 +1,18 @@
/*
This file is part of cpp-ethereum.
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file CodeHighlighter.cpp
* @author Arkadiy Paronyan arkadiy@ethdev.com

98
mix/ContractCallDataEncoder.cpp

@ -44,89 +44,37 @@ void ContractCallDataEncoder::encode(QFunctionDefinition const* _function)
m_encodedData.insert(m_encodedData.end(), hash.begin(), hash.end());
}
void ContractCallDataEncoder::encode(QVariableDeclaration const* _dec, bool _value)
void ContractCallDataEncoder::push(bytes const& _b)
{
return encode(_dec, QString(formatBool(_value)));
m_encodedData.insert(m_encodedData.end(), _b.begin(), _b.end());
}
void ContractCallDataEncoder::encode(QVariableDeclaration const* _dec, QString _value)
{
int padding = this->padding(_dec->type());
bytes data = padded(jsToBytes(_value.toStdString()), padding);
m_encodedData.insert(m_encodedData.end(), data.begin(), data.end());
}
void ContractCallDataEncoder::encode(QVariableDeclaration const* _dec, u256 _value)
{
int padding = this->padding(_dec->type());
std::ostringstream s;
s << std::hex << "0x" << _value;
bytes data = padded(jsToBytes(s.str()), padding);
m_encodedData.insert(m_encodedData.end(), data.begin(), data.end());
encodedData();
}
QList<QVariableDefinition*> ContractCallDataEncoder::decode(QList<QVariableDeclaration*> _returnParameters, bytes _value)
QList<QVariableDefinition*> ContractCallDataEncoder::decode(QList<QVariableDeclaration*> const& _returnParameters, bytes _value)
{
QList<QVariableDefinition*> r;
std::string returnValue = toJS(_value);
returnValue = returnValue.substr(2, returnValue.length() - 1);
for (int k = 0; k <_returnParameters.length(); k++)
{
QVariableDeclaration* dec = (QVariableDeclaration*)_returnParameters.at(k);
int padding = this->padding(dec->type());
std::string rawParam = returnValue.substr(0, padding * 2);
r.append(new QVariableDefinition(dec, convertToReadable(unpadLeft(rawParam), dec)));
returnValue = returnValue.substr(rawParam.length(), returnValue.length() - 1);
QVariableDefinition* def = nullptr;
if (dec->type().contains("int"))
def = new QIntType(dec, QString());
else if (dec->type().contains("real"))
def = new QRealType(dec, QString());
else if (dec->type().contains("bool"))
def = new QBoolType(dec, QString());
else if (dec->type().contains("string") || dec->type().contains("text"))
def = new QStringType(dec, QString());
else if (dec->type().contains("hash") || dec->type().contains("address"))
def = new QHashType(dec, QString());
else
BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Parameter declaration not found"));
bytes rawParam(_value.begin(), _value.begin() + 32);
def->decodeValue(rawParam);
r.push_back(def);
if (_value.size() > 32)
_value = bytes(_value.begin() + 32, _value.end());
qDebug() << "decoded return value : " << dec->type() << " " << def->value();
}
return r;
}
int ContractCallDataEncoder::padding(QString type)
{
// TODO : to be improved (load types automatically from solidity library).
if (type.indexOf("uint") != -1)
return integerPadding(type.remove("uint").toInt());
else if (type.indexOf("int") != -1)
return integerPadding(type.remove("int").toInt());
else if (type.indexOf("bool") != -1)
return 1;
else if ((type.indexOf("address") != -1))
return 32;
else
return 0;
}
int ContractCallDataEncoder::integerPadding(int bitValue)
{
return bitValue / 8;
}
QString ContractCallDataEncoder::formatBool(bool _value)
{
return (_value ? "1" : "0");
}
QString ContractCallDataEncoder::convertToReadable(std::string _v, QVariableDeclaration* _dec)
{
if (_dec->type().indexOf("int") != -1)
return convertToInt(_v);
else if (_dec->type().indexOf("bool") != -1)
return convertToBool(_v);
else
return QString::fromStdString(_v);
}
QString ContractCallDataEncoder::convertToBool(std::string _v)
{
return _v == "1" ? "true" : "false";
}
QString ContractCallDataEncoder::convertToInt(std::string _v)
{
//TO DO to be improve to manage all int, uint size (128, 256, ...) in ethereum QML types task #612.
int x = std::stol(_v, nullptr, 16);
std::stringstream ss;
ss << std::dec << x;
return QString::fromStdString(ss.str());
}

16
mix/ContractCallDataEncoder.h

@ -41,27 +41,17 @@ class ContractCallDataEncoder
{
public:
ContractCallDataEncoder() {}
/// Encode variable in order to be sent as parameter.
void encode(QVariableDeclaration const* _dec, QString _value);
/// Encode variable in order to be sent as parameter.
void encode(QVariableDeclaration const* _dec, u256 _value);
/// Encode variable in order to be sent as parameter.
void encode(QVariableDeclaration const* _dec, bool _value);
/// Encode hash of the function to call.
void encode(QFunctionDefinition const* _function);
/// Decode variable in order to be sent to QML view.
QList<QVariableDefinition*> decode(QList<QVariableDeclaration*> _dec, bytes _value);
QList<QVariableDefinition*> decode(QList<QVariableDeclaration*> const& _dec, bytes _value);
/// Get all encoded data encoded by encode function.
bytes encodedData();
/// Push the given @a _b to the current param context.
void push(bytes const& _b);
private:
int padding(QString _type);
bytes m_encodedData;
static QString convertToReadable(std::string _v, QVariableDeclaration* _dec);
static QString convertToBool(std::string _v);
static QString convertToInt(std::string _v);
static int integerPadding(int _bitValue);
static QString formatBool(bool _value);
};
}

1
mix/Exceptions.h

@ -38,6 +38,7 @@ struct FileIoException: virtual Exception {};
struct InvalidBlockException: virtual Exception {};
struct FunctionNotFoundException: virtual Exception {};
struct ExecutionStateException: virtual Exception {};
struct ParameterChangedException: virtual Exception {};
typedef boost::error_info<struct tagQmlError, QQmlError> QmlErrorInfo;
typedef boost::error_info<struct tagFileError, std::string> FileError;

79
mix/MachineStates.h

@ -0,0 +1,79 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file MixClient.h
* @author Yann yann@ethdev.com
* @author Arkadiy Paronyan arkadiy@ethdev.com
* @date 2015
* Ethereum IDE client.
*/
#pragma once
#include <vector>
#include <map>
#include <stdint.h>
#include <libdevcore/Common.h>
#include <libdevcrypto/Common.h>
#include <libevmcore/Instruction.h>
#include <libethereum/TransactionReceipt.h>
namespace dev
{
namespace mix
{
/**
* @brief Store information about a machine state.
*/
struct MachineState
{
uint64_t steps;
dev::Address address;
dev::u256 curPC;
dev::eth::Instruction inst;
dev::bigint newMemSize;
dev::u256 gas;
dev::u256s stack;
dev::bytes memory;
dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage;
std::vector<unsigned> levels;
unsigned codeIndex;
unsigned dataIndex;
};
/**
* @brief Store information about a machine states.
*/
struct ExecutionResult
{
ExecutionResult() : receipt(dev::h256(), dev::h256(), dev::eth::LogEntries()) {}
std::vector<MachineState> machineStates;
std::vector<bytes> transactionData;
std::vector<bytes> executionCode;
bytes returnValue;
dev::Address address;
dev::Address sender;
dev::Address contractAddress;
dev::u256 value;
dev::eth::TransactionReceipt receipt;
};
using ExecutionResults = std::vector<ExecutionResult>;
}
}

9
mix/MixClient.cpp

@ -50,12 +50,15 @@ void MixClient::resetState(u256 _balance)
Guard fl(m_filterLock);
m_filters.clear();
m_watches.clear();
m_state = eth::State(m_userAccount.address(), m_stateDB, BaseState::Empty);
m_state = eth::State(m_userAccount.address(), m_stateDB, BaseState::Genesis);
m_state.addBalance(m_userAccount.address(), _balance);
Block genesis;
genesis.state = m_state;
Block open;
m_blocks = Blocks { genesis, open }; //last block contains a list of pending transactions to be finalized
// m_lastHashes.clear();
// m_lastHashes.resize(256);
// m_lastHashes[0] = genesis.hash;
}
void MixClient::executeTransaction(Transaction const& _t, State& _state)
@ -159,11 +162,15 @@ void MixClient::mine()
{
WriteGuard l(x_state);
Block& block = m_blocks.back();
m_state.mine(0, true);
m_state.completeMine();
m_state.commitToMine(BlockChain());
m_state.cleanup(true);
block.state = m_state;
block.info = m_state.info();
block.hash = block.info.hash;
m_blocks.push_back(Block());
h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter };
noteChanged(changed);
}

41
mix/MixClient.h

@ -26,52 +26,13 @@
#include <vector>
#include <libethereum/Interface.h>
#include <libethereum/Client.h>
#include "MachineStates.h"
namespace dev
{
namespace mix
{
/**
* @brief Store information about a machine state.
*/
struct MachineState
{
uint64_t steps;
dev::Address address;
dev::u256 curPC;
dev::eth::Instruction inst;
dev::bigint newMemSize;
dev::u256 gas;
dev::u256s stack;
dev::bytes memory;
dev::bigint gasCost;
std::map<dev::u256, dev::u256> storage;
std::vector<unsigned> levels;
unsigned codeIndex;
unsigned dataIndex;
};
/**
* @brief Store information about a machine states.
*/
struct ExecutionResult
{
ExecutionResult(): receipt(dev::h256(), dev::h256(), dev::eth::LogEntries()) {}
std::vector<MachineState> machineStates;
std::vector<bytes> transactionData;
std::vector<bytes> executionCode;
bytes returnValue;
dev::Address address;
dev::Address sender;
dev::Address contractAddress;
dev::u256 value;
dev::eth::TransactionReceipt receipt;
};
using ExecutionResults = std::vector<ExecutionResult>;
struct Block
{
ExecutionResults transactions;

3
mix/QBigInt.h

@ -36,7 +36,7 @@ namespace dev
namespace mix
{
using BigIntVariant = boost::variant<dev::u256, dev::bigint>;
using BigIntVariant = boost::variant<dev::u256, dev::bigint, dev::s256>;
struct add: public boost::static_visitor<BigIntVariant>
{
@ -75,6 +75,7 @@ public:
QBigInt(dev::u256 const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); }
QBigInt(dev::bigint const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); }
QBigInt(BigIntVariant const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value){ QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); }
QBigInt(dev::s256 const& _value, QObject* _parent = 0): QObject(_parent), m_internalValue(_value) { QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); }
~QBigInt() {}
/// @returns the current used big integer.

8
mix/QVariableDeclaration.h

@ -19,6 +19,8 @@
* @date 2014
*/
#include <QDebug>
#include <QStringList>
#include <libsolidity/AST.h>
#include "QBasicNodeDefinition.h"
@ -32,16 +34,20 @@ namespace mix
class QVariableDeclaration: public QBasicNodeDefinition
{
Q_OBJECT
Q_PROPERTY(QString type READ type CONSTANT)
Q_PROPERTY(QString type READ type WRITE setType)
public:
QVariableDeclaration() {}
QVariableDeclaration(solidity::VariableDeclaration const* _v): QBasicNodeDefinition(_v), m_type(QString::fromStdString(_v->getType()->toString())) {}
QVariableDeclaration(std::string const& _name, std::string const& _type): QBasicNodeDefinition(_name), m_type(QString::fromStdString(_type)) {}
QString type() const { return m_type; }
void setType(QString _type) { m_type = _type; }
private:
QString m_type;
};
}
}
Q_DECLARE_METATYPE(dev::mix::QVariableDeclaration*)

90
mix/QVariableDefinition.cpp

@ -19,6 +19,8 @@
* @date 2014
*/
#include <libdevcore/CommonData.h>
#include <libdevcore/CommonJS.h>
#include "QVariableDefinition.h"
using namespace dev::mix;
@ -53,3 +55,91 @@ QVariableDefinition* QVariableDefinitionList::val(int _idx)
return nullptr;
return m_def.at(_idx);
}
/*
* QIntType
*/
void QIntType::setValue(dev::bigint _value)
{
m_bigIntvalue = _value;
std::stringstream str;
str << std::dec << m_bigIntvalue;
m_value = QString::fromStdString(str.str());
}
dev::bytes QIntType::encodeValue()
{
dev::bigint i(value().toStdString());
bytes ret(32);
toBigEndian((u256)i, ret);
return ret;
}
void QIntType::decodeValue(dev::bytes const& _rawValue)
{
dev::u256 un = dev::fromBigEndian<dev::u256>(_rawValue);
if (un >> 255)
setValue(-s256(~un + 1));
else
setValue(un);
}
/*
* QHashType
*/
dev::bytes QHashType::encodeValue()
{
QByteArray bytesAr = value().toLocal8Bit();
bytes r = bytes(bytesAr.begin(), bytesAr.end());
return padded(r, 32);
}
void QHashType::decodeValue(dev::bytes const& _rawValue)
{
std::string _ret = asString(unpadLeft(_rawValue));
setValue(QString::fromStdString(_ret));
}
/*
* QRealType
*/
dev::bytes QRealType::encodeValue()
{
return bytes();
}
void QRealType::decodeValue(dev::bytes const& _rawValue)
{
Q_UNUSED(_rawValue);
}
/*
* QStringType
*/
dev::bytes QStringType::encodeValue()
{
QByteArray b = value().toUtf8();
bytes r = bytes(b.begin(), b.end());
return paddedRight(r, 32);
}
void QStringType::decodeValue(dev::bytes const& _rawValue)
{
setValue(QString::fromUtf8((char*)_rawValue.data()));
}
/*
* QBoolType
*/
dev::bytes QBoolType::encodeValue()
{
return padded(jsToBytes(value().toStdString()), 32);
}
void QBoolType::decodeValue(dev::bytes const& _rawValue)
{
byte ret = _rawValue.at(_rawValue.size() - 1);
bool boolRet = (ret == byte(1));
m_boolValue = boolRet;
m_value = m_boolValue ? "1" : "0";
}

90
mix/QVariableDefinition.h

@ -22,6 +22,7 @@
#pragma once
#include <QAbstractListModel>
#include "QBigInt.h"
#include "QVariableDeclaration.h"
namespace dev
@ -37,15 +38,26 @@ class QVariableDefinition: public QObject
Q_PROPERTY(QVariableDeclaration* declaration READ declaration CONSTANT)
public:
QVariableDefinition() {}
QVariableDefinition(QVariableDeclaration* _def, QString _value): QObject(), m_value(_value), m_dec(_def) {}
/// Return the associated declaration of this variable definition.
QVariableDeclaration* declaration() const { return m_dec; }
/// Return the associated declaration of this variable definition. Invokable from QML.
Q_INVOKABLE QVariableDeclaration* declaration() const { return m_dec; }
/// Return the variable value.
QString value() const { return m_value; }
/// Set a new value for this instance. Invokable from QML.
Q_INVOKABLE void setValue(QString _value) { m_value = _value; }
/// Set a new Declaration for this instance. Invokable from QML.
Q_INVOKABLE void setDeclaration(QVariableDeclaration* _dec) { m_dec = _dec; }
/// Encode the current value in order to be used as function parameter.
virtual bytes encodeValue() = 0;
/// Decode the return value @a _rawValue.
virtual void decodeValue(dev::bytes const& _rawValue) = 0;
protected:
QString m_value;
private:
QString m_value;
QVariableDeclaration* m_dec;
};
@ -67,7 +79,77 @@ private:
QList<QVariableDefinition*> m_def;
};
class QIntType: public QVariableDefinition
{
Q_OBJECT
public:
QIntType() {}
QIntType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {}
dev::bytes encodeValue() override;
void decodeValue(dev::bytes const& _rawValue) override;
/// @returns an instance of QBigInt for the current value.
QBigInt* toBigInt() { return new QBigInt(m_bigIntvalue); }
dev::bigint bigInt() { return m_bigIntvalue; }
void setValue(dev::bigint _value);
private:
dev::bigint m_bigIntvalue;
};
class QRealType: public QVariableDefinition
{
Q_OBJECT
public:
QRealType() {}
QRealType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {}
dev::bytes encodeValue() override;
void decodeValue(dev::bytes const& _rawValue) override;
};
class QStringType: public QVariableDefinition
{
Q_OBJECT
public:
QStringType() {}
QStringType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {}
dev::bytes encodeValue() override;
void decodeValue(dev::bytes const& _rawValue) override;
};
class QHashType: public QVariableDefinition
{
Q_OBJECT
public:
QHashType() {}
QHashType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {}
dev::bytes encodeValue() override;
void decodeValue(dev::bytes const& _rawValue) override;
};
class QBoolType: public QVariableDefinition
{
Q_OBJECT
public:
QBoolType() {}
QBoolType(QVariableDeclaration* _def, QString _value): QVariableDefinition(_def, _value) {}
dev::bytes encodeValue() override;
void decodeValue(dev::bytes const& _rawValue) override;
/// @returns the boolean value for the current definition.
bool toBool() { return m_boolValue; }
private:
bool m_boolValue;
};
}
}
Q_DECLARE_METATYPE(dev::mix::QVariableDefinition*)
Q_DECLARE_METATYPE(dev::mix::QIntType*)
Q_DECLARE_METATYPE(dev::mix::QStringType*)
Q_DECLARE_METATYPE(dev::mix::QHashType*)
Q_DECLARE_METATYPE(dev::mix::QBoolType*)

2
mix/Web3Server.cpp

@ -57,8 +57,6 @@ void Web3Server::put(std::string const& _name, std::string const& _key, std::str
Json::Value Web3Server::eth_changed(int const& _id)
{
cnote << "eth_changed(" << _id << ") ->" << client()->peekWatch(_id).size();
return WebThreeStubServerBase::eth_changed(_id);
}

1
mix/main.cpp

@ -35,6 +35,7 @@ int main(int _argc, char* _argv[])
//work around ubuntu appmenu-qt5 bug
//https://bugs.launchpad.net/ubuntu/+source/appmenu-qt5/+bug/1323853
putenv((char*)"QT_QPA_PLATFORMTHEME=");
putenv((char*)"QSG_RENDER_LOOP=threaded");
#endif
try
{

215
mix/qml/MainContent.qml

@ -23,14 +23,20 @@ Rectangle {
property alias rightViewVisible : rightView.visible
property alias webViewVisible : webPreview.visible
property alias projectViewVisible : projectList.visible
property alias runOnProjectLoad : mainSettings.runOnProjectLoad
property bool webViewHorizontal : codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally
onWidthChanged:
{
if (rightView.visible)
contentView.width = parent.width - projectList.width - rightView.width;
else
contentView.width = parent.width - projectList.width;
property bool firstCompile: true
Connections {
target: codeModel
onCompilationComplete: {
if (firstCompile) {
firstCompile = false;
if (codeModel.code.successful && runOnProjectLoad)
startQuickDebugging();
}
}
}
function startQuickDebugging()
@ -40,15 +46,11 @@ Rectangle {
}
function toggleRightView() {
if (!rightView.visible)
rightView.show();
else
rightView.hide();
rightView.visible = !rightView.visible;
}
function ensureRightView() {
if (!rightView.visible)
rightView.show();
rightView.visible = true;
}
function rightViewIsVisible()
@ -65,6 +67,10 @@ Rectangle {
webPreview.visible = !webPreview.visible;
}
function toggleProjectView() {
projectList.visible = !projectList.visible;
}
function toggleWebPreviewOrientation() {
codeWebSplitter.orientation = (codeWebSplitter.orientation === Qt.Vertical ? Qt.Horizontal : Qt.Vertical);
}
@ -75,19 +81,18 @@ Rectangle {
}
Settings {
id: mainLayoutSettings
id: mainSettings
property alias codeWebOrientation: codeWebSplitter.orientation
property alias webWidth: webPreview.width
property alias webHeight: webPreview.height
property alias showProjectView: projectList.visible
property bool runOnProjectLoad: false
}
GridLayout
ColumnLayout
{
anchors.fill: parent
rows: 2
flow: GridLayout.TopToBottom
columnSpacing: 0
rowSpacing: 0
spacing: 0
Rectangle {
width: parent.width
height: 50
@ -128,116 +133,90 @@ Rectangle {
property alias rightViewWidth: rightView.width
}
ProjectList {
anchors.left: parent.left
id: projectList
width: 200
height: parent.height
Layout.minimumWidth: 200
}
Splitter
SplitView
{
id: resizeLeft
itemToStick: projectList
itemMinimumWidth: projectList.Layout.minimumWidth
direction: "right"
brother: contentView
color: "#a2a2a2"
}
Rectangle {
anchors.left: projectList.right
id: contentView
width: parent.width - projectList.width
height: parent.height
SplitView {
handleDelegate: Rectangle {
width: 4
height: 4
color: "#cccccc"
}
id: codeWebSplitter
anchors.fill: parent
orientation: Qt.Vertical
CodeEditorView {
height: parent.height * 0.6
anchors.top: parent.top
Layout.fillWidth: true
Layout.fillHeight: true
}
WebPreview {
id: webPreview
height: parent.height * 0.4
Layout.fillWidth: codeWebSplitter.orientation === Qt.Vertical
Layout.fillHeight: codeWebSplitter.orientation === Qt.Horizontal
Layout.minimumHeight: 200
Layout.minimumWidth: 200
}
anchors.fill: parent
handleDelegate: Rectangle {
width: 4
height: 4
color: "#cccccc"
}
}
Splitter
{
id: resizeRight
visible: false;
itemToStick: rightView
itemMinimumWidth: rightView.Layout.minimumWidth
direction: "left"
brother: contentView
color: "#a2a2a2"
}
Rectangle {
visible: false;
id: rightView;
orientation: Qt.Horizontal
Keys.onEscapePressed: hide()
function show() {
visible = true;
resizeRight.visible = true;
contentView.width = parent.width - projectList.width - rightView.width;
ProjectList {
id: projectList
width: 200
Layout.minimumWidth: 180
Layout.fillHeight: true
}
function hide() {
resizeRight.visible = false;
visible = false;
contentView.width = parent.width - projectList.width;
Rectangle {
id: contentView
Layout.fillHeight: true
Layout.fillWidth: true
SplitView {
handleDelegate: Rectangle {
width: 4
height: 4
color: "#cccccc"
}
id: codeWebSplitter
anchors.fill: parent
orientation: Qt.Vertical
CodeEditorView {
height: parent.height * 0.6
anchors.top: parent.top
Layout.fillWidth: true
Layout.fillHeight: true
}
WebPreview {
id: webPreview
height: parent.height * 0.4
Layout.fillWidth: codeWebSplitter.orientation === Qt.Vertical
Layout.fillHeight: codeWebSplitter.orientation === Qt.Horizontal
Layout.minimumHeight: 200
Layout.minimumWidth: 200
}
}
}
height: parent.height;
width: 515
Layout.minimumWidth: 515
anchors.right: parent.right
Rectangle {
anchors.fill: parent;
id: rightPaneView
TabView {
id: rightPaneTabs
tabsVisible: true
antialiasing: true
anchors.fill: parent
style: TabViewStyle {
frameOverlap: 1
tabBar:
Rectangle {
visible: false;
id: rightView;
Layout.fillHeight: true
Keys.onEscapePressed: visible = false
height: parent.height;
width: 515
Layout.minimumWidth: 515
anchors.right: parent.right
Rectangle {
anchors.fill: parent;
id: rightPaneView
TabView {
id: rightPaneTabs
tabsVisible: true
antialiasing: true
anchors.fill: parent
style: TabViewStyle {
frameOverlap: 1
tabBar:
Rectangle {
color: "#ededed"
id: background
}
tab: Rectangle {
color: "#ededed"
id: background
implicitWidth: 80
implicitHeight: 20
radius: 2
Text {
anchors.centerIn: parent
text: styleData.title
color: styleData.selected ? "#7da4cd" : "#202020"
}
}
tab: Rectangle {
color: "#ededed"
implicitWidth: 80
implicitHeight: 20
radius: 2
Text {
anchors.centerIn: parent
text: styleData.title
color: styleData.selected ? "#7da4cd" : "#202020"
frame: Rectangle {
}
}
frame: Rectangle {
}
}
}
}

3
mix/qml/ProjectModel.qml

@ -10,7 +10,8 @@ Item {
id: projectModel
signal projectClosed
signal projectLoaded(var projectData)
signal projectLoading(var projectData)
signal projectLoaded()
signal documentOpened(var document)
signal documentRemoved(var documentId)
signal documentUpdated(var documentId) //renamed

7
mix/qml/QBoolType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QBoolType 1.0
QBoolType
{
}

42
mix/qml/QBoolTypeView.qml

@ -0,0 +1,42 @@
import QtQuick 2.0
import QtQuick.Controls 1.3
Item
{
id: editRoot
property string text
property string defaultValue
Rectangle {
anchors.fill: parent
ComboBox
{
property bool inited: false
Component.onCompleted:
{
if (text === "")
currentIndex = parseInt(defaultValue);
else
currentIndex = parseInt(text);
inited = true
}
id: boolCombo
anchors.fill: parent
onCurrentIndexChanged:
{
if (inited)
text = comboModel.get(currentIndex).value;
}
model: ListModel
{
id: comboModel
ListElement { text: qsTr("False"); value: "0" }
ListElement { text: qsTr("True"); value: "1" }
}
}
}
}

7
mix/qml/QHashType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QHashType 1.0
QHashType
{
}

22
mix/qml/QHashTypeView.qml

@ -0,0 +1,22 @@
import QtQuick 2.0
Item
{
property alias text: textinput.text
id: editRoot
Rectangle {
anchors.fill: parent
TextInput {
id: textinput
text: text
anchors.fill: parent
wrapMode: Text.WrapAnywhere
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: textinput.forceActiveFocus()
}
}
}
}

7
mix/qml/QIntType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QIntType 1.0
QIntType
{
}

24
mix/qml/QIntTypeView.qml

@ -0,0 +1,24 @@
import QtQuick 2.0
Item
{
property alias text: textinput.text
id: editRoot
Rectangle {
anchors.fill: parent
TextInput {
id: textinput
text: text
anchors.fill: parent
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: textinput.forceActiveFocus()
}
}
}
}

7
mix/qml/QRealType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QRealType 1.0
QRealType
{
}

15
mix/qml/QRealTypeView.qml

@ -0,0 +1,15 @@
import QtQuick 2.0
Component
{
Rectangle {
anchors.fill: parent
Text{
anchors.fill: parent
text: qsTr("Real")
}
}
}

7
mix/qml/QStringType.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QStringType 1.0
QStringType
{
}

25
mix/qml/QStringTypeView.qml

@ -0,0 +1,25 @@
import QtQuick 2.0
Item
{
property alias text: textinput.text
id: editRoot
Rectangle {
anchors.fill: parent
TextInput {
id: textinput
text: text
anchors.fill: parent
wrapMode: Text.WrapAnywhere
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: textinput.forceActiveFocus()
}
}
}
}

7
mix/qml/QVariableDeclaration.qml

@ -0,0 +1,7 @@
import QtQuick 2.0
import org.ethereum.qml.QVariableDeclaration 1.0
QVariableDeclaration
{
}

13
mix/qml/QVariableDefinition.qml

@ -0,0 +1,13 @@
/*
* Used to instanciate a QVariableDefinition obj using Qt.createComponent function.
*/
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import org.ethereum.qml.QVariableDefinition 1.0
QVariableDefinition
{
id: qVariableDefinition
}

47
mix/qml/Splitter.qml

@ -1,47 +0,0 @@
import QtQuick 2.2
Rectangle {
property variant itemToStick;
property int itemMinimumWidth;
property string direction;
property variant brother;
Component.onCompleted:
{
if (direction === "left")
anchors.right = itemToStick.left;
else if (direction === "right")
anchors.left = itemToStick.right;
}
width: 5
height: parent.height
anchors.top: parent.top;
MouseArea
{
property int startX: 0;
anchors.fill: parent
onPressed: startX = mouseX;
onPositionChanged:
{
parent.x += mouseX;
var diff = 0;
if (direction == "left")
diff = mouseX - startX;
else if (direction == "right")
diff = -(mouseX - startX);
if (itemMinimumWidth > itemToStick.width - diff)
{
brother.width = brother.width + diff;
itemToStick.width = itemMinimumWidth;
}
else
{
brother.width = brother.width + diff;
itemToStick.width = itemToStick.width - diff;
}
}
cursorShape: Qt.SizeHorCursor
}
}

4
mix/qml/StateDialog.qml

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

1
mix/qml/StateList.qml

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

99
mix/qml/StateListModel.qml

@ -8,7 +8,7 @@ import "js/QEtherHelper.js" as QEtherHelper
Item {
property int defaultStateIndex: -1
property int defaultStateIndex: 0
property alias model: stateListModel
property var stateList: []
@ -31,12 +31,30 @@ Item {
stdContract: t.stdContract,
parameters: {}
};
for (var key in t.parameters) {
var intComponent = Qt.createComponent("qrc:/qml/BigIntValue.qml");
var param = intComponent.createObject();
param.setValue(t.parameters[key]);
r.parameters[key] = param;
var qType = [];
for (var key in t.parameters)
{
r.parameters[key] = t.parameters[key].value;
var type = t.parameters[key].type;
var varComponent;
if (type.indexOf("int") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QIntType.qml");
else if (type.indexOf("real") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QRealType.qml");
else if (type.indexOf("string") !== -1 || type.indexOf("text") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QStringType.qml");
else if (type.indexOf("hash") !== -1 || type.indexOf("address") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QHashType.qml");
else if (type.indexOf("bool") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QBoolType.qml");
var param = varComponent.createObject(stateListModel);
var dec = Qt.createComponent("qrc:/qml/QVariableDeclaration.qml");
param.setDeclaration(dec.createObject(stateListModel, { "type": type }));
param.setValue(r.parameters[key]);
qType.push(param);
}
r.qType = qType;
return r;
}
@ -48,6 +66,16 @@ Item {
};
}
function getParamType(param, params)
{
for (var k in params)
{
if (params[k].declaration.name === param)
return params[k].declaration.type;
}
return '';
}
function toPlainTransactionItem(t) {
var r = {
functionId: t.functionId,
@ -60,7 +88,14 @@ Item {
parameters: {}
};
for (var key in t.parameters)
r.parameters[key] = t.parameters[key].value();
{
var param = {
name: key,
value: t.parameters[key],
type: getParamType(key, t.qType)
}
r.parameters[key] = param;
}
return r;
}
@ -70,20 +105,7 @@ Item {
stateListModel.clear();
stateList = [];
}
onProjectLoaded: {
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);
}
}
onProjectLoading: stateListModel.loadStatesFromProject(projectData);
onProjectSaving: {
projectData.states = []
for(var i = 0; i < stateListModel.count; i++) {
@ -114,7 +136,8 @@ Item {
stateList.push(item);
stateListModel.append(item);
}
if (stateDialog.isDefault)
stateListModel.defaultStateChanged();
stateListModel.save();
}
}
@ -126,6 +149,9 @@ Item {
ListModel {
id: stateListModel
signal defaultStateChanged;
signal stateListModelReady;
function defaultTransactionItem() {
return {
value: QEtherHelper.createEther("100", QEther.Wei),
@ -164,7 +190,7 @@ Item {
function addState() {
var item = createDefaultState();
stateDialog.open(stateListModel.count, item, defaultStateIndex === -1);
stateDialog.open(stateListModel.count, item, false);
}
function editState(index) {
@ -185,12 +211,37 @@ Item {
stateListModel.remove(index);
stateList.splice(index, 1);
if (index === defaultStateIndex)
defaultStateIndex = -1;
{
defaultStateIndex = 0;
defaultStateChanged();
}
save();
}
function save() {
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();
}
}
}

155
mix/qml/TransactionDialog.qml

@ -9,7 +9,7 @@ Window {
id: modalTransactionDialog
modality: Qt.WindowModal
width:640
height:480
height:640
visible: false
property int transactionIndex
@ -21,10 +21,12 @@ Window {
property var itemParams;
property bool isConstructorTransaction;
property bool useTransactionDefaultValue: false
property var qType;
signal accepted;
function open(index, item) {
qType = [];
rowFunction.visible = !useTransactionDefaultValue;
rowValue.visible = !useTransactionDefaultValue;
rowGas.visible = !useTransactionDefaultValue;
@ -68,6 +70,7 @@ Window {
}
function loadParameters() {
paramsModel.clear();
if (!paramsModel)
return;
if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) {
@ -75,7 +78,27 @@ Window {
var parameters = func.parameters;
for (var p = 0; p < parameters.length; p++) {
var pname = parameters[p].name;
paramsModel.append({ name: pname, type: parameters[p].type, value: itemParams[pname] !== undefined ? itemParams[pname].value() : "" });
var varComponent;
var type = parameters[p].type;
if (type.indexOf("int") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QIntType.qml");
else if (type.indexOf("real") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QRealType.qml");
else if (type.indexOf("string") !== -1 || type.indexOf("text") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QStringType.qml");
else if (type.indexOf("hash") !== -1 || type.indexOf("address") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QHashType.qml");
else if (type.indexOf("bool") !== -1)
varComponent = Qt.createComponent("qrc:/qml/QBoolType.qml");
var param = varComponent.createObject(modalTransactionDialog);
var value = itemParams[pname] !== undefined ? itemParams[pname] : "";
param.setValue(value);
param.setDeclaration(parameters[p]);
qType.push({ name: pname, value: param });
paramsModel.append({ name: pname, type: parameters[p].type, value: value });
}
}
}
@ -85,6 +108,15 @@ Window {
visible = false;
}
function qTypeParam(name)
{
for (var k in qType)
{
if (qType[k].name === name)
return qType[k].value;
}
}
function getItem()
{
var item;
@ -109,14 +141,15 @@ Window {
if (isConstructorTransaction)
item.functionId = qsTr("Constructor");
var orderedQType = [];
for (var p = 0; p < transactionDialog.transactionParams.count; p++) {
var parameter = transactionDialog.transactionParams.get(p);
var intComponent = Qt.createComponent("qrc:/qml/BigIntValue.qml");
var param = intComponent.createObject(modalTransactionDialog);
param.setValue(parameter.value);
item.parameters[parameter.name] = param;
var qtypeParam = qTypeParam(parameter.name);
qtypeParam.setValue(parameter.value);
orderedQType.push(qtypeParam);
item.parameters[parameter.name] = parameter.value;
}
item.qType = orderedQType;
return item;
}
@ -219,8 +252,10 @@ Window {
}
TableView {
model: paramsModel
Layout.fillWidth: true
Layout.preferredWidth: 120 * 2 + 240
Layout.minimumHeight: 150
Layout.preferredHeight: 400
Layout.maximumHeight: 600
TableViewColumn {
role: "name"
title: qsTr("Name")
@ -234,12 +269,11 @@ Window {
TableViewColumn {
role: "value"
title: qsTr("Value")
width: 120
width: 240
}
itemDelegate: {
return editableDelegate;
}
rowDelegate: rowDelegate
itemDelegate: editableDelegate
}
}
}
@ -268,19 +302,15 @@ Window {
}
Component {
id: editableDelegate
id: rowDelegate
Item {
height: 100
}
}
Text {
width: parent.width
anchors.margins: 4
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
elide: styleData.elideMode
text: styleData.value !== undefined ? styleData.value : ""
color: styleData.textColor
visible: !styleData.selected
}
Component {
id: editableDelegate
Item {
Loader {
id: loaderEditor
anchors.fill: parent
@ -289,14 +319,87 @@ Window {
target: loaderEditor.item
onTextChanged: {
if (styleData.role === "value" && styleData.row < paramsModel.count)
paramsModel.setProperty(styleData.row, styleData.role, loaderEditor.item.text);
loaderEditor.updateValue(styleData.row, styleData.role, loaderEditor.item.text);
}
}
sourceComponent: (styleData.selected) ? editor : null
function updateValue(row, role, value)
{
paramsModel.setProperty(styleData.row, styleData.role, value);
}
sourceComponent:
{
if (styleData.role === "value")
{
if (paramsModel.get(styleData.row) === undefined)
return null;
if (paramsModel.get(styleData.row).type.indexOf("int") !== -1)
return intViewComp;
else if (paramsModel.get(styleData.row).type.indexOf("bool") !== -1)
return boolViewComp;
else if (paramsModel.get(styleData.row).type.indexOf("string") !== -1)
return stringViewComp;
else if (paramsModel.get(styleData.row).type.indexOf("hash") !== -1)
return hashViewComp;
}
else
return editor;
}
Component
{
id: intViewComp
QIntTypeView
{
id: intView
text: styleData.value
}
}
Component
{
id: boolViewComp
QBoolTypeView
{
id: boolView
defaultValue: "1"
Component.onCompleted:
{
loaderEditor.updateValue(styleData.row, styleData.role,
(paramsModel.get(styleData.row).value === "" ? defaultValue :
paramsModel.get(styleData.row).value));
text = (paramsModel.get(styleData.row).value === "" ? defaultValue : paramsModel.get(styleData.row).value);
}
}
}
Component
{
id: stringViewComp
QStringTypeView
{
id: stringView
text: styleData.value
}
}
Component
{
id: hashViewComp
QHashTypeView
{
id: hashView
text: styleData.value
}
}
Component {
id: editor
TextInput {
id: textinput
readOnly: true
color: styleData.textColor
text: styleData.value
MouseArea {

2
mix/qml/WebPreview.qml

@ -86,7 +86,7 @@ Item {
updateDocument(documentId, function(i) { pageListModel.set(i, projectModel.getDocument(documentId)) } )
}
onProjectLoaded: {
onProjectLoading: {
for (var i = 0; i < target.listModel.count; i++) {
var document = target.listModel.get(i);
if (document.isHtml) {

1
mix/qml/html/codeeditor.js

@ -31,6 +31,7 @@ getText = function() {
setTextBase64 = function(text) {
editor.setValue(window.atob(text));
editor.getDoc().clearHistory();
editor.focus();
};

7
mix/qml/js/ProjectModel.js

@ -73,7 +73,8 @@ function loadProject(path) {
addFile(projectData.files[i]);
}
projectSettings.lastProjectPath = path;
projectLoaded(projectData);
projectLoading(projectData);
projectLoaded()
}
function addExistingFile() {
@ -171,8 +172,8 @@ function doCreateProject(title, path) {
files: [ contractsFile, indexFile ]
};
//TODO: copy from template
fileIo.writeFile(dirPath + indexFile, "<html></html>");
fileIo.writeFile(dirPath + contractsFile, "contract MyContract {\n}\n");
fileIo.writeFile(dirPath + indexFile, "<html>\n<head>\n<script>\nvar web3 = parent.web3;\nvar theContract = parent.contract;\n</script>\n</head>\n<body>\n<script>\n</script>\n</body>\n</html>");
fileIo.writeFile(dirPath + contractsFile, "contract Contract {\n}\n");
newProject(projectData);
var json = JSON.stringify(projectData, null, "\t");
fileIo.writeFile(projectFile, json);

55
mix/qml/main.qml

@ -4,6 +4,7 @@ import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import QtQuick.PrivateWidgets 1.1
import Qt.labs.settings 1.0
import org.ethereum.qml.QEther 1.0
@ -34,16 +35,18 @@ ApplicationWindow {
MenuItem { action: exitAppAction }
}
Menu {
title: qsTr("Debug")
title: qsTr("Deploy")
MenuItem { action: debugRunAction }
MenuItem { action: debugResetStateAction }
MenuItem { action: mineAction }
MenuSeparator {}
MenuItem { action: toggleRunOnLoadAction }
}
Menu {
title: qsTr("Windows")
MenuItem { action: openNextDocumentAction }
MenuItem { action: openPrevDocumentAction }
MenuSeparator {}
MenuItem { action: toggleProjectNavigatorAction }
MenuItem { action: showHideRightPanelAction }
MenuItem { action: toggleWebPreviewAction }
MenuItem { action: toggleWebPreviewOrientationAction }
@ -82,47 +85,71 @@ ApplicationWindow {
Action {
id: mineAction
text: "Mine"
text: qsTr("Mine")
shortcut: "Ctrl+M"
onTriggered: clientModel.mine();
enabled: codeModel.hasContract && !clientModel.running
}
Connections {
target: projectModel.stateListModel
function updateRunLabel()
{
debugRunAction.text = qsTr("Deploy") + " \"" + projectModel.stateListModel.defaultStateName() + "\"";
}
onDefaultStateChanged: updateRunLabel()
onStateListModelReady: updateRunLabel()
}
Action {
id: debugRunAction
text: "&Run"
text: qsTr("Deploy")
shortcut: "F5"
onTriggered: mainContent.startQuickDebugging()
enabled: codeModel.hasContract && !clientModel.running
}
Action {
id: debugResetStateAction
text: "Reset &State"
shortcut: "F6"
onTriggered: clientModel.resetState();
}
Action {
id: toggleWebPreviewAction
text: "Show Web View"
text: qsTr("Show Web View")
shortcut: "F2"
checkable: true
checked: mainContent.webViewVisible
onTriggered: mainContent.toggleWebPreview();
}
Action {
id: toggleProjectNavigatorAction
text: qsTr("Show Project Navigator")
shortcut: "Alt+0"
checkable: true
checked: mainContent.projectViewVisible
onTriggered: mainContent.toggleProjectView();
}
Action {
id: toggleWebPreviewOrientationAction
text: "Horizontal Web View"
text: qsTr("Horizontal Web View")
shortcut: ""
checkable: true
checked: mainContent.webViewHorizontal
onTriggered: mainContent.toggleWebPreviewOrientation();
}
Action {
id: toggleRunOnLoadAction
text: qsTr("Load State on Startup")
shortcut: ""
checkable: true
checked: mainContent.runOnProjectLoad
onTriggered: mainContent.runOnProjectLoad = !mainContent.runOnProjectLoad
}
Action {
id: showHideRightPanelAction
text: "Show Right View"
text: qsTr("Show Right View")
shortcut: "F7"
checkable: true
checked: mainContent.rightViewVisible

13
mix/res.qrc

@ -42,9 +42,19 @@
<file>qml/Ether.qml</file>
<file>qml/EtherValue.qml</file>
<file>qml/BigIntValue.qml</file>
<file>qml/QVariableDefinition.qml</file>
<file>qml/QBoolType.qml</file>
<file>qml/QHashType.qml</file>
<file>qml/QIntType.qml</file>
<file>qml/QRealType.qml</file>
<file>qml/js/QEtherHelper.js</file>
<file>qml/js/TransactionHelper.js</file>
<file>qml/Splitter.qml</file>
<file>qml/QStringType.qml</file>
<file>qml/QBoolTypeView.qml</file>
<file>qml/QIntTypeView.qml</file>
<file>qml/QRealTypeView.qml</file>
<file>qml/QStringTypeView.qml</file>
<file>qml/QHashTypeView.qml</file>
<file>qml/ContractLibrary.qml</file>
<file>stdc/config.sol</file>
<file>stdc/namereg.sol</file>
@ -52,5 +62,6 @@
<file>qml/TransactionLog.qml</file>
<file>res/mix_256x256x32.png</file>
<file>qml/CallStack.qml</file>
<file>qml/QVariableDeclaration.qml</file>
</qresource>
</RCC>

55
test/SolidityEndToEndTest.cpp

@ -92,6 +92,26 @@ BOOST_AUTO_TEST_CASE(multiple_functions)
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(disorder_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({c: 3, a: 1, b: 2}); }\n"
"}\n";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("b()", bytes()) == toBigEndian(u256(123)));
}
BOOST_AUTO_TEST_CASE(while_loop)
{
char const* sourceCode = "contract test {\n"
@ -885,7 +905,7 @@ BOOST_AUTO_TEST_CASE(constructor)
BOOST_AUTO_TEST_CASE(simple_accessor)
{
char const* sourceCode = "contract test {\n"
" uint256 data;\n"
" uint256 public data;\n"
" function test() {\n"
" data = 8;\n"
" }\n"
@ -897,10 +917,10 @@ BOOST_AUTO_TEST_CASE(simple_accessor)
BOOST_AUTO_TEST_CASE(multiple_elementary_accessors)
{
char const* sourceCode = "contract test {\n"
" uint256 data;\n"
" string6 name;\n"
" hash a_hash;\n"
" address an_address;\n"
" uint256 public data;\n"
" string6 public name;\n"
" hash public a_hash;\n"
" address public an_address;\n"
" function test() {\n"
" data = 8;\n"
" name = \"Celina\";\n"
@ -908,7 +928,6 @@ BOOST_AUTO_TEST_CASE(multiple_elementary_accessors)
" an_address = address(0x1337);\n"
" super_secret_data = 42;\n"
" }\n"
" private:"
" uint256 super_secret_data;"
"}\n";
compileAndRun(sourceCode);
@ -919,6 +938,27 @@ BOOST_AUTO_TEST_CASE(multiple_elementary_accessors)
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)
{
char const* sourceCode = "contract test {\n"
@ -1490,8 +1530,7 @@ BOOST_AUTO_TEST_CASE(functions_called_by_constructor)
setName("abc");
}
function getName() returns (string3 ret) { return name; }
private:
function setName(string3 _name) { name = _name; }
function setName(string3 _name) private { name = _name; }
})";
compileAndRun(sourceCode);
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_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)
{
char const* text = R"(
@ -636,7 +654,9 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors)
" function fun() {\n"
" uint64(2);\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";
ASTPointer<SourceUnit> source;
@ -644,10 +664,27 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors)
BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text));
BOOST_REQUIRE((contract = retrieveContract(source, 0)) != nullptr);
FunctionTypePointer function = retrieveFunctionBySignature(contract, "foo()");
BOOST_REQUIRE(function->hasDeclaration());
BOOST_REQUIRE(function && function->hasDeclaration());
auto returnParams = function->getReturnParameterTypeNames();
BOOST_CHECK_EQUAL(returnParams.at(0), "uint256");
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)
@ -668,16 +705,19 @@ BOOST_AUTO_TEST_CASE(private_state_variable)
" function fun() {\n"
" uint64(2);\n"
" }\n"
"private:\n"
"uint256 foo;\n"
"uint256 private foo;\n"
"uint256 protected bar;\n"
"}\n";
ASTPointer<SourceUnit> source;
ContractDefinition const* contract;
BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text));
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");
function = retrieveFunctionBySignature(contract, "bar()");
BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a protected variable should not exist");
}
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_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()
}

49
test/SolidityParser.cpp

@ -124,14 +124,30 @@ BOOST_AUTO_TEST_CASE(single_function_param)
BOOST_CHECK_NO_THROW(parseText(text));
}
BOOST_AUTO_TEST_CASE(missing_parameter_name_in_named_args)
{
char const* text = "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({: 1, : 2, : 3}); }\n"
"}\n";
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_CASE(missing_argument_in_named_args)
{
char const* text = "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: , b: , c: }); }\n"
"}\n";
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_CASE(function_natspec_documentation)
{
ASTPointer<ContractDefinition> contract;
ASTPointer<FunctionDefinition> function;
char const* text = "contract test {\n"
" private:\n"
" uint256 stateVar;\n"
" public:\n"
" uint256 stateVar;\n"
" /// This is a test function\n"
" function functionName(hash hashin) returns (hash hashout) {}\n"
"}\n";
@ -162,9 +178,7 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation)
ASTPointer<ContractDefinition> contract;
ASTPointer<FunctionDefinition> function;
char const* text = "contract test {\n"
" private:\n"
" uint256 stateVar;\n"
" public:\n"
" /// This is test function 1\n"
" function functionName1(hash hashin) returns (hash hashout) {}\n"
" /// This is test function 2\n"
@ -621,6 +635,31 @@ BOOST_AUTO_TEST_CASE(event_arguments_indexed)
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()
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save