Browse Source

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

cl-refactor
Gav Wood 10 years ago
parent
commit
2e005d1796
  1. 2
      cmake/EthCompilerSettings.cmake
  2. 20
      docker/Dockerfile
  3. 13
      evmjit/libevmjit-cpp/JitVM.cpp
  4. 2
      libethcore/BlockInfo.cpp
  5. 5
      libethereum/BlockChain.cpp
  6. 8
      libethereum/Client.cpp
  7. 2
      libethereum/Executive.cpp
  8. 3
      libethereum/Transaction.cpp
  9. 63
      libjsqrc/ethereumjs/.jshintrc
  10. 2
      libjsqrc/ethereumjs/README.md
  11. 5
      libjsqrc/ethereumjs/bower.json
  12. 29
      libjsqrc/ethereumjs/dist/ethereum.js
  13. 18
      libjsqrc/ethereumjs/dist/ethereum.js.map
  14. 2
      libjsqrc/ethereumjs/dist/ethereum.min.js
  15. 4
      libjsqrc/ethereumjs/gulpfile.js
  16. 2
      libjsqrc/ethereumjs/lib/abi.js
  17. 2
      libjsqrc/ethereumjs/lib/contract.js
  18. 4
      libjsqrc/ethereumjs/lib/event.js
  19. 2
      libjsqrc/ethereumjs/lib/filter.js
  20. 1
      libjsqrc/ethereumjs/lib/formatters.js
  21. 11
      libjsqrc/ethereumjs/lib/requestmanager.js
  22. 1
      libjsqrc/ethereumjs/lib/utils.js
  23. 4
      libjsqrc/ethereumjs/lib/web3.js
  24. 1
      libjsqrc/ethereumjs/package.json
  25. 58
      libsolidity/AST.cpp
  26. 16
      libsolidity/AST.h
  27. 304
      libsolidity/ArrayUtils.cpp
  28. 78
      libsolidity/ArrayUtils.h
  29. 108
      libsolidity/Compiler.cpp
  30. 7
      libsolidity/Compiler.h
  31. 33
      libsolidity/CompilerContext.cpp
  32. 8
      libsolidity/CompilerContext.h
  33. 10
      libsolidity/CompilerStack.cpp
  34. 18
      libsolidity/CompilerStack.h
  35. 170
      libsolidity/CompilerUtils.cpp
  36. 13
      libsolidity/CompilerUtils.h
  37. 8
      libsolidity/ExpressionCompiler.cpp
  38. 122
      libsolidity/LValue.cpp
  39. 44
      libsolidity/LValue.h
  40. 10
      libsolidity/SourceReferenceFormatter.cpp
  41. 29
      libsolidity/Types.cpp
  42. 1
      mix/AppContext.cpp
  43. 37
      mix/ClientModel.cpp
  44. 25
      mix/ClientModel.h
  45. 2
      mix/CodeModel.cpp
  46. 10
      mix/CodeModel.h
  47. 9
      mix/DebuggingStateWrapper.cpp
  48. 30
      mix/DebuggingStateWrapper.h
  49. 12
      mix/FileIo.cpp
  50. 2
      mix/FileIo.h
  51. 13
      mix/MachineStates.h
  52. 12
      mix/MixClient.cpp
  53. 2
      mix/MixClient.h
  54. 43
      mix/qml/CodeEditorView.qml
  55. 98
      mix/qml/Debugger.qml
  56. 308
      mix/qml/DeploymentDialog.qml
  57. 348
      mix/qml/FilesSection.qml
  58. 31
      mix/qml/MainContent.qml
  59. 2
      mix/qml/ProjectFilesStyle.qml
  60. 20
      mix/qml/ProjectList.qml
  61. 19
      mix/qml/ProjectModel.qml
  62. 128
      mix/qml/StatusPane.qml
  63. 49
      mix/qml/TransactionLog.qml
  64. 28
      mix/qml/WebCodeEditor.qml
  65. 60
      mix/qml/WebPreview.qml
  66. 4
      mix/qml/html/cm/codemirror.css
  67. 6
      mix/qml/html/cm/solarized.css
  68. 50
      mix/qml/html/codeeditor.js
  69. BIN
      mix/qml/img/search_filled.png
  70. 147
      mix/qml/js/Debugger.js
  71. 386
      mix/qml/js/ProjectModel.js
  72. 25
      mix/qml/js/TransactionHelper.js
  73. 37
      mix/qml/main.qml
  74. 1
      mix/res.qrc
  75. 242
      test/SolidityEndToEndTest.cpp
  76. 109
      test/SolidityNameAndTypeResolution.cpp
  77. 34
      test/SolidityParser.cpp
  78. 50
      test/TestHelper.cpp
  79. 10
      test/block.cpp
  80. 69
      test/stMemoryStressTestFiller.json
  81. 1465
      test/stMemoryTestFiller.json
  82. 682
      test/stQuadraticComplexityTestFiller.json
  83. 158
      test/stRefundTestFiller.json
  84. 55
      test/stSolidityTestFiller.json
  85. 1015
      test/stSystemOperationsTestFiller.json
  86. 10
      test/stTransactionTestFiller.json
  87. 41
      test/state.cpp
  88. 19
      test/transaction.cpp
  89. 169
      test/ttTransactionTestFiller.json
  90. 6
      test/vm.cpp
  91. 366
      test/vmArithmeticTestFiller.json
  92. 168
      test/vmEnvironmentalInfoTestFiller.json
  93. 85
      test/vmIOandFlowOperationsTestFiller.json
  94. 238
      test/vmSha3TestFiller.json

2
cmake/EthCompilerSettings.cmake

@ -3,7 +3,7 @@
# C++11 check and activation # C++11 check and activation
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB -fPIC") set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -Werror -DSHAREDLIB -fPIC")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE")

20
docker/Dockerfile

@ -8,23 +8,29 @@ RUN apt-get upgrade -y
RUN apt-get install -qy build-essential g++-4.8 git cmake libboost-all-dev libcurl4-openssl-dev wget RUN apt-get install -qy build-essential g++-4.8 git cmake libboost-all-dev libcurl4-openssl-dev wget
RUN apt-get install -qy automake unzip libgmp-dev libtool libleveldb-dev yasm libminiupnpc-dev libreadline-dev scons RUN apt-get install -qy automake unzip libgmp-dev libtool libleveldb-dev yasm libminiupnpc-dev libreadline-dev scons
RUN apt-get install -qy libjsoncpp-dev libargtable2-dev RUN apt-get install -qy libjsoncpp-dev libargtable2-dev
RUN apt-get install -qy libncurses5-dev libcurl4-openssl-dev wget
# NCurses based GUI (not optional though for a succesful compilation, see https://github.com/ethereum/cpp-ethereum/issues/452 ) RUN apt-get install -qy libjsoncpp-dev libargtable2-dev libmicrohttpd-dev
RUN apt-get install -qy libncurses5-dev
# Qt-based GUI
# RUN apt-get install -qy qtbase5-dev qt5-default qtdeclarative5-dev libqt5webkit5-dev
# Ethereum PPA # Ethereum PPA
RUN apt-get install -qy software-properties-common RUN apt-get install -qy software-properties-common
RUN add-apt-repository ppa:ethereum/ethereum RUN add-apt-repository ppa:ethereum/ethereum
RUN add-apt-repository ppa:ethereum/ethereum-dev
RUN apt-get update RUN apt-get update
RUN apt-get install -qy libcryptopp-dev libjson-rpc-cpp-dev RUN apt-get install -qy libcryptopp-dev libjson-rpc-cpp-dev
# LLVM-3.5
RUN wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add -
RUN echo "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.5 main\ndeb-src http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.5 main" > /etc/apt/sources.list.d/llvm-trusty.list
RUN apt-get update
RUN apt-get install -qy llvm-3.5 libedit-dev
# Fix llvm-3.5 cmake paths
RUN mkdir -p /usr/lib/llvm-3.5/share/llvm && ln -s /usr/share/llvm-3.5/cmake /usr/lib/llvm-3.5/share/llvm/cmake
# Build Ethereum (HEADLESS) # Build Ethereum (HEADLESS)
RUN git clone --depth=1 https://github.com/ethereum/cpp-ethereum RUN git clone --depth=1 https://github.com/ethereum/cpp-ethereum
RUN mkdir -p cpp-ethereum/build RUN mkdir -p cpp-ethereum/build
RUN cd cpp-ethereum/build && cmake .. -DCMAKE_BUILD_TYPE=Release -DHEADLESS=1 && make -j $(cat /proc/cpuinfo | grep processor | wc -l) && make install RUN cd cpp-ethereum/build && cmake .. -DHEADLESS=1 -DLLVM_DIR=/usr/share/llvm-3.5/cmake -DEVMJIT=1 && make -j $(cat /proc/cpuinfo | grep processor | wc -l) && make install
RUN ldconfig RUN ldconfig
ENTRYPOINT ["/usr/local/bin/eth"] ENTRYPOINT ["/usr/local/bin/eth"]

13
evmjit/libevmjit-cpp/JitVM.cpp

@ -1,10 +1,14 @@
#pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wconversion"
#include "JitVM.h" #include "JitVM.h"
#include <libdevcore/Log.h>
#include <libdevcrypto/SHA3.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
#include <libdevcrypto/SHA3.h>
#include <evmjit/libevmjit/ExecutionEngine.h> #include <evmjit/libevmjit/ExecutionEngine.h>
#include "Utils.h" #include "Utils.h"
namespace dev namespace dev
@ -27,12 +31,13 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step)
if (rejected) if (rejected)
{ {
UNTESTED; cwarn << "Execution rejected by EVM JIT (gas limit: " << m_gas << "), executing with interpreter";
std::cerr << "Rejected\n";
VMFactory::setKind(VMKind::Interpreter); VMFactory::setKind(VMKind::Interpreter);
m_fallbackVM = VMFactory::create(m_gas); m_fallbackVM = VMFactory::create(m_gas);
VMFactory::setKind(VMKind::JIT); VMFactory::setKind(VMKind::JIT);
return m_fallbackVM->go(_ext, _onOp, _step); auto&& output = m_fallbackVM->go(_ext, _onOp, _step);
m_gas = m_fallbackVM->gas(); // copy remaining gas, Executive expects it
return output;
} }
m_data.gas = static_cast<decltype(m_data.gas)>(m_gas); m_data.gas = static_cast<decltype(m_data.gas)>(m_gas);

2
libethcore/BlockInfo.cpp

@ -134,7 +134,7 @@ void BlockInfo::populate(bytesConstRef _block, bool _checkNonce)
RLP header = root[0]; RLP header = root[0];
if (!header.isList()) if (!header.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat(0,header.data()) << errinfo_comment("block header needs to be a list")); BOOST_THROW_EXCEPTION(InvalidBlockFormat(0, header.data()) << errinfo_comment("block header needs to be a list"));
populateFromHeader(header, _checkNonce); populateFromHeader(header, _checkNonce);
if (!root[1].isList()) if (!root[1].isList())

5
libethereum/BlockChain.cpp

@ -209,6 +209,11 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
try try
#endif #endif
{ {
RLP blockRLP(_block);
if (!blockRLP.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat(0, blockRLP.data()) << errinfo_comment("block header needs to be a list"));
bi.populate(&_block); bi.populate(&_block);
bi.verifyInternals(&_block); bi.verifyInternals(&_block);
} }

8
libethereum/Client.cpp

@ -257,9 +257,13 @@ LocalisedLogEntries Client::peekWatch(unsigned _watchId) const
Guard l(m_filterLock); Guard l(m_filterLock);
try { try {
#if ETH_DEBUG
cdebug << "peekWatch" << _watchId; cdebug << "peekWatch" << _watchId;
#endif
auto& w = m_watches.at(_watchId); auto& w = m_watches.at(_watchId);
#if ETH_DEBUG
cdebug << "lastPoll updated to " << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count(); cdebug << "lastPoll updated to " << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();
#endif
w.lastPoll = chrono::system_clock::now(); w.lastPoll = chrono::system_clock::now();
return w.changes; return w.changes;
} catch (...) {} } catch (...) {}
@ -273,9 +277,13 @@ LocalisedLogEntries Client::checkWatch(unsigned _watchId)
LocalisedLogEntries ret; LocalisedLogEntries ret;
try { try {
#if ETH_DEBUG
cdebug << "checkWatch" << _watchId; cdebug << "checkWatch" << _watchId;
#endif
auto& w = m_watches.at(_watchId); auto& w = m_watches.at(_watchId);
#if ETH_DEBUG
cdebug << "lastPoll updated to " << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count(); cdebug << "lastPoll updated to " << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();
#endif
std::swap(ret, w.changes); std::swap(ret, w.changes);
w.lastPoll = chrono::system_clock::now(); w.lastPoll = chrono::system_clock::now();
} catch (...) {} } catch (...) {}

2
libethereum/Executive.cpp

@ -176,7 +176,7 @@ OnOpFunc Executive::simpleTrace()
o << endl << " STACK" << endl; o << endl << " STACK" << endl;
for (auto i: vm.stack()) for (auto i: vm.stack())
o << (h256)i << endl; o << (h256)i << endl;
o << " MEMORY" << endl << memDump(vm.memory()); o << " MEMORY" << endl << (vm.memory().size() > 1000) ? " mem size greater than 1000 bytes " : memDump(vm.memory());
o << " STORAGE" << endl; o << " STORAGE" << endl;
for (auto const& i: ext.state().storage(ext.myAddress)) for (auto const& i: ext.state().storage(ext.myAddress))
o << showbase << hex << i.first << ": " << i.second << endl; o << showbase << hex << i.first << ": " << i.second << endl;

3
libethereum/Transaction.cpp

@ -36,6 +36,9 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckSignature _checkSig)
RLP rlp(_rlpData); RLP rlp(_rlpData);
try try
{ {
if (!rlp.isList())
BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("transaction RLP must be a list"));
m_nonce = rlp[field = 0].toInt<u256>(); m_nonce = rlp[field = 0].toInt<u256>();
m_gasPrice = rlp[field = 1].toInt<u256>(); m_gasPrice = rlp[field = 1].toInt<u256>();
m_gas = rlp[field = 2].toInt<u256>(); m_gas = rlp[field = 2].toInt<u256>();

63
libjsqrc/ethereumjs/.jshintrc

@ -1,50 +1,19 @@
{ {
"predef": [ "browserify": true,
"console", "bitwise": true,
"require", "camelcase": true,
"equal",
"test",
"testBoth",
"testWithDefault",
"raises",
"deepEqual",
"start",
"stop",
"ok",
"strictEqual",
"module",
"expect",
"reject",
"impl"
],
"esnext": true,
"proto": true,
"node" : true,
"browser" : true,
"browserify" : true,
"boss" : true,
"curly": false,
"debug": true,
"devel": true,
"eqeqeq": true, "eqeqeq": true,
"evil": true, "freeze": true,
"forin": false, "funcscope": false,
"immed": false, "maxcomplexity": 4, /* our target is 3! */
"laxbreak": false, "maxdepth": 3,
"newcap": true, "maxerr": 50,
"noarg": true, /*"maxlen": 80*/ /*this should be our goal*/
"noempty": false, "maxparams": 3,
"nonew": false, "nonew": true,
"nomen": false, "unused": true,
"onevar": false,
"plusplus": false,
"regexp": false,
"undef": true, "undef": true,
"sub": true, "predef": [
"strict": false, "console"
"white": false, ]
"shadow": true, }
"eqnull": true
}

2
libjsqrc/ethereumjs/README.md

@ -1,7 +1,7 @@
# Ethereum JavaScript API # Ethereum JavaScript API
This is the Ethereum compatible [JavaScript API](https://github.com/ethereum/wiki/wiki/JavaScript-API) This is the Ethereum compatible [JavaScript API](https://github.com/ethereum/wiki/wiki/JavaScript-API)
which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC) spec. It's available on npm as a node module and also for bower and component as an embeddable js which implements the [Generic JSON RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) spec. It's available on npm as a node module and also for bower and component as an embeddable js
[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url][![Coverage Status][coveralls-image]][coveralls-url] [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![dependency status][dep-image]][dep-url] [![dev dependency status][dep-dev-image]][dep-dev-url][![Coverage Status][coveralls-image]][coveralls-url]

5
libjsqrc/ethereumjs/bower.json

@ -3,7 +3,10 @@
"namespace": "ethereum", "namespace": "ethereum",
"version": "0.0.15", "version": "0.0.15",
"description": "Ethereum Compatible JavaScript API", "description": "Ethereum Compatible JavaScript API",
"main": ["./dist/ethereum.js", "./dist/ethereum.min.js"], "main": [
"./dist/ethereum.js",
"./dist/ethereum.min.js"
],
"dependencies": { "dependencies": {
"bignumber.js": ">=2.0.0" "bignumber.js": ">=2.0.0"
}, },

29
libjsqrc/ethereumjs/dist/ethereum.js

@ -53,7 +53,6 @@ var inputTypes = types.inputTypes();
/// @returns bytes representation of input params /// @returns bytes representation of input params
var formatInput = function (inputs, params) { var formatInput = function (inputs, params) {
var bytes = ""; var bytes = "";
var padding = c.ETH_PADDING * 2;
/// first we iterate in search for dynamic /// first we iterate in search for dynamic
inputs.forEach(function (input, index) { inputs.forEach(function (input, index) {
@ -110,6 +109,7 @@ var formatOutput = function (outs, output) {
output = output.slice(dynamicPartLength); output = output.slice(dynamicPartLength);
outs.forEach(function (out, i) { outs.forEach(function (out, i) {
/*jshint maxcomplexity:6 */
var typeMatch = false; var typeMatch = false;
for (var j = 0; j < outputTypes.length && !typeMatch; j++) { for (var j = 0; j < outputTypes.length && !typeMatch; j++) {
typeMatch = outputTypes[j].type(outs[i].type); typeMatch = outputTypes[j].type(outs[i].type);
@ -296,7 +296,6 @@ var web3 = require('./web3');
var abi = require('./abi'); var abi = require('./abi');
var utils = require('./utils'); var utils = require('./utils');
var eventImpl = require('./event'); var eventImpl = require('./event');
var filter = require('./filter');
var exportNatspecGlobals = function (vars) { var exportNatspecGlobals = function (vars) {
// it's used byt natspec.js // it's used byt natspec.js
@ -342,6 +341,7 @@ var addFunctionsToContract = function (contract, desc, address) {
var typeName = utils.extractTypeName(method.name); var typeName = utils.extractTypeName(method.name);
var impl = function () { var impl = function () {
/*jshint maxcomplexity:7 */
var params = Array.prototype.slice.call(arguments); var params = Array.prototype.slice.call(arguments);
var signature = abi.signatureFromAscii(method.name); var signature = abi.signatureFromAscii(method.name);
var parsed = inputParser[displayName][typeName].apply(null, params); var parsed = inputParser[displayName][typeName].apply(null, params);
@ -489,7 +489,7 @@ var contract = function (address, desc) {
module.exports = contract; module.exports = contract;
},{"./abi":1,"./event":6,"./filter":7,"./utils":15,"./web3":17}],4:[function(require,module,exports){ },{"./abi":1,"./event":6,"./utils":15,"./web3":17}],4:[function(require,module,exports){
/* /*
This file is part of ethereum.js. This file is part of ethereum.js.
@ -697,9 +697,9 @@ var getArgumentsObject = function (inputs, indexed, notIndexed) {
return inputs.reduce(function (acc, current) { return inputs.reduce(function (acc, current) {
var value; var value;
if (current.indexed) if (current.indexed)
value = indexed.splice(0, 1)[0]; value = indexedCopy.splice(0, 1)[0];
else else
value = notIndexed.splice(0, 1)[0]; value = notIndexedCopy.splice(0, 1)[0];
acc[current.name] = value; acc[current.name] = value;
return acc; return acc;
@ -847,7 +847,7 @@ var filter = function(options, implementation, formatter) {
return implementation.getMessages(filterId); return implementation.getMessages(filterId);
}; };
var uninstall = function (callback) { var uninstall = function () {
implementation.stopPolling(filterId); implementation.stopPolling(filterId);
implementation.uninstallFilter(filterId); implementation.uninstallFilter(filterId);
callbacks = []; callbacks = [];
@ -909,6 +909,7 @@ var padLeft = function (string, chars, sign) {
/// If the value is floating point, round it down /// If the value is floating point, round it down
/// @returns right-aligned byte representation of int /// @returns right-aligned byte representation of int
var formatInputInt = function (value) { var formatInputInt = function (value) {
/*jshint maxcomplexity:7 */
var padding = c.ETH_PADDING * 2; var padding = c.ETH_PADDING * 2;
if (value instanceof BigNumber || typeof value === 'number') { if (value instanceof BigNumber || typeof value === 'number') {
if (typeof value === 'number') if (typeof value === 'number')
@ -1210,6 +1211,7 @@ var c = require('./const');
*/ */
var requestManager = function() { var requestManager = function() {
var polls = []; var polls = [];
var timeout = null;
var provider; var provider;
var send = function (data) { var send = function (data) {
@ -1234,9 +1236,11 @@ var requestManager = function() {
provider = p; provider = p;
}; };
/*jshint maxparams:4 */
var startPolling = function (data, pollId, callback, uninstall) { var startPolling = function (data, pollId, callback, uninstall) {
polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall});
}; };
/*jshint maxparams:3 */
var stopPolling = function (pollId) { var stopPolling = function (pollId) {
for (var i = polls.length; i--;) { for (var i = polls.length; i--;) {
@ -1252,6 +1256,12 @@ var requestManager = function() {
poll.uninstall(poll.id); poll.uninstall(poll.id);
}); });
polls = []; polls = [];
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
poll();
}; };
var poll = function () { var poll = function () {
@ -1262,7 +1272,7 @@ var requestManager = function() {
} }
data.callback(result); data.callback(result);
}); });
setTimeout(poll, c.ETH_POLLING_TIMEOUT); timeout = setTimeout(poll, c.ETH_POLLING_TIMEOUT);
}; };
poll(); poll();
@ -1509,6 +1519,7 @@ var filterEvents = function (json) {
/// TODO: use BigNumber.js to parse int /// TODO: use BigNumber.js to parse int
/// TODO: add tests for it! /// TODO: add tests for it!
var toEth = function (str) { var toEth = function (str) {
/*jshint maxcomplexity:7 */
var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str; var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
var unit = 0; var unit = 0;
var units = c.ETH_UNITS; var units = c.ETH_UNITS;
@ -1677,12 +1688,14 @@ var setupProperties = function (obj, properties) {
}); });
}; };
/*jshint maxparams:4 */
var startPolling = function (method, id, callback, uninstall) { var startPolling = function (method, id, callback, uninstall) {
web3.manager.startPolling({ web3.manager.startPolling({
method: method, method: method,
params: [id] params: [id]
}, id, callback, uninstall); }, id, callback, uninstall);
}; };
/*jshint maxparams:3 */
var stopPolling = function (id) { var stopPolling = function (id) {
web3.manager.stopPolling(id); web3.manager.stopPolling(id);
@ -1740,12 +1753,14 @@ var web3 = {
/// @param indexed is optional, this is an object with optional event indexed params /// @param indexed is optional, this is an object with optional event indexed params
/// @param options is optional, this is an object with optional event options ('max'...) /// @param options is optional, this is an object with optional event options ('max'...)
/// TODO: fix it, 4 params? no way /// TODO: fix it, 4 params? no way
/*jshint maxparams:4 */
watch: function (fil, indexed, options, formatter) { watch: function (fil, indexed, options, formatter) {
if (fil._isEvent) { if (fil._isEvent) {
return fil(indexed, options); return fil(indexed, options);
} }
return filter(fil, ethWatch, formatter); return filter(fil, ethWatch, formatter);
} }
/*jshint maxparams:3 */
}, },
/// db object prototype /// db object prototype

18
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

4
libjsqrc/ethereumjs/gulpfile.js

@ -10,8 +10,6 @@ var browserify = require('browserify');
var jshint = require('gulp-jshint'); var jshint = require('gulp-jshint');
var uglify = require('gulp-uglify'); var uglify = require('gulp-uglify');
var rename = require('gulp-rename'); var rename = require('gulp-rename');
var envify = require('envify/custom');
var unreach = require('unreachable-branch-transform');
var source = require('vinyl-source-stream'); var source = require('vinyl-source-stream');
var exorcist = require('exorcist'); var exorcist = require('exorcist');
var bower = require('bower'); var bower = require('bower');
@ -23,7 +21,7 @@ var dst = 'ethereum';
var browserifyOptions = { var browserifyOptions = {
debug: true, debug: true,
insert_global_vars: false, insert_global_vars: false, // jshint ignore:line
detectGlobals: false, detectGlobals: false,
bundleExternal: false bundleExternal: false
}; };

2
libjsqrc/ethereumjs/lib/abi.js

@ -52,7 +52,6 @@ var inputTypes = types.inputTypes();
/// @returns bytes representation of input params /// @returns bytes representation of input params
var formatInput = function (inputs, params) { var formatInput = function (inputs, params) {
var bytes = ""; var bytes = "";
var padding = c.ETH_PADDING * 2;
/// first we iterate in search for dynamic /// first we iterate in search for dynamic
inputs.forEach(function (input, index) { inputs.forEach(function (input, index) {
@ -109,6 +108,7 @@ var formatOutput = function (outs, output) {
output = output.slice(dynamicPartLength); output = output.slice(dynamicPartLength);
outs.forEach(function (out, i) { outs.forEach(function (out, i) {
/*jshint maxcomplexity:6 */
var typeMatch = false; var typeMatch = false;
for (var j = 0; j < outputTypes.length && !typeMatch; j++) { for (var j = 0; j < outputTypes.length && !typeMatch; j++) {
typeMatch = outputTypes[j].type(outs[i].type); typeMatch = outputTypes[j].type(outs[i].type);

2
libjsqrc/ethereumjs/lib/contract.js

@ -24,7 +24,6 @@ var web3 = require('./web3');
var abi = require('./abi'); var abi = require('./abi');
var utils = require('./utils'); var utils = require('./utils');
var eventImpl = require('./event'); var eventImpl = require('./event');
var filter = require('./filter');
var exportNatspecGlobals = function (vars) { var exportNatspecGlobals = function (vars) {
// it's used byt natspec.js // it's used byt natspec.js
@ -70,6 +69,7 @@ var addFunctionsToContract = function (contract, desc, address) {
var typeName = utils.extractTypeName(method.name); var typeName = utils.extractTypeName(method.name);
var impl = function () { var impl = function () {
/*jshint maxcomplexity:7 */
var params = Array.prototype.slice.call(arguments); var params = Array.prototype.slice.call(arguments);
var signature = abi.signatureFromAscii(method.name); var signature = abi.signatureFromAscii(method.name);
var parsed = inputParser[displayName][typeName].apply(null, params); var parsed = inputParser[displayName][typeName].apply(null, params);

4
libjsqrc/ethereumjs/lib/event.js

@ -81,9 +81,9 @@ var getArgumentsObject = function (inputs, indexed, notIndexed) {
return inputs.reduce(function (acc, current) { return inputs.reduce(function (acc, current) {
var value; var value;
if (current.indexed) if (current.indexed)
value = indexed.splice(0, 1)[0]; value = indexedCopy.splice(0, 1)[0];
else else
value = notIndexed.splice(0, 1)[0]; value = notIndexedCopy.splice(0, 1)[0];
acc[current.name] = value; acc[current.name] = value;
return acc; return acc;

2
libjsqrc/ethereumjs/lib/filter.js

@ -93,7 +93,7 @@ var filter = function(options, implementation, formatter) {
return implementation.getMessages(filterId); return implementation.getMessages(filterId);
}; };
var uninstall = function (callback) { var uninstall = function () {
implementation.stopPolling(filterId); implementation.stopPolling(filterId);
implementation.uninstallFilter(filterId); implementation.uninstallFilter(filterId);
callbacks = []; callbacks = [];

1
libjsqrc/ethereumjs/lib/formatters.js

@ -40,6 +40,7 @@ var padLeft = function (string, chars, sign) {
/// If the value is floating point, round it down /// If the value is floating point, round it down
/// @returns right-aligned byte representation of int /// @returns right-aligned byte representation of int
var formatInputInt = function (value) { var formatInputInt = function (value) {
/*jshint maxcomplexity:7 */
var padding = c.ETH_PADDING * 2; var padding = c.ETH_PADDING * 2;
if (value instanceof BigNumber || typeof value === 'number') { if (value instanceof BigNumber || typeof value === 'number') {
if (typeof value === 'number') if (typeof value === 'number')

11
libjsqrc/ethereumjs/lib/requestmanager.js

@ -33,6 +33,7 @@ var c = require('./const');
*/ */
var requestManager = function() { var requestManager = function() {
var polls = []; var polls = [];
var timeout = null;
var provider; var provider;
var send = function (data) { var send = function (data) {
@ -57,9 +58,11 @@ var requestManager = function() {
provider = p; provider = p;
}; };
/*jshint maxparams:4 */
var startPolling = function (data, pollId, callback, uninstall) { var startPolling = function (data, pollId, callback, uninstall) {
polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall});
}; };
/*jshint maxparams:3 */
var stopPolling = function (pollId) { var stopPolling = function (pollId) {
for (var i = polls.length; i--;) { for (var i = polls.length; i--;) {
@ -75,6 +78,12 @@ var requestManager = function() {
poll.uninstall(poll.id); poll.uninstall(poll.id);
}); });
polls = []; polls = [];
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
poll();
}; };
var poll = function () { var poll = function () {
@ -85,7 +94,7 @@ var requestManager = function() {
} }
data.callback(result); data.callback(result);
}); });
setTimeout(poll, c.ETH_POLLING_TIMEOUT); timeout = setTimeout(poll, c.ETH_POLLING_TIMEOUT);
}; };
poll(); poll();

1
libjsqrc/ethereumjs/lib/utils.js

@ -107,6 +107,7 @@ var filterEvents = function (json) {
/// TODO: use BigNumber.js to parse int /// TODO: use BigNumber.js to parse int
/// TODO: add tests for it! /// TODO: add tests for it!
var toEth = function (str) { var toEth = function (str) {
/*jshint maxcomplexity:7 */
var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str; var val = typeof str === "string" ? str.indexOf('0x') === 0 ? parseInt(str.substr(2), 16) : parseInt(str) : str;
var unit = 0; var unit = 0;
var units = c.ETH_UNITS; var units = c.ETH_UNITS;

4
libjsqrc/ethereumjs/lib/web3.js

@ -80,12 +80,14 @@ var setupProperties = function (obj, properties) {
}); });
}; };
/*jshint maxparams:4 */
var startPolling = function (method, id, callback, uninstall) { var startPolling = function (method, id, callback, uninstall) {
web3.manager.startPolling({ web3.manager.startPolling({
method: method, method: method,
params: [id] params: [id]
}, id, callback, uninstall); }, id, callback, uninstall);
}; };
/*jshint maxparams:3 */
var stopPolling = function (id) { var stopPolling = function (id) {
web3.manager.stopPolling(id); web3.manager.stopPolling(id);
@ -143,12 +145,14 @@ var web3 = {
/// @param indexed is optional, this is an object with optional event indexed params /// @param indexed is optional, this is an object with optional event indexed params
/// @param options is optional, this is an object with optional event options ('max'...) /// @param options is optional, this is an object with optional event options ('max'...)
/// TODO: fix it, 4 params? no way /// TODO: fix it, 4 params? no way
/*jshint maxparams:4 */
watch: function (fil, indexed, options, formatter) { watch: function (fil, indexed, options, formatter) {
if (fil._isEvent) { if (fil._isEvent) {
return fil(indexed, options); return fil(indexed, options);
} }
return filter(fil, ethWatch, formatter); return filter(fil, ethWatch, formatter);
} }
/*jshint maxparams:3 */
}, },
/// db object prototype /// db object prototype

1
libjsqrc/ethereumjs/package.json

@ -9,7 +9,6 @@
}, },
"dependencies": { "dependencies": {
"bignumber.js": ">=2.0.0", "bignumber.js": ">=2.0.0",
"ws": "*",
"xmlhttprequest": "*" "xmlhttprequest": "*"
}, },
"devDependencies": { "devDependencies": {

58
libsolidity/AST.cpp

@ -209,6 +209,33 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::getIn
return *m_interfaceFunctionList; return *m_interfaceFunctionList;
} }
vector<Declaration const*> const& ContractDefinition::getInheritableMembers() const
{
if (!m_inheritableMembers)
{
set<string> memberSeen;
m_inheritableMembers.reset(new vector<Declaration const*>());
auto addInheritableMember = [&](Declaration const* _decl)
{
if (memberSeen.count(_decl->getName()) == 0 && _decl->isVisibleInDerivedContracts())
{
memberSeen.insert(_decl->getName());
m_inheritableMembers->push_back(_decl);
}
};
for (ASTPointer<FunctionDefinition> const& f: getDefinedFunctions())
addInheritableMember(f.get());
for (ASTPointer<VariableDeclaration> const& v: getStateVariables())
addInheritableMember(v.get());
for (ASTPointer<StructDefinition> const& s: getDefinedStructs())
addInheritableMember(s.get());
}
return *m_inheritableMembers;
}
TypePointer EnumValue::getType(ContractDefinition const*) const TypePointer EnumValue::getType(ContractDefinition const*) const
{ {
EnumDefinition const* parentDef = dynamic_cast<EnumDefinition const*>(getScope()); EnumDefinition const* parentDef = dynamic_cast<EnumDefinition const*>(getScope());
@ -281,7 +308,9 @@ void FunctionDefinition::checkTypeRequirements()
if (!var->getType()->canLiveOutsideStorage()) if (!var->getType()->canLiveOutsideStorage())
BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage.")); BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage."));
for (ASTPointer<ModifierInvocation> const& modifier: m_functionModifiers) for (ASTPointer<ModifierInvocation> const& modifier: m_functionModifiers)
modifier->checkTypeRequirements(); modifier->checkTypeRequirements(isConstructor() ?
dynamic_cast<ContractDefinition const&>(*getScope()).getBaseContracts() :
vector<ASTPointer<InheritanceSpecifier>>());
m_body->checkTypeRequirements(); m_body->checkTypeRequirements();
} }
@ -324,19 +353,34 @@ void ModifierDefinition::checkTypeRequirements()
m_body->checkTypeRequirements(); m_body->checkTypeRequirements();
} }
void ModifierInvocation::checkTypeRequirements() void ModifierInvocation::checkTypeRequirements(vector<ASTPointer<InheritanceSpecifier>> const& _bases)
{ {
m_modifierName->checkTypeRequirements(); m_modifierName->checkTypeRequirements();
for (ASTPointer<Expression> const& argument: m_arguments) for (ASTPointer<Expression> const& argument: m_arguments)
argument->checkTypeRequirements(); argument->checkTypeRequirements();
ModifierDefinition const* modifier = dynamic_cast<ModifierDefinition const*>(m_modifierName->getReferencedDeclaration()); auto declaration = m_modifierName->getReferencedDeclaration();
solAssert(modifier, "Function modifier not found."); vector<ASTPointer<VariableDeclaration>> emptyParameterList;
vector<ASTPointer<VariableDeclaration>> const& parameters = modifier->getParameters(); vector<ASTPointer<VariableDeclaration>> const* parameters = nullptr;
if (parameters.size() != m_arguments.size()) if (auto modifier = dynamic_cast<ModifierDefinition const*>(declaration))
parameters = &modifier->getParameters();
else
// check parameters for Base constructors
for (auto const& base: _bases)
if (declaration == base->getName()->getReferencedDeclaration())
{
if (auto referencedConstructor = dynamic_cast<ContractDefinition const&>(*declaration).getConstructor())
parameters = &referencedConstructor->getParameters();
else
parameters = &emptyParameterList;
break;
}
if (!parameters)
BOOST_THROW_EXCEPTION(createTypeError("Referenced declaration is neither modifier nor base class."));
if (parameters->size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for modifier invocation.")); BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for modifier invocation."));
for (size_t i = 0; i < m_arguments.size(); ++i) for (size_t i = 0; i < m_arguments.size(); ++i)
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType())) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*(*parameters)[i]->getType()))
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in modifier invocation.")); BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in modifier invocation."));
} }

16
libsolidity/AST.h

@ -144,7 +144,7 @@ public:
Visibility getVisibility() const { return m_visibility == Visibility::Default ? getDefaultVisibility() : m_visibility; } Visibility getVisibility() const { return m_visibility == Visibility::Default ? getDefaultVisibility() : m_visibility; }
bool isPublic() const { return getVisibility() >= Visibility::Public; } bool isPublic() const { return getVisibility() >= Visibility::Public; }
bool isVisibleInContract() const { return getVisibility() != Visibility::External; } bool isVisibleInContract() const { return getVisibility() != Visibility::External; }
bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Internal; } virtual bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Internal; }
/// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope.
/// Available only after name and type resolution step. /// Available only after name and type resolution step.
@ -247,6 +247,9 @@ public:
/// as intended for use by the ABI. /// as intended for use by the ABI.
std::map<FixedHash<4>, FunctionTypePointer> getInterfaceFunctions() const; std::map<FixedHash<4>, FunctionTypePointer> getInterfaceFunctions() const;
/// @returns a list of the inheritable members of this contract
std::vector<Declaration const*> const& getInheritableMembers() const;
/// List of all (direct and indirect) base contracts in order from derived to base, including /// List of all (direct and indirect) base contracts in order from derived to base, including
/// the contract itself. Available after name resolution /// the contract itself. Available after name resolution
std::vector<ContractDefinition const*> const& getLinearizedBaseContracts() const { return m_linearizedBaseContracts; } std::vector<ContractDefinition const*> const& getLinearizedBaseContracts() const { return m_linearizedBaseContracts; }
@ -273,6 +276,7 @@ private:
std::vector<ContractDefinition const*> m_linearizedBaseContracts; std::vector<ContractDefinition const*> m_linearizedBaseContracts;
mutable std::unique_ptr<std::vector<std::pair<FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList; mutable std::unique_ptr<std::vector<std::pair<FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList;
mutable std::unique_ptr<std::vector<ASTPointer<EventDefinition>>> m_interfaceEvents; mutable std::unique_ptr<std::vector<ASTPointer<EventDefinition>>> m_interfaceEvents;
mutable std::unique_ptr<std::vector<Declaration const*>> m_inheritableMembers;
}; };
class InheritanceSpecifier: public ASTNode class InheritanceSpecifier: public ASTNode
@ -405,6 +409,11 @@ public:
ASTPointer<ParameterList> const& getReturnParameterList() const { return m_returnParameters; } ASTPointer<ParameterList> const& getReturnParameterList() const { return m_returnParameters; }
Block const& getBody() const { return *m_body; } Block const& getBody() const { return *m_body; }
virtual bool isVisibleInDerivedContracts() const override
{
return !isConstructor() && !getName().empty() && isVisibleInContract() &&
getVisibility() >= Visibility::Internal;
}
virtual TypePointer getType(ContractDefinition const*) const override; virtual TypePointer getType(ContractDefinition const*) const override;
/// Checks that all parameters have allowed types and calls checkTypeRequirements on the body. /// Checks that all parameters have allowed types and calls checkTypeRequirements on the body.
@ -501,7 +510,7 @@ private:
}; };
/** /**
* Invocation/usage of a modifier in a function header. * Invocation/usage of a modifier in a function header or a base constructor call.
*/ */
class ModifierInvocation: public ASTNode class ModifierInvocation: public ASTNode
{ {
@ -516,7 +525,8 @@ public:
ASTPointer<Identifier> const& getName() const { return m_modifierName; } ASTPointer<Identifier> const& getName() const { return m_modifierName; }
std::vector<ASTPointer<Expression>> const& getArguments() const { return m_arguments; } std::vector<ASTPointer<Expression>> const& getArguments() const { return m_arguments; }
void checkTypeRequirements(); /// @param _bases is the list of base contracts for base constructor calls. For modifiers an empty vector should be passed.
void checkTypeRequirements(std::vector<ASTPointer<InheritanceSpecifier>> const& _bases);
private: private:
ASTPointer<Identifier> m_modifierName; ASTPointer<Identifier> m_modifierName;

304
libsolidity/ArrayUtils.cpp

@ -0,0 +1,304 @@
/*
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/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2015
* Code generation utils that handle arrays.
*/
#include <libsolidity/ArrayUtils.h>
#include <libevmcore/Instruction.h>
#include <libsolidity/CompilerContext.h>
#include <libsolidity/CompilerUtils.h>
#include <libsolidity/Types.h>
#include <libsolidity/Utils.h>
#include <libsolidity/LValue.h>
using namespace std;
using namespace dev;
using namespace solidity;
void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const
{
// stack layout: [source_ref] target_ref (top)
// need to leave target_ref on the stack at the end
solAssert(_targetType.getLocation() == ArrayType::Location::Storage, "");
IntegerType uint256(256);
Type const* targetBaseType = _targetType.isByteArray() ? &uint256 : &(*_targetType.getBaseType());
Type const* sourceBaseType = _sourceType.isByteArray() ? &uint256 : &(*_sourceType.getBaseType());
switch (_sourceType.getLocation())
{
case ArrayType::Location::CallData:
{
solAssert(_targetType.isByteArray(), "Non byte arrays not yet implemented here.");
solAssert(_sourceType.isByteArray(), "Non byte arrays not yet implemented here.");
// This also assumes that after "length" we only have zeros, i.e. it cannot be used to
// slice a byte array from calldata.
// stack: source_offset source_len target_ref
// fetch old length and convert to words
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
convertLengthToSize(_targetType);
// stack here: source_offset source_len target_ref target_length_words
// actual array data is stored at SHA3(storage_offset)
m_context << eth::Instruction::DUP2;
CompilerUtils(m_context).computeHashStatic();
// compute target_data_end
m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2 << eth::Instruction::ADD
<< eth::Instruction::SWAP1;
// stack here: source_offset source_len target_ref target_data_end target_data_ref
// store length (in bytes)
m_context << eth::Instruction::DUP4 << eth::Instruction::DUP1 << eth::Instruction::DUP5
<< eth::Instruction::SSTORE;
// jump to end if length is zero
m_context << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
// store start offset
m_context << eth::Instruction::DUP5;
// stack now: source_offset source_len target_ref target_data_end target_data_ref calldata_offset
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart
// copy from calldata and store
<< eth::Instruction::DUP1 << eth::Instruction::CALLDATALOAD
<< eth::Instruction::DUP3 << eth::Instruction::SSTORE
// increment target_data_ref by 1
<< eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD
// increment calldata_offset by 32
<< eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD
// check for loop condition
<< eth::Instruction::DUP1 << eth::Instruction::DUP6 << eth::Instruction::GT;
m_context.appendConditionalJumpTo(copyLoopStart);
m_context << eth::Instruction::POP;
m_context << copyLoopEnd;
// now clear leftover bytes of the old value
// stack now: source_offset source_len target_ref target_data_end target_data_ref
clearStorageLoop(IntegerType(256));
// stack now: source_offset source_len target_ref target_data_end
m_context << eth::Instruction::POP << eth::Instruction::SWAP2
<< eth::Instruction::POP << eth::Instruction::POP;
break;
}
case ArrayType::Location::Storage:
{
// this copies source to target and also clears target if it was larger
solAssert(sourceBaseType->getStorageSize() == targetBaseType->getStorageSize(),
"Copying with different storage sizes not yet implemented.");
// stack: source_ref target_ref
// store target_ref
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;
// stack: target_ref source_ref target_ref
// fetch lengthes
retrieveLength(_targetType);
m_context << eth::Instruction::SWAP2;
// stack: target_ref target_len target_ref source_ref
retrieveLength(_sourceType);
// stack: target_ref target_len target_ref source_ref source_len
if (_targetType.isDynamicallySized())
// store new target length
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::SSTORE;
// compute hashes (data positions)
m_context << eth::Instruction::SWAP2;
if (_targetType.isDynamicallySized())
CompilerUtils(m_context).computeHashStatic();
m_context << eth::Instruction::SWAP1;
if (_sourceType.isDynamicallySized())
CompilerUtils(m_context).computeHashStatic();
// stack: target_ref target_len source_len target_data_pos source_data_pos
m_context << eth::Instruction::DUP4;
convertLengthToSize(_sourceType);
m_context << eth::Instruction::DUP4;
convertLengthToSize(_sourceType);
// stack: target_ref target_len source_len target_data_pos source_data_pos target_size source_size
// @todo we might be able to go without a third counter
m_context << u256(0);
// stack: target_ref target_len source_len target_data_pos source_data_pos target_size source_size counter
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart;
// check for loop condition
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3
<< eth::Instruction::GT << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
// copy
m_context << eth::Instruction::DUP4 << eth::Instruction::DUP2 << eth::Instruction::ADD;
StorageItem(m_context, *sourceBaseType).retrieveValue(SourceLocation(), true);
m_context << eth::dupInstruction(5 + sourceBaseType->getSizeOnStack())
<< eth::dupInstruction(2 + sourceBaseType->getSizeOnStack()) << eth::Instruction::ADD;
StorageItem(m_context, *targetBaseType).storeValue(*sourceBaseType, SourceLocation(), true);
// increment
m_context << targetBaseType->getStorageSize() << eth::Instruction::ADD;
m_context.appendJumpTo(copyLoopStart);
m_context << copyLoopEnd;
// zero-out leftovers in target
// stack: target_ref target_len source_len target_data_pos source_data_pos target_size source_size counter
// add counter to target_data_pos
m_context << eth::Instruction::DUP5 << eth::Instruction::ADD
<< eth::Instruction::SWAP5 << eth::Instruction::POP;
// stack: target_ref target_len target_data_pos_updated target_data_pos source_data_pos target_size source_size
// add size to target_data_pos to get target_data_end
m_context << eth::Instruction::POP << eth::Instruction::DUP3 << eth::Instruction::ADD
<< eth::Instruction::SWAP4
<< eth::Instruction::POP << eth::Instruction::POP << eth::Instruction::POP;
// stack: target_ref target_data_end target_data_pos_updated
clearStorageLoop(*targetBaseType);
m_context << eth::Instruction::POP;
break;
}
default:
solAssert(false, "Given byte array location not implemented.");
}
}
void ArrayUtils::clearArray(ArrayType const& _type) const
{
solAssert(_type.getLocation() == ArrayType::Location::Storage, "");
if (_type.isDynamicallySized())
clearDynamicArray(_type);
else if (_type.getLength() == 0)
m_context << eth::Instruction::POP;
else if (_type.getLength() < 5) // unroll loop for small arrays @todo choose a good value
{
for (unsigned i = 1; i < _type.getLength(); ++i)
{
StorageItem(m_context, *_type.getBaseType()).setToZero(SourceLocation(), false);
m_context << u256(_type.getBaseType()->getStorageSize()) << eth::Instruction::ADD;
}
StorageItem(m_context, *_type.getBaseType()).setToZero(SourceLocation(), true);
}
else
{
m_context
<< eth::Instruction::DUP1 << u256(_type.getLength())
<< u256(_type.getBaseType()->getStorageSize())
<< eth::Instruction::MUL << eth::Instruction::ADD << eth::Instruction::SWAP1;
clearStorageLoop(*_type.getBaseType());
m_context << eth::Instruction::POP;
}
}
void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
{
solAssert(_type.getLocation() == ArrayType::Location::Storage, "");
solAssert(_type.isDynamicallySized(), "");
// fetch length
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
// set length to zero
m_context << u256(0) << eth::Instruction::DUP3 << eth::Instruction::SSTORE;
// stack: ref old_length
convertLengthToSize(_type);
// compute data positions
m_context << eth::Instruction::SWAP1;
CompilerUtils(m_context).computeHashStatic();
// stack: len data_pos (len is in slots for byte array and in items for other arrays)
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD
<< eth::Instruction::SWAP1;
// stack: data_pos_end data_pos
if (_type.isByteArray())
clearStorageLoop(IntegerType(256));
else
clearStorageLoop(*_type.getBaseType());
// cleanup
m_context << eth::Instruction::POP;
}
void ArrayUtils::resizeDynamicArray(const ArrayType& _type) const
{
solAssert(_type.getLocation() == ArrayType::Location::Storage, "");
solAssert(_type.isDynamicallySized(), "");
eth::AssemblyItem resizeEnd = m_context.newTag();
// stack: ref new_length
// fetch old length
m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD;
// stack: ref new_length old_length
// store new length
m_context << eth::Instruction::DUP2 << eth::Instruction::DUP4 << eth::Instruction::SSTORE;
// skip if size is not reduced
m_context << eth::Instruction::DUP2 << eth::Instruction::DUP2
<< eth::Instruction::ISZERO << eth::Instruction::GT;
m_context.appendConditionalJumpTo(resizeEnd);
// size reduced, clear the end of the array
// stack: ref new_length old_length
convertLengthToSize(_type);
m_context << eth::Instruction::DUP2;
convertLengthToSize(_type);
// stack: ref new_length old_size new_size
// compute data positions
m_context << eth::Instruction::DUP4;
CompilerUtils(m_context).computeHashStatic();
// stack: ref new_length old_size new_size data_pos
m_context << eth::Instruction::SWAP2 << eth::Instruction::DUP3 << eth::Instruction::ADD;
// stack: ref new_length data_pos new_size delete_end
m_context << eth::Instruction::SWAP2 << eth::Instruction::ADD;
// stack: ref new_length delete_end delete_start
if (_type.isByteArray())
clearStorageLoop(IntegerType(256));
else
clearStorageLoop(*_type.getBaseType());
m_context << resizeEnd;
// cleanup
m_context << eth::Instruction::POP << eth::Instruction::POP << eth::Instruction::POP;
}
void ArrayUtils::clearStorageLoop(Type const& _type) const
{
// stack: end_pos pos
eth::AssemblyItem loopStart = m_context.newTag();
m_context << loopStart;
// check for loop condition
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3
<< eth::Instruction::GT << eth::Instruction::ISZERO;
eth::AssemblyItem zeroLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(zeroLoopEnd);
// delete
StorageItem(m_context, _type).setToZero(SourceLocation(), false);
// increment
m_context << u256(1) << eth::Instruction::ADD;
m_context.appendJumpTo(loopStart);
// cleanup
m_context << zeroLoopEnd;
m_context << eth::Instruction::POP;
}
void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType) const
{
if (_arrayType.isByteArray())
m_context << u256(31) << eth::Instruction::ADD
<< u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
else if (_arrayType.getBaseType()->getStorageSize() > 1)
m_context << _arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL;
}
void ArrayUtils::retrieveLength(ArrayType const& _arrayType) const
{
if (_arrayType.isDynamicallySized())
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
else
m_context << _arrayType.getLength();
}

78
libsolidity/ArrayUtils.h

@ -0,0 +1,78 @@
/*
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/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2015
* Code generation utils that handle arrays.
*/
#pragma once
namespace dev
{
namespace solidity
{
class CompilerContext;
class Type;
class ArrayType;
/**
* Class that provides code generation for handling arrays.
*/
class ArrayUtils
{
public:
ArrayUtils(CompilerContext& _context): m_context(_context) {}
/// Copies an array to an array in storage. The arrays can be of different types only if
/// their storage representation is the same.
/// Stack pre: [source_reference] target_reference
/// Stack post: target_reference
void copyArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const;
/// Clears the given dynamic or static array.
/// Stack pre: reference
/// Stack post:
void clearArray(ArrayType const& _type) const;
/// Clears the length and data elements of the array referenced on the stack.
/// Stack pre: reference
/// Stack post:
void clearDynamicArray(ArrayType const& _type) const;
/// Changes the size of a dynamic array and clears the tail if it is shortened.
/// Stack pre: reference new_length
/// Stack post:
void resizeDynamicArray(ArrayType const& _type) const;
/// Appends a loop that clears a sequence of storage slots of the given type (excluding end).
/// Stack pre: end_ref start_ref
/// Stack post: end_ref
void clearStorageLoop(Type const& _type) const;
/// Converts length to size (multiplies by size on stack), rounds up for byte arrays.
/// Stack pre: length
/// Stack post: size
void convertLengthToSize(ArrayType const& _arrayType) const;
/// Retrieves the length (number of elements) of the array ref on the stack. This also
/// works for statically-sized arrays.
/// Stack pre: reference
/// Stack post: reference length
void retrieveLength(ArrayType const& _arrayType) const;
private:
CompilerContext& m_context;
};
}
}

108
libsolidity/Compiler.cpp

@ -58,7 +58,10 @@ void Compiler::compileContract(ContractDefinition const& _contract,
while (!functions.empty()) while (!functions.empty())
{ {
for (Declaration const* function: functions) for (Declaration const* function: functions)
{
m_context.setStackOffset(0);
function->accept(*this); function->accept(*this);
}
functions = m_context.getFunctionsWithoutCode(); functions = m_context.getFunctionsWithoutCode();
} }
@ -79,37 +82,38 @@ void Compiler::initializeContext(ContractDefinition const& _contract,
void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext) void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext)
{ {
// arguments for base constructors, filled in derived-to-base order
map<ContractDefinition const*, vector<ASTPointer<Expression>> const*> baseArguments;
// Determine the arguments that are used for the base constructors. // Determine the arguments that are used for the base constructors.
std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts(); std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts();
for (ContractDefinition const* contract: bases) for (ContractDefinition const* contract: bases)
{
if (FunctionDefinition const* constructor = contract->getConstructor())
for (auto const& modifier: constructor->getModifiers())
{
auto baseContract = dynamic_cast<ContractDefinition const*>(
modifier->getName()->getReferencedDeclaration());
if (baseContract)
if (m_baseArguments.count(baseContract->getConstructor()) == 0)
m_baseArguments[baseContract->getConstructor()] = &modifier->getArguments();
}
for (ASTPointer<InheritanceSpecifier> const& base: contract->getBaseContracts()) for (ASTPointer<InheritanceSpecifier> const& base: contract->getBaseContracts())
{ {
ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>( ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>(
base->getName()->getReferencedDeclaration()); base->getName()->getReferencedDeclaration());
solAssert(baseContract, ""); solAssert(baseContract, "");
if (baseArguments.count(baseContract) == 0)
baseArguments[baseContract] = &base->getArguments();
}
// Call constructors in base-to-derived order. if (m_baseArguments.count(baseContract->getConstructor()) == 0)
// The Constructor for the most derived contract is called later. m_baseArguments[baseContract->getConstructor()] = &base->getArguments();
for (unsigned i = 1; i < bases.size(); i++) }
{
ContractDefinition const* base = bases[bases.size() - i];
solAssert(base, "");
initializeStateVariables(*base);
FunctionDefinition const* baseConstructor = base->getConstructor();
if (!baseConstructor)
continue;
solAssert(baseArguments[base], "");
appendBaseConstructorCall(*baseConstructor, *baseArguments[base]);
} }
initializeStateVariables(_contract); // Initialization of state variables in base-to-derived order.
if (_contract.getConstructor()) for (ContractDefinition const* contract: boost::adaptors::reverse(bases))
appendConstructorCall(*_contract.getConstructor()); initializeStateVariables(*contract);
if (FunctionDefinition const* constructor = _contract.getConstructor())
appendConstructor(*constructor);
else if (auto c = m_context.getNextConstructor(_contract))
appendBaseConstructor(*c);
eth::AssemblyItem sub = m_context.addSubroutine(_runtimeContext.getAssembly()); eth::AssemblyItem sub = m_context.addSubroutine(_runtimeContext.getAssembly());
// stack contains sub size // stack contains sub size
@ -126,22 +130,23 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
} }
} }
void Compiler::appendBaseConstructorCall(FunctionDefinition const& _constructor, void Compiler::appendBaseConstructor(FunctionDefinition const& _constructor)
vector<ASTPointer<Expression>> const& _arguments)
{ {
CompilerContext::LocationSetter locationSetter(m_context, &_constructor); CompilerContext::LocationSetter locationSetter(m_context, &_constructor);
FunctionType constructorType(_constructor); FunctionType constructorType(_constructor);
eth::AssemblyItem returnLabel = m_context.pushNewTag(); if (!constructorType.getParameterTypes().empty())
for (unsigned i = 0; i < _arguments.size(); ++i) {
compileExpression(*_arguments[i], constructorType.getParameterTypes()[i]); std::vector<ASTPointer<Expression>> const* arguments = m_baseArguments[&_constructor];
m_context.appendJumpTo(m_context.getFunctionEntryLabel(_constructor)); solAssert(arguments, "");
m_context << returnLabel; for (unsigned i = 0; i < arguments->size(); ++i)
compileExpression(*(arguments->at(i)), constructorType.getParameterTypes()[i]);
}
_constructor.accept(*this);
} }
void Compiler::appendConstructorCall(FunctionDefinition const& _constructor) void Compiler::appendConstructor(FunctionDefinition const& _constructor)
{ {
CompilerContext::LocationSetter locationSetter(m_context, &_constructor); CompilerContext::LocationSetter locationSetter(m_context, &_constructor);
eth::AssemblyItem returnTag = m_context.pushNewTag();
// copy constructor arguments from code to memory and then to stack, they are supplied after the actual program // copy constructor arguments from code to memory and then to stack, they are supplied after the actual program
unsigned argumentSize = 0; unsigned argumentSize = 0;
for (ASTPointer<VariableDeclaration> const& var: _constructor.getParameters()) for (ASTPointer<VariableDeclaration> const& var: _constructor.getParameters())
@ -155,8 +160,7 @@ void Compiler::appendConstructorCall(FunctionDefinition const& _constructor)
m_context << eth::Instruction::CODECOPY; m_context << eth::Instruction::CODECOPY;
appendCalldataUnpacker(FunctionType(_constructor).getParameterTypes(), true); appendCalldataUnpacker(FunctionType(_constructor).getParameterTypes(), true);
} }
m_context.appendJumpTo(m_context.getFunctionEntryLabel(_constructor)); _constructor.accept(*this);
m_context << returnTag;
} }
void Compiler::appendFunctionSelector(ContractDefinition const& _contract) void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
@ -296,28 +300,36 @@ bool Compiler::visit(FunctionDefinition const& _function)
// although note that this reduces the size of the visible stack // although note that this reduces the size of the visible stack
m_context.startFunction(_function); m_context.startFunction(_function);
m_returnTag = m_context.newTag();
m_breakTags.clear();
m_continueTags.clear();
m_stackCleanupForReturn = 0;
m_currentFunction = &_function;
m_modifierDepth = 0;
// stack upon entry: [return address] [arg0] [arg1] ... [argn] // stack upon entry: [return address] [arg0] [arg1] ... [argn]
// reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp] // reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp]
unsigned parametersSize = CompilerUtils::getSizeOnStack(_function.getParameters()); unsigned parametersSize = CompilerUtils::getSizeOnStack(_function.getParameters());
m_context.adjustStackOffset(parametersSize); if (!_function.isConstructor())
// adding 1 for return address.
m_context.adjustStackOffset(parametersSize + 1);
for (ASTPointer<VariableDeclaration const> const& variable: _function.getParameters()) for (ASTPointer<VariableDeclaration const> const& variable: _function.getParameters())
{ {
m_context.addVariable(*variable, parametersSize); m_context.addVariable(*variable, parametersSize);
parametersSize -= variable->getType()->getSizeOnStack(); parametersSize -= variable->getType()->getSizeOnStack();
} }
for (ASTPointer<VariableDeclaration const> const& variable: _function.getReturnParameters()) for (ASTPointer<VariableDeclaration const> const& variable: _function.getReturnParameters())
m_context.addAndInitializeVariable(*variable); m_context.addAndInitializeVariable(*variable);
for (VariableDeclaration const* localVariable: _function.getLocalVariables()) for (VariableDeclaration const* localVariable: _function.getLocalVariables())
m_context.addAndInitializeVariable(*localVariable); m_context.addAndInitializeVariable(*localVariable);
if (_function.isConstructor())
if (auto c = m_context.getNextConstructor(dynamic_cast<ContractDefinition const&>(*_function.getScope())))
appendBaseConstructor(*c);
m_returnTag = m_context.newTag();
m_breakTags.clear();
m_continueTags.clear();
m_stackCleanupForReturn = 0;
m_currentFunction = &_function;
m_modifierDepth = 0;
appendModifierOrFunctionCode(); appendModifierOrFunctionCode();
m_context << m_returnTag; m_context << m_returnTag;
@ -352,8 +364,14 @@ bool Compiler::visit(FunctionDefinition const& _function)
} }
//@todo assert that everything is in place now //@todo assert that everything is in place now
m_context << eth::Instruction::JUMP; for (ASTPointer<VariableDeclaration const> const& variable: _function.getParameters() + _function.getReturnParameters())
m_context.removeVariable(*variable);
for (VariableDeclaration const* localVariable: _function.getLocalVariables())
m_context.removeVariable(*localVariable);
m_context.adjustStackOffset(-c_returnValuesSize);
if (!_function.isConstructor())
m_context << eth::Instruction::JUMP;
return false; return false;
} }
@ -515,6 +533,16 @@ void Compiler::appendModifierOrFunctionCode()
else else
{ {
ASTPointer<ModifierInvocation> const& modifierInvocation = m_currentFunction->getModifiers()[m_modifierDepth]; ASTPointer<ModifierInvocation> const& modifierInvocation = m_currentFunction->getModifiers()[m_modifierDepth];
// constructor call should be excluded
if (dynamic_cast<ContractDefinition const*>(modifierInvocation->getName()->getReferencedDeclaration()))
{
++m_modifierDepth;
appendModifierOrFunctionCode();
--m_modifierDepth;
return;
}
ModifierDefinition const& modifier = m_context.getFunctionModifier(modifierInvocation->getName()->getName()); ModifierDefinition const& modifier = m_context.getFunctionModifier(modifierInvocation->getName()->getName());
CompilerContext::LocationSetter locationSetter(m_context, &modifier); CompilerContext::LocationSetter locationSetter(m_context, &modifier);
solAssert(modifier.getParameters().size() == modifierInvocation->getArguments().size(), ""); solAssert(modifier.getParameters().size() == modifierInvocation->getArguments().size(), "");

7
libsolidity/Compiler.h

@ -55,9 +55,8 @@ private:
/// Adds the code that is run at creation time. Should be run after exchanging the run-time context /// Adds the code that is run at creation time. Should be run after exchanging the run-time context
/// with a new and initialized context. Adds the constructor code. /// with a new and initialized context. Adds the constructor code.
void packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext); void packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext);
void appendBaseConstructorCall(FunctionDefinition const& _constructor, void appendBaseConstructor(FunctionDefinition const& _constructor);
std::vector<ASTPointer<Expression>> const& _arguments); void appendConstructor(FunctionDefinition const& _constructor);
void appendConstructorCall(FunctionDefinition const& _constructor);
void appendFunctionSelector(ContractDefinition const& _contract); void appendFunctionSelector(ContractDefinition const& _contract);
/// Creates code that unpacks the arguments for the given function represented by a vector of TypePointers. /// Creates code that unpacks the arguments for the given function represented by a vector of TypePointers.
/// From memory if @a _fromMemory is true, otherwise from call data. /// From memory if @a _fromMemory is true, otherwise from call data.
@ -94,6 +93,8 @@ private:
unsigned m_modifierDepth = 0; unsigned m_modifierDepth = 0;
FunctionDefinition const* m_currentFunction; FunctionDefinition const* m_currentFunction;
unsigned m_stackCleanupForReturn; ///< this number of stack elements need to be removed before jump to m_returnTag unsigned m_stackCleanupForReturn; ///< this number of stack elements need to be removed before jump to m_returnTag
// arguments for base constructors, filled in derived-to-base order
std::map<FunctionDefinition const*, std::vector<ASTPointer<Expression>> const*> m_baseArguments;
}; };
} }

33
libsolidity/CompilerContext.cpp

@ -51,8 +51,6 @@ void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
void CompilerContext::startFunction(Declaration const& _function) void CompilerContext::startFunction(Declaration const& _function)
{ {
m_functionsWithCode.insert(&_function); m_functionsWithCode.insert(&_function);
m_localVariables.clear();
m_asm.setDeposit(0);
*this << getFunctionEntryLabel(_function); *this << getFunctionEntryLabel(_function);
} }
@ -63,6 +61,12 @@ void CompilerContext::addVariable(VariableDeclaration const& _declaration,
m_localVariables[&_declaration] = unsigned(m_asm.deposit()) - _offsetToCurrent; m_localVariables[&_declaration] = unsigned(m_asm.deposit()) - _offsetToCurrent;
} }
void CompilerContext::removeVariable(VariableDeclaration const& _declaration)
{
solAssert(m_localVariables.count(&_declaration), "");
m_localVariables.erase(&_declaration);
}
void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration) void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration)
{ {
LocationSetter locationSetter(*this, &_declaration); LocationSetter locationSetter(*this, &_declaration);
@ -110,11 +114,8 @@ eth::AssemblyItem CompilerContext::getVirtualFunctionEntryLabel(FunctionDefiniti
eth::AssemblyItem CompilerContext::getSuperFunctionEntryLabel(string const& _name, ContractDefinition const& _base) eth::AssemblyItem CompilerContext::getSuperFunctionEntryLabel(string const& _name, ContractDefinition const& _base)
{ {
// search for first contract after _base auto it = getSuperContract(_base);
solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); for (; it != m_inheritanceHierarchy.end(); ++it)
auto it = find(m_inheritanceHierarchy.begin(), m_inheritanceHierarchy.end(), &_base);
solAssert(it != m_inheritanceHierarchy.end(), "Base not found in inheritance hierarchy.");
for (++it; it != m_inheritanceHierarchy.end(); ++it)
for (ASTPointer<FunctionDefinition> const& function: (*it)->getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: (*it)->getDefinedFunctions())
if (!function->isConstructor() && function->getName() == _name) if (!function->isConstructor() && function->getName() == _name)
return getFunctionEntryLabel(*function); return getFunctionEntryLabel(*function);
@ -122,6 +123,16 @@ eth::AssemblyItem CompilerContext::getSuperFunctionEntryLabel(string const& _nam
return m_asm.newTag(); // not reached return m_asm.newTag(); // not reached
} }
FunctionDefinition const* CompilerContext::getNextConstructor(ContractDefinition const& _contract) const
{
vector<ContractDefinition const*>::const_iterator it = getSuperContract(_contract);
for (; it != m_inheritanceHierarchy.end(); ++it)
if ((*it)->getConstructor())
return (*it)->getConstructor();
return nullptr;
}
set<Declaration const*> CompilerContext::getFunctionsWithoutCode() set<Declaration const*> CompilerContext::getFunctionsWithoutCode()
{ {
set<Declaration const*> functions; set<Declaration const*> functions;
@ -201,5 +212,13 @@ CompilerContext& CompilerContext::operator<<(bytes const& _data)
return *this; return *this;
} }
vector<ContractDefinition const*>::const_iterator CompilerContext::getSuperContract(ContractDefinition const& _contract) const
{
solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
auto it = find(m_inheritanceHierarchy.begin(), m_inheritanceHierarchy.end(), &_contract);
solAssert(it != m_inheritanceHierarchy.end(), "Base not found in inheritance hierarchy.");
return ++it;
}
} }
} }

8
libsolidity/CompilerContext.h

@ -43,11 +43,13 @@ public:
void addMagicGlobal(MagicVariableDeclaration const& _declaration); void addMagicGlobal(MagicVariableDeclaration const& _declaration);
void addStateVariable(VariableDeclaration const& _declaration); void addStateVariable(VariableDeclaration const& _declaration);
void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0); void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0);
void removeVariable(VariableDeclaration const& _declaration);
void addAndInitializeVariable(VariableDeclaration const& _declaration); void addAndInitializeVariable(VariableDeclaration const& _declaration);
void setCompiledContracts(std::map<ContractDefinition const*, bytes const*> const& _contracts) { m_compiledContracts = _contracts; } void setCompiledContracts(std::map<ContractDefinition const*, bytes const*> const& _contracts) { m_compiledContracts = _contracts; }
bytes const& getCompiledContract(ContractDefinition const& _contract) const; bytes const& getCompiledContract(ContractDefinition const& _contract) const;
void setStackOffset(int _offset) { m_asm.setDeposit(_offset); }
void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); }
unsigned getStackHeight() const { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); } unsigned getStackHeight() const { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); }
@ -62,6 +64,8 @@ public:
/// @returns the entry label of function with the given name from the most derived class just /// @returns the entry label of function with the given name from the most derived class just
/// above _base in the current inheritance hierarchy. /// above _base in the current inheritance hierarchy.
eth::AssemblyItem getSuperFunctionEntryLabel(std::string const& _name, ContractDefinition const& _base); eth::AssemblyItem getSuperFunctionEntryLabel(std::string const& _name, ContractDefinition const& _base);
FunctionDefinition const* getNextConstructor(ContractDefinition const& _contract) const;
/// @returns the set of functions for which we still need to generate code /// @returns the set of functions for which we still need to generate code
std::set<Declaration const*> getFunctionsWithoutCode(); std::set<Declaration const*> getFunctionsWithoutCode();
/// Resets function specific members, inserts the function entry label and marks the function /// Resets function specific members, inserts the function entry label and marks the function
@ -126,9 +130,11 @@ public:
LocationSetter(CompilerContext& _compilerContext, ASTNode const* _node): LocationSetter(CompilerContext& _compilerContext, ASTNode const* _node):
ScopeGuard(std::bind(&CompilerContext::popVisitedNodes, _compilerContext)) { _compilerContext.pushVisitedNodes(_node); } ScopeGuard(std::bind(&CompilerContext::popVisitedNodes, _compilerContext)) { _compilerContext.pushVisitedNodes(_node); }
}; };
eth::Assembly m_asm;
private: private:
std::vector<ContractDefinition const*>::const_iterator getSuperContract(const ContractDefinition &_contract) const;
eth::Assembly m_asm;
/// Magic global variables like msg, tx or this, distinguished by type. /// Magic global variables like msg, tx or this, distinguished by type.
std::set<Declaration const*> m_magicGlobals; std::set<Declaration const*> m_magicGlobals;
/// Other already compiled contracts to be used in contract creation calls. /// Other already compiled contracts to be used in contract creation calls.

10
libsolidity/CompilerStack.cpp

@ -155,6 +155,16 @@ bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize)
return getBytecode(); return getBytecode();
} }
eth::AssemblyItems const& CompilerStack::getAssemblyItems(string const& _contractName) const
{
return getContract(_contractName).compiler->getAssemblyItems();
}
eth::AssemblyItems const& CompilerStack::getRuntimeAssemblyItems(string const& _contractName) const
{
return getContract(_contractName).compiler->getRuntimeAssemblyItems();
}
bytes const& CompilerStack::getBytecode(string const& _contractName) const bytes const& CompilerStack::getBytecode(string const& _contractName) const
{ {
return getContract(_contractName).bytecode; return getContract(_contractName).bytecode;

18
libsolidity/CompilerStack.h

@ -26,12 +26,22 @@
#include <ostream> #include <ostream>
#include <string> #include <string>
#include <memory> #include <memory>
#include <vector>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h> #include <libdevcore/FixedHash.h>
namespace dev { namespace dev
namespace solidity { {
namespace eth
{
class AssemblyItem;
using AssemblyItems = std::vector<AssemblyItem>;
}
namespace solidity
{
// forward declarations // forward declarations
class Scanner; class Scanner;
@ -85,6 +95,10 @@ public:
bytes const& getBytecode(std::string const& _contractName = "") const; bytes const& getBytecode(std::string const& _contractName = "") const;
/// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor. /// @returns the runtime bytecode for the contract, i.e. the code that is returned by the constructor.
bytes const& getRuntimeBytecode(std::string const& _contractName = "") const; bytes const& getRuntimeBytecode(std::string const& _contractName = "") const;
/// @returns normal contract assembly items
eth::AssemblyItems const& getAssemblyItems(std::string const& _contractName = "") const;
/// @returns runtime contract assembly items
eth::AssemblyItems const& getRuntimeAssemblyItems(std::string const& _contractName = "") const;
/// @returns hash of the runtime bytecode for the contract, i.e. the code that is returned by the constructor. /// @returns hash of the runtime bytecode for the contract, i.e. the code that is returned by the constructor.
dev::h256 getContractCodeHash(std::string const& _contractName = "") const; dev::h256 getContractCodeHash(std::string const& _contractName = "") const;

170
libsolidity/CompilerUtils.cpp

@ -164,134 +164,6 @@ void CompilerUtils::computeHashStatic(Type const& _type, bool _padToWordBoundari
m_context << u256(length) << u256(0) << eth::Instruction::SHA3; m_context << u256(length) << u256(0) << eth::Instruction::SHA3;
} }
void CompilerUtils::copyByteArrayToStorage(
ArrayType const& _targetType, ArrayType const& _sourceType) const
{
// stack layout: [source_ref] target_ref (top)
// need to leave target_ref on the stack at the end
solAssert(_targetType.getLocation() == ArrayType::Location::Storage, "");
solAssert(_targetType.isByteArray(), "Non byte arrays not yet implemented here.");
solAssert(_sourceType.isByteArray(), "Non byte arrays not yet implemented here.");
switch (_sourceType.getLocation())
{
case ArrayType::Location::CallData:
{
// This also assumes that after "length" we only have zeros, i.e. it cannot be used to
// slice a byte array from calldata.
// stack: source_offset source_len target_ref
// fetch old length and convert to words
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
m_context << u256(31) << eth::Instruction::ADD
<< u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
// stack here: source_offset source_len target_ref target_length_words
// actual array data is stored at SHA3(storage_offset)
m_context << eth::Instruction::DUP2;
CompilerUtils(m_context).computeHashStatic();
// compute target_data_end
m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2 << eth::Instruction::ADD
<< eth::Instruction::SWAP1;
// stack here: source_offset source_len target_ref target_data_end target_data_ref
// store length (in bytes)
m_context << eth::Instruction::DUP4 << eth::Instruction::DUP1 << eth::Instruction::DUP5
<< eth::Instruction::SSTORE;
// jump to end if length is zero
m_context << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
// store start offset
m_context << eth::Instruction::DUP5;
// stack now: source_offset source_len target_ref target_data_end target_data_ref calldata_offset
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart
// copy from calldata and store
<< eth::Instruction::DUP1 << eth::Instruction::CALLDATALOAD
<< eth::Instruction::DUP3 << eth::Instruction::SSTORE
// increment target_data_ref by 1
<< eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD
// increment calldata_offset by 32
<< eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD
// check for loop condition
<< eth::Instruction::DUP1 << eth::Instruction::DUP6 << eth::Instruction::GT;
m_context.appendConditionalJumpTo(copyLoopStart);
m_context << eth::Instruction::POP;
m_context << copyLoopEnd;
// now clear leftover bytes of the old value
// stack now: source_offset source_len target_ref target_data_end target_data_ref
clearStorageLoop();
// stack now: source_offset source_len target_ref target_data_end
m_context << eth::Instruction::POP << eth::Instruction::SWAP2
<< eth::Instruction::POP << eth::Instruction::POP;
break;
}
case ArrayType::Location::Storage:
{
// this copies source to target and also clears target if it was larger
// stack: source_ref target_ref
// store target_ref
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;
// fetch lengthes
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP2
<< eth::Instruction::DUP1 << eth::Instruction::SLOAD;
// stack: target_ref target_len_bytes target_ref source_ref source_len_bytes
// store new target length
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::SSTORE;
// compute hashes (data positions)
m_context << eth::Instruction::SWAP2;
CompilerUtils(m_context).computeHashStatic();
m_context << eth::Instruction::SWAP1;
CompilerUtils(m_context).computeHashStatic();
// stack: target_ref target_len_bytes source_len_bytes target_data_pos source_data_pos
// convert lengthes from bytes to storage slots
m_context << u256(31) << u256(32) << eth::Instruction::DUP1 << eth::Instruction::DUP3
<< eth::Instruction::DUP8 << eth::Instruction::ADD << eth::Instruction::DIV
<< eth::Instruction::SWAP2
<< eth::Instruction::DUP6 << eth::Instruction::ADD << eth::Instruction::DIV;
// stack: target_ref target_len_bytes source_len_bytes target_data_pos source_data_pos target_len source_len
// @todo we might be able to go without a third counter
m_context << u256(0);
// stack: target_ref target_len_bytes source_len_bytes target_data_pos source_data_pos target_len source_len counter
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart;
// check for loop condition
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3
<< eth::Instruction::GT << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
// copy
m_context << eth::Instruction::DUP4 << eth::Instruction::DUP2 << eth::Instruction::ADD
<< eth::Instruction::SLOAD
<< eth::Instruction::DUP6 << eth::Instruction::DUP3 << eth::Instruction::ADD
<< eth::Instruction::SSTORE;
// increment
m_context << u256(1) << eth::Instruction::ADD;
m_context.appendJumpTo(copyLoopStart);
m_context << copyLoopEnd;
// zero-out leftovers in target
// stack: target_ref target_len_bytes source_len_bytes target_data_pos source_data_pos target_len source_len counter
// add counter to target_data_pos
m_context << eth::Instruction::DUP5 << eth::Instruction::ADD
<< eth::Instruction::SWAP5 << eth::Instruction::POP;
// stack: target_ref target_len_bytes target_data_pos_updated target_data_pos source_data_pos target_len source_len
// add length to target_data_pos to get target_data_end
m_context << eth::Instruction::POP << eth::Instruction::DUP3 << eth::Instruction::ADD
<< eth::Instruction::SWAP4
<< eth::Instruction::POP << eth::Instruction::POP << eth::Instruction::POP;
// stack: target_ref target_data_end target_data_pos_updated
clearStorageLoop();
m_context << eth::Instruction::POP;
break;
}
default:
solAssert(false, "Given byte array location not implemented.");
}
}
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries) unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
{ {
unsigned _encodedSize = _type.getCalldataEncodedSize(); unsigned _encodedSize = _type.getCalldataEncodedSize();
@ -316,28 +188,6 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
return numBytes; return numBytes;
} }
void CompilerUtils::clearByteArray(ArrayType const& _type) const
{
solAssert(_type.getLocation() == ArrayType::Location::Storage, "");
solAssert(_type.isByteArray(), "Non byte arrays not yet implemented here.");
// fetch length
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
// set length to zero
m_context << u256(0) << eth::Instruction::DUP3 << eth::Instruction::SSTORE;
// convert length from bytes to storage slots
m_context << u256(31) << eth::Instruction::ADD
<< u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
// compute data positions
m_context << eth::Instruction::SWAP1;
CompilerUtils(m_context).computeHashStatic();
// stack: len data_pos
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD
<< eth::Instruction::SWAP1;
clearStorageLoop();
// cleanup
m_context << eth::Instruction::POP;
}
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const
{ {
@ -356,25 +206,5 @@ unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBou
return numBytes; return numBytes;
} }
void CompilerUtils::clearStorageLoop() const
{
// stack: end_pos pos
eth::AssemblyItem loopStart = m_context.newTag();
m_context << loopStart;
// check for loop condition
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3
<< eth::Instruction::GT << eth::Instruction::ISZERO;
eth::AssemblyItem zeroLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(zeroLoopEnd);
// zero out
m_context << u256(0) << eth::Instruction::DUP2 << eth::Instruction::SSTORE;
// increment
m_context << u256(1) << eth::Instruction::ADD;
m_context.appendJumpTo(loopStart);
// cleanup
m_context << zeroLoopEnd;
m_context << eth::Instruction::POP;
}
} }
} }

13
libsolidity/CompilerUtils.h

@ -79,15 +79,6 @@ public:
/// @note Only works for types of fixed size. /// @note Only works for types of fixed size.
void computeHashStatic(Type const& _type = IntegerType(256), bool _padToWordBoundaries = false); void computeHashStatic(Type const& _type = IntegerType(256), bool _padToWordBoundaries = false);
/// Copies a byte array to a byte array in storage.
/// Stack pre: [source_reference] target_reference
/// Stack post: target_reference
void copyByteArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const;
/// Clears the length and data elements of the byte array referenced on the stack.
/// Stack pre: reference
/// Stack post:
void clearByteArray(ArrayType const& _type) const;
/// Bytes we need to the start of call data. /// Bytes we need to the start of call data.
/// - The size in bytes of the function (hash) identifier. /// - The size in bytes of the function (hash) identifier.
static const unsigned int dataStartOffset; static const unsigned int dataStartOffset;
@ -97,10 +88,6 @@ private:
unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const; unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const;
/// Loads type from memory assuming memory offset is on stack top. /// Loads type from memory assuming memory offset is on stack top.
unsigned loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries); unsigned loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries);
/// Appends a loop that clears a sequence of storage slots (excluding end).
/// Stack pre: end_ref start_ref
/// Stack post: end_ref
void clearStorageLoop() const;
CompilerContext& m_context; CompilerContext& m_context;
}; };

8
libsolidity/ExpressionCompiler.cpp

@ -93,7 +93,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
m_context << eth::Instruction::DUP1 m_context << eth::Instruction::DUP1
<< structType->getStorageOffsetOfMember(names[i]) << structType->getStorageOffsetOfMember(names[i])
<< eth::Instruction::ADD; << eth::Instruction::ADD;
StorageItem(m_context, types[i]).retrieveValue(SourceLocation(), true); StorageItem(m_context, *types[i]).retrieveValue(SourceLocation(), true);
solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented."); solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented.");
m_context << eth::Instruction::SWAP1; m_context << eth::Instruction::SWAP1;
retSizeOnStack += types[i]->getSizeOnStack(); retSizeOnStack += types[i]->getSizeOnStack();
@ -104,7 +104,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
{ {
// simple value // simple value
solAssert(accessorType.getReturnParameterTypes().size() == 1, ""); solAssert(accessorType.getReturnParameterTypes().size() == 1, "");
StorageItem(m_context, returnType).retrieveValue(SourceLocation(), true); StorageItem(m_context, *returnType).retrieveValue(SourceLocation(), true);
retSizeOnStack = returnType->getSizeOnStack(); retSizeOnStack = returnType->getSizeOnStack();
} }
solAssert(retSizeOnStack <= 15, "Stack too deep."); solAssert(retSizeOnStack <= 15, "Stack too deep.");
@ -680,7 +680,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
break; break;
case ArrayType::Location::Storage: case ArrayType::Location::Storage:
setLValueToStorageItem(_memberAccess); setLValue<StorageArrayLength>(_memberAccess, type);
break; break;
default: default:
solAssert(false, "Unsupported array location."); solAssert(false, "Unsupported array location.");
@ -1047,7 +1047,7 @@ void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaratio
void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression) void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression)
{ {
setLValue<StorageItem>(_expression, _expression.getType()); setLValue<StorageItem>(_expression, *_expression.getType());
} }
} }

122
libsolidity/LValue.cpp

@ -32,15 +32,14 @@ using namespace solidity;
StackVariable::StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration): StackVariable::StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration):
LValue(_compilerContext, _declaration.getType()), LValue(_compilerContext, *_declaration.getType()),
m_baseStackOffset(m_context.getBaseStackOffsetOfVariable(_declaration)), m_baseStackOffset(m_context.getBaseStackOffsetOfVariable(_declaration)),
m_size(m_dataType->getSizeOnStack()) m_size(m_dataType.getSizeOnStack())
{ {
} }
void StackVariable::retrieveValue(SourceLocation const& _location, bool _remove) const void StackVariable::retrieveValue(SourceLocation const& _location, bool) const
{ {
(void)_remove;
unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset); unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset);
if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory
BOOST_THROW_EXCEPTION(CompilerError() BOOST_THROW_EXCEPTION(CompilerError()
@ -49,9 +48,8 @@ void StackVariable::retrieveValue(SourceLocation const& _location, bool _remove)
m_context << eth::dupInstruction(stackPos + 1); m_context << eth::dupInstruction(stackPos + 1);
} }
void StackVariable::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const void StackVariable::storeValue(Type const&, SourceLocation const& _location, bool _move) const
{ {
(void)_sourceType;
unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1; unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1;
if (stackDiff > 16) if (stackDiff > 16)
BOOST_THROW_EXCEPTION(CompilerError() BOOST_THROW_EXCEPTION(CompilerError()
@ -63,7 +61,7 @@ void StackVariable::storeValue(Type const& _sourceType, SourceLocation const& _l
retrieveValue(_location); retrieveValue(_location);
} }
void StackVariable::setToZero(SourceLocation const& _location) const void StackVariable::setToZero(SourceLocation const& _location, bool) const
{ {
unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset); unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset);
if (stackDiff > 16) if (stackDiff > 16)
@ -77,20 +75,20 @@ void StackVariable::setToZero(SourceLocation const& _location) const
StorageItem::StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration): StorageItem::StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration):
StorageItem(_compilerContext, _declaration.getType()) StorageItem(_compilerContext, *_declaration.getType())
{ {
m_context << m_context.getStorageLocationOfVariable(_declaration); m_context << m_context.getStorageLocationOfVariable(_declaration);
} }
StorageItem::StorageItem(CompilerContext& _compilerContext, TypePointer const& _type): StorageItem::StorageItem(CompilerContext& _compilerContext, Type const& _type):
LValue(_compilerContext, _type) LValue(_compilerContext, _type)
{ {
if (m_dataType->isValueType()) if (m_dataType.isValueType())
{ {
solAssert(m_dataType->getStorageSize() == m_dataType->getSizeOnStack(), ""); solAssert(m_dataType.getStorageSize() == m_dataType.getSizeOnStack(), "");
solAssert(m_dataType->getStorageSize() <= numeric_limits<unsigned>::max(), solAssert(m_dataType.getStorageSize() <= numeric_limits<unsigned>::max(),
"The storage size of " + m_dataType->toString() + " should fit in an unsigned"); "The storage size of " + m_dataType.toString() + " should fit in an unsigned");
m_size = unsigned(m_dataType->getStorageSize()); m_size = unsigned(m_dataType.getStorageSize());
} }
else else
m_size = 0; // unused m_size = 0; // unused
@ -98,7 +96,7 @@ StorageItem::StorageItem(CompilerContext& _compilerContext, TypePointer const& _
void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
{ {
if (!m_dataType->isValueType()) if (!m_dataType.isValueType())
return; // no distinction between value and reference for non-value types return; // no distinction between value and reference for non-value types
if (!_remove) if (!_remove)
m_context << eth::Instruction::DUP1; m_context << eth::Instruction::DUP1;
@ -118,7 +116,7 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const
{ {
// stack layout: value value ... value target_ref // stack layout: value value ... value target_ref
if (m_dataType->isValueType()) if (m_dataType.isValueType())
{ {
if (!_move) // copy values if (!_move) // copy values
{ {
@ -143,20 +141,20 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
} }
else else
{ {
solAssert(_sourceType.getCategory() == m_dataType->getCategory(), solAssert(_sourceType.getCategory() == m_dataType.getCategory(),
"Wrong type conversation for assignment."); "Wrong type conversation for assignment.");
if (m_dataType->getCategory() == Type::Category::Array) if (m_dataType.getCategory() == Type::Category::Array)
{ {
CompilerUtils(m_context).copyByteArrayToStorage( ArrayUtils(m_context).copyArrayToStorage(
dynamic_cast<ArrayType const&>(*m_dataType), dynamic_cast<ArrayType const&>(m_dataType),
dynamic_cast<ArrayType const&>(_sourceType)); dynamic_cast<ArrayType const&>(_sourceType));
if (_move) if (_move)
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
} }
else if (m_dataType->getCategory() == Type::Category::Struct) else if (m_dataType.getCategory() == Type::Category::Struct)
{ {
// stack layout: source_ref target_ref // stack layout: source_ref target_ref
auto const& structType = dynamic_cast<StructType const&>(*m_dataType); auto const& structType = dynamic_cast<StructType const&>(m_dataType);
solAssert(structType == _sourceType, "Struct assignment with conversion."); solAssert(structType == _sourceType, "Struct assignment with conversion.");
for (auto const& member: structType.getMembers()) for (auto const& member: structType.getMembers())
{ {
@ -167,12 +165,12 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
m_context << structType.getStorageOffsetOfMember(member.first) m_context << structType.getStorageOffsetOfMember(member.first)
<< eth::Instruction::DUP3 << eth::Instruction::DUP2 << eth::Instruction::ADD; << eth::Instruction::DUP3 << eth::Instruction::DUP2 << eth::Instruction::ADD;
// stack: source_ref target_ref member_offset source_member_ref // stack: source_ref target_ref member_offset source_member_ref
StorageItem(m_context, memberType).retrieveValue(_location, true); StorageItem(m_context, *memberType).retrieveValue(_location, true);
// stack: source_ref target_ref member_offset source_value... // stack: source_ref target_ref member_offset source_value...
m_context << eth::dupInstruction(2 + memberType->getSizeOnStack()) m_context << eth::dupInstruction(2 + memberType->getSizeOnStack())
<< eth::dupInstruction(2 + memberType->getSizeOnStack()) << eth::Instruction::ADD; << eth::dupInstruction(2 + memberType->getSizeOnStack()) << eth::Instruction::ADD;
// stack: source_ref target_ref member_offset source_value... target_member_ref // stack: source_ref target_ref member_offset source_value... target_member_ref
StorageItem(m_context, memberType).storeValue(*memberType, _location, true); StorageItem(m_context, *memberType).storeValue(*memberType, _location, true);
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
} }
if (_move) if (_move)
@ -187,16 +185,18 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
} }
} }
void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
void StorageItem::setToZero(SourceLocation const& _location) const
{ {
(void)_location; if (m_dataType.getCategory() == Type::Category::Array)
if (m_dataType->getCategory() == Type::Category::Array) {
CompilerUtils(m_context).clearByteArray(dynamic_cast<ArrayType const&>(*m_dataType)); if (!_removeReference)
else if (m_dataType->getCategory() == Type::Category::Struct) m_context << eth::Instruction::DUP1;
ArrayUtils(m_context).clearArray(dynamic_cast<ArrayType const&>(m_dataType));
}
else if (m_dataType.getCategory() == Type::Category::Struct)
{ {
// stack layout: ref // stack layout: ref
auto const& structType = dynamic_cast<StructType const&>(*m_dataType); auto const& structType = dynamic_cast<StructType const&>(m_dataType);
for (auto const& member: structType.getMembers()) for (auto const& member: structType.getMembers())
{ {
// zero each member that is not a mapping // zero each member that is not a mapping
@ -205,19 +205,61 @@ void StorageItem::setToZero(SourceLocation const& _location) const
continue; continue;
m_context << structType.getStorageOffsetOfMember(member.first) m_context << structType.getStorageOffsetOfMember(member.first)
<< eth::Instruction::DUP2 << eth::Instruction::ADD; << eth::Instruction::DUP2 << eth::Instruction::ADD;
StorageItem(m_context, memberType).setToZero(); StorageItem(m_context, *memberType).setToZero();
} }
m_context << eth::Instruction::POP; if (_removeReference)
m_context << eth::Instruction::POP;
} }
else else
{ {
if (m_size == 0) if (m_size == 0 && _removeReference)
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
for (unsigned i = 0; i < m_size; ++i) else if (m_size == 1)
if (i + 1 >= m_size) m_context
m_context << u256(0) << eth::Instruction::SWAP1 << eth::Instruction::SSTORE; << u256(0) << (_removeReference ? eth::Instruction::SWAP1 : eth::Instruction::DUP2)
else << eth::Instruction::SSTORE;
m_context << u256(0) << eth::Instruction::DUP2 << eth::Instruction::SSTORE else
<< u256(1) << eth::Instruction::ADD; {
if (!_removeReference)
m_context << eth::Instruction::DUP1;
for (unsigned i = 0; i < m_size; ++i)
if (i + 1 >= m_size)
m_context << u256(0) << eth::Instruction::SWAP1 << eth::Instruction::SSTORE;
else
m_context << u256(0) << eth::Instruction::DUP2 << eth::Instruction::SSTORE
<< u256(1) << eth::Instruction::ADD;
}
} }
} }
StorageArrayLength::StorageArrayLength(CompilerContext& _compilerContext, const ArrayType& _arrayType):
LValue(_compilerContext, *_arrayType.getMemberType("length")),
m_arrayType(_arrayType)
{
solAssert(m_arrayType.isDynamicallySized(), "");
}
void StorageArrayLength::retrieveValue(SourceLocation const&, bool _remove) const
{
if (!_remove)
m_context << eth::Instruction::DUP1;
m_context << eth::Instruction::SLOAD;
}
void StorageArrayLength::storeValue(Type const&, SourceLocation const&, bool _move) const
{
if (_move)
m_context << eth::Instruction::SWAP1;
else
m_context << eth::Instruction::DUP2;
ArrayUtils(m_context).resizeDynamicArray(m_arrayType);
}
void StorageArrayLength::setToZero(SourceLocation const&, bool _removeReference) const
{
if (!_removeReference)
m_context << eth::Instruction::DUP1;
ArrayUtils(m_context).clearDynamicArray(m_arrayType);
}

44
libsolidity/LValue.h

@ -24,6 +24,7 @@
#include <memory> #include <memory>
#include <libevmcore/SourceLocation.h> #include <libevmcore/SourceLocation.h>
#include <libsolidity/ArrayUtils.h>
namespace dev namespace dev
{ {
@ -32,6 +33,7 @@ namespace solidity
class Declaration; class Declaration;
class Type; class Type;
class ArrayType;
class CompilerContext; class CompilerContext;
/** /**
@ -40,7 +42,7 @@ class CompilerContext;
class LValue class LValue
{ {
protected: protected:
LValue(CompilerContext& _compilerContext, std::shared_ptr<Type const> const& _dataType): LValue(CompilerContext& _compilerContext, Type const& _dataType):
m_context(_compilerContext), m_dataType(_dataType) {} m_context(_compilerContext), m_dataType(_dataType) {}
public: public:
@ -56,13 +58,14 @@ public:
/// Stack post: if !_move: value_of(lvalue_ref) /// Stack post: if !_move: value_of(lvalue_ref)
virtual void storeValue(Type const& _sourceType, virtual void storeValue(Type const& _sourceType,
SourceLocation const& _location = SourceLocation(), bool _move = false) const = 0; SourceLocation const& _location = SourceLocation(), bool _move = false) const = 0;
/// Stores zero in the lvalue. /// Stores zero in the lvalue. Removes the reference from the stack if @a _removeReference is true.
/// @a _location is the source location of the requested operation /// @a _location is the source location of the requested operation
virtual void setToZero(SourceLocation const& _location = SourceLocation()) const = 0; virtual void setToZero(
SourceLocation const& _location = SourceLocation(), bool _removeReference = true) const = 0;
protected: protected:
CompilerContext& m_context; CompilerContext& m_context;
std::shared_ptr<Type const> m_dataType; Type const& m_dataType;
}; };
/** /**
@ -71,13 +74,14 @@ protected:
class StackVariable: public LValue class StackVariable: public LValue
{ {
public: public:
explicit StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration); StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration);
virtual bool storesReferenceOnStack() const { return false; } virtual bool storesReferenceOnStack() const { return false; }
virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override; virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
virtual void storeValue(Type const& _sourceType, virtual void storeValue(Type const& _sourceType,
SourceLocation const& _location = SourceLocation(), bool _move = false) const override; SourceLocation const& _location = SourceLocation(), bool _move = false) const override;
virtual void setToZero(SourceLocation const& _location = SourceLocation()) const override; virtual void setToZero(
SourceLocation const& _location = SourceLocation(), bool _removeReference = true) const override;
private: private:
/// Base stack offset (@see CompilerContext::getBaseStackOffsetOfVariable) of the local variable. /// Base stack offset (@see CompilerContext::getBaseStackOffsetOfVariable) of the local variable.
@ -93,14 +97,15 @@ class StorageItem: public LValue
{ {
public: public:
/// Constructs the LValue and pushes the location of @a _declaration onto the stack. /// Constructs the LValue and pushes the location of @a _declaration onto the stack.
explicit StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration); StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration);
/// Constructs the LValue and assumes that the storage reference is already on the stack. /// Constructs the LValue and assumes that the storage reference is already on the stack.
explicit StorageItem(CompilerContext& _compilerContext, std::shared_ptr<Type const> const& _type); StorageItem(CompilerContext& _compilerContext, Type const& _type);
virtual bool storesReferenceOnStack() const { return true; } virtual bool storesReferenceOnStack() const { return true; }
virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override; virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
virtual void storeValue(Type const& _sourceType, virtual void storeValue(Type const& _sourceType,
SourceLocation const& _location = SourceLocation(), bool _move = false) const override; SourceLocation const& _location = SourceLocation(), bool _move = false) const override;
virtual void setToZero(SourceLocation const& _location = SourceLocation()) const override; virtual void setToZero(
SourceLocation const& _location = SourceLocation(), bool _removeReference = true) const override;
private: private:
/// Number of stack elements occupied by the value (not the reference). /// Number of stack elements occupied by the value (not the reference).
@ -108,5 +113,26 @@ private:
unsigned m_size; unsigned m_size;
}; };
/**
* Reference to the "length" member of a dynamically-sized array. This is an LValue with special
* semantics since assignments to it might reduce its length and thus arrays members have to be
* deleted.
*/
class StorageArrayLength: public LValue
{
public:
/// Constructs the LValue, assumes that the reference to the array head is already on the stack.
StorageArrayLength(CompilerContext& _compilerContext, ArrayType const& _arrayType);
virtual bool storesReferenceOnStack() const { return true; }
virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
virtual void storeValue(Type const& _sourceType,
SourceLocation const& _location = SourceLocation(), bool _move = false) const override;
virtual void setToZero(
SourceLocation const& _location = SourceLocation(), bool _removeReference = true) const override;
private:
ArrayType const& m_arrayType;
};
} }
} }

10
libsolidity/SourceReferenceFormatter.cpp

@ -44,8 +44,14 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream,
tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end);
if (startLine == endLine) if (startLine == endLine)
{ {
_stream << _scanner.getLineAtPosition(_location.start) << endl string line = _scanner.getLineAtPosition(_location.start);
<< string(startColumn, ' ') << "^"; _stream << line << endl;
std::for_each(line.cbegin(), line.cbegin() + startColumn,
[&_stream](char const& ch)
{
_stream << (ch == '\t' ? '\t' : ' ');
});
_stream << "^";
if (endColumn > startColumn + 2) if (endColumn > startColumn + 2)
_stream << string(endColumn - startColumn - 2, '-'); _stream << string(endColumn - startColumn - 2, '-');
if (endColumn > startColumn + 1) if (endColumn > startColumn + 1)

29
libsolidity/Types.cpp

@ -537,7 +537,19 @@ TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const
bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const
{ {
return _convertTo.getCategory() == getCategory(); if (_convertTo.getCategory() != getCategory())
return false;
auto& convertTo = dynamic_cast<ArrayType const&>(_convertTo);
// let us not allow assignment to memory arrays for now
if (convertTo.getLocation() != Location::Storage)
return false;
if (convertTo.isByteArray() != isByteArray())
return false;
if (!getBaseType()->isImplicitlyConvertibleTo(*convertTo.getBaseType()))
return false;
if (convertTo.isDynamicallySized())
return true;
return !isDynamicallySized() && convertTo.getLength() >= getLength();
} }
TypePointer ArrayType::unaryOperatorResult(Token::Value _operator) const TypePointer ArrayType::unaryOperatorResult(Token::Value _operator) const
@ -552,7 +564,10 @@ bool ArrayType::operator==(Type const& _other) const
if (_other.getCategory() != getCategory()) if (_other.getCategory() != getCategory())
return false; return false;
ArrayType const& other = dynamic_cast<ArrayType const&>(_other); ArrayType const& other = dynamic_cast<ArrayType const&>(_other);
return other.m_location == m_location; if (other.m_location != m_location || other.isByteArray() != isByteArray() ||
other.isDynamicallySized() != isDynamicallySized())
return false;
return isDynamicallySized() || getLength() == other.getLength();
} }
u256 ArrayType::getStorageSize() const u256 ArrayType::getStorageSize() const
@ -628,8 +643,7 @@ MemberList const& ContractType::getMembers() const
{ {
for (ContractDefinition const* base: m_contract.getLinearizedBaseContracts()) for (ContractDefinition const* base: m_contract.getLinearizedBaseContracts())
for (ASTPointer<FunctionDefinition> const& function: base->getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: base->getDefinedFunctions())
if (!function->isConstructor() && !function->getName().empty()&& if (function->isVisibleInDerivedContracts())
function->isVisibleInDerivedContracts())
members.push_back(make_pair(function->getName(), make_shared<FunctionType>(*function, true))); members.push_back(make_pair(function->getName(), make_shared<FunctionType>(*function, true)));
} }
else else
@ -1024,10 +1038,9 @@ MemberList const& TypeType::getMembers() const
vector<ContractDefinition const*> currentBases = m_currentContract->getLinearizedBaseContracts(); vector<ContractDefinition const*> currentBases = m_currentContract->getLinearizedBaseContracts();
if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end()) if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end())
// We are accessing the type of a base contract, so add all public and protected // We are accessing the type of a base contract, so add all public and protected
// functions. Note that this does not add inherited functions on purpose. // members. Note that this does not add inherited functions on purpose.
for (ASTPointer<FunctionDefinition> const& f: contract.getDefinedFunctions()) for (Declaration const* decl: contract.getInheritableMembers())
if (!f->isConstructor() && !f->getName().empty() && f->isVisibleInDerivedContracts()) members.push_back(make_pair(decl->getName(), decl->getType()));
members.push_back(make_pair(f->getName(), make_shared<FunctionType>(*f)));
} }
else if (m_actualType->getCategory() == Category::Enum) else if (m_actualType->getCategory() == Category::Enum)
{ {

1
mix/AppContext.cpp

@ -73,6 +73,7 @@ void AppContext::load()
qmlRegisterType<QHashType>("org.ethereum.qml.QHashType", 1, 0, "QHashType"); qmlRegisterType<QHashType>("org.ethereum.qml.QHashType", 1, 0, "QHashType");
qmlRegisterType<QBoolType>("org.ethereum.qml.QBoolType", 1, 0, "QBoolType"); qmlRegisterType<QBoolType>("org.ethereum.qml.QBoolType", 1, 0, "QBoolType");
qmlRegisterType<QVariableDeclaration>("org.ethereum.qml.QVariableDeclaration", 1, 0, "QVariableDeclaration"); qmlRegisterType<QVariableDeclaration>("org.ethereum.qml.QVariableDeclaration", 1, 0, "QVariableDeclaration");
qmlRegisterType<RecordLogEntry>("org.ethereum.qml.RecordLogEntry", 1, 0, "RecordLogEntry");
QQmlComponent projectModelComponent(m_applicationEngine, QUrl("qrc:/qml/ProjectModel.qml")); QQmlComponent projectModelComponent(m_applicationEngine, QUrl("qrc:/qml/ProjectModel.qml"));
QObject* projectModel = projectModelComponent.create(); QObject* projectModel = projectModelComponent.create();
if (projectModelComponent.isError()) if (projectModelComponent.isError())

37
mix/ClientModel.cpp

@ -82,7 +82,7 @@ ClientModel::ClientModel(AppContext* _context):
qRegisterMetaType<QInstruction*>("QInstruction"); qRegisterMetaType<QInstruction*>("QInstruction");
qRegisterMetaType<QCode*>("QCode"); qRegisterMetaType<QCode*>("QCode");
qRegisterMetaType<QCallData*>("QCallData"); qRegisterMetaType<QCallData*>("QCallData");
qRegisterMetaType<RecordLogEntry*>("RecordLogEntry"); qRegisterMetaType<RecordLogEntry*>("RecordLogEntry*");
connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection); connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection);
m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString()));
@ -305,8 +305,21 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
QDebugData* debugData = new QDebugData(); QDebugData* debugData = new QDebugData();
QQmlEngine::setObjectOwnership(debugData, QQmlEngine::JavaScriptOwnership); QQmlEngine::setObjectOwnership(debugData, QQmlEngine::JavaScriptOwnership);
QList<QCode*> codes; QList<QCode*> codes;
for (bytes const& code: _t.executionCode) for (MachineCode const& code: _t.executionCode)
codes.push_back(QMachineState::getHumanReadableCode(debugData, code)); {
codes.push_back(QMachineState::getHumanReadableCode(debugData, code.address, code.code));
//try to resolve contract for source level debugging
auto nameIter = m_contractNames.find(code.address);
if (nameIter != m_contractNames.end())
{
CompiledContract const& compilerRes = m_context->codeModel()->contract(nameIter->second);
eth::AssemblyItems assemblyItems = !_t.isConstructor() ? compilerRes.assemblyItems() : compilerRes.constructorAssemblyItems();
QVariantList locations;
for (eth::AssemblyItem const& item: assemblyItems)
locations.push_back(QVariant::fromValue(new QSourceLocation(debugData, item.getLocation().start, item.getLocation().end)));
codes.back()->setLocations(compilerRes.documentId(), std::move(locations));
}
}
QList<QCallData*> data; QList<QCallData*> data;
for (bytes const& d: _t.transactionData) for (bytes const& d: _t.transactionData)
@ -325,6 +338,10 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
debugDataReady(debugData); debugDataReady(debugData);
} }
void ClientModel::emptyRecord()
{
debugDataReady(new QDebugData());
}
void ClientModel::debugRecord(unsigned _index) void ClientModel::debugRecord(unsigned _index)
{ {
@ -349,6 +366,18 @@ void ClientModel::callContract(Address const& _contract, bytes const& _data, Tra
m_client->transact(m_client->userAccount().secret(), _tr.value, _contract, _data, _tr.gas, _tr.gasPrice); m_client->transact(m_client->userAccount().secret(), _tr.value, _contract, _data, _tr.gas, _tr.gasPrice);
} }
RecordLogEntry* ClientModel::lastBlock() const
{
eth::BlockInfo blockInfo = m_client->blockInfo();
std::stringstream strGas;
strGas << blockInfo.gasUsed;
std::stringstream strNumber;
strNumber << blockInfo.number;
RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(toHex(blockInfo.hash.ref()))), tr("Gas Used: ") + QString::fromStdString(strGas.str()), QString(), QString(), false, RecordLogEntry::RecordType::Block);
QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership);
return record;
}
void ClientModel::onStateReset() void ClientModel::onStateReset()
{ {
m_contractAddresses.clear(); m_contractAddresses.clear();
@ -424,7 +453,7 @@ void ClientModel::onNewTransaction()
} }
} }
RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall()); RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction);
QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership); QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership);
emit newRecord(log); emit newRecord(log);
} }

25
mix/ClientModel.h

@ -72,6 +72,7 @@ struct TransactionSettings
class RecordLogEntry: public QObject class RecordLogEntry: public QObject
{ {
Q_OBJECT Q_OBJECT
Q_ENUMS(RecordType)
/// Recording index /// Recording index
Q_PROPERTY(unsigned recordIndex MEMBER m_recordIndex CONSTANT) Q_PROPERTY(unsigned recordIndex MEMBER m_recordIndex CONSTANT)
/// Human readable transaction bloack and transaction index /// Human readable transaction bloack and transaction index
@ -88,13 +89,20 @@ class RecordLogEntry: public QObject
Q_PROPERTY(QString returned MEMBER m_returned CONSTANT) Q_PROPERTY(QString returned MEMBER m_returned CONSTANT)
/// true if call, false if transaction /// true if call, false if transaction
Q_PROPERTY(bool call MEMBER m_call CONSTANT) Q_PROPERTY(bool call MEMBER m_call CONSTANT)
/// @returns record type
Q_PROPERTY(RecordType type MEMBER m_type CONSTANT)
public: public:
enum RecordType
{
Transaction,
Block
};
RecordLogEntry(): RecordLogEntry():
m_recordIndex(0), m_call(false) {} m_recordIndex(0), m_call(false), m_type(RecordType::Transaction) {}
RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call): RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type):
m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call) {} m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type) {}
private: private:
unsigned m_recordIndex; unsigned m_recordIndex;
@ -105,6 +113,7 @@ private:
QString m_address; QString m_address;
QString m_returned; QString m_returned;
bool m_call; bool m_call;
RecordType m_type;
}; };
/** /**
@ -123,11 +132,12 @@ public:
Q_PROPERTY(bool mining MEMBER m_mining NOTIFY miningStateChanged) Q_PROPERTY(bool mining MEMBER m_mining NOTIFY miningStateChanged)
/// @returns deployed contracts addresses /// @returns deployed contracts addresses
Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged) Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged)
// @returns the last block
Q_PROPERTY(RecordLogEntry* lastBlock READ lastBlock CONSTANT)
/// ethereum.js RPC request entry point /// ethereum.js RPC request entry point
/// @param _message RPC request in Json format /// @param _message RPC request in Json format
/// @returns RPC response in Json format /// @returns RPC response in Json format
Q_INVOKABLE QString apiCall(QString const& _message); Q_INVOKABLE QString apiCall(QString const& _message);
/// Simulate mining. Creates a new block /// Simulate mining. Creates a new block
Q_INVOKABLE void mine(); Q_INVOKABLE void mine();
@ -139,6 +149,8 @@ public slots:
void setupState(QVariantMap _state); void setupState(QVariantMap _state);
/// Show the debugger for a specified record /// Show the debugger for a specified record
Q_INVOKABLE void debugRecord(unsigned _index); Q_INVOKABLE void debugRecord(unsigned _index);
/// Show the debugger for an empty record
Q_INVOKABLE void emptyRecord();
private slots: private slots:
/// Update UI with machine states result. Display a modal dialog. /// Update UI with machine states result. Display a modal dialog.
@ -177,6 +189,7 @@ signals:
void stateCleared(); void stateCleared();
private: private:
RecordLogEntry* lastBlock() const;
QVariantMap contractAddresses() const; QVariantMap contractAddresses() const;
void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance); void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance);
dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings());
@ -199,3 +212,5 @@ private:
} }
} }
Q_DECLARE_METATYPE(dev::mix::RecordLogEntry*)

2
mix/CodeModel.cpp

@ -56,6 +56,8 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler
m_contract.reset(new QContractDefinition(&contractDefinition)); m_contract.reset(new QContractDefinition(&contractDefinition));
QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership); QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership);
m_bytes = _compiler.getBytecode(_contractName.toStdString()); m_bytes = _compiler.getBytecode(_contractName.toStdString());
m_assemblyItems = _compiler.getRuntimeAssemblyItems(_contractName.toStdString());
m_constructorAssemblyItems = _compiler.getAssemblyItems(_contractName.toStdString());
dev::solidity::InterfaceHandler interfaceHandler; dev::solidity::InterfaceHandler interfaceHandler;
m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition)); m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition));
if (m_contractInterface.isEmpty()) if (m_contractInterface.isEmpty())

10
mix/CodeModel.h

@ -30,6 +30,7 @@
#include <QHash> #include <QHash>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libevmcore/Assembly.h>
class QTextDocument; class QTextDocument;
@ -70,7 +71,7 @@ class CompiledContract: public QObject
Q_PROPERTY(QContractDefinition* contract READ contract) Q_PROPERTY(QContractDefinition* contract READ contract)
Q_PROPERTY(QString contractInterface READ contractInterface CONSTANT) Q_PROPERTY(QString contractInterface READ contractInterface CONSTANT)
Q_PROPERTY(QString codeHex READ codeHex CONSTANT) Q_PROPERTY(QString codeHex READ codeHex CONSTANT)
Q_PROPERTY(QString documentId MEMBER m_documentId CONSTANT) Q_PROPERTY(QString documentId READ documentId CONSTANT)
public: public:
/// Successful compilation result constructor /// Successful compilation result constructor
@ -86,6 +87,11 @@ public:
QString codeHex() const; QString codeHex() const;
/// @returns contract definition in JSON format /// @returns contract definition in JSON format
QString contractInterface() const { return m_contractInterface; } QString contractInterface() const { return m_contractInterface; }
/// @return assebly item locations
eth::AssemblyItems const& assemblyItems() const { return m_assemblyItems; }
eth::AssemblyItems const& constructorAssemblyItems() const { return m_constructorAssemblyItems; }
/// @returns contract source Id
QString documentId() const { return m_documentId; }
private: private:
uint m_sourceHash; uint m_sourceHash;
@ -94,6 +100,8 @@ private:
dev::bytes m_bytes; dev::bytes m_bytes;
QString m_contractInterface; QString m_contractInterface;
QString m_documentId; QString m_documentId;
eth::AssemblyItems m_assemblyItems;
eth::AssemblyItems m_constructorAssemblyItems;
friend class CodeModel; friend class CodeModel;
}; };

9
mix/DebuggingStateWrapper.cpp

@ -69,7 +69,7 @@ namespace
} }
} }
QCode* QMachineState::getHumanReadableCode(QObject* _owner, const bytes& _code) QCode* QMachineState::getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code)
{ {
QVariantList codeStr; QVariantList codeStr;
for (unsigned i = 0; i <= _code.size(); ++i) for (unsigned i = 0; i <= _code.size(); ++i)
@ -96,7 +96,7 @@ QCode* QMachineState::getHumanReadableCode(QObject* _owner, const bytes& _code)
break; // probably hit data segment break; // probably hit data segment
} }
} }
return new QCode(_owner, std::move(codeStr)); return new QCode(_owner, QString::fromStdString(toString(_address)), std::move(codeStr));
} }
QBigInt* QMachineState::gasCost() QBigInt* QMachineState::gasCost()
@ -152,11 +152,6 @@ QVariantList QMachineState::levels()
return levelList; return levelList;
} }
QString QMachineState::address()
{
return QString::fromStdString(toString(m_state.address));
}
QString QMachineState::instruction() QString QMachineState::instruction()
{ {
return QString::fromStdString(dev::eth::instructionInfo(m_state.inst).name); return QString::fromStdString(dev::eth::instructionInfo(m_state.inst).name);

30
mix/DebuggingStateWrapper.h

@ -53,6 +53,22 @@ private:
int m_processIndex; int m_processIndex;
}; };
class QSourceLocation: public QObject
{
Q_OBJECT
Q_PROPERTY(int start MEMBER m_start CONSTANT)
Q_PROPERTY(int end MEMBER m_end CONSTANT)
public:
QSourceLocation(QObject* _owner, int _start, int _end): QObject(_owner), m_start(_start), m_end(_end) {}
private:
int m_start;
int m_end;
};
/** /**
* @brief Shared container for lines * @brief Shared container for lines
*/ */
@ -60,12 +76,19 @@ class QCode: public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QVariantList instructions MEMBER m_instructions CONSTANT) Q_PROPERTY(QVariantList instructions MEMBER m_instructions CONSTANT)
Q_PROPERTY(QVariantList locations MEMBER m_locations CONSTANT)
Q_PROPERTY(QString address MEMBER m_address CONSTANT)
Q_PROPERTY(QString documentId MEMBER m_document CONSTANT)
public: public:
QCode(QObject* _owner, QVariantList&& _instrunctions): QObject(_owner), m_instructions(_instrunctions) {} QCode(QObject* _owner, QString const& _address, QVariantList&& _instrunctions): QObject(_owner), m_instructions(_instrunctions), m_address(_address) {}
void setLocations(QString const& _document, QVariantList&& _locations) { m_document = _document; m_locations = _locations; }
private: private:
QVariantList m_instructions; QVariantList m_instructions;
QString m_address;
QString m_document;
QVariantList m_locations;
}; };
/** /**
@ -110,7 +133,6 @@ class QMachineState: public QObject
Q_PROPERTY(QBigInt* gasCost READ gasCost CONSTANT) Q_PROPERTY(QBigInt* gasCost READ gasCost CONSTANT)
Q_PROPERTY(QBigInt* gas READ gas CONSTANT) Q_PROPERTY(QBigInt* gas READ gas CONSTANT)
Q_PROPERTY(QString instruction READ instruction CONSTANT) Q_PROPERTY(QString instruction READ instruction CONSTANT)
Q_PROPERTY(QString address READ address CONSTANT)
Q_PROPERTY(QStringList debugStack READ debugStack CONSTANT) Q_PROPERTY(QStringList debugStack READ debugStack CONSTANT)
Q_PROPERTY(QStringList debugStorage READ debugStorage CONSTANT) Q_PROPERTY(QStringList debugStorage READ debugStorage CONSTANT)
Q_PROPERTY(QVariantList debugMemory READ debugMemory CONSTANT) Q_PROPERTY(QVariantList debugMemory READ debugMemory CONSTANT)
@ -133,8 +155,6 @@ public:
unsigned codeIndex() { return m_state.codeIndex; } unsigned codeIndex() { return m_state.codeIndex; }
/// Get the call data id /// Get the call data id
unsigned dataIndex() { return m_state.dataIndex; } unsigned dataIndex() { return m_state.dataIndex; }
/// Get address for call stack
QString address();
/// Get gas cost. /// Get gas cost.
QBigInt* gasCost(); QBigInt* gasCost();
/// Get gas used. /// Get gas used.
@ -158,7 +178,7 @@ public:
/// Set the current processed machine state. /// Set the current processed machine state.
void setState(MachineState _state) { m_state = _state; } void setState(MachineState _state) { m_state = _state; }
/// Convert all machine states in human readable code. /// Convert all machine states in human readable code.
static QCode* getHumanReadableCode(QObject* _owner, bytes const& _code); static QCode* getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code);
/// Convert call data into human readable form /// Convert call data into human readable form
static QCallData* getDebugCallData(QObject* _owner, bytes const& _data); static QCallData* getDebugCallData(QObject* _owner, bytes const& _data);

12
mix/FileIo.cpp

@ -20,6 +20,9 @@
* Ethereum IDE client. * Ethereum IDE client.
*/ */
#include <QDebug>
#include <QDesktopServices>
#include <QMimeDatabase>
#include <QDirIterator> #include <QDirIterator>
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
@ -37,6 +40,12 @@ using namespace dev;
using namespace dev::crypto; using namespace dev::crypto;
using namespace dev::mix; using namespace dev::mix;
void FileIo::openFileBrowser(QString const& _dir)
{
QDesktopServices::openUrl(QUrl(_dir));
}
QString FileIo::pathFromUrl(QString const& _url) QString FileIo::pathFromUrl(QString const& _url)
{ {
QUrl url(_url); QUrl url(_url);
@ -126,6 +135,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder)
dev::RLPStream rlpStr; dev::RLPStream rlpStr;
int k = 1; int k = 1;
std::vector<bytes> files; std::vector<bytes> files;
QMimeDatabase mimeDb;
for (auto item: deployDir.entryInfoList(QDir::Files)) for (auto item: deployDir.entryInfoList(QDir::Files))
{ {
QFile qFile(item.filePath()); QFile qFile(item.filePath());
@ -137,7 +147,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder)
std::string path = fileInfo.fileName() == "index.html" ? "/" : fileInfo.fileName().toStdString(); std::string path = fileInfo.fileName() == "index.html" ? "/" : fileInfo.fileName().toStdString();
jsonValue["path"] = path; //TODO: Manage relative sub folder jsonValue["path"] = path; //TODO: Manage relative sub folder
jsonValue["file"] = "/" + fileInfo.fileName().toStdString(); jsonValue["file"] = "/" + fileInfo.fileName().toStdString();
jsonValue["contentType"] = "text/html"; //TODO: manage multiple content type jsonValue["contentType"] = mimeDb.mimeTypeForFile(qFile.fileName()).name().toStdString();
QByteArray a = qFile.readAll(); QByteArray a = qFile.readAll();
bytes data = bytes(a.begin(), a.end()); bytes data = bytes(a.begin(), a.end());
files.push_back(data); files.push_back(data);

2
mix/FileIo.h

@ -55,6 +55,8 @@ public:
Q_INVOKABLE bool fileExists(QString const& _url); Q_INVOKABLE bool fileExists(QString const& _url);
/// Compress a folder, @returns sha3 of the compressed file. /// Compress a folder, @returns sha3 of the compressed file.
Q_INVOKABLE QStringList makePackage(QString const& _deploymentFolder); Q_INVOKABLE QStringList makePackage(QString const& _deploymentFolder);
/// Open a file browser
Q_INVOKABLE void openFileBrowser(QString const& _dir);
private: private:
QString getHomePath() const; QString getHomePath() const;

13
mix/MachineStates.h

@ -42,7 +42,6 @@ namespace mix
struct MachineState struct MachineState
{ {
uint64_t steps; uint64_t steps;
dev::Address address;
dev::u256 curPC; dev::u256 curPC;
dev::eth::Instruction inst; dev::eth::Instruction inst;
dev::bigint newMemSize; dev::bigint newMemSize;
@ -56,6 +55,15 @@ namespace mix
unsigned dataIndex; unsigned dataIndex;
}; };
/**
* @brief Executed conract code info
*/
struct MachineCode
{
dev::Address address;
bytes code;
};
/** /**
* @brief Store information about a machine states. * @brief Store information about a machine states.
*/ */
@ -65,7 +73,7 @@ namespace mix
std::vector<MachineState> machineStates; std::vector<MachineState> machineStates;
std::vector<bytes> transactionData; std::vector<bytes> transactionData;
std::vector<bytes> executionCode; std::vector<MachineCode> executionCode;
bytes returnValue; bytes returnValue;
dev::Address address; dev::Address address;
dev::Address sender; dev::Address sender;
@ -74,6 +82,7 @@ namespace mix
unsigned transactionIndex; unsigned transactionIndex;
bool isCall() const { return transactionIndex == std::numeric_limits<unsigned>::max(); } bool isCall() const { return transactionIndex == std::numeric_limits<unsigned>::max(); }
bool isConstructor() const { return !isCall() && !address; }
}; };
using ExecutionResults = std::vector<ExecutionResult>; using ExecutionResults = std::vector<ExecutionResult>;

12
mix/MixClient.cpp

@ -107,7 +107,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
execution.setup(&rlp); execution.setup(&rlp);
std::vector<MachineState> machineStates; std::vector<MachineState> machineStates;
std::vector<unsigned> levels; std::vector<unsigned> levels;
std::vector<bytes> codes; std::vector<MachineCode> codes;
std::map<bytes const*, unsigned> codeIndexes; std::map<bytes const*, unsigned> codeIndexes;
std::vector<bytes> data; std::vector<bytes> data;
std::map<bytesConstRef const*, unsigned> dataIndexes; std::map<bytesConstRef const*, unsigned> dataIndexes;
@ -127,7 +127,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
else else
{ {
codeIndex = codes.size(); codeIndex = codes.size();
codes.push_back(ext.code); codes.push_back(MachineCode({ext.myAddress, ext.code}));
codeIndexes[&ext.code] = codeIndex; codeIndexes[&ext.code] = codeIndex;
} }
lastCode = &ext.code; lastCode = &ext.code;
@ -152,7 +152,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
else else
levels.resize(ext.depth); levels.resize(ext.depth);
machineStates.emplace_back(MachineState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), machineStates.emplace_back(MachineState({steps, vm.curPC(), inst, newMemSize, vm.gas(),
vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels, codeIndex, dataIndex})); vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels, codeIndex, dataIndex}));
}; };
@ -436,6 +436,12 @@ h256 MixClient::hashFromNumber(unsigned _number) const
eth::BlockInfo MixClient::blockInfo(h256 _hash) const eth::BlockInfo MixClient::blockInfo(h256 _hash) const
{ {
return BlockInfo(bc().block(_hash)); return BlockInfo(bc().block(_hash));
}
eth::BlockInfo MixClient::blockInfo() const
{
return BlockInfo(bc().block());
} }
eth::BlockDetails MixClient::blockDetails(h256 _hash) const eth::BlockDetails MixClient::blockDetails(h256 _hash) const

2
mix/MixClient.h

@ -89,6 +89,8 @@ public:
eth::MineProgress miningProgress() const override; eth::MineProgress miningProgress() const override;
std::pair<h256, u256> getWork() override { return std::pair<h256, u256>(); } std::pair<h256, u256> getWork() override { return std::pair<h256, u256>(); }
bool submitNonce(h256 const&) override { return false; } bool submitNonce(h256 const&) override { return false; }
/// @returns the last mined block information
eth::BlockInfo blockInfo() const;
private: private:
void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call); void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call);

43
mix/qml/CodeEditorView.qml

@ -7,6 +7,7 @@ Item {
id: codeEditorView id: codeEditorView
property string currentDocumentId: "" property string currentDocumentId: ""
signal documentEdit(string documentId) signal documentEdit(string documentId)
signal breakpointsChanged(string documentId)
function getDocumentText(documentId) { function getDocumentText(documentId) {
for (var i = 0; i < editorListModel.count; i++) { for (var i = 0; i < editorListModel.count; i++) {
@ -45,9 +46,51 @@ Item {
if (document.isContract) if (document.isContract)
codeModel.registerCodeChange(document.documentId, editor.getText()); codeModel.registerCodeChange(document.documentId, editor.getText());
}); });
editor.onBreakpointsChanged.connect(function() {
if (document.isContract)
breakpointsChanged(document.documentId);
});
editor.setText(data, document.syntaxMode); editor.setText(data, document.syntaxMode);
} }
function getEditor(documentId) {
for (var i = 0; i < editorListModel.count; i++)
if (editorListModel.get(i).documentId === documentId)
return editors.itemAt(i).item;
return null;
}
function highlightExecution(documentId, location) {
var editor = getEditor(documentId);
if (editor)
editor.highlightExecution(location);
}
function editingContract() {
for (var i = 0; i < editorListModel.count; i++)
if (editorListModel.get(i).documentId === currentDocumentId)
return editorListModel.get(i).isContract;
return false;
}
function getBreakpoints() {
var bpMap = {};
for (var i = 0; i < editorListModel.count; i++) {
var documentId = editorListModel.get(i).documentId;
var editor = editors.itemAt(i).item;
if (editor) {
bpMap[documentId] = editor.getBreakpoints();
}
}
return bpMap;
}
function toggleBreakpoint() {
var editor = getEditor(currentDocumentId);
if (editor)
editor.toggleBreakpoint();
}
Component.onCompleted: projectModel.codeEditor = codeEditorView; Component.onCompleted: projectModel.codeEditor = codeEditorView;
Connections { Connections {

98
mix/qml/Debugger.qml

@ -11,7 +11,10 @@ import "."
Rectangle { Rectangle {
id: debugPanel id: debugPanel
property alias transactionLog : transactionLog property alias transactionLog: transactionLog
signal debugExecuteLocation(string documentId, var location)
property string compilationErrorMessage
property bool assemblyMode: false
objectName: "debugPanel" objectName: "debugPanel"
color: "#ededed" color: "#ededed"
@ -23,29 +26,44 @@ Rectangle {
forceActiveFocus(); forceActiveFocus();
} }
onAssemblyModeChanged:
{
Debugger.updateMode();
}
function displayCompilationErrorIfAny()
{
debugScrollArea.visible = false;
compilationErrorArea.visible = true;
machineStates.visible = false;
var errorInfo = ErrorLocationFormater.extractErrorInfo(compilationErrorMessage, false);
errorLocation.text = errorInfo.errorLocation;
errorDetail.text = errorInfo.errorDetail;
errorLine.text = errorInfo.errorLine;
}
function update(data, giveFocus) function update(data, giveFocus)
{ {
if (statusPane && codeModel.hasContract) if (data === null)
Debugger.init(null);
else if (data.states.length === 0)
Debugger.init(null);
else if (codeModel.hasContract)
{ {
Debugger.init(data); Debugger.init(data);
debugScrollArea.visible = true; debugScrollArea.visible = true;
compilationErrorArea.visible = false; compilationErrorArea.visible = false;
machineStates.visible = true; machineStates.visible = true;
} }
else
{
debugScrollArea.visible = false;
compilationErrorArea.visible = true;
machineStates.visible = false;
var errorInfo = ErrorLocationFormater.extractErrorInfo(statusPane.result.compilerMessage, false);
errorLocation.text = errorInfo.errorLocation;
errorDetail.text = errorInfo.errorDetail;
errorLine.text = errorInfo.errorLine;
}
if (giveFocus) if (giveFocus)
forceActiveFocus(); forceActiveFocus();
} }
function setBreakpoints(bp)
{
Debugger.setBreakpoints(bp);
}
Connections { Connections {
target: clientModel target: clientModel
onDebugDataReady: { onDebugDataReady: {
@ -55,7 +73,13 @@ Rectangle {
Connections { Connections {
target: codeModel target: codeModel
onCompilationComplete: update(null, false); onCompilationComplete: {
debugPanel.compilationErrorMessage = "";
}
onCompilationError: {
debugPanel.compilationErrorMessage = _error;
}
} }
Settings { Settings {
@ -73,7 +97,7 @@ Rectangle {
visible: false; visible: false;
id: compilationErrorArea id: compilationErrorArea
width: parent.width - 20 width: parent.width - 20
height: 500 height: 600
color: "#ededed" color: "#ededed"
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
@ -82,7 +106,20 @@ Rectangle {
{ {
width: parent.width width: parent.width
anchors.top: parent.top anchors.top: parent.top
spacing: 25 spacing: 15
Rectangle
{
height: 15
Button {
text: qsTr("Back to Debugger")
onClicked: {
debugScrollArea.visible = true;
compilationErrorArea.visible = false;
machineStates.visible = true;
}
}
}
RowLayout RowLayout
{ {
height: 100 height: 100
@ -173,11 +210,23 @@ Rectangle {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
color: "transparent" color: "transparent"
width: stateListContainer.width width: parent.width * 0.4
RowLayout { RowLayout {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
id: jumpButtons id: jumpButtons
spacing: 3 spacing: 3
StepActionImage
{
id: runBackAction;
enabledStateImg: "qrc:/qml/img/jumpoutback.png"
disableStateImg: "qrc:/qml/img/jumpoutbackdisabled.png"
onClicked: Debugger.runBack()
width: 30
height: 30
buttonShortcut: "Ctrl+Shift+F5"
buttonTooltip: qsTr("Run Back")
}
StepActionImage StepActionImage
{ {
id: jumpOutBackAction; id: jumpOutBackAction;
@ -249,6 +298,20 @@ Rectangle {
buttonShortcut: "Shift+F11" buttonShortcut: "Shift+F11"
buttonTooltip: qsTr("Step Out Forward") buttonTooltip: qsTr("Step Out Forward")
} }
StepActionImage
{
id: runForwardAction
enabledStateImg: "qrc:/qml/img/jumpoutforward.png"
disableStateImg: "qrc:/qml/img/jumpoutforwarddisabled.png"
onClicked: Debugger.runForward()
width: 30
height: 30
buttonShortcut: "Ctrl+F5"
buttonTooltip: qsTr("Run Forward")
}
} }
} }
@ -256,7 +319,7 @@ Rectangle {
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
width: debugInfoContainer.width width: parent.width * 0.6
color: "transparent" color: "transparent"
Slider { Slider {
id: statesSlider id: statesSlider
@ -291,6 +354,7 @@ Rectangle {
height: 405 height: 405
implicitHeight: 405 implicitHeight: 405
color: "transparent" color: "transparent"
visible: assemblyMode
Rectangle Rectangle
{ {

308
mix/qml/DeploymentDialog.qml

@ -12,18 +12,20 @@ import "."
Window { Window {
id: modalDeploymentDialog id: modalDeploymentDialog
modality: Qt.ApplicationModal modality: Qt.ApplicationModal
width: 600 width: 930
height: 350 height: 350
visible: false visible: false
property alias applicationUrlEth: applicationUrlEth.text property alias applicationUrlEth: applicationUrlEth.text
property alias applicationUrlHttp: applicationUrlHttp.text property alias applicationUrlHttp: applicationUrlHttp.text
property string urlHintContract: "c83d3e22645fb015d02043a744921cc2f828c64d" property string urlHintContract: "c83d3e22645fb015d02043a744921cc2f828c64d" /* TODO: replace with the good address */
property string packageHash property string packageHash
property alias packageBase64: base64Value.text property alias packageBase64: base64Value.text
property string eth: "afb7cdbd076674fd2c67f8a66518e3145b184ae4"; property string eth: "4c3f7330690ed3657d3fa20fe5717b84010528ae"; /* TODO: replace with the good address */
property string wallet: "c83d3e22645fb015d02043a744921cc2f828c64d"; property string currentAccount
property alias gasToUse: gasToUseInput.text
color: Style.generic.layout.backgroundColor color: Style.generic.layout.backgroundColor
@ -37,6 +39,59 @@ Window {
modalDeploymentDialog.setX((Screen.width - width) / 2); modalDeploymentDialog.setX((Screen.width - width) / 2);
modalDeploymentDialog.setY((Screen.height - height) / 2); modalDeploymentDialog.setY((Screen.height - height) / 2);
visible = true; visible = true;
var requests = [{
//accounts
jsonrpc: "2.0",
method: "eth_accounts",
params: null,
id: 0
}];
TransactionHelper.rpcCall(requests, function(arg1, arg2)
{
modelAccounts.clear();
var ids = JSON.parse(arg2)[0].result;
requests = [];
for (var k in ids)
{
modelAccounts.append({ "id": ids[k] })
requests.push({
//accounts
jsonrpc: "2.0",
method: "eth_balanceAt",
params: [ids[k]],
id: k
});
}
if (ids.length > 0)
currentAccount = modelAccounts.get(0).id;
TransactionHelper.rpcCall(requests, function (request, response){
var balanceRet = JSON.parse(response);
for (var k in balanceRet)
{
var ether = QEtherHelper.createEther(balanceRet[k].result, QEther.Wei);
comboAccounts.balances.push(ether.format());
}
balance.text = comboAccounts.balances[0];
});
});
}
function stopForInputError(inError)
{
errorDialog.text = "";
if (inError.length > 0)
{
errorDialog.text = qsTr("The length of a string cannot exceed 32 characters.\nPlease verify the following value(s):\n\n")
for (var k in inError)
errorDialog.text += inError[k] + "\n";
errorDialog.open();
return true;
}
return false;
} }
function pad(h) function pad(h)
@ -49,6 +104,52 @@ Window {
return h; return h;
} }
function waitForTrCountToIncrement(callBack)
{
poolLog.callBack = callBack;
poolLog.k = -1;
poolLog.elapsed = 0;
poolLog.start();
}
Timer
{
id: poolLog
property var callBack
property int k: -1
property int elapsed
interval: 500
running: false
repeat: true
onTriggered: {
elapsed += interval;
var requests = [];
var jsonRpcRequestId = 0;
requests.push({
jsonrpc: "2.0",
method: "eth_countAt",
params: [ currentAccount ],
id: jsonRpcRequestId++
});
TransactionHelper.rpcCall(requests, function (httpRequest, response){
response = response.replace(/,0+/, ''); // ==> result:27,00000000
var count = JSON.parse(response)[0].result
if (k < parseInt(count) && k > 0)
{
stop();
callBack(1);
}
else if (elapsed > 25000)
{
stop();
callBack(-1);
}
else
k = parseInt(JSON.parse(response)[0].result);
})
}
}
Rectangle Rectangle
{ {
anchors.fill : parent anchors.fill : parent
@ -60,15 +161,63 @@ Window {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
width: parent.width width: parent.width
DefaultLabel
{
text: qsTr("Account used to deploy:")
}
Rectangle
{
width: 300
height: 25
color: "transparent"
ComboBox {
id: comboAccounts
property var balances: []
onCurrentIndexChanged : {
if (modelAccounts.count > 0)
{
currentAccount = modelAccounts.get(currentIndex).id;
balance.text = balances[currentIndex];
}
}
model: ListModel {
id: modelAccounts
}
}
DefaultLabel
{
anchors.verticalCenter: parent.verticalCenter
anchors.left: comboAccounts.right
anchors.leftMargin: 20
id: balance;
}
}
DefaultLabel DefaultLabel
{ {
text: qsTr("Ethereum Application URL: ") text: qsTr("Ethereum Application URL: ")
} }
DefaultTextField Rectangle
{ {
Layout.fillWidth: true Layout.fillWidth: true
id: applicationUrlEth height: 25
color: "transparent"
DefaultTextField
{
width: 350
id: applicationUrlEth
}
DefaultLabel
{
anchors.verticalCenter: parent.verticalCenter;
anchors.left: applicationUrlEth.right
text: "/" + projectModel.projectTitle
}
} }
DefaultLabel DefaultLabel
@ -82,6 +231,18 @@ Window {
id: applicationUrlHttp id: applicationUrlHttp
} }
DefaultLabel
{
text: qsTr("Amount of gas to use for each contract deployment: ")
}
DefaultTextField
{
text: "20000"
Layout.fillWidth: true
id: gasToUseInput
}
DefaultLabel DefaultLabel
{ {
text: qsTr("Package (Base64): ") text: qsTr("Package (Base64): ")
@ -103,16 +264,47 @@ Window {
icon: StandardIcon.Warning icon: StandardIcon.Warning
} }
MessageDialog {
id: errorDialog
standardButtons: StandardButton.Ok
icon: StandardIcon.Error
}
RowLayout RowLayout
{ {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right; anchors.right: parent.right;
anchors.bottomMargin: 10 anchors.bottomMargin: 10
Button { Button {
text: qsTr("Deploy to Ethereum"); text: qsTr("Deploy contract / Package resources");
tooltip: qsTr("Deploy contract and package resources files.") tooltip: qsTr("Deploy contract and package resources files.")
onClicked: { onClicked: {
deployWarningDialog.open(); var inError = [];
var ethUrl = ProjectModelCode.formatAppUrl(applicationUrlEth.text);
for (var k in ethUrl)
{
if (ethUrl[k].length > 32)
inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n");
}
if (!stopForInputError(inError))
deployWarningDialog.open();
}
}
Button {
text: qsTr("Package resources only");
tooltip: qsTr("Package resources files.")
enabled: Object.keys(projectModel.deploymentAddresses).length > 0
onClicked: {
ProjectModelCode.startDeployProject(false);
}
}
Button {
text: qsTr("Open Package Directory");
enabled: projectModel.deploymentDir !== ""
onClicked: {
fileIo.openFileBrowser(projectModel.deploymentDir);
} }
} }
@ -123,10 +315,14 @@ Window {
if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "")
{ {
deployDialog.title = text; deployDialog.title = text;
deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step. ") deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step.")
deployDialog.open(); deployDialog.open();
return;
} }
else var inError = [];
if (applicationUrlHttp.text.length > 32)
inError.push(qsTr(applicationUrlHttp.text));
if (!stopForInputError(inError))
ProjectModelCode.registerToUrlHint(); ProjectModelCode.registerToUrlHint();
} }
} }
@ -135,98 +331,6 @@ Window {
text: qsTr("Close"); text: qsTr("Close");
onClicked: close(); onClicked: close();
} }
Button {
text: qsTr("Check Ownership");
visible : false
onClicked: {
var requests = [];
var ethStr = QEtherHelper.createString("wallet");
var ethHash = QEtherHelper.createHash(eth);
requests.push({ //owner
jsonrpc: "2.0",
method: "eth_call",
params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0xec7b9200" + ethStr.encodeValueAsString() } ],
id: 3
});
requests.push({ //register
jsonrpc: "2.0",
method: "eth_call",
params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x6be16bed" + ethStr.encodeValueAsString() } ],
id: 4
});
var jsonRpcUrl = "http://localhost:8080";
var rpcRequest = JSON.stringify(requests);
var httpRequest = new XMLHttpRequest();
httpRequest.open("POST", jsonRpcUrl, true);
httpRequest.setRequestHeader("Content-type", "application/json");
httpRequest.setRequestHeader("Content-length", rpcRequest.length);
httpRequest.setRequestHeader("Connection", "close");
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
console.log(httpRequest.responseText);
} else {
var errorText = qsTr("path registration failed ") + httpRequest.status;
console.log(errorText);
}
}
}
httpRequest.send(rpcRequest);
}
}
Button {
text: qsTr("Generate registrar init");
visible: false
onClicked: {
console.log("registering eth/wallet")
var jsonRpcRequestId = 0;
var requests = [];
var walletStr = QEtherHelper.createString("wallet");
requests.push({ //reserve
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x1c83171b" + walletStr.encodeValueAsString() } ],
id: jsonRpcRequestId++
});
requests.push({ //setRegister
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x96077307" + walletStr.encodeValueAsString() + pad(wallet) } ],
id: jsonRpcRequestId++
});
var jsonRpcUrl = "http://localhost:8080";
var rpcRequest = JSON.stringify(requests);
var httpRequest = new XMLHttpRequest();
httpRequest.open("POST", jsonRpcUrl, true);
httpRequest.setRequestHeader("Content-type", "application/json");
httpRequest.setRequestHeader("Content-length", rpcRequest.length);
httpRequest.setRequestHeader("Connection", "close");
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
console.log(httpRequest.responseText);
} else {
var errorText = qsTr("path registration failed ") + httpRequest.status;
console.log(errorText);
}
}
}
httpRequest.send(rpcRequest);
}
}
} }
} }
} }

348
mix/qml/FilesSection.qml

@ -6,17 +6,19 @@ import QtQuick.Controls.Styles 1.3
import "." import "."
ColumnLayout { Rectangle
{
Layout.fillWidth: true
Layout.minimumHeight: hiddenHeightTopLevel()
height: hiddenHeightTopLevel()
Layout.maximumHeight: hiddenHeightTopLevel()
id: wrapperItem id: wrapperItem
signal documentSelected(string doc, string groupName) signal documentSelected(string doc, string groupName)
property alias model: filesList.model property alias model: filesList.model
property string sectionName; property string sectionName;
property variant selManager; property variant selManager;
Layout.fillWidth: true property int index;
Layout.minimumHeight: hiddenHeightTopLevel() color: index % 2 === 0 ? "transparent" : ProjectFilesStyle.title.background
height: hiddenHeightTopLevel()
Layout.maximumHeight: hiddenHeightTopLevel()
spacing: 0
function hiddenHeightTopLevel() function hiddenHeightTopLevel()
{ {
@ -48,196 +50,203 @@ ColumnLayout {
model.remove(i); model.remove(i);
} }
SourceSansProRegular ColumnLayout {
{ anchors.fill: parent
id: fileNameFont spacing: 0
}
SourceSansProBold
{
id: boldFont
}
RowLayout SourceSansProRegular
{ {
anchors.top: parent.top id: fileNameFont
id: rowCol
width: parent.width
height: ProjectFilesStyle.documentsList.height
Image {
source: "qrc:/qml/img/opentriangleindicator_filesproject.png"
width: 15
sourceSize.width: 12
id: imgArrow
anchors.right: section.left
anchors.rightMargin: 8
anchors.top: parent.top
anchors.topMargin: 6
} }
Text SourceSansProBold
{ {
id: section id: boldFont
text: sectionName
anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin
color: ProjectFilesStyle.documentsList.sectionColor
font.family: boldFont.name
font.pointSize: ProjectFilesStyle.documentsList.sectionFontSize
states: [
State {
name: "hidden"
PropertyChanges { target: filesList; visible: false; }
PropertyChanges { target: rowCol; Layout.minimumHeight: ProjectFilesStyle.documentsList.height; Layout.maximumHeight: ProjectFilesStyle.documentsList.height; height: ProjectFilesStyle.documentsList.height; }
PropertyChanges { target: imgArrow; source: "qrc:/qml/img/closedtriangleindicator_filesproject.png" }
}
]
} }
MouseArea { RowLayout
id: titleMouseArea {
anchors.fill: parent anchors.top: parent.top
hoverEnabled: true id: rowCol
z: 2 height: ProjectFilesStyle.documentsList.height
onClicked: { Layout.fillWidth: true
if (section.state === "hidden")
section.state = "";
else Image {
section.state = "hidden"; source: "qrc:/qml/img/opentriangleindicator_filesproject.png"
width: 15
sourceSize.width: 12
id: imgArrow
anchors.right: section.left
anchors.rightMargin: 8
anchors.top: parent.top
anchors.topMargin: 10
}
Text
{
id: section
text: sectionName
anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin
color: ProjectFilesStyle.documentsList.sectionColor
font.family: boldFont.name
font.pointSize: ProjectFilesStyle.documentsList.sectionFontSize
states: [
State {
name: "hidden"
PropertyChanges { target: filesList; visible: false; }
PropertyChanges { target: rowCol; Layout.minimumHeight: ProjectFilesStyle.documentsList.height; Layout.maximumHeight: ProjectFilesStyle.documentsList.height; height: ProjectFilesStyle.documentsList.height; }
PropertyChanges { target: imgArrow; source: "qrc:/qml/img/closedtriangleindicator_filesproject.png" }
}
]
}
MouseArea {
id: titleMouseArea
anchors.fill: parent
hoverEnabled: true
z: 2
onClicked: {
if (section.state === "hidden")
section.state = "";
else
section.state = "hidden";
}
} }
} }
}
ColumnLayout { ColumnLayout {
height: wrapperItem.hiddenHeightRepeater() height: wrapperItem.hiddenHeightRepeater()
Layout.minimumHeight: wrapperItem.hiddenHeightRepeater() Layout.minimumHeight: wrapperItem.hiddenHeightRepeater()
Layout.preferredHeight: wrapperItem.hiddenHeightRepeater() Layout.preferredHeight: wrapperItem.hiddenHeightRepeater()
Layout.maximumHeight: wrapperItem.hiddenHeightRepeater() Layout.maximumHeight: wrapperItem.hiddenHeightRepeater()
width: parent.width width: parent.width
visible: section.state !== "hidden"
spacing: 0
Repeater
{
id: filesList
visible: section.state !== "hidden" visible: section.state !== "hidden"
Rectangle spacing: 0
Repeater
{ {
id: filesList
visible: section.state !== "hidden" visible: section.state !== "hidden"
id: rootItem Rectangle
Layout.fillWidth: true {
Layout.minimumHeight: wrapperItem.hiddenHeightElement() visible: section.state !== "hidden"
Layout.preferredHeight: wrapperItem.hiddenHeightElement() id: rootItem
Layout.maximumHeight: wrapperItem.hiddenHeightElement() Layout.fillWidth: true
height: wrapperItem.hiddenHeightElement() Layout.minimumHeight: wrapperItem.hiddenHeightElement()
color: isSelected ? ProjectFilesStyle.documentsList.highlightColor : ProjectFilesStyle.documentsList.background Layout.preferredHeight: wrapperItem.hiddenHeightElement()
property bool isSelected Layout.maximumHeight: wrapperItem.hiddenHeightElement()
property bool renameMode height: wrapperItem.hiddenHeightElement()
Text { color: isSelected ? ProjectFilesStyle.documentsList.highlightColor : "transparent"
id: nameText property bool isSelected
height: parent.height property bool renameMode
visible: !renameMode Text {
color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color id: nameText
text: name; height: parent.height
font.family: fileNameFont.name visible: !renameMode
font.pointSize: ProjectFilesStyle.documentsList.fontSize color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color
anchors.verticalCenter: parent.verticalCenter text: name;
verticalAlignment: Text.AlignVCenter font.family: fileNameFont.name
anchors.left: parent.left font.pointSize: ProjectFilesStyle.documentsList.fontSize
anchors.leftMargin: ProjectFilesStyle.general.leftMargin + 2 anchors.verticalCenter: parent.verticalCenter
width: parent.width verticalAlignment: Text.AlignVCenter
Connections anchors.left: parent.left
{ anchors.leftMargin: ProjectFilesStyle.general.leftMargin + 2
target: selManager width: parent.width
onSelected: { Connections
if (groupName != sectionName) {
rootItem.isSelected = false; target: selManager
else if (doc === documentId) onSelected: {
rootItem.isSelected = true; if (groupName != sectionName)
else rootItem.isSelected = false;
rootItem.isSelected = false; else if (doc === documentId)
rootItem.isSelected = true;
else
rootItem.isSelected = false;
if (rootItem.isSelected && section.state === "hidden") if (rootItem.isSelected && section.state === "hidden")
section.state = ""; section.state = "";
}
} }
} }
}
TextInput { TextInput {
id: textInput id: textInput
text: nameText.text text: nameText.text
visible: renameMode visible: renameMode
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin anchors.leftMargin: ProjectFilesStyle.general.leftMargin
MouseArea { MouseArea {
id: textMouseArea id: textMouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
z: 2 z: 2
onClicked: { onClicked: {
textInput.forceActiveFocus(); textInput.forceActiveFocus();
}
} }
}
onVisibleChanged: { onVisibleChanged: {
if (visible) { if (visible) {
selectAll(); selectAll();
forceActiveFocus(); forceActiveFocus();
}
} }
}
onAccepted: close(true); onAccepted: close(true);
onCursorVisibleChanged: { onCursorVisibleChanged: {
if (!cursorVisible) if (!cursorVisible)
close(false); close(false);
} }
onFocusChanged: { onFocusChanged: {
if (!focus) if (!focus)
close(false); close(false);
} }
function close(accept) { function close(accept) {
rootItem.renameMode = false; rootItem.renameMode = false;
if (accept) if (accept)
{ {
var i = getDocumentIndex(documentId); var i = getDocumentIndex(documentId);
projectModel.renameDocument(documentId, textInput.text); projectModel.renameDocument(documentId, textInput.text);
wrapperItem.model.set(i, projectModel.getDocument(documentId)); wrapperItem.model.set(i, projectModel.getDocument(documentId));
}
} }
} }
}
MouseArea { MouseArea {
id: mouseArea id: mouseArea
z: 1 z: 1
hoverEnabled: false hoverEnabled: false
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked:{ onClicked:{
if (mouse.button === Qt.RightButton && !isContract) if (mouse.button === Qt.RightButton && !isContract)
contextMenu.popup(); contextMenu.popup();
else if (mouse.button === Qt.LeftButton) else if (mouse.button === Qt.LeftButton)
{ {
rootItem.isSelected = true; rootItem.isSelected = true;
projectModel.openDocument(documentId); projectModel.openDocument(documentId);
documentSelected(documentId, groupName); documentSelected(documentId, groupName);
}
} }
} }
}
Menu { Menu {
id: contextMenu id: contextMenu
MenuItem { MenuItem {
text: qsTr("Rename") text: qsTr("Rename")
onTriggered: { onTriggered: {
rootItem.renameMode = true; rootItem.renameMode = true;
}
} }
} MenuItem {
MenuItem { text: qsTr("Delete")
text: qsTr("Delete") onTriggered: {
onTriggered: { projectModel.removeDocument(documentId);
projectModel.removeDocument(documentId); wrapperItem.removeDocument(documentId);
wrapperItem.removeDocument(documentId); }
} }
} }
} }
@ -245,4 +254,3 @@ ColumnLayout {
} }
} }
} }

31
mix/qml/MainContent.qml

@ -26,6 +26,7 @@ Rectangle {
property alias projectViewVisible: projectList.visible property alias projectViewVisible: projectList.visible
property alias runOnProjectLoad: mainSettings.runOnProjectLoad property alias runOnProjectLoad: mainSettings.runOnProjectLoad
property alias rightPane: rightView property alias rightPane: rightView
property alias codeEditor: codeEditor
property bool webViewHorizontal: codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally property bool webViewHorizontal: codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally
property bool firstCompile: true property bool firstCompile: true
@ -40,6 +41,20 @@ Rectangle {
} }
} }
Connections {
target: rightView
onDebugExecuteLocation: {
codeEditor.highlightExecution(documentId, location);
}
}
Connections {
target: codeEditor
onBreakpointsChanged: {
rightPane.setBreakpoints(codeEditor.getBreakpoints());
}
}
function startQuickDebugging() function startQuickDebugging()
{ {
ensureRightView(); ensureRightView();
@ -75,6 +90,17 @@ Rectangle {
codeWebSplitter.orientation = (codeWebSplitter.orientation === Qt.Vertical ? Qt.Horizontal : Qt.Vertical); codeWebSplitter.orientation = (codeWebSplitter.orientation === Qt.Vertical ? Qt.Horizontal : Qt.Vertical);
} }
//TODO: move this to debugger.js after refactoring, introduce events
function toggleBreakpoint() {
codeEditor.toggleBreakpoint();
}
function displayCompilationErrorIfAny()
{
rightView.visible = true;
rightView.displayCompilationErrorIfAny();
}
CodeEditorExtensionManager { CodeEditorExtensionManager {
headerView: headerPaneTabs; headerView: headerPaneTabs;
} }
@ -168,6 +194,7 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
orientation: Qt.Vertical orientation: Qt.Vertical
CodeEditorView { CodeEditorView {
id: codeEditor
height: parent.height * 0.6 height: parent.height * 0.6
anchors.top: parent.top anchors.top: parent.top
Layout.fillWidth: true Layout.fillWidth: true
@ -196,7 +223,3 @@ Rectangle {
} }
} }
} }

2
mix/qml/ProjectFilesStyle.qml

@ -25,7 +25,7 @@ QtObject {
property string sectionColor: "#808080" property string sectionColor: "#808080"
property string selectedColor: "white" property string selectedColor: "white"
property string highlightColor: "#4a90e2" property string highlightColor: "#4a90e2"
property int height: 25 property int height: 35
property int fileNameHeight: 30 property int fileNameHeight: 30
property int fontSize: absoluteSize(2)// 13 property int fontSize: absoluteSize(2)// 13
property int sectionFontSize: absoluteSize(2)// 13 property int sectionFontSize: absoluteSize(2)// 13

20
mix/qml/ProjectList.qml

@ -26,11 +26,9 @@ Item {
Image { Image {
id: projectIcon id: projectIcon
source: "qrc:/qml/img/dappProjectIcon.png" source: "qrc:/qml/img/dappProjectIcon.png"
//sourceSize.height: 32
anchors.right: projectTitle.left anchors.right: projectTitle.left
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: 6 anchors.rightMargin: 6
//anchors.centerIn: parent
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
width: 32 width: 32
height: 32 height: 32
@ -65,7 +63,7 @@ Item {
Rectangle Rectangle
{ {
Layout.fillWidth: true Layout.fillWidth: true
height: 10 height: 3
color: ProjectFilesStyle.documentsList.background color: ProjectFilesStyle.documentsList.background
} }
@ -82,14 +80,24 @@ Item {
anchors.top: parent.top anchors.top: parent.top
width: parent.width width: parent.width
spacing: 0 spacing: 0
Repeater { Repeater {
model: [qsTr("Contracts"), qsTr("Javascript"), qsTr("Web Pages"), qsTr("Styles"), qsTr("Images"), qsTr("Misc")]; model: [qsTr("Contracts"), qsTr("Javascript"), qsTr("Web Pages"), qsTr("Styles"), qsTr("Images"), qsTr("Misc")];
signal selected(string doc, string groupName) signal selected(string doc, string groupName)
property int incr: -1;
id: sectionRepeater id: sectionRepeater
FilesSection FilesSection
{ {
id: section;
sectionName: modelData sectionName: modelData
index:
{
for (var k in sectionRepeater.model)
{
if (sectionRepeater.model[k] === modelData)
return k;
}
}
model: sectionModel model: sectionModel
selManager: sectionRepeater selManager: sectionRepeater
@ -119,7 +127,7 @@ Item {
ci++; ci++;
} }
} }
} }
} }
} }
@ -170,10 +178,10 @@ Item {
projectModel.openDocument(newDoc.documentId); projectModel.openDocument(newDoc.documentId);
sectionRepeater.selected(newDoc.documentId, modelData); sectionRepeater.selected(newDoc.documentId, modelData);
} }
} }
} }
} }
} }
} }
} }

19
mix/qml/ProjectModel.qml

@ -7,6 +7,7 @@ import Qt.labs.settings 1.0
import "js/ProjectModel.js" as ProjectModelCode import "js/ProjectModel.js" as ProjectModelCode
Item { Item {
id: projectModel id: projectModel
signal projectClosed signal projectClosed
@ -33,6 +34,7 @@ Item {
property string projectTitle: "" property string projectTitle: ""
property string currentDocumentId: "" property string currentDocumentId: ""
property var deploymentAddresses: [] property var deploymentAddresses: []
property string deploymentDir
property var listModel: projectListModel property var listModel: projectListModel
property var stateListModel: projectStateListModel.model property var stateListModel: projectStateListModel.model
property CodeEditorView codeEditor: null property CodeEditorView codeEditor: null
@ -57,6 +59,7 @@ Item {
function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); } function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); }
function deployProject() { ProjectModelCode.deployProject(false); } function deployProject() { ProjectModelCode.deployProject(false); }
function registerToUrlHint() { ProjectModelCode.registerToUrlHint(); } function registerToUrlHint() { ProjectModelCode.registerToUrlHint(); }
function formatAppUrl() { ProjectModelCode.formatAppUrl(url); }
Connections { Connections {
target: appContext target: appContext
@ -93,28 +96,17 @@ Item {
MessageDialog { MessageDialog {
id: deployWarningDialog id: deployWarningDialog
property bool redeploy
title: qsTr("Project") title: qsTr("Project")
text: text:
{ {
if (Object.keys(projectModel.deploymentAddresses).length > 0) if (Object.keys(projectModel.deploymentAddresses).length > 0)
{ return qsTr("This project has been already deployed to the network. Do you want to redeploy it? (Contract state will be reset)")
redeploy = true
standardButtons = StandardButton.Ok | StandardButton.Reset | StandardButton.Abort;
return qsTr("This project has been already deployed to the network. Do you want to repackage the resources only, or also reset the deployed contract to its initial state?")
}
else else
{
redeploy = false;
standardButtons = StandardButton.Ok | StandardButton.Abort;
return qsTr("This action will deploy to the network. Do you want to deploy it?") return qsTr("This action will deploy to the network. Do you want to deploy it?")
}
} }
icon: StandardIcon.Question icon: StandardIcon.Question
standardButtons: StandardButton.Ok | StandardButton.Abort
onAccepted: { onAccepted: {
ProjectModelCode.startDeployProject(!redeploy);
}
onReset: {
ProjectModelCode.startDeployProject(true); ProjectModelCode.startDeployProject(true);
} }
} }
@ -123,7 +115,6 @@ Item {
id: deployRessourcesDialog id: deployRessourcesDialog
title: qsTr("Project") title: qsTr("Project")
standardButtons: StandardButton.Ok standardButtons: StandardButton.Ok
icon: StandardIcon.Info
} }
DeploymentDialog DeploymentDialog

128
mix/qml/StatusPane.qml

@ -1,6 +1,7 @@
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.3
import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "js/ErrorLocationFormater.js" as ErrorLocationFormater
import "." import "."
@ -13,7 +14,7 @@ Rectangle {
if (!message) if (!message)
{ {
status.state = ""; status.state = "";
status.text = qsTr("Compile without errors."); status.text = qsTr("Compile successfully.");
logslink.visible = false; logslink.visible = false;
debugImg.state = "active"; debugImg.state = "active";
} }
@ -35,17 +36,24 @@ Rectangle {
logslink.visible = false; logslink.visible = false;
} }
function errorMessage(text)
{
status.state = "error";
status.text = text
logslink.visible = false;
}
Connections { Connections {
target:clientModel target:clientModel
onRunStarted: infoMessage(qsTr("Running transactions...")); onRunStarted: infoMessage(qsTr("Running transactions..."));
onRunFailed: infoMessage(qsTr("Error running transactions")); onRunFailed: errorMessage(qsTr("Error running transactions"));
onRunComplete: infoMessage(qsTr("Run complete")); onRunComplete: infoMessage(qsTr("Run complete"));
onNewBlock: infoMessage(qsTr("New block created")); onNewBlock: infoMessage(qsTr("New block created"));
} }
Connections { Connections {
target:projectModel target:projectModel
onDeploymentStarted: infoMessage(qsTr("Running deployment...")); onDeploymentStarted: infoMessage(qsTr("Running deployment..."));
onDeploymentError: infoMessage(error); onDeploymentError: errorMessage(error);
onDeploymentComplete: infoMessage(qsTr("Deployment complete")); onDeploymentComplete: infoMessage(qsTr("Deployment complete"));
onDeploymentStepChanged: infoMessage(message); onDeploymentStepChanged: infoMessage(message);
} }
@ -57,6 +65,7 @@ Rectangle {
color: "transparent" color: "transparent"
anchors.fill: parent anchors.fill: parent
Rectangle { Rectangle {
id: statusContainer id: statusContainer
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@ -65,49 +74,84 @@ Rectangle {
width: 500 width: 500
height: 30 height: 30
color: "#fcfbfc" color: "#fcfbfc"
RowLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
spacing: 5
Text { Text {
font.pointSize: StatusPaneStyle.general.statusFontSize anchors.verticalCenter: parent.verticalCenter
height: 9 anchors.horizontalCenter: parent.horizontalCenter
font.family: "sans serif" font.pointSize: StatusPaneStyle.general.statusFontSize
objectName: "status" height: 15
id: status font.family: "sans serif"
states:[ objectName: "status"
State { wrapMode: Text.WrapAnywhere
name: "error" elide: Text.ElideRight
PropertyChanges { maximumLineCount: 1
target: status clip: true
color: "red" id: status
} states: [
PropertyChanges { State {
target: statusContainer name: "error"
color: "#fffcd5" PropertyChanges {
} target: status
color: "red"
} }
] PropertyChanges {
target: statusContainer
color: "#fffcd5"
}
}
]
onTextChanged:
{
updateWidth()
toolTipInfo.tooltip = text;
} }
Text { function updateWidth()
visible: false {
font.pointSize: StatusPaneStyle.general.logLinkFontSize if (text.length > 80)
height: 9 width = parent.width - 10
text: qsTr("See Log.") else
font.family: "Monospace" width = undefined
objectName: "status" }
id: logslink }
color: "#8c8a74"
MouseArea { Button
anchors.fill: parent {
onClicked: { anchors.fill: parent
mainContent.ensureRightView(); id: toolTip
} action: toolTipInfo
text: ""
style:
ButtonStyle {
background:Rectangle {
color: "transparent"
} }
} }
} }
Action {
id: toolTipInfo
tooltip: ""
}
}
Button
{
id: logslink
anchors.left: statusContainer.right
anchors.leftMargin: 9
visible: false
anchors.verticalCenter: parent.verticalCenter
action: displayLogAction
iconSource: "qrc:/qml/img/search_filled.png"
}
Action {
id: displayLogAction
tooltip: qsTr("Display Log")
onTriggered: {
mainContent.displayCompilationErrorIfAny();
}
} }
Rectangle Rectangle
@ -120,9 +164,13 @@ Rectangle {
RowLayout RowLayout
{ {
anchors.fill: parent anchors.fill: parent
Rectangle { anchors.top: statusHeader.top
anchors.right: statusHeader.right
Rectangle
{
color: "transparent" color: "transparent"
anchors.fill: parent anchors.fill: parent
Button Button
{ {
anchors.right: parent.right anchors.right: parent.right

49
mix/qml/TransactionLog.qml

@ -3,15 +3,13 @@ import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.1 import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import org.ethereum.qml.RecordLogEntry 1.0
Item { Item {
property bool showLogs: true
property ListModel fullModel: ListModel{} property ListModel fullModel: ListModel{}
property ListModel transactionModel: ListModel{} property ListModel transactionModel: ListModel{}
onShowLogsChanged: { property ListModel callModel: ListModel{}
logTable.model = showLogs ? fullModel : transactionModel
}
Action { Action {
id: addStateAction id: addStateAction
@ -78,13 +76,24 @@ Item {
action: mineAction action: mineAction
} }
CheckBox { ComboBox {
id: recording id: itemFilter
text: qsTr("Record transactions");
checked: true function getCurrentModel()
Layout.fillWidth: true {
return currentIndex === 0 ? fullModel : currentIndex === 1 ? transactionModel : currentIndex === 2 ? callModel : fullModel;
}
model: ListModel {
ListElement { text: qsTr("Calls and Transactions"); value: 0; }
ListElement { text: qsTr("Only Transactions"); value: 1; }
ListElement { text: qsTr("Only Calls"); value: 2; }
}
onCurrentIndexChanged:
{
logTable.model = itemFilter.getCurrentModel();
}
} }
} }
TableView { TableView {
@ -125,7 +134,10 @@ Item {
} }
onActivated: { onActivated: {
var item = logTable.model.get(row); var item = logTable.model.get(row);
clientModel.debugRecord(item.recordIndex); if (item.type === RecordLogEntry.Transaction)
clientModel.debugRecord(item.recordIndex);
else
clientModel.emptyRecord();
} }
Keys.onPressed: { Keys.onPressed: {
if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < logTable.model.count) { if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < logTable.model.count) {
@ -141,15 +153,18 @@ Item {
onStateCleared: { onStateCleared: {
fullModel.clear(); fullModel.clear();
transactionModel.clear(); transactionModel.clear();
callModel.clear();
} }
onNewRecord: { onNewRecord: {
if (recording.checked) fullModel.append(_r);
{ if (!_r.call)
fullModel.append(_r); transactionModel.append(_r);
if (!_r.call) else
transactionModel.append(_r); callModel.append(_r);
} }
onMiningComplete: {
fullModel.append(clientModel.lastBlock);
transactionModel.append(clientModel.lastBlock);
} }
} }
} }

28
mix/qml/WebCodeEditor.qml

@ -2,15 +2,16 @@ import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import QtQuick.Layouts 1.0 import QtQuick.Layouts 1.0
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import CodeEditorExtensionManager 1.0
import QtWebEngine 1.0 import QtWebEngine 1.0
import QtWebEngine.experimental 1.0 import QtWebEngine.experimental 1.0
Item { Item {
signal editorTextChanged signal editorTextChanged;
signal breakpointsChanged;
property string currentText: "" property string currentText: ""
property string currentMode: "" property string currentMode: ""
property bool initialized: false property bool initialized: false
property var currentBreakpoints: [];
function setText(text, mode) { function setText(text, mode) {
currentText = text; currentText = text;
@ -37,6 +38,18 @@ Item {
} }
} }
function highlightExecution(location) {
editorBrowser.runJavaScript("highlightExecution(" + location.start + "," + location.end + ")");
}
function getBreakpoints() {
return currentBreakpoints;
}
function toggleBreakpoint() {
editorBrowser.runJavaScript("toggleBreakpoint()");
}
Connections { Connections {
target: appContext target: appContext
onClipboardChanged: syncClipboard() onClipboardChanged: syncClipboard()
@ -80,6 +93,17 @@ Item {
}); });
} }
}); });
editorBrowser.runJavaScript("getBreakpointsChanged()", function(result) {
if (result === true) {
editorBrowser.runJavaScript("getBreakpoints()" , function(bp) {
if (currentBreakpoints !== bp) {
currentBreakpoints = bp;
breakpointsChanged();
}
});
}
});
} }
} }
} }

60
mix/qml/WebPreview.qml

@ -26,7 +26,8 @@ Item {
function reload() { function reload() {
if (initialized) { if (initialized) {
updateContract(); updateContract();
webView.runJavaScript("reloadPage()"); //webView.runJavaScript("reloadPage()");
setPreviewUrl(urlInput.text);
} }
} }
@ -55,11 +56,13 @@ Item {
} }
function changePage() { function changePage() {
if (pageCombo.currentIndex >= 0 && pageCombo.currentIndex < pageListModel.count) { setPreviewUrl(urlInput.text);
/*if (pageCombo.currentIndex >= 0 && pageCombo.currentIndex < pageListModel.count) {
urlInput.text = httpServer.url + "/" + pageListModel.get(pageCombo.currentIndex).documentId;
setPreviewUrl(httpServer.url + "/" + pageListModel.get(pageCombo.currentIndex).documentId); setPreviewUrl(httpServer.url + "/" + pageListModel.get(pageCombo.currentIndex).documentId);
} else { } else {
setPreviewUrl(""); setPreviewUrl("");
} }*/
} }
Connections { Connections {
target: appContext target: appContext
@ -98,24 +101,16 @@ Item {
updateDocument(documentId, function(i) { pageListModel.set(i, projectModel.getDocument(documentId)) } ) updateDocument(documentId, function(i) { pageListModel.set(i, projectModel.getDocument(documentId)) } )
} }
onDocumentOpened: {
if (!document.isHtml)
return;
for (var i = 0; i < pageListModel.count; i++) {
var doc = pageListModel.get(i);
if (doc.documentId === document.documentId) {
pageCombo.currentIndex = i;
}
}
}
onProjectLoading: { onProjectLoading: {
for (var i = 0; i < target.listModel.count; i++) { for (var i = 0; i < target.listModel.count; i++) {
var document = target.listModel.get(i); var document = target.listModel.get(i);
if (document.isHtml) { if (document.isHtml) {
pageListModel.append(document); pageListModel.append(document);
if (pageListModel.count === 1) //first page added if (pageListModel.count === 1) //first page added
changePage(); {
urlInput.text = httpServer.url + "/" + document.documentId;
setPreviewUrl(httpServer.url + "/" + document.documentId);
}
} }
} }
} }
@ -151,13 +146,20 @@ Item {
else else
{ {
//document request //document request
if (urlPath === "/")
urlPath = "/index.html";
var documentId = urlPath.substr(urlPath.lastIndexOf("/") + 1); var documentId = urlPath.substr(urlPath.lastIndexOf("/") + 1);
var content = ""; var content = "";
if (projectModel.codeEditor.isDocumentOpen(documentId)) if (projectModel.codeEditor.isDocumentOpen(documentId))
content = projectModel.codeEditor.getDocumentText(documentId); content = projectModel.codeEditor.getDocumentText(documentId);
else else
content = fileIo.readFile(projectModel.getDocument(documentId).path); {
if (documentId === pageListModel.get(pageCombo.currentIndex).documentId) { var doc = projectModel.getDocument(documentId);
if (doc !== undefined)
content = fileIo.readFile(doc.path);
}
if (documentId === urlInput.text.replace(httpServer.url + "/", "")) {
//root page, inject deployment script //root page, inject deployment script
content = "<script>web3=parent.web3;contracts=parent.contracts;</script>\n" + content; content = "<script>web3=parent.web3;contracts=parent.contracts;</script>\n" + content;
_request.setResponseContentType("text/html"); _request.setResponseContentType("text/html");
@ -181,19 +183,23 @@ Item {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 3 anchors.leftMargin: 3
spacing: 3 spacing: 3
DefaultLabel {
text: qsTr("Preview of")
anchors.verticalCenter: parent.verticalCenter
}
ComboBox { DefaultTextField
id: pageCombo {
model: pageListModel id: urlInput
textRole: "name"
currentIndex: -1
onCurrentIndexChanged: changePage()
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
height: 21 height: 21
width: 300
Keys.onEnterPressed:
{
setPreviewUrl(text);
}
Keys.onReturnPressed:
{
setPreviewUrl(text);
}
focus: true
} }
Action { Action {

4
mix/qml/html/cm/codemirror.css

@ -8,6 +8,10 @@
font-size:12px font-size:12px
} }
/* BREAKPOINTS */
.breakpoints {width: .8em;}
.breakpoint { color: #822; }
/* PADDING */ /* PADDING */
.CodeMirror-lines { .CodeMirror-lines {

6
mix/qml/html/cm/solarized.css

@ -163,3 +163,9 @@ view-port
.cm-s-solarized.cm-s-light .CodeMirror-activeline-background { .cm-s-solarized.cm-s-light .CodeMirror-activeline-background {
background: rgba(0, 0, 0, 0.10); background: rgba(0, 0, 0, 0.10);
} }
/* Code execution */
.CodeMirror-exechighlight {
background: rgba(255, 255, 255, 0.10);
}

50
mix/qml/html/codeeditor.js

@ -4,6 +4,7 @@ var editor = CodeMirror(document.body, {
//styleActiveLine: true, //styleActiveLine: true,
matchBrackets: true, matchBrackets: true,
autofocus: true, autofocus: true,
gutters: ["CodeMirror-linenumbers", "breakpoints"]
}); });
@ -13,6 +14,7 @@ editor.setOption("indentWithTabs", true);
editor.setOption("fullScreen", true); editor.setOption("fullScreen", true);
editor.changeRegistered = false; editor.changeRegistered = false;
editor.breakpointsChangeRegistered = false;
editor.on("change", function(eMirror, object) { editor.on("change", function(eMirror, object) {
editor.changeRegistered = true; editor.changeRegistered = true;
@ -33,6 +35,28 @@ editor.setOption("extraKeys", {
}}); }});
} }
makeMarker = function() {
var marker = document.createElement("div");
marker.style.color = "#822";
marker.innerHTML = "●";
return marker;
};
toggleBreakpointLine = function(n) {
var info = editor.lineInfo(n);
editor.setGutterMarker(n, "breakpoints", info.gutterMarkers ? null : makeMarker());
editor.breakpointsChangeRegistered = true;
}
editor.on("gutterClick", function(cm, n) {
toggleBreakpointLine(n);
});
toggleBreakpoint = function() {
var line = editor.getCursor().line;
toggleBreakpointLine(line);
}
getTextChanged = function() { getTextChanged = function() {
return editor.changeRegistered; return editor.changeRegistered;
}; };
@ -42,6 +66,25 @@ getText = function() {
return editor.getValue(); return editor.getValue();
}; };
getBreakpointsChanged = function() {
return editor.changeRegistered || editor.breakpointsChangeRegistered; //TODO: track new lines
};
getBreakpoints = function() {
var locations = [];
editor.breakpointsChangeRegistered = false;
var doc = editor.doc;
doc.iter(function(line) {
if (line.gutterMarkers && line.gutterMarkers["breakpoints"]) {
var l = doc.getLineNumber(line);
locations.push({
start: editor.indexFromPos({ line: l, ch: 0}),
end: editor.indexFromPos({ line: l + 1, ch: 0})
});;
}
});
return locations;
};
setTextBase64 = function(text) { setTextBase64 = function(text) {
editor.setValue(window.atob(text)); editor.setValue(window.atob(text));
@ -60,3 +103,10 @@ setMode = function(mode) {
setClipboardBase64 = function(text) { setClipboardBase64 = function(text) {
clipboard = window.atob(text); clipboard = window.atob(text);
}; };
var executionMark;
highlightExecution = function(start, end) {
if (executionMark)
executionMark.clear();
executionMark = editor.markText(editor.posFromIndex(start), editor.posFromIndex(end), { className: "CodeMirror-exechighlight" });
}

BIN
mix/qml/img/search_filled.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

147
mix/qml/js/Debugger.js

@ -5,6 +5,9 @@ var currentSelectedState = null;
var currentDisplayedState = null; var currentDisplayedState = null;
var debugData = null; var debugData = null;
var codeMap = null; var codeMap = null;
var locations = [];
var locationMap = {};
var breakpoints = {};
function init(data) function init(data)
{ {
@ -22,6 +25,8 @@ function init(data)
currentSelectedState = null; currentSelectedState = null;
currentDisplayedState = null; currentDisplayedState = null;
debugData = null; debugData = null;
locations = [];
locationMap = {};
return; return;
} }
@ -30,9 +35,59 @@ function init(data)
currentDisplayedState = 0; currentDisplayedState = 0;
setupInstructions(currentSelectedState); setupInstructions(currentSelectedState);
setupCallData(currentSelectedState); setupCallData(currentSelectedState);
statesSlider.maximumValue = data.states.length - 1; initLocations();
initSlider();
selectState(currentSelectedState);
}
function updateMode()
{
initSlider();
}
function initLocations()
{
locations = [];
if (debugData.states.length === 0)
return;
var nullLocation = { start: -1, end: -1, documentId: "", state: 0 };
var prevLocation = nullLocation;
for (var i = 0; i < debugData.states.length - 1; i++) {
var code = debugData.states[i].code;
var location = code.documentId ? code.locations[codeStr(i)] : nullLocation;
if (location.start !== prevLocation.start || location.end !== prevLocation.end || code.documentId !== prevLocation.documentId)
{
prevLocation = { start: location.start, end: location.end, documentId: code.documentId, state: i };
locations.push(prevLocation);
}
locationMap[i] = locations.length - 1;
}
locations.push({ start: -1, end: -1, documentId: code.documentId, state: i });
locationMap[debugData.states.length - 1] = locations.length - 1;
}
function setBreakpoints(bp)
{
breakpoints = bp;
}
function srcMode()
{
return !assemblyMode && locations.length;
}
function initSlider()
{
if (!debugData)
statesSlider.maximumValue = 0;
else if (srcMode()) {
statesSlider.maximumValue = locations.length - 1;
} else {
statesSlider.maximumValue = debugData.states.length - 1;
}
statesSlider.value = 0; statesSlider.value = 0;
select(currentSelectedState);
} }
function setupInstructions(stateIndex) function setupInstructions(stateIndex)
@ -54,11 +109,13 @@ function setupCallData(stateIndex)
function moveSelection(incr) function moveSelection(incr)
{ {
var prevState = currentSelectedState; if (srcMode()) {
if (currentSelectedState + incr >= 0) var locationIndex = locationMap[currentSelectedState];
{ if (locationIndex + incr >= 0 && locationIndex + incr < locations.length)
if (currentSelectedState + incr < debugData.states.length) selectState(locations[locationIndex + incr].state);
select(currentSelectedState + incr); } else {
if (currentSelectedState + incr >= 0 && currentSelectedState + incr < debugData.states.length)
selectState(currentSelectedState + incr);
} }
} }
@ -67,7 +124,7 @@ function display(stateIndex)
if (stateIndex < 0) if (stateIndex < 0)
stateIndex = 0; stateIndex = 0;
if (stateIndex >= debugData.states.length) if (stateIndex >= debugData.states.length)
stateIndex = debugData.state.length - 1; stateIndex = debugData.states.length - 1;
if (debugData.states[stateIndex].codeIndex !== debugData.states[currentDisplayedState].codeIndex) if (debugData.states[stateIndex].codeIndex !== debugData.states[currentDisplayedState].codeIndex)
setupInstructions(stateIndex); setupInstructions(stateIndex);
if (debugData.states[stateIndex].dataIndex !== debugData.states[currentDisplayedState].dataIndex) if (debugData.states[stateIndex].dataIndex !== debugData.states[currentDisplayedState].dataIndex)
@ -77,6 +134,9 @@ function display(stateIndex)
highlightSelection(codeLine); highlightSelection(codeLine);
completeCtxInformation(state); completeCtxInformation(state);
currentDisplayedState = stateIndex; currentDisplayedState = stateIndex;
var docId = debugData.states[stateIndex].code.documentId;
if (docId)
debugExecuteLocation(docId, locations[locationMap[stateIndex]]);
} }
function displayFrame(frameIndex) function displayFrame(frameIndex)
@ -88,26 +148,39 @@ function displayFrame(frameIndex)
display(state.levels[frameIndex - 1]); display(state.levels[frameIndex - 1]);
} }
function select(stateIndex) function select(index)
{
if (srcMode())
selectState(locations[index].state);
else
selectState(index);
}
function selectState(stateIndex)
{ {
display(stateIndex); display(stateIndex);
currentSelectedState = stateIndex; currentSelectedState = stateIndex;
var state = debugData.states[stateIndex]; var state = debugData.states[stateIndex];
statesSlider.value = stateIndex;
jumpIntoForwardAction.enabled(stateIndex < debugData.states.length - 1) jumpIntoForwardAction.enabled(stateIndex < debugData.states.length - 1)
jumpIntoBackAction.enabled(stateIndex > 0); jumpIntoBackAction.enabled(stateIndex > 0);
jumpOverForwardAction.enabled(stateIndex < debugData.states.length - 1); jumpOverForwardAction.enabled(stateIndex < debugData.states.length - 1);
jumpOverBackAction.enabled(stateIndex > 0); jumpOverBackAction.enabled(stateIndex > 0);
jumpOutBackAction.enabled(state.levels.length > 1); jumpOutBackAction.enabled(state.levels.length > 1);
jumpOutForwardAction.enabled(state.levels.length > 1); jumpOutForwardAction.enabled(state.levels.length > 1);
runForwardAction.enabled(stateIndex < debugData.states.length - 1)
runBackAction.enabled(stateIndex > 0);
var callStackData = []; var callStackData = [];
for (var l = 0; l < state.levels.length; l++) { for (var l = 0; l < state.levels.length; l++) {
var address = debugData.states[state.levels[l] + 1].address; var address = debugData.states[state.levels[l] + 1].code.address;
callStackData.push(address); callStackData.push(address);
} }
callStackData.push(debugData.states[0].address); callStackData.push(debugData.states[0].code.address);
callStack.listModel = callStackData; callStack.listModel = callStackData;
if (srcMode())
statesSlider.value = locationMap[stateIndex];
else
statesSlider.value = stateIndex;
} }
function codeStr(stateIndex) function codeStr(stateIndex)
@ -147,6 +220,24 @@ function isReturnInstruction(index)
return state.instruction === "RETURN" return state.instruction === "RETURN"
} }
function locationsIntersect(l1, l2)
{
return l1.start <= l2.end && l1.end >= l2.start;
}
function breakpointHit(i)
{
var bpLocations = breakpoints[debugData.states[i].code.documentId];
if (bpLocations) {
var location = locations[locationMap[i]];
if (location.start >= 0 && location.end >= location.start)
for (var b = 0; b < bpLocations.length; b++)
if (locationsIntersect(location, bpLocations[b]))
return true;
}
return false;
}
function stepIntoBack() function stepIntoBack()
{ {
moveSelection(-1); moveSelection(-1);
@ -173,25 +264,48 @@ function stepIntoForward()
moveSelection(1); moveSelection(1);
} }
function runBack()
{
var i = currentSelectedState - 1;
while (i > 0 && !breakpointHit(i)) {
--i;
}
selectState(i);
}
function runForward()
{
var i = currentSelectedState + 1;
while (i < debugData.states.length - 1 && !breakpointHit(i)) {
++i;
}
selectState(i);
}
function stepOutBack() function stepOutBack()
{ {
var i = currentSelectedState - 1; var i = currentSelectedState - 1;
var depth = 0; var depth = 0;
while (--i >= 0) while (--i >= 0) {
if (breakpointHit(i))
break;
if (isCallInstruction(i)) if (isCallInstruction(i))
if (depth == 0) if (depth == 0)
break; break;
else depth--; else depth--;
else if (isReturnInstruction(i)) else if (isReturnInstruction(i))
depth++; depth++;
select(i); }
selectState(i);
} }
function stepOutForward() function stepOutForward()
{ {
var i = currentSelectedState; var i = currentSelectedState;
var depth = 0; var depth = 0;
while (++i < debugData.states.length) while (++i < debugData.states.length) {
if (breakpointHit(i))
break;
if (isReturnInstruction(i)) if (isReturnInstruction(i))
if (depth == 0) if (depth == 0)
break; break;
@ -199,7 +313,8 @@ function stepOutForward()
depth--; depth--;
else if (isCallInstruction(i)) else if (isCallInstruction(i))
depth++; depth++;
select(i + 1); }
selectState(i + 1);
} }
function jumpTo(value) function jumpTo(value)

386
mix/qml/js/ProjectModel.js

@ -20,6 +20,7 @@
* Ethereum IDE client. * Ethereum IDE client.
*/ */
Qt.include("QEtherHelper.js") Qt.include("QEtherHelper.js")
Qt.include("TransactionHelper.js")
var htmlTemplate = "<html>\n<head>\n<script>\n</script>\n</head>\n<body>\n<script>\n</script>\n</body>\n</html>"; var htmlTemplate = "<html>\n<head>\n<script>\n</script>\n</head>\n<body>\n<script>\n</script>\n</body>\n</html>";
var contractTemplate = "contract Contract {\n}\n"; var contractTemplate = "contract Contract {\n}\n";
@ -50,7 +51,8 @@ function saveProject() {
applicationUrlEth: deploymentDialog.applicationUrlEth, applicationUrlEth: deploymentDialog.applicationUrlEth,
applicationUrlHttp: deploymentDialog.applicationUrlHttp, applicationUrlHttp: deploymentDialog.applicationUrlHttp,
packageHash: deploymentDialog.packageHash, packageHash: deploymentDialog.packageHash,
packageBase64: deploymentDialog.packageBase64 packageBase64: deploymentDialog.packageBase64,
deploymentDir: projectModel.deploymentDir
}; };
for (var i = 0; i < projectListModel.count; i++) for (var i = 0; i < projectListModel.count; i++)
projectData.files.push(projectListModel.get(i).fileName) projectData.files.push(projectListModel.get(i).fileName)
@ -64,10 +66,12 @@ function saveProject() {
function loadProject(path) { function loadProject(path) {
closeProject(); closeProject();
console.log("loading project at " + path); console.log("Loading project at " + path);
var projectFile = path + projectFileName; var projectFile = path + projectFileName;
var json = fileIo.readFile(projectFile); var json = fileIo.readFile(projectFile);
var projectData = JSON.parse(json); var projectData = JSON.parse(json);
if (projectData.deploymentDir)
projectModel.deploymentDir = projectData.deploymentDir
if (projectData.packageHash) if (projectData.packageHash)
deploymentDialog.packageHash = projectData.packageHash deploymentDialog.packageHash = projectData.packageHash
if (projectData.packageBase64) if (projectData.packageBase64)
@ -185,7 +189,7 @@ function doCloseProject() {
function doCreateProject(title, path) { function doCreateProject(title, path) {
closeProject(); closeProject();
console.log("creating project " + title + " at " + path); console.log("Creating project " + title + " at " + path);
if (path[path.length - 1] !== "/") if (path[path.length - 1] !== "/")
path += "/"; path += "/";
var dirPath = path + title + "/"; var dirPath = path + title + "/";
@ -303,49 +307,61 @@ function startDeployProject(erasePrevious)
console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); console.log("Deploying " + deploymentId + " to " + jsonRpcUrl);
deploymentStarted(); deploymentStarted();
var requests = []; var ctrNames = Object.keys(codeModel.contracts);
var requestNames = []; var ctrAddresses = {};
setDefaultBlock(0, function() {
for (var c in codeModel.contracts) { //TODO: order based on dependencies deployContracts(0, ctrAddresses, ctrNames, function (){
var code = codeModel.contracts[c].codeHex; finalizeDeployment(deploymentId, ctrAddresses);
requests.push({
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "code": code } ],
id: jsonRpcRequestId++
}); });
requestNames.push(c); });
} }
var rpcRequest = JSON.stringify(requests); function setDefaultBlock(val, callBack)
var httpRequest = new XMLHttpRequest(); {
httpRequest.open("POST", jsonRpcUrl, true); var requests = [{
httpRequest.setRequestHeader("Content-type", "application/json"); jsonrpc: "2.0",
httpRequest.setRequestHeader("Content-length", rpcRequest.length); method: "eth_setDefaultBlock",
httpRequest.setRequestHeader("Connection", "close"); params: [val],
httpRequest.onreadystatechange = function() { id: 0
if (httpRequest.readyState === XMLHttpRequest.DONE) { }];
if (httpRequest.status === 200) { rpcCall(requests, function (httpCall, response){
var rpcResponse = JSON.parse(httpRequest.responseText); callBack();
if (rpcResponse.length === requestNames.length) { });
var contractAddresses = {}; }
for (var r = 0; r < rpcResponse.length; r++)
contractAddresses[requestNames[r]] = rpcResponse[r].result; function deployContracts(ctrIndex, ctrAddresses, ctrNames, callBack)
finalizeDeployment(deploymentId, contractAddresses); {
} var code = codeModel.contracts[ctrNames[ctrIndex]].codeHex;
} else { var requests = [{
var errorText = qsTr("Deployment error: RPC server HTTP status ") + httpRequest.status; jsonrpc: "2.0",
console.log(errorText); method: "eth_transact",
deploymentError(errorText); params: [ { "from": deploymentDialog.currentAccount, "gas": deploymentDialog.gasToUse, "code": code } ],
id: 0
}];
rpcCall(requests, function (httpCall, response){
var txt = qsTr("Please wait while " + ctrNames[ctrIndex] + " is published ...")
deploymentStepChanged(txt);
console.log(txt);
ctrAddresses[ctrNames[ctrIndex]] = JSON.parse(response)[0].result
deploymentDialog.waitForTrCountToIncrement(function(status) {
if (status === -1)
{
trCountIncrementTimeOut();
return;
} }
} ctrIndex++;
} if (ctrIndex < ctrNames.length)
httpRequest.send(rpcRequest); deployContracts(ctrIndex, ctrAddresses, ctrNames, callBack);
else
callBack();
});
});
} }
function finalizeDeployment(deploymentId, addresses) { function finalizeDeployment(deploymentId, addresses) {
deploymentStepChanged(qsTr("Packaging application ...")); deploymentStepChanged(qsTr("Packaging application ..."));
var deploymentDir = projectPath + deploymentId + "/"; var deploymentDir = projectPath + deploymentId + "/";
projectModel.deploymentDir = deploymentDir;
fileIo.makeDir(deploymentDir); fileIo.makeDir(deploymentDir);
for (var i = 0; i < projectListModel.count; i++) { for (var i = 0; i < projectListModel.count; i++) {
var doc = projectListModel.get(i); var doc = projectListModel.get(i);
@ -372,16 +388,16 @@ function finalizeDeployment(deploymentId, addresses) {
} }
//write deployment js //write deployment js
var deploymentJs = var deploymentJs =
"// Autogenerated by Mix\n" + "// Autogenerated by Mix\n" +
"web3 = require(\"web3\");\n" + "web3 = require(\"web3\");\n" +
"contracts = {};\n"; "contracts = {};\n";
for (var c in codeModel.contracts) { for (var c in codeModel.contracts) {
var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]"; var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]";
deploymentJs += contractAccessor + " = {\n" + deploymentJs += contractAccessor + " = {\n" +
"\tinterface: " + codeModel.contracts[c].contractInterface + ",\n" + "\tinterface: " + codeModel.contracts[c].contractInterface + ",\n" +
"\taddress: \"" + addresses[c] + "\"\n" + "\taddress: \"" + addresses[c] + "\"\n" +
"};\n" + "};\n" +
contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n"; contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n";
} }
fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs); fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs);
//copy scripts //copy scripts
@ -395,152 +411,185 @@ function finalizeDeployment(deploymentId, addresses) {
deploymentDialog.packageBase64 = packageRet[1]; deploymentDialog.packageBase64 = packageRet[1];
var applicationUrlEth = deploymentDialog.applicationUrlEth; var applicationUrlEth = deploymentDialog.applicationUrlEth;
applicationUrlEth = formatAppUrl(applicationUrlEth);
applicationUrlEth = formatAppUrl(applicationUrlEth);
deploymentStepChanged(qsTr("Registering application on the Ethereum network ...")); deploymentStepChanged(qsTr("Registering application on the Ethereum network ..."));
checkRegistration(applicationUrlEth, deploymentDialog.eth, function () { checkEthPath(applicationUrlEth, function () {
deploymentComplete(); deploymentComplete();
deployRessourcesDialog.text = qsTr("Register Web Application to finalize deployment."); deployRessourcesDialog.text = qsTr("Register Web Application to finalize deployment.");
deployRessourcesDialog.open(); deployRessourcesDialog.open();
setDefaultBlock(-1, function() {});
}); });
} }
function rpcCall(requests, callBack) function checkEthPath(dappUrl, callBack)
{ {
var jsonRpcUrl = "http://localhost:8080"; if (dappUrl.length === 1)
var rpcRequest = JSON.stringify(requests); registerContentHash(deploymentDialog.eth, callBack); // we directly create a dapp under the root registrar.
var httpRequest = new XMLHttpRequest(); else
httpRequest.open("POST", jsonRpcUrl, true);
httpRequest.setRequestHeader("Content-type", "application/json");
httpRequest.setRequestHeader("Content-length", rpcRequest.length);
httpRequest.setRequestHeader("Connection", "close");
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status !== 200)
{
var errorText = qsTr("Deployment error: Error while registering Dapp ") + httpRequest.status;
console.log(errorText);
deploymentError(errorText);
return;
}
callBack(httpRequest.status, httpRequest.responseText)
}
}
httpRequest.send(rpcRequest);
}
function checkRegistration(dappUrl, addr, callBack)
{
var requests = [];
var data = "";
if (dappUrl.length > 0)
{ {
//checking path (register). // the first owned reigstrar must have been created to follow the path.
var str = createString(dappUrl[0]); var str = createString(dappUrl[0]);
data = "0x6be16bed" + str.encodeValueAsString(); var requests = [];
console.log("checking if path exists (register) => " + JSON.stringify(dappUrl));
requests.push({ requests.push({
jsonrpc: "2.0", //register()
method: "eth_call", jsonrpc: "2.0",
params: [ { "to": '0x' + addr, "data": data } ], method: "eth_call",
id: jsonRpcRequestId++ params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0x6be16bed" + str.encodeValueAsString() } ],
}); id: jsonRpcRequestId++
});
rpcCall(requests, function (httpRequest, response) { rpcCall(requests, function (httpRequest, response) {
var address = JSON.parse(response)[0].result.replace('0x', ''); var res = JSON.parse(response);
if (address === "") var addr = normalizeAddress(res[0].result);
if (addr.replace(/0+/g, "") === "")
{ {
var errorTxt = qsTr("Path does not exists " + JSON.stringify(dappUrl) + " cannot continue"); var errorTxt = qsTr("Path does not exists " + JSON.stringify(dappUrl) + ". Please register using Registration Dapp. Aborting.");
deploymentError(errorTxt); deploymentError(errorTxt);
console.log(errorTxt); console.log(errorTxt);
return;
} }
else
dappUrl.splice(0, 1); {
checkRegistration(dappUrl, address, callBack); dappUrl.splice(0, 1);
checkRegistration(dappUrl, addr, callBack);
}
}); });
} }
}
function checkRegistration(dappUrl, addr, callBack)
{
if (dappUrl.length === 1)
registerContentHash(addr, callBack); // We do not create the register for the last part, just registering the content hash.
else else
{ {
var paramTitle = createString(projectModel.projectTitle); var txt = qsTr("Checking " + JSON.stringify(dappUrl) + " ... in registrar " + addr);
deploymentStepChanged(txt);
console.log(txt);
var requests = [];
var registrar = {}
var str = createString(dappUrl[0]);
requests.push({ requests.push({
//owner() //getOwner()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_call", method: "eth_call",
params: [ { "to": '0x' + addr, "data": "0xec7b9200" + paramTitle.encodeValueAsString() } ], params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x893d20e8" } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
requests.push({ requests.push({
//accounts //register()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_accounts", method: "eth_call",
params: null, params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x6be16bed" + str.encodeValueAsString() } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
rpcCall(requests, function (httpRequest, response) { rpcCall(requests, function (httpRequest, response) {
requests = [];
var res = JSON.parse(response); var res = JSON.parse(response);
var currentOwner = res[0].result; var nextAddr = normalizeAddress(res[1].result);
var noOwner = currentOwner.replace('0x', '').replace(/0/g, '') === ''; var errorTxt;
if (res[1].result === "0x")
if (noOwner)
{ {
requests.push({ errorTxt = qsTr("Error when creating new owned regsitrar. Please use the regsitration Dapp. Aborting");
//reserve() deploymentError(errorTxt);
jsonrpc: "2.0", console.log(errorTxt);
method: "eth_transact", }
params: [ { "to": '0x' + addr, "data": "0x1c83171b" + paramTitle.encodeValueAsString() } ], else if (normalizeAddress(deploymentDialog.currentAccount) !== normalizeAddress(res[0].result))
id: jsonRpcRequestId++ {
}); errorTxt = qsTr("You are not the owner of " + dappUrl[0] + ". Aborting");
deploymentError(errorTxt);
console.log(errorTxt);
}
else if (nextAddr.replace(/0+/g, "") !== "")
{
dappUrl.splice(0, 1);
checkRegistration(dappUrl, nextAddr, callBack);
} }
else else
{ {
var bOwner = false; var txt = qsTr("Registering sub domain " + dappUrl[0] + " ...");
currentOwner = normalizeAddress(currentOwner); console.log(txt);
for (var u in res[1].result) deploymentStepChanged(txt);
{ //current registrar is owned => ownedregistrar creation and continue.
if (normalizeAddress(res[1].result[u]) === currentOwner) requests = [];
bOwner = true;
} requests.push({
jsonrpc: "2.0",
if (!bOwner) method: "eth_transact",
{ params: [ { "from": deploymentDialog.currentAccount, "gas": 20000, "code": "0x60056013565b61059e8061001d6000396000f35b33600081905550560060003560e060020a90048063019848921461009a578063449c2090146100af5780635d574e32146100cd5780635fd4b08a146100e1578063618242da146100f65780636be16bed1461010b5780636c4489b414610129578063893d20e8146101585780639607730714610173578063c284bc2a14610187578063e50f599a14610198578063e5811b35146101af578063ec7b9200146101cd57005b6100a560043561031b565b8060005260206000f35b6100ba6004356103a0565b80600160a060020a031660005260206000f35b6100db600435602435610537565b60006000f35b6100ec600435610529565b8060005260206000f35b6101016004356103dd565b8060005260206000f35b6101166004356103bd565b80600160a060020a031660005260206000f35b61013460043561034b565b82600160a060020a031660005281600160a060020a03166020528060405260606000f35b610160610341565b80600160a060020a031660005260206000f35b6101816004356024356102b4565b60006000f35b6101926004356103fd565b60006000f35b6101a96004356024356044356101f2565b60006000f35b6101ba6004356101eb565b80600160a060020a031660005260206000f35b6101d8600435610530565b80600160a060020a031660005260206000f35b6000919050565b600054600160a060020a031633600160a060020a031614610212576102af565b8160026000858152602001908152602001600020819055508061023457610287565b81600160a060020a0316837f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a3826001600084600160a060020a03168152602001908152602001600020819055505b827f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505050565b600054600160a060020a031633600160a060020a0316146102d457610317565b806002600084815260200190815260200160002060010181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b5050565b60006001600083600160a060020a03168152602001908152602001600020549050919050565b6000600054905090565b6000600060006002600085815260200190815260200160002054925060026000858152602001908152602001600020600101549150600260008581526020019081526020016000206002015490509193909250565b600060026000838152602001908152602001600020549050919050565b600060026000838152602001908152602001600020600101549050919050565b600060026000838152602001908152602001600020600201549050919050565b600054600160a060020a031633600160a060020a03161461041d57610526565b80600160006002600085815260200190815260200160002054600160a060020a031681526020019081526020016000205414610458576104d2565b6002600082815260200190815260200160002054600160a060020a0316817f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a36000600160006002600085815260200190815260200160002054600160a060020a03168152602001908152602001600020819055505b6002600082815260200190815260200160002060008101600090556001810160009055600281016000905550807f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b50565b6000919050565b6000919050565b600054600160a060020a031633600160a060020a0316146105575761059a565b806002600084815260200190815260200160002060020181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505056" } ],
var errorTxt = qsTr("Current user is not the owner of this path. Cannot continue") id: jsonRpcRequestId++
deploymentError(errorTxt); });
console.log(errorTxt);
return; rpcCall(requests, function(httpRequest, response) {
} var newCtrAddress = normalizeAddress(JSON.parse(response)[0].result);
requests = [];
var txt = qsTr("Please wait " + dappUrl[0] + " is registering ...");
deploymentStepChanged(txt);
console.log(txt);
deploymentDialog.waitForTrCountToIncrement(function(status) {
if (status === -1)
{
trCountIncrementTimeOut();
return;
}
var crLevel = createString(dappUrl[0]).encodeValueAsString();
requests.push({
//setRegister()
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "from": deploymentDialog.currentAccount, "gas": 2000, "to": '0x' + addr, "data": "0x96077307" + crLevel + deploymentDialog.pad(newCtrAddress) } ],
id: jsonRpcRequestId++
});
rpcCall(requests, function(request, response){
dappUrl.splice(0, 1);
checkRegistration(dappUrl, newCtrAddress, callBack);
});
});
});
} }
console.log("setContentHash");
requests.push({
//setContent()
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "to": '0x' + addr, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + deploymentDialog.packageHash } ],
id: jsonRpcRequestId++
});
rpcCall(requests, function (httpRequest, response) {
callBack();
});
}); });
} }
} }
function trCountIncrementTimeOut()
{
var error = qsTr("Something went wrong during the deployment. Please verify the amount of gas for this transaction and check your balance.")
console.log(error);
deploymentError(error);
}
function registerContentHash(registrar, callBack)
{
var txt = qsTr("Finalizing Dapp registration ...");
deploymentStepChanged(txt);
console.log(txt);
var requests = [];
var paramTitle = createString(projectModel.projectTitle);
requests.push({
//setContent()
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "from": deploymentDialog.currentAccount, "gas": 2000, "gasPrice": "10", "to": '0x' + registrar, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + deploymentDialog.packageHash } ],
id: jsonRpcRequestId++
});
rpcCall(requests, function (httpRequest, response) {
callBack();
});
}
function registerToUrlHint() function registerToUrlHint()
{ {
deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.applicationUrlHttp) + ") ..."); deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.applicationUrlHttp) + ") ...");
var requests = []; var requests = [];
var paramUrlHttp = createString(deploymentDialog.applicationUrlHttp); var paramUrlHttp = createString(deploymentDialog.applicationUrlHttp);
requests.push({ requests.push({
//urlHint => suggestUrl //urlHint => suggestUrl
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_transact", method: "eth_transact",
params: [ { "to": '0x' + deploymentDialog.urlHintContract, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ], params: [ { "to": '0x' + deploymentDialog.urlHintContract, "gas": 2000, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
rpcCall(requests, function (httpRequest, response) { rpcCall(requests, function (httpRequest, response) {
deploymentComplete(); deploymentComplete();
@ -550,40 +599,35 @@ function registerToUrlHint()
function normalizeAddress(addr) function normalizeAddress(addr)
{ {
addr = addr.replace('0x', ''); addr = addr.replace('0x', '');
var i = 0; if (addr.length <= 40)
for (var k in addr) return addr;
{ var left = addr.length - 40;
if (addr[k] !== "0") return addr.substring(left);
break;
else
i++;
}
return addr.substring(i);
} }
function formatAppUrl(url) function formatAppUrl(url)
{ {
var slash = url.indexOf("/"); if (url.toLowerCase().indexOf("eth://") === 0)
var dot = url.indexOf("."); url = url.substring(6);
if (slash === -1 && dot === -1) if (url === "")
return url; return [projectModel.projectTitle];
if ((slash !== -1 && slash < dot) || dot === -1)
return url.split("/"); var ret;
if (url.indexOf("/") === -1)
ret = url.split('.').reverse();
else else
{ {
var dotted; var slash = url.indexOf("/");
var ret = []; var left = url.substring(0, slash);
if (slash !== -1) var leftA = left.split(".");
{ leftA.reverse();
ret.push(url.split("/"));
dotted = ret[0].split("."); var right = url.substring(slash + 1);
} var rightA = right.split('/');
else ret = leftA.concat(rightA);
dotted = url.split(".");
for (var k in dotted)
ret.unshift(dotted[k]);
return ret;
} }
if (ret[0].toLowerCase() === "eth")
ret.splice(0, 1);
ret.push(projectModel.projectTitle);
return ret;
} }

25
mix/qml/js/TransactionHelper.js

@ -10,3 +10,28 @@ function defaultTransaction()
parameters: {} parameters: {}
}; };
} }
function rpcCall(requests, callBack)
{
var jsonRpcUrl = "http://localhost:8080";
var rpcRequest = JSON.stringify(requests);
var httpRequest = new XMLHttpRequest();
httpRequest.open("POST", jsonRpcUrl, true);
httpRequest.setRequestHeader("Content-type", "application/json");
httpRequest.setRequestHeader("Content-length", rpcRequest.length);
httpRequest.setRequestHeader("Connection", "close");
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status !== 200 || httpRequest.responseText === "")
{
var errorText = qsTr("Deployment error: Error while registering Dapp ") + httpRequest.status;
console.log(errorText);
deploymentError(errorText);
}
else
callBack(httpRequest.status, httpRequest.responseText)
}
}
httpRequest.send(rpcRequest);
}

37
mix/qml/main.qml

@ -37,7 +37,6 @@ ApplicationWindow {
} }
Menu { Menu {
title: qsTr("Deploy") title: qsTr("Deploy")
MenuItem { action: debugRunAction }
MenuItem { action: mineAction } MenuItem { action: mineAction }
MenuSeparator {} MenuSeparator {}
MenuItem { action: editStatesAction } MenuItem { action: editStatesAction }
@ -46,6 +45,12 @@ ApplicationWindow {
MenuSeparator {} MenuSeparator {}
MenuItem { action: toggleRunOnLoadAction } MenuItem { action: toggleRunOnLoadAction }
} }
Menu {
title: qsTr("Debug")
MenuItem { action: debugRunAction }
MenuSeparator {}
MenuItem { action: toggleAssemblyDebuggingAction }
}
Menu { Menu {
title: qsTr("Windows") title: qsTr("Windows")
MenuItem { action: openNextDocumentAction } MenuItem { action: openNextDocumentAction }
@ -56,7 +61,7 @@ ApplicationWindow {
MenuItem { action: toggleTransactionLogAction } MenuItem { action: toggleTransactionLogAction }
MenuItem { action: toggleWebPreviewAction } MenuItem { action: toggleWebPreviewAction }
MenuItem { action: toggleWebPreviewOrientationAction } MenuItem { action: toggleWebPreviewOrientationAction }
MenuItem { action: toggleCallsInLog } //MenuItem { action: toggleCallsInLog }
} }
} }
@ -92,7 +97,7 @@ ApplicationWindow {
Action { Action {
id: mineAction id: mineAction
text: qsTr("Mine") text: qsTr("New Block")
shortcut: "Ctrl+M" shortcut: "Ctrl+M"
onTriggered: clientModel.mine(); onTriggered: clientModel.mine();
enabled: codeModel.hasContract && !clientModel.running && !clientModel.mining enabled: codeModel.hasContract && !clientModel.running && !clientModel.mining
@ -129,6 +134,15 @@ ApplicationWindow {
enabled: codeModel.hasContract && !clientModel.running enabled: codeModel.hasContract && !clientModel.running
} }
Action {
id: toggleAssemblyDebuggingAction
text: qsTr("Show VM Code")
shortcut: "Ctrl+Alt+V"
onTriggered: mainContent.rightPane.assemblyMode = !mainContent.rightPane.assemblyMode;
checked: mainContent.rightPane.assemblyMode;
enabled: true
}
Action { Action {
id: toggleWebPreviewAction id: toggleWebPreviewAction
text: qsTr("Show Web View") text: qsTr("Show Web View")
@ -165,15 +179,6 @@ ApplicationWindow {
onTriggered: mainContent.toggleWebPreviewOrientation(); onTriggered: mainContent.toggleWebPreviewOrientation();
} }
Action {
id: toggleCallsInLog
text: qsTr("Show Calls in Transaction Log")
shortcut: ""
checkable: true
checked: mainContent.rightPane.transactionLog.showLogs
onTriggered: mainContent.rightPane.transactionLog.showLogs = !mainContent.rightPane.transactionLog.showLogs
}
Action { Action {
id: toggleRunOnLoadAction id: toggleRunOnLoadAction
text: qsTr("Load State on Startup") text: qsTr("Load State on Startup")
@ -303,6 +308,14 @@ ApplicationWindow {
onTriggered: projectModel.openPrevDocument(); onTriggered: projectModel.openPrevDocument();
} }
Action {
id: toggleBreakpointAction
text: qsTr("Toggle Breakpoint")
shortcut: "F9"
enabled: mainContent.codeEditor.editingContract();
onTriggered: mainContent.toggleBreakpoint();
}
Action { Action {
id: deployViaRpcAction id: deployViaRpcAction
text: qsTr("Deploy to Network") text: qsTr("Deploy to Network")

1
mix/res.qrc

@ -102,5 +102,6 @@
<file>qml/WebPreviewStyle.qml</file> <file>qml/WebPreviewStyle.qml</file>
<file>qml/img/available_updates.png</file> <file>qml/img/available_updates.png</file>
<file>qml/DeploymentDialog.qml</file> <file>qml/DeploymentDialog.qml</file>
<file>qml/img/search_filled.png</file>
</qresource> </qresource>
</RCC> </RCC>

242
test/SolidityEndToEndTest.cpp

@ -2768,6 +2768,248 @@ BOOST_AUTO_TEST_CASE(dynamic_out_of_bounds_array_access)
BOOST_CHECK(callContractFunction("length()") == encodeArgs(4)); BOOST_CHECK(callContractFunction("length()") == encodeArgs(4));
} }
BOOST_AUTO_TEST_CASE(fixed_array_cleanup)
{
char const* sourceCode = R"(
contract c {
uint spacer1;
uint spacer2;
uint[20] data;
function fill() {
for (uint i = 0; i < data.length; ++i) data[i] = i+1;
}
function clear() { delete data; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("fill()") == bytes());
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("clear()") == bytes());
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(short_fixed_array_cleanup)
{
char const* sourceCode = R"(
contract c {
uint spacer1;
uint spacer2;
uint[3] data;
function fill() {
for (uint i = 0; i < data.length; ++i) data[i] = i+1;
}
function clear() { delete data; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("fill()") == bytes());
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("clear()") == bytes());
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(dynamic_array_cleanup)
{
char const* sourceCode = R"(
contract c {
uint[20] spacer;
uint[] dynamic;
function fill() {
dynamic.length = 21;
for (uint i = 0; i < dynamic.length; ++i) dynamic[i] = i+1;
}
function halfClear() { dynamic.length = 5; }
function fullClear() { delete dynamic; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("fill()") == bytes());
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("halfClear()") == bytes());
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("fullClear()") == bytes());
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(dynamic_multi_array_cleanup)
{
char const* sourceCode = R"(
contract c {
struct s { uint[][] d; }
s[] data;
function fill() returns (uint) {
data.length = 3;
data[2].d.length = 4;
data[2].d[3].length = 5;
data[2].d[3][4] = 8;
return data[2].d[3][4];
}
function clear() { delete data; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("fill()") == encodeArgs(8));
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("clear()") == bytes());
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(array_copy_storage_storage_dyn_dyn)
{
char const* sourceCode = R"(
contract c {
uint[] data1;
uint[] data2;
function setData1(uint length, uint index, uint value) {
data1.length = length; if (index < length) data1[index] = value;
}
function copyStorageStorage() { data2 = data1; }
function getData2(uint index) returns (uint len, uint val) {
len = data2.length; if (index < len) val = data2[index];
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("setData1(uint256,uint256,uint256)", 10, 5, 4) == bytes());
BOOST_CHECK(callContractFunction("copyStorageStorage()") == bytes());
BOOST_CHECK(callContractFunction("getData2(uint256)", 5) == encodeArgs(10, 4));
BOOST_CHECK(callContractFunction("setData1(uint256,uint256,uint256)", 0, 0, 0) == bytes());
BOOST_CHECK(callContractFunction("copyStorageStorage()") == bytes());
BOOST_CHECK(callContractFunction("getData2(uint256)", 0) == encodeArgs(0, 0));
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(array_copy_storage_storage_static_static)
{
char const* sourceCode = R"(
contract c {
uint[40] data1;
uint[20] data2;
function test() returns (uint x, uint y){
data1[30] = 4;
data1[2] = 7;
data1[3] = 9;
data2[3] = 8;
data1 = data2;
x = data1[3];
y = data1[30]; // should be cleared
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(8, 0));
}
BOOST_AUTO_TEST_CASE(array_copy_storage_storage_static_dynamic)
{
char const* sourceCode = R"(
contract c {
uint[9] data1;
uint[] data2;
function test() returns (uint x, uint y){
data1[8] = 4;
data2 = data1;
x = data2.length;
y = data2[8];
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(9, 4));
}
BOOST_AUTO_TEST_CASE(array_copy_storage_storage_struct)
{
char const* sourceCode = R"(
contract c {
struct Data { uint x; uint y; }
Data[] data1;
Data[] data2;
function test() returns (uint x, uint y) {
data1.length = 9;
data1[8].x = 4;
data1[8].y = 5;
data2 = data1;
x = data2[8].x;
y = data2[8].y;
data1.length = 0;
data2 = data1;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(4, 5));
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base)
{
char const* sourceCode = R"(
contract Base {
function Base(uint i)
{
m_i = i;
}
uint public m_i;
}
contract Derived is Base(2) {
function Derived(uint i) Base(i)
{}
}
contract Final is Derived(4) {
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("m_i()") == encodeArgs(4));
}
BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base_base)
{
char const* sourceCode = R"(
contract Base {
function Base(uint j)
{
m_i = j;
}
uint public m_i;
}
contract Base1 is Base(3) {
function Base1(uint k) Base(k*k) {}
}
contract Derived is Base(3), Base1(2) {
function Derived(uint i) Base(i) Base1(i)
{}
}
contract Final is Derived(4) {
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("m_i()") == encodeArgs(4));
}
BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base_base_with_gap)
{
char const* sourceCode = R"(
contract Base {
function Base(uint i)
{
m_i = i;
}
uint public m_i;
}
contract Base1 is Base(3) {}
contract Derived is Base(2), Base1 {
function Derived(uint i) Base(i) {}
}
contract Final is Derived(4) {
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("m_i()") == encodeArgs(4));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

109
test/SolidityNameAndTypeResolution.cpp

@ -436,7 +436,7 @@ BOOST_AUTO_TEST_CASE(inheritance_diamond_basic)
function g() { f(); rootFunction(); } function g() { f(); rootFunction(); }
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
} }
BOOST_AUTO_TEST_CASE(cyclic_inheritance) BOOST_AUTO_TEST_CASE(cyclic_inheritance)
@ -720,6 +720,58 @@ BOOST_AUTO_TEST_CASE(private_state_variable)
BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an internal variable should not exist"); BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an internal variable should not exist");
} }
BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor)
{
// test for issue #1126 https://github.com/ethereum/cpp-ethereum/issues/1126
char const* text = "contract Parent {\n"
" uint256 public m_aMember;\n"
"}\n"
"contract Child is Parent{\n"
" function foo() returns (uint256) { return Parent.m_aMember; }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
}
BOOST_AUTO_TEST_CASE(base_class_state_variable_internal_member)
{
char const* text = "contract Parent {\n"
" uint256 internal m_aMember;\n"
"}\n"
"contract Child is Parent{\n"
" function foo() returns (uint256) { return Parent.m_aMember; }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
}
BOOST_AUTO_TEST_CASE(state_variable_member_of_wrong_class1)
{
char const* text = "contract Parent1 {\n"
" uint256 internal m_aMember1;\n"
"}\n"
"contract Parent2 is Parent1{\n"
" uint256 internal m_aMember2;\n"
"}\n"
"contract Child is Parent2{\n"
" function foo() returns (uint256) { return Parent2.m_aMember1; }\n"
"}\n";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(state_variable_member_of_wrong_class2)
{
char const* text = "contract Parent1 {\n"
" uint256 internal m_aMember1;\n"
"}\n"
"contract Parent2 is Parent1{\n"
" uint256 internal m_aMember2;\n"
"}\n"
"contract Child is Parent2{\n"
" function foo() returns (uint256) { return Child.m_aMember2; }\n"
" uint256 public m_aMember3;\n"
"}\n";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(fallback_function) BOOST_AUTO_TEST_CASE(fallback_function)
{ {
char const* text = R"( char const* text = R"(
@ -1185,6 +1237,61 @@ BOOST_AUTO_TEST_CASE(array_with_nonconstant_length)
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
} }
BOOST_AUTO_TEST_CASE(array_copy_with_different_types1)
{
char const* text = R"(
contract c {
bytes a;
uint[] b;
function f() { b = a; }
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types2)
{
char const* text = R"(
contract c {
uint32[] a;
uint8[] b;
function f() { b = a; }
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types_conversion_possible)
{
char const* text = R"(
contract c {
uint32[] a;
uint8[] b;
function f() { a = b; }
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types_static_dynamic)
{
char const* text = R"(
contract c {
uint32[] a;
uint8[80] b;
function f() { a = b; }
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types_dynamic_static)
{
char const* text = R"(
contract c {
uint[] a;
uint[80] b;
function f() { b = a; }
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

34
test/SolidityParser.cpp

@ -367,6 +367,40 @@ BOOST_AUTO_TEST_CASE(variable_definition_with_initialization)
BOOST_CHECK_NO_THROW(parseText(text)); BOOST_CHECK_NO_THROW(parseText(text));
} }
BOOST_AUTO_TEST_CASE(variable_definition_in_function_parameter)
{
char const* text = R"(
contract test {
function fun(var a) {}
}
)";
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_CASE(variable_definition_in_mapping)
{
char const* text = R"(
contract test {
function fun() {
mapping(var=>hash) d;
}
}
)";
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_CASE(variable_definition_in_function_return)
{
char const* text = R"(
contract test {
function fun() returns(var d) {
return 1;
}
}
)";
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_CASE(operator_expression) BOOST_AUTO_TEST_CASE(operator_expression)
{ {
char const* text = "contract test {\n" char const* text = "contract test {\n"

50
test/TestHelper.cpp

@ -139,27 +139,35 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state)
} }
void ImportTest::importTransaction(json_spirit::mObject& _o) void ImportTest::importTransaction(json_spirit::mObject& _o)
{ {
BOOST_REQUIRE(_o.count("nonce")> 0); if (_o.count("secretKey") > 0)
BOOST_REQUIRE(_o.count("gasPrice") > 0); {
BOOST_REQUIRE(_o.count("gasLimit") > 0); BOOST_REQUIRE(_o.count("nonce") > 0);
BOOST_REQUIRE(_o.count("to") > 0); BOOST_REQUIRE(_o.count("gasPrice") > 0);
BOOST_REQUIRE(_o.count("value") > 0); BOOST_REQUIRE(_o.count("gasLimit") > 0);
BOOST_REQUIRE(_o.count("secretKey") > 0); BOOST_REQUIRE(_o.count("to") > 0);
BOOST_REQUIRE(_o.count("data") > 0); BOOST_REQUIRE(_o.count("value") > 0);
BOOST_REQUIRE(_o.count("data") > 0);
if (bigint(_o["nonce"].get_str()) >= c_max256plus1)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'nonce' is equal or greater than 2**256") ); if (bigint(_o["nonce"].get_str()) >= c_max256plus1)
if (bigint(_o["gasPrice"].get_str()) >= c_max256plus1) BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'nonce' is equal or greater than 2**256") );
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasPrice' is equal or greater than 2**256") ); if (bigint(_o["gasPrice"].get_str()) >= c_max256plus1)
if (bigint(_o["gasLimit"].get_str()) >= c_max256plus1) BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasPrice' is equal or greater than 2**256") );
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasLimit' is equal or greater than 2**256") ); if (bigint(_o["gasLimit"].get_str()) >= c_max256plus1)
if (bigint(_o["value"].get_str()) >= c_max256plus1) BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasLimit' is equal or greater than 2**256") );
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'value' is equal or greater than 2**256") ); if (bigint(_o["value"].get_str()) >= c_max256plus1)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'value' is equal or greater than 2**256") );
m_transaction = _o["to"].get_str().empty() ?
Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())) : m_transaction = _o["to"].get_str().empty() ?
Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), Address(_o["to"].get_str()), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())); Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())) :
Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), Address(_o["to"].get_str()), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str()));
}
else
{
RLPStream transactionRLPStream = createRLPStreamFromTransactionFields(_o);
RLP transactionRLP(transactionRLPStream.out());
m_transaction = Transaction(transactionRLP.data(), CheckSignature::Sender);
}
} }
void ImportTest::exportTest(bytes _output, State& _statePost) void ImportTest::exportTest(bytes _output, State& _statePost)

10
test/block.cpp

@ -496,11 +496,21 @@ BOOST_AUTO_TEST_CASE(blValidBlockTest)
dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests); dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests);
} }
BOOST_AUTO_TEST_CASE(blInvalidTransactionRLP)
{
dev::test::executeTests("blInvalidTransactionRLP", "/BlockTests", dev::test::doBlockTests);
}
BOOST_AUTO_TEST_CASE(blInvalidHeaderTest) BOOST_AUTO_TEST_CASE(blInvalidHeaderTest)
{ {
dev::test::executeTests("blInvalidHeaderTest", "/BlockTests", dev::test::doBlockTests); dev::test::executeTests("blInvalidHeaderTest", "/BlockTests", dev::test::doBlockTests);
} }
BOOST_AUTO_TEST_CASE(blForkBlocks)
{
dev::test::executeTests("blForkBlocks", "/BlockTests", dev::test::doBlockTests);
}
BOOST_AUTO_TEST_CASE(userDefinedFileBl) BOOST_AUTO_TEST_CASE(userDefinedFileBl)
{ {
dev::test::userDefinedTest("--bltest", dev::test::doBlockTests); dev::test::userDefinedTest("--bltest", dev::test::doBlockTests);

69
test/stMemoryStressTestFiller.json

@ -0,0 +1,69 @@
{
"mload32bitBound": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "17592320524892",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 1 ]] (MLOAD 4294967296) } ",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "175923205248920",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "17592320524892",
"to" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"value" : "10",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"mload32bitBound2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "37791080412587",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 1 ]] (MLOAD 6294967296) } ",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "377910804219850",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "37791080412587",
"to" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"value" : "10",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
}
}

1465
test/stMemoryTestFiller.json

File diff suppressed because it is too large

682
test/stQuadraticComplexityTestFiller.json

File diff suppressed because one or more lines are too long

158
test/stRefundTestFiller.json

@ -304,33 +304,135 @@
"data" : "" "data" : ""
} }
}, },
"RefundOverflow" : { "refund_CallA" : {
"env" : { "env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentDifficulty" : "45678256", "currentNumber" : "0",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentDifficulty" : "256",
"currentTimestamp" : 1, "currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
}, },
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "400", "balance" : "1000000000000000000",
"code" : "0x", "nonce" : "0",
"nonce" : "0", "code" : "{ [[ 0 ]] (CALL 500 0xaaae7baea6a6c7c4c2dfeb977efac326af552aaa 0 0 0 0 0 )}",
"storage" : { "storage" : {
} "0x01" : "0x01"
} }
}, },
"transaction" : { "aaae7baea6a6c7c4c2dfeb977efac326af552aaa" : {
"data" : "", "balance" : "1000000000000000000",
"gasLimit" : "5789604461865809771178549250434395392663499233282028201972879200395656482016", "nonce" : "0",
"gasPrice" : "20", "code" : "{ [[ 1 ]] 0 }",
"nonce" : "0", "storage" : {
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "0x01" : "0x01"
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", }
"value" : "" },
} "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
} "balance" : "2000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "1500",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"refund_CallA2" : {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (CALL 50 0xaaae7baea6a6c7c4c2dfeb977efac326af552aaa 0 0 0 0 0 )}",
"storage" : {
"0x01" : "0x01"
}
},
"aaae7baea6a6c7c4c2dfeb977efac326af552aaa" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 1 ]] 0 }",
"storage" : {
"0x01" : "0x01"
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "850",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"refund_CallA_OOG" : {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (CALL 1 0xaaae7baea6a6c7c4c2dfeb977efac326af552aaa 0 0 0 0 0 )}",
"storage" : {
"0x01" : "0x01"
}
},
"aaae7baea6a6c7c4c2dfeb977efac326af552aaa" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 1 ]] 0 }",
"storage" : {
"0x01" : "0x01"
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "850",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
}
} }

55
test/stSolidityTestFiller.json

@ -525,60 +525,5 @@
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "1" "value" : "1"
} }
},
"QuadraticComplexity" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "100000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000",
"//" : "contract caller ",
"//" : "{ ",
"//" : " int value; ",
"//" : " function run(int count) ",
"//" : " { ",
"//" : " value = count; ",
"//" : " address a = 0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b; ",
"//" : " while(count > 0) ",
"//" : " { ",
"//" : " a.call('just', 'call'); ",
"//" : " count = count - 1; ",
"//" : " } ",
"//" : " } ",
"//" : "} ",
"code" : "0x60003560e060020a9004806361a4770614601557005b601e6004356024565b60006000f35b60008160008190555073b94f5374fce5edbc8e2a8697c15331677e6ebf0b90505b600082131560bf5780600160a060020a03166000600060007f6a7573740000000000000000000000000000000000000000000000000000000081526004017f63616c6c000000000000000000000000000000000000000000000000000000008152602001600060008560155a03f150506001820391506045565b505056",
"nonce" : "0",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000",
"code" : "{ (CALLDATACOPY 0 0 32) }",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"//" : "run(int256)",
"data" : "0x61a47706000000000000000000000000000000000000000000000000000000000000c350",
"gasLimit" : "904+68*x+e",
"gasLimit" : "3500000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "1"
}
} }
} }

1015
test/stSystemOperationsTestFiller.json

File diff suppressed because it is too large

10
test/stTransactionTestFiller.json

@ -547,7 +547,7 @@
"code" : "{(CALL 0 0 1 0 0 0 0) (SUICIDE 0)}", "code" : "{(CALL 0 0 1 0 0 0 0) (SUICIDE 0)}",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"0000000000000000000000000000000000000000" : { "0000000000000000000000000000000000000000" : {
@ -596,7 +596,7 @@
"code" : "{(CALL 20 0 1 0 0 0 0) (SUICIDE 0)}", "code" : "{(CALL 20 0 1 0 0 0 0) (SUICIDE 0)}",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"0000000000000000000000000000000000000000" : { "0000000000000000000000000000000000000000" : {
@ -645,7 +645,7 @@
"code" : "{(SUICIDE 0) (CALL 0 2000 0 0 0 0 0) }", "code" : "{(SUICIDE 0) (CALL 0 2000 0 0 0 0 0) }",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"0000000000000000000000000000000000000000" : { "0000000000000000000000000000000000000000" : {
@ -693,7 +693,7 @@
"code" : "{(SUICIDE 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b)}", "code" : "{(SUICIDE 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b)}",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },
@ -733,7 +733,7 @@
"code" : "{(SUICIDE 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b)}", "code" : "{(SUICIDE 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b)}",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },

41
test/state.cpp

@ -159,11 +159,52 @@ BOOST_AUTO_TEST_CASE(stBlockHashTest)
dev::test::executeTests("stBlockHashTest", "/StateTests", dev::test::doStateTests); dev::test::executeTests("stBlockHashTest", "/StateTests", dev::test::doStateTests);
} }
BOOST_AUTO_TEST_CASE(stQuadraticComplexityTest)
{
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
{
string arg = boost::unit_test::framework::master_test_suite().argv[i];
if (arg == "--quadratic" || arg == "--all")
{
auto start = chrono::steady_clock::now();
dev::test::executeTests("stQuadraticComplexityTest", "/StateTests", dev::test::doStateTests);
auto end = chrono::steady_clock::now();
auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
cnote << "test duration: " << duration.count() << " milliseconds.\n";
}
}
}
BOOST_AUTO_TEST_CASE(stMemoryStressTest)
{
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
{
string arg = boost::unit_test::framework::master_test_suite().argv[i];
if (arg == "--memory" || arg == "--all")
{
auto start = chrono::steady_clock::now();
dev::test::executeTests("stMemoryStressTest", "/StateTests", dev::test::doStateTests);
auto end = chrono::steady_clock::now();
auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
cnote << "test duration: " << duration.count() << " milliseconds.\n";
}
}
}
BOOST_AUTO_TEST_CASE(stSolidityTest) BOOST_AUTO_TEST_CASE(stSolidityTest)
{ {
dev::test::executeTests("stSolidityTest", "/StateTests", dev::test::doStateTests); dev::test::executeTests("stSolidityTest", "/StateTests", dev::test::doStateTests);
} }
BOOST_AUTO_TEST_CASE(stMemoryTest)
{
dev::test::executeTests("stMemoryTest", "/StateTests", dev::test::doStateTests);
}
BOOST_AUTO_TEST_CASE(stCreateTest) BOOST_AUTO_TEST_CASE(stCreateTest)
{ {
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)

19
test/transaction.cpp

@ -90,8 +90,9 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
o["sender"] = toString(txFromFields.sender()); o["sender"] = toString(txFromFields.sender());
} }
catch(...) catch(Exception const& _e)
{ {
cnote << "Transaction Exception: " << diagnostic_information(_e);
o.erase(o.find("transaction")); o.erase(o.find("transaction"));
} }
} }
@ -115,7 +116,21 @@ BOOST_AUTO_TEST_CASE(ttWrongRLPTransaction)
BOOST_AUTO_TEST_CASE(tt10mbDataField) BOOST_AUTO_TEST_CASE(tt10mbDataField)
{ {
dev::test::executeTests("tt10mbDataField", "/TransactionTests", dev::test::doTransactionTests); for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
{
string arg = boost::unit_test::framework::master_test_suite().argv[i];
if (arg == "--bigdata" || arg == "--all")
{
auto start = chrono::steady_clock::now();
dev::test::executeTests("tt10mbDataField", "/TransactionTests", dev::test::doTransactionTests);
auto end = chrono::steady_clock::now();
auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
cnote << "test duration: " << duration.count() << " milliseconds.\n";
}
}
} }
BOOST_AUTO_TEST_CASE(ttCreateTest) BOOST_AUTO_TEST_CASE(ttCreateTest)

169
test/ttTransactionTestFiller.json

@ -14,7 +14,7 @@
} }
}, },
"WrongVRSTestVl27" : { "WrongVRSTestVl26" : {
"transaction" : "transaction" :
{ {
"data" : "", "data" : "",
@ -29,6 +29,21 @@
} }
}, },
"WrongVRSTestVl29" : {
"transaction" :
{
"data" : "",
"gasLimit" : "2000",
"gasPrice" : "1",
"nonce" : "0",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10",
"v" : "29",
"r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a",
"s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"
}
},
"WrongVRSTestVge31" : { "WrongVRSTestVge31" : {
"transaction" : "transaction" :
{ {
@ -136,7 +151,22 @@
} }
}, },
"TransactionWithSvalueOverflow" : { "TransactionWithSvalueHigh" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "11",
"v" : "27",
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
"s" : "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e"
}
},
"TransactionWithSvalueTooHigh" : {
"transaction" : "transaction" :
{ {
"data" : "", "data" : "",
@ -151,7 +181,52 @@
} }
}, },
"TransactionWithSvalueOverflow" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "11",
"v" : "27",
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
"s" : "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0000"
}
},
"TransactionWithRvalueOverflow" : { "TransactionWithRvalueOverflow" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "11",
"v" : "27",
"r" : "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410000",
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithRvalueHigh" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "11",
"v" : "27",
"r" : "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
"s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"
}
},
"TransactionWithRvalueTooHigh" : {
"transaction" : "transaction" :
{ {
"data" : "", "data" : "",
@ -166,6 +241,51 @@
} }
}, },
"TransactionWithRvalueWrongSize" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "11",
"v" : "27",
"r" : "0xebaaedce6af48a03bbfd25e8cd0364141",
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithSvalueWrongSize" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "11",
"v" : "27",
"r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a",
"s" : "0xef0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithHihghNonce" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0",
"v" : "27",
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithNonceOverflow" : { "TransactionWithNonceOverflow" : {
"transaction" : "transaction" :
{ {
@ -181,6 +301,51 @@
} }
}, },
"TransactionWithHihghGas" : {
"transaction" :
{
"data" : "",
"gasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0",
"v" : "27",
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithHihghGasPrice" : {
"transaction" :
{
"data" : "",
"gasLimit" : "1000",
"gasPrice" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0",
"v" : "27",
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithGasLimitxPriceOverflow" : {
"transaction" :
{
"data" : "",
"gasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"gasPrice" : "100000000000000000",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0",
"v" : "27",
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithGasPriceOverflow" : { "TransactionWithGasPriceOverflow" : {
"transaction" : "transaction" :
{ {

6
test/vm.cpp

@ -518,7 +518,7 @@ BOOST_AUTO_TEST_CASE(vmPerformanceTest)
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
{ {
string arg = boost::unit_test::framework::master_test_suite().argv[i]; string arg = boost::unit_test::framework::master_test_suite().argv[i];
if (arg == "--performance") if (arg == "--performance" || arg == "--all")
{ {
auto start = chrono::steady_clock::now(); auto start = chrono::steady_clock::now();
@ -536,7 +536,7 @@ BOOST_AUTO_TEST_CASE(vmInputLimitsTest1)
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
{ {
string arg = boost::unit_test::framework::master_test_suite().argv[i]; string arg = boost::unit_test::framework::master_test_suite().argv[i];
if (arg == "--inputlimits") if (arg == "--inputlimits" || arg == "--all")
{ {
auto start = chrono::steady_clock::now(); auto start = chrono::steady_clock::now();
@ -554,7 +554,7 @@ BOOST_AUTO_TEST_CASE(vmInputLimitsTest2)
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
{ {
string arg = boost::unit_test::framework::master_test_suite().argv[i]; string arg = boost::unit_test::framework::master_test_suite().argv[i];
if (arg == "--inputlimits") if (arg == "--inputlimits" || arg == "--all")
dev::test::executeTests("vmInputLimitsTest2", "/VMTests", dev::test::doVMTests); dev::test::executeTests("vmInputLimitsTest2", "/VMTests", dev::test::doVMTests);
} }
} }

366
test/vmArithmeticTestFiller.json

@ -897,7 +897,7 @@
} }
}, },
"sdiv5": { "sdiv_i256min": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0", "currentNumber" : "0",
@ -925,6 +925,62 @@
} }
}, },
"sdiv_i256min2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SDIV (- 0 57896044618658097711785492504343953926634992332820282019728792003956564819968) (- 0 1) ) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"sdiv_i256min3": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SDIV 115792089237316195423570985008687907853269984665640564039457584007913129639935 (- 0 57896044618658097711785492504343953926634992332820282019728792003956564819967) ) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"mod0": { "mod0": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
@ -1205,6 +1261,90 @@
} }
}, },
"smod5": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SMOD (- 0 57896044618658097711785492504343953926634992332820282019728792003956564819967) 57896044618658097711785492504343953926634992332820282019728792003956564819967)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"smod6": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SMOD (- 0 115792089237316195423570985008687907853269984665640564039457584007913129639935) 57896044618658097711785492504343953926634992332820282019728792003956564819967)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"smod7": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SMOD (- 0 57896044618658097711785492504343953926634992332820282019728792003956564819967) 115792089237316195423570985008687907853269984665640564039457584007913129639935)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"addmod0": { "addmod0": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
@ -1261,6 +1401,118 @@
} }
}, },
"addmod1_overflowDiff": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (ADDMOD (- 0 1) (- 0 2) 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"addmod1_overflow2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (ADDMOD (- 0 1) 0 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"addmod1_overflow3": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (ADDMOD (- 0 1) 1 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"addmod1_overflow3": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (ADDMOD (- 0 1) 2 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"addmod2": { "addmod2": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
@ -1542,6 +1794,118 @@
} }
}, },
"mulmod1_overflow": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (MULMOD (- 0 1) 2 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"mulmod1_overflow2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (MULMOD 57896044618658097711785492504343953926634992332820282019728792003956564819968 2 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"mulmod1_overflow3": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (MULMOD 57896044618658097711785492504343953926634992332820282019728792003956564819967 2 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"mulmod1_overflow4": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (MULMOD 57896044618658097711785492504343953926634992332820282019728792003956564819969 2 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"mulmod2": { "mulmod2": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

168
test/vmEnvironmentalInfoTestFiller.json

@ -703,6 +703,174 @@
} }
}, },
"calldatacopy0_return": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (CALLDATACOPY 0 1 2 ) (RETURN 0 (MSIZE))}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "0x1234567890abcdef01234567890abcdef",
"gasPrice" : "1000000000",
"gas" : "100000000000"
}
},
"calldatacopyZeroMemExpansion_return": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (CALLDATACOPY 0 0 0 ) (RETURN 0 (MSIZE))}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "0x1234567890abcdef01234567890abcdef",
"gasPrice" : "1000000000",
"gas" : "100000000000"
}
},
"calldatacopy_DataIndexTooHigh_return": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (CALLDATACOPY 0 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa 0xff ) (RETURN 0 (MSIZE))}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "0x1234567890abcdef01234567890abcdef",
"gasPrice" : "1000000000",
"gas" : "100000000000"
}
},
"calldatacopy_DataIndexTooHigh2_return": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (CALLDATACOPY 0 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa 9 ) (RETURN 0 (MSIZE))}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "0x1234567890abcdef01234567890abcdef",
"gasPrice" : "1000000000",
"gas" : "100000000000"
}
},
"calldatacopy1_return": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (CALLDATACOPY 0 1 1 ) (RETURN 0 (MSIZE))}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "0x1234567890abcdef01234567890abcdef",
"gasPrice" : "1000000000",
"gas" : "100000000000"
}
},
"calldatacopy2_return": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (CALLDATACOPY 0 1 0 ) (RETURN 0 (MSIZE))}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "0x1234567890abcdef01234567890abcdef",
"gasPrice" : "1000000000",
"gas" : "100000000000"
}
},
"codesize": { "codesize": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

85
test/vmIOandFlowOperationsTestFiller.json

@ -727,6 +727,91 @@
} }
}, },
"jumpTo1InstructionafterJump": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "0x6003565b6001600055",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"jumpTo1InstructionafterJump_noJumpDest": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "0x6003566001600055",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"jumpTo1InstructionafterJump_jumpdestFirstInstruction": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "0x5b6003565b6001600055",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"jumpDynamicJumpSameDest": { "jumpDynamicJumpSameDest": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

238
test/vmSha3TestFiller.json

@ -201,13 +201,13 @@
"currentNumber" : "0", "currentNumber" : "0",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentDifficulty" : "256", "currentDifficulty" : "256",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
}, },
"pre" : { "pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : 0, "nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)}", "code" : "{ [[ 0 ]] (SHA3 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)}",
"storage": {} "storage": {}
} }
@ -229,13 +229,13 @@
"currentNumber" : "0", "currentNumber" : "0",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentDifficulty" : "256", "currentDifficulty" : "256",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
}, },
"pre" : { "pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : 0, "nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 2)}", "code" : "{ [[ 0 ]] (SHA3 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 2)}",
"storage": {} "storage": {}
} }
@ -257,13 +257,13 @@
"currentNumber" : "0", "currentNumber" : "0",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentDifficulty" : "256", "currentDifficulty" : "256",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
}, },
"pre" : { "pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : 0, "nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 0x1000000 2)}", "code" : "{ [[ 0 ]] (SHA3 0x1000000 2)}",
"storage": {} "storage": {}
} }
@ -277,5 +277,229 @@
"gasPrice" : "1", "gasPrice" : "1",
"gas" : "0x100000000" "gas" : "0x100000000"
} }
} },
"sha3_memSizeNoQuadraticCost31": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 960 1)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost32": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 992 1)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost32_zeroSize": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 1024 0)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost33": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 1024 1)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost63": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 1984 1)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost64": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 2016 1)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost64_2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 2016 32)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost65": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 2048 1)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
} }

Loading…
Cancel
Save