Browse Source

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

cl-refactor
arkpar 10 years ago
parent
commit
87c74bbc75
  1. 3
      CMakeLists.txt
  2. 2
      alethzero/DappLoader.cpp
  3. 20
      ethminer/MinerAux.h
  4. 8
      libdevcore/CommonIO.cpp
  5. 2
      libdevcore/RLP.h
  6. 4
      libethcore/BlockInfo.cpp
  7. 7
      libethcore/EthashAux.cpp
  8. 2
      libethcore/EthashAux.h
  9. 16
      libethcore/ICAP.cpp
  10. 2
      libethcore/KeyManager.h
  11. 1
      libethereum/EthereumHost.cpp
  12. 2
      libethereum/State.cpp
  13. 120
      libjsqrc/admin.js
  14. 8
      libjsqrc/ethereumjs/LICENSE
  15. 2
      libjsqrc/ethereumjs/README.md
  16. 2
      libjsqrc/ethereumjs/bower.json
  17. 5683
      libjsqrc/ethereumjs/dist/web3-light.js
  18. 2
      libjsqrc/ethereumjs/dist/web3-light.min.js
  19. 228
      libjsqrc/ethereumjs/dist/web3.js
  20. 85
      libjsqrc/ethereumjs/dist/web3.js.map
  21. 4
      libjsqrc/ethereumjs/dist/web3.min.js
  22. 153
      libjsqrc/ethereumjs/example/coin.html
  23. 5
      libjsqrc/ethereumjs/example/event_inc.html
  24. 2
      libjsqrc/ethereumjs/gulpfile.js
  25. 2
      libjsqrc/ethereumjs/lib/utils/config.js
  26. 2
      libjsqrc/ethereumjs/lib/version.json
  27. 33
      libjsqrc/ethereumjs/lib/web3.js
  28. 95
      libjsqrc/ethereumjs/lib/web3/filter.js
  29. 10
      libjsqrc/ethereumjs/lib/web3/formatters.js
  30. 13
      libjsqrc/ethereumjs/lib/web3/function.js
  31. 2
      libjsqrc/ethereumjs/lib/web3/httpprovider.js
  32. 1
      libjsqrc/ethereumjs/lib/web3/property.js
  33. 55
      libjsqrc/ethereumjs/lib/web3/requestmanager.js
  34. 4
      libjsqrc/ethereumjs/lib/web3/watches.js
  35. 2
      libjsqrc/ethereumjs/package.js
  36. 6
      libjsqrc/ethereumjs/package.json
  37. 55
      libjsqrc/ethereumjs/test/contract.js
  38. 70
      libjsqrc/ethereumjs/test/formatters.outputBlockFormatter.js
  39. 32
      libjsqrc/ethereumjs/test/formatters.outputLogFormatter.js
  40. 35
      libjsqrc/ethereumjs/test/formatters.outputTransactionFormatter.js
  41. 10
      libjsqrc/ethereumjs/test/helpers/FakeHttpProvider2.js
  42. 7
      libjsqrc/ethereumjs/test/helpers/FakeXMLHttpRequest.js
  43. 76
      libjsqrc/ethereumjs/test/web3.extend.js
  44. 1
      libjsqrc/js.qrc
  45. 26
      libsolidity/ArrayUtils.cpp
  46. 15
      libsolidity/Compiler.cpp
  47. 2
      libsolidity/CompilerUtils.cpp
  48. 13
      libsolidity/ExpressionCompiler.cpp
  49. 40
      libsolidity/Types.cpp
  50. 10
      libsolidity/Types.h
  51. BIN
      mix/qml/img/edittransaction.png
  52. BIN
      mix/qml/img/edittransaction2.png
  53. BIN
      mix/qml/img/edittransaction2@2x.png
  54. BIN
      mix/qml/img/edittransaction@2x.png
  55. BIN
      mix/qml/img/newblock.png
  56. BIN
      mix/qml/img/newblock@2x.png
  57. 55
      test/TestHelper.cpp
  58. 4
      test/TestHelper.h
  59. 67
      test/fuzzTesting/createRandomTest.cpp
  60. 40
      test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json
  61. 2
      test/libethereum/state.cpp
  62. 4
      test/libethereum/transaction.cpp
  63. 6
      test/libevm/vm.cpp
  64. 162
      test/libsolidity/SolidityEndToEndTest.cpp
  65. 13
      test/libsolidity/SolidityNameAndTypeResolution.cpp

3
CMakeLists.txt

@ -84,7 +84,10 @@ function(configureProject)
add_definitions(-DETH_CURL) add_definitions(-DETH_CURL)
endif() endif()
if (NOBOOST)
add_definitions(-DNOBOOST) add_definitions(-DNOBOOST)
endif()
add_definitions(-DETH_TRUE) add_definitions(-DETH_TRUE)
endfunction() endfunction()

2
alethzero/DappLoader.cpp

@ -193,6 +193,8 @@ QByteArray const& DappLoader::web3Content()
code += "\n"; code += "\n";
code += contentsOfQResource(":/js/setup.js"); code += contentsOfQResource(":/js/setup.js");
code += "\n"; code += "\n";
code += contentsOfQResource(":/js/admin.js");
code += "\n";
m_web3Js = code.toLatin1(); m_web3Js = code.toLatin1();
} }
return m_web3Js; return m_web3Js;

20
ethminer/MinerAux.h

@ -107,7 +107,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
else if (arg == "--opencl-platform" && i + 1 < argc) else if (arg == "--opencl-platform" && i + 1 < argc)
try { try {
@ -116,7 +116,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
else if (arg == "--opencl-device" && i + 1 < argc) else if (arg == "--opencl-device" && i + 1 < argc)
try { try {
@ -126,7 +126,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
else if (arg == "--list-devices") else if (arg == "--list-devices")
m_shouldListDevices = true; m_shouldListDevices = true;
@ -144,7 +144,7 @@ public:
else else
{ {
cerr << "Bad " << arg << " option: " << m << endl; cerr << "Bad " << arg << " option: " << m << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
} }
else if (arg == "--benchmark-warmup" && i + 1 < argc) else if (arg == "--benchmark-warmup" && i + 1 < argc)
@ -154,7 +154,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
else if (arg == "--benchmark-trial" && i + 1 < argc) else if (arg == "--benchmark-trial" && i + 1 < argc)
try { try {
@ -163,7 +163,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
else if (arg == "--benchmark-trials" && i + 1 < argc) else if (arg == "--benchmark-trials" && i + 1 < argc)
try { try {
@ -172,7 +172,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
else if (arg == "-C" || arg == "--cpu") else if (arg == "-C" || arg == "--cpu")
m_minerType = MinerType::CPU; m_minerType = MinerType::CPU;
@ -195,7 +195,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << m << endl; cerr << "Bad " << arg << " option: " << m << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
} }
else if ((arg == "-w" || arg == "--check-pow") && i + 4 < argc) else if ((arg == "-w" || arg == "--check-pow") && i + 4 < argc)
@ -232,7 +232,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << m << endl; cerr << "Bad " << arg << " option: " << m << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
} }
else if (arg == "-M" || arg == "--benchmark") else if (arg == "-M" || arg == "--benchmark")
@ -245,7 +245,7 @@ public:
catch (...) catch (...)
{ {
cerr << "Bad " << arg << " option: " << argv[i] << endl; cerr << "Bad " << arg << " option: " << argv[i] << endl;
throw BadArgument(); BOOST_THROW_EXCEPTION(BadArgument());
} }
} }
else else

8
libdevcore/CommonIO.cpp

@ -98,9 +98,9 @@ string dev::contentsString(string const& _file)
void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename) void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename)
{ {
namespace fs = boost::filesystem;
if (_writeDeleteRename) if (_writeDeleteRename)
{ {
namespace fs = boost::filesystem;
fs::path tempPath = fs::unique_path(_file + "-%%%%%%"); fs::path tempPath = fs::unique_path(_file + "-%%%%%%");
writeFile(tempPath.string(), _data, false); writeFile(tempPath.string(), _data, false);
// will delete _file if it exists // will delete _file if it exists
@ -108,10 +108,14 @@ void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDe
} }
else else
{ {
// create directory if not existent
fs::path p(_file);
fs::create_directories(p.parent_path());
ofstream s(_file, ios::trunc | ios::binary); ofstream s(_file, ios::trunc | ios::binary);
s.write(reinterpret_cast<char const*>(_data.data()), _data.size()); s.write(reinterpret_cast<char const*>(_data.data()), _data.size());
if (!s) if (!s)
BOOST_THROW_EXCEPTION(FileError()); BOOST_THROW_EXCEPTION(FileError() << errinfo_comment("Could not write to file: " + _file));
} }
} }

2
libdevcore/RLP.h

@ -292,7 +292,7 @@ public:
RLPs toList() const; RLPs toList() const;
/// @returns the data payload. Valid for all types. /// @returns the data payload. Valid for all types.
bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) throw BadRLP(); return m_data.cropped(payloadOffset(), l); } bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) BOOST_THROW_EXCEPTION(BadRLP()); return m_data.cropped(payloadOffset(), l); }
/// @returns the theoretical size of this item. /// @returns the theoretical size of this item.
/// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work. /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work.

4
libethcore/BlockInfo.cpp

@ -122,7 +122,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const
try try
{ {
if (_header.itemCount() != 15) if (_header.itemCount() != 15)
throw InvalidBlockHeaderItemCount(); BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount());
parentHash = _header[field = 0].toHash<h256>(RLP::VeryStrict); parentHash = _header[field = 0].toHash<h256>(RLP::VeryStrict);
sha3Uncles = _header[field = 1].toHash<h256>(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash<h256>(RLP::VeryStrict);
coinbaseAddress = _header[field = 2].toHash<Address>(RLP::VeryStrict); coinbaseAddress = _header[field = 2].toHash<Address>(RLP::VeryStrict);
@ -146,7 +146,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const
} }
if (number > ~(unsigned)0) if (number > ~(unsigned)0)
throw InvalidNumber(); BOOST_THROW_EXCEPTION(InvalidNumber());
// check it hashes according to proof of work or that it's the genesis block. // check it hashes according to proof of work or that it's the genesis block.
if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this))

7
libethcore/EthashAux.cpp

@ -49,6 +49,13 @@ EthashAux::~EthashAux()
{ {
} }
EthashAux* EthashAux::get()
{
static std::once_flag flag;
std::call_once(flag, []{s_this = new EthashAux();});
return s_this;
}
uint64_t EthashAux::cacheSize(BlockInfo const& _header) uint64_t EthashAux::cacheSize(BlockInfo const& _header)
{ {
return ethash_get_cachesize((uint64_t)_header.number); return ethash_get_cachesize((uint64_t)_header.number);

2
libethcore/EthashAux.h

@ -38,7 +38,7 @@ class EthashAux
public: public:
~EthashAux(); ~EthashAux();
static EthashAux* get() { if (!s_this) s_this = new EthashAux(); return s_this; } static EthashAux* get();
struct LightAllocation struct LightAllocation
{ {

16
libethcore/ICAP.cpp

@ -71,7 +71,7 @@ ICAP ICAP::decoded(std::string const& _encoded)
std::string data; std::string data;
std::tie(country, data) = fromIBAN(_encoded); std::tie(country, data) = fromIBAN(_encoded);
if (country != "XE") if (country != "XE")
throw InvalidICAP(); BOOST_THROW_EXCEPTION(InvalidICAP());
if (data.size() == 30) if (data.size() == 30)
{ {
ret.m_type = Direct; ret.m_type = Direct;
@ -88,10 +88,10 @@ ICAP ICAP::decoded(std::string const& _encoded)
ret.m_client = data.substr(7); ret.m_client = data.substr(7);
} }
else else
throw InvalidICAP(); BOOST_THROW_EXCEPTION(InvalidICAP());
} }
else else
throw InvalidICAP(); BOOST_THROW_EXCEPTION(InvalidICAP());
return ret; return ret;
} }
@ -101,7 +101,7 @@ std::string ICAP::encoded() const
if (m_type == Direct) if (m_type == Direct)
{ {
if (!!m_direct[0]) if (!!m_direct[0])
throw InvalidICAP(); BOOST_THROW_EXCEPTION(InvalidICAP());
std::string d = toBase36<Address::size>(m_direct); std::string d = toBase36<Address::size>(m_direct);
while (d.size() < 30) while (d.size() < 30)
d = "0" + d; d = "0" + d;
@ -118,11 +118,11 @@ std::string ICAP::encoded() const
m_institution.size() != 4 || m_institution.size() != 4 ||
m_client.size() != 9 m_client.size() != 9
) )
throw InvalidICAP(); BOOST_THROW_EXCEPTION(InvalidICAP());
return iban("XE", m_asset + m_institution + m_client); return iban("XE", m_asset + m_institution + m_client);
} }
else else
throw InvalidICAP(); BOOST_THROW_EXCEPTION(InvalidICAP());
} }
pair<Address, bytes> ICAP::lookup(std::function<bytes(Address, bytes)> const& _call, Address const& _reg) const pair<Address, bytes> ICAP::lookup(std::function<bytes(Address, bytes)> const& _call, Address const& _reg) const
@ -149,9 +149,9 @@ pair<Address, bytes> ICAP::lookup(std::function<bytes(Address, bytes)> const& _c
else if (m_institution[0] != 'X') else if (m_institution[0] != 'X')
return make_pair(resolve(m_institution + "/" + m_client), bytes()); return make_pair(resolve(m_institution + "/" + m_client), bytes());
else else
throw InterfaceNotSupported("ICAP::lookup(), bad institution"); BOOST_THROW_EXCEPTION(InterfaceNotSupported("ICAP::lookup(), bad institution"));
} }
throw InterfaceNotSupported("ICAP::lookup(), bad asset"); BOOST_THROW_EXCEPTION(InterfaceNotSupported("ICAP::lookup(), bad asset"));
} }
} }

2
libethcore/KeyManager.h

@ -46,7 +46,7 @@ struct KeyInfo
static h256 const UnknownPassword; static h256 const UnknownPassword;
/// Password query function that never returns a password. /// Password query function that never returns a password.
static auto const DontKnowThrow = [](){ throw PasswordUnknown(); return std::string(); }; static auto const DontKnowThrow = [](){ BOOST_THROW_EXCEPTION(PasswordUnknown()); return std::string(); };
enum class SemanticPassword enum class SemanticPassword
{ {

1
libethereum/EthereumHost.cpp

@ -41,7 +41,6 @@ using namespace dev::eth;
using namespace p2p; using namespace p2p;
unsigned const EthereumHost::c_oldProtocolVersion = 60; //TODO: remove this once v61+ is common unsigned const EthereumHost::c_oldProtocolVersion = 60; //TODO: remove this once v61+ is common
unsigned const c_chainReorgSize = 30000;
char const* const EthereumHost::s_stateNames[static_cast<int>(SyncState::Size)] = {"Idle", "Waiting", "Hashes", "Blocks", "NewBlocks" }; char const* const EthereumHost::s_stateNames[static_cast<int>(SyncState::Size)] = {"Idle", "Waiting", "Hashes", "Blocks", "NewBlocks" };

2
libethereum/State.cpp

@ -456,7 +456,7 @@ unordered_map<Address, u256> State::addresses() const
ret[i.first] = RLP(i.second)[1].toInt<u256>(); ret[i.first] = RLP(i.second)[1].toInt<u256>();
return ret; return ret;
#else #else
throw InterfaceNotSupported("State::addresses()"); BOOST_THROW_EXCEPTION(InterfaceNotSupported("State::addresses()"));
#endif #endif
} }

120
libjsqrc/admin.js

@ -0,0 +1,120 @@
web3.admin = {};
web3.admin.setSessionKey = function(s) { web3.admin.sessionKey = s; };
var getSessionKey = function () { return web3.admin.sessionKey; };
web3._extend({
property: 'admin',
methods: [new web3._extend.Method({
name: 'web3.setVerbosity',
call: 'admin_web3_setVerbosity',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'net.start',
call: 'admin_net_start',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'net.stop',
call: 'admin_net_stop',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'net.connect',
call: 'admin_net_connect',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'net.peers',
call: 'admin_net_peers',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'eth.blockQueueStatus',
call: 'admin_eth_blockQueueStatus',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'eth.setAskPrice',
call: 'admin_eth_setAskPrice',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.setBidPrice',
call: 'admin_eth_setBidPrice',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.setReferencePrice',
call: 'admin_eth_setReferencePrice',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.setPriority',
call: 'admin_eth_setPriority',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.setMining',
call: 'admin_eth_setMining',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.findBlock',
call: 'admin_eth_findBlock',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.blockQueueFirstUnknown',
call: 'admin_eth_blockQueueFirstUnknown',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'eth.blockQueueRetryUnknown',
call: 'admin_eth_blockQueueRetryUnknown',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'eth.allAccounts',
call: 'admin_eth_allAccounts',
inputFormatter: [getSessionKey],
params: 1
}), new web3._extend.Method({
name: 'eth.newAccount',
call: 'admin_eth_newAccount',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.setSigningKey',
call: 'admin_eth_setSigningKey',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.setMiningBenefactor',
call: 'admin_eth_setMiningBenefactor',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.inspect',
call: 'admin_eth_inspect',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.reprocess',
call: 'admin_eth_reprocess',
inputFormatter: [null, getSessionKey],
params: 2
}), new web3._extend.Method({
name: 'eth.vmTrace',
call: 'admin_eth_vmTrace',
inputFormatter: [null, null, getSessionKey],
params: 3
}), new web3._extend.Method({
name: 'eth.getReceiptByHashAndIndex',
call: 'admin_eth_getReceiptByHashAndIndex',
inputFormatter: [null, null, getSessionKey],
params: 3
})]
});

8
libjsqrc/ethereumjs/LICENSE

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

2
libjsqrc/ethereumjs/README.md

@ -108,7 +108,7 @@ eth -j
[travis-url]: https://travis-ci.org/ethereum/web3.js [travis-url]: https://travis-ci.org/ethereum/web3.js
[dep-image]: https://david-dm.org/ethereum/web3.js.svg [dep-image]: https://david-dm.org/ethereum/web3.js.svg
[dep-url]: https://david-dm.org/ethereum/web3.js [dep-url]: https://david-dm.org/ethereum/web3.js
[dep-dev-image]: https://david-dm.org/ethereum/web.js/dev-status.svg [dep-dev-image]: https://david-dm.org/ethereum/web3.js/dev-status.svg
[dep-dev-url]: https://david-dm.org/ethereum/web3.js#info=devDependencies [dep-dev-url]: https://david-dm.org/ethereum/web3.js#info=devDependencies
[coveralls-image]: https://coveralls.io/repos/ethereum/web3.js/badge.svg?branch=master [coveralls-image]: https://coveralls.io/repos/ethereum/web3.js/badge.svg?branch=master
[coveralls-url]: https://coveralls.io/r/ethereum/web3.js?branch=master [coveralls-url]: https://coveralls.io/r/ethereum/web3.js?branch=master

2
libjsqrc/ethereumjs/bower.json

@ -1,7 +1,7 @@
{ {
"name": "web3", "name": "web3",
"namespace": "ethereum", "namespace": "ethereum",
"version": "0.5.0", "version": "0.6.0",
"description": "Ethereum Compatible JavaScript API", "description": "Ethereum Compatible JavaScript API",
"main": [ "main": [
"./dist/web3.js", "./dist/web3.js",

5683
libjsqrc/ethereumjs/dist/web3-light.js

File diff suppressed because it is too large

2
libjsqrc/ethereumjs/dist/web3-light.min.js

File diff suppressed because one or more lines are too long

228
libjsqrc/ethereumjs/dist/web3.js

File diff suppressed because one or more lines are too long

85
libjsqrc/ethereumjs/dist/web3.js.map

File diff suppressed because one or more lines are too long

4
libjsqrc/ethereumjs/dist/web3.min.js

File diff suppressed because one or more lines are too long

153
libjsqrc/ethereumjs/example/coin.html

@ -1,153 +0,0 @@
<!doctype>
<html>
<title>JevCoin</title>
<head>
<script type="text/javascript" src="../dist/web3.js"></script>
</head>
<body>
<h1>JevCoin <code id="contract_addr"></code></h1>
<div>
<strong>Balance</strong>
<span id="balance"></strong>
</div>
<div>
<span>Address:</span>
<input type="text" id="address" style="width:200px">
<span>Amount:</span>
<input type="text" id="amount" style="width:200px">
<button onclick="transact()">Send</button>
<span id="message"></span>
</div>
<hr>
<table width="100%" id="table">
<tr><td style="width:40%;">Address</td><td>Balance</td></tr>
<tbody id="table_body"></tbody>
</table>
</body>
<script type="text/javascript">
var web3 = require('web3');
var eth = web3.eth;
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8080'));
var desc = [{
"name": "balance(address)",
"type": "function",
"inputs": [{
"name": "who",
"type": "address"
}],
"constant": true,
"outputs": [{
"name": "value",
"type": "uint256"
}]
}, {
"name": "send(address,uint256)",
"type": "function",
"inputs": [{
"name": "to",
"type": "address"
}, {
"name": "value",
"type": "uint256"
}],
"outputs": []
}, {
"name":"Changed",
"type":"event",
"inputs": [
{"name":"from","type":"address","indexed":true},
{"name":"amount","type":"uint256","indexed":true},
],
}];
var address = localStorage.getItem("address");
// deploy if not exist
if(address === null) {
var code = "0x60056013565b61014f8061003a6000396000f35b620f42406000600033600160a060020a0316815260200190815260200160002081905550560060e060020a600035048063d0679d3414610020578063e3d670d71461003457005b61002e600435602435610049565b60006000f35b61003f600435610129565b8060005260206000f35b806000600033600160a060020a03168152602001908152602001600020541061007157610076565b610125565b806000600033600160a060020a03168152602001908152602001600020908154039081905550806000600084600160a060020a031681526020019081526020016000209081540190819055508033600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a38082600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a35b5050565b60006000600083600160a060020a0316815260200190815260200160002054905091905056";
address = web3.eth.transact({from: eth.coinbase, data: code, gas: "1000000"});
localStorage.setItem("address", address);
}
document.querySelector("#contract_addr").innerHTML = address;
var Contract = web3.eth.contract(desc);
contract = new Contract(address);
contract.Changed({from: eth.accounts[0]}).changed(function() {
refresh();
});
function refresh() {
document.querySelector("#balance").innerHTML = contract.balance(eth.coinbase);
var table = document.querySelector("#table_body");
table.innerHTML = ""; // clear
/*var storage = eth.getStorage(address);*/
/*table.innerHTML = "";*/
/*for( var item in storage ) {*/
/*table.innerHTML += "<tr><td>"+item+"</td><td>"+web3.toDecimal(storage[item])+"</td></tr>";*/
/*}*/
}
function transact() {
var to = document.querySelector("#address");
if( to.value.length == 0 ) {
to = "0x4205b06c2cfa0e30359edcab94543266cb6fa1d3";
} else {
if (to.value.substr(0,2) != "0x")
to.value = "0x"+to.value;
}
var value = document.querySelector("#amount");
var amount = parseInt( value.value );
console.log("transact: ", to.value, " => ", amount)
contract.sendTransaction({from: eth.accounts[0]}).send( to.value, amount );
to.value = "";
value.value = "";
var message = document.querySelector("#message")
message.innerHTML = "Submitted";
setTimeout(function() {
message.innerHTML = "";
}, 1000);
}
refresh();
</script>
</html>
<!--
contract JevCoin {
function JevCoin()
{
balances[msg.sender] = 1000000;
}
event Changed(address indexed from, uint indexed amount);
function send(address to, uint value)
{
if( balances[msg.sender] < value ) return;
balances[msg.sender] -= value;
balances[to] += value;
Changed(msg.sender, value);
Changed(to, value);
}
function balance(address who) constant returns(uint t)
{
t = balances[who];
}
mapping(address => uint256) balances;
}
-!>

5
libjsqrc/ethereumjs/example/event_inc.html

@ -25,6 +25,7 @@
var address; var address;
var contract; var contract;
var inc;
var update = function (err, x) { var update = function (err, x) {
document.getElementById('result').textContent = JSON.stringify(x, null, 2); document.getElementById('result').textContent = JSON.stringify(x, null, 2);
@ -55,8 +56,8 @@
} }
}); });
contract.Incremented({odd: true}).watch(update); inc = contract.Incremented({odd: true});
inc.watch(update);
}; };
var counter = 0; var counter = 0;

2
libjsqrc/ethereumjs/gulpfile.js

@ -73,7 +73,7 @@ gulp.task('buildLight', ['clean'], function () {
.pipe(gulp.dest( DEST )); .pipe(gulp.dest( DEST ));
}); });
gulp.task('buildStandalone', [], function () { gulp.task('buildStandalone', ['clean'], function () {
return browserify(browserifyOptions) return browserify(browserifyOptions)
.require('./' + src + '.js', {expose: 'web3'}) .require('./' + src + '.js', {expose: 'web3'})
.require('bignumber.js') // expose it to dapp users .require('bignumber.js') // expose it to dapp users

2
libjsqrc/ethereumjs/lib/utils/config.js

@ -71,7 +71,7 @@ module.exports = {
ETH_SIGNATURE_LENGTH: 4, ETH_SIGNATURE_LENGTH: 4,
ETH_UNITS: ETH_UNITS, ETH_UNITS: ETH_UNITS,
ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },
ETH_POLLING_TIMEOUT: 1000, ETH_POLLING_TIMEOUT: 1000/2,
defaultBlock: 'latest', defaultBlock: 'latest',
defaultAccount: undefined defaultAccount: undefined
}; };

2
libjsqrc/ethereumjs/lib/version.json

@ -1,3 +1,3 @@
{ {
"version": "0.5.0" "version": "0.6.0"
} }

33
libjsqrc/ethereumjs/lib/web3.js

@ -34,7 +34,6 @@ var Filter = require('./web3/filter');
var utils = require('./utils/utils'); var utils = require('./utils/utils');
var formatters = require('./web3/formatters'); var formatters = require('./web3/formatters');
var RequestManager = require('./web3/requestmanager'); var RequestManager = require('./web3/requestmanager');
var Method = require('./web3/method');
var c = require('./utils/config'); var c = require('./utils/config');
var Property = require('./web3/property'); var Property = require('./web3/property');
var Batch = require('./web3/batch'); var Batch = require('./web3/batch');
@ -94,8 +93,7 @@ web3.eth.filter = function (fil, eventParams, options, formatter) {
return fil(eventParams, options); return fil(eventParams, options);
} }
// what outputLogFormatter? that's wrong // output logs works for blockFilter and pendingTransaction filters?
//return new Filter(fil, watches.eth(), formatters.outputLogFormatter);
return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter); return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter);
}; };
/*jshint maxparams:3 */ /*jshint maxparams:3 */
@ -150,6 +148,23 @@ Object.defineProperty(web3.eth, 'defaultAccount', {
} }
}); });
// EXTEND
web3._extend = function(extension){
/*jshint maxcomplexity: 6 */
if(extension.property && !web3[extension.property])
web3[extension.property] = {};
setupMethods(web3[extension.property] || web3, extension.methods || []);
setupProperties(web3[extension.property] || web3, extension.properties || []);
};
web3._extend.formatters = formatters;
web3._extend.utils = utils;
web3._extend.Method = require('./web3/method');
web3._extend.Property = require('./web3/property');
/// setups all api methods /// setups all api methods
setupProperties(web3, web3Properties); setupProperties(web3, web3Properties);
setupMethods(web3.net, net.methods); setupMethods(web3.net, net.methods);
@ -159,17 +174,5 @@ setupProperties(web3.eth, eth.properties);
setupMethods(web3.db, db.methods); setupMethods(web3.db, db.methods);
setupMethods(web3.shh, shh.methods); setupMethods(web3.shh, shh.methods);
web3.admin = {};
web3.admin.setSessionKey = function(s) { web3.admin.sessionKey = s; };
var blockQueueStatus = new Property({
name: 'blockQueueStatus',
call: 'admin_eth_blockQueueStatus',
params: 1,
inputFormatter: [function() { return web3.admin.sessionKey; }]
});
setupMethods(web3.admin, [blockQueueStatus]);
module.exports = web3; module.exports = web3;

95
libjsqrc/ethereumjs/lib/web3/filter.js

@ -74,21 +74,36 @@ var getOptions = function (options) {
}; };
}; };
var Filter = function (options, methods, formatter) { /**
var implementation = {}; Adds the callback and sets up the methods, to iterate over the results.
methods.forEach(function (method) {
method.attachToObject(implementation); @method getLogsAtStart
@param {Object} self
@param {funciton}
*/
var getLogsAtStart = function(self, callback){
// call getFilterLogs for the first watch callback start
if (!utils.isString(self.options)) {
self.get(function (err, messages) {
// don't send all the responses to all the watches again... just to self one
if (err) {
callback(err);
}
messages.forEach(function (message) {
callback(null, message);
}); });
this.options = getOptions(options); });
this.implementation = implementation; }
this.callbacks = [];
this.formatter = formatter;
this.filterId = this.implementation.newFilter(this.options);
}; };
Filter.prototype.watch = function (callback) { /**
this.callbacks.push(callback); Adds the callback and sets up the methods, to iterate over the results.
var self = this;
@method pollFilter
@param {Object} self
*/
var pollFilter = function(self) {
var onMessage = function (error, messages) { var onMessage = function (error, messages) {
if (error) { if (error) {
@ -105,29 +120,55 @@ Filter.prototype.watch = function (callback) {
}); });
}; };
// call getFilterLogs on start RequestManager.getInstance().startPolling({
if (!utils.isString(this.options)) { method: self.implementation.poll.call,
this.get(function (err, messages) { params: [self.filterId],
// don't send all the responses to all the watches again... just to this one }, self.filterId, onMessage, self.stopWatching.bind(self));
if (err) {
callback(err);
}
messages.forEach(function (message) { };
callback(null, message);
var Filter = function (options, methods, formatter) {
var self = this;
var implementation = {};
methods.forEach(function (method) {
method.attachToObject(implementation);
});
this.options = getOptions(options);
this.implementation = implementation;
this.callbacks = [];
this.pollFilters = [];
this.formatter = formatter;
this.implementation.newFilter(this.options, function(error, id){
if(error) {
self.callbacks.forEach(function(callback){
callback(error);
}); });
} else {
self.filterId = id;
// get filter logs at start
self.callbacks.forEach(function(callback){
getLogsAtStart(self, callback);
});
pollFilter(self);
}
}); });
};
Filter.prototype.watch = function (callback) {
this.callbacks.push(callback);
if(this.filterId) {
getLogsAtStart(this, callback);
pollFilter(this);
} }
RequestManager.getInstance().startPolling({ return this;
method: this.implementation.poll.call,
params: [this.filterId],
}, this.filterId, onMessage, this.stopWatching.bind(this));
}; };
Filter.prototype.stopWatching = function () { Filter.prototype.stopWatching = function () {
RequestManager.getInstance().stopPolling(this.filterId); RequestManager.getInstance().stopPolling(this.filterId);
this.implementation.uninstallFilter(this.filterId); // remove filter async
this.implementation.uninstallFilter(this.filterId, function(){});
this.callbacks = []; this.callbacks = [];
}; };
@ -149,6 +190,8 @@ Filter.prototype.get = function (callback) {
return self.formatter ? self.formatter(log) : log; return self.formatter ? self.formatter(log) : log;
}); });
} }
return this;
}; };
module.exports = Filter; module.exports = Filter;

10
libjsqrc/ethereumjs/lib/web3/formatters.js

@ -89,7 +89,9 @@ var inputTransactionFormatter = function (options){
* @returns {Object} transaction * @returns {Object} transaction
*/ */
var outputTransactionFormatter = function (tx){ var outputTransactionFormatter = function (tx){
if(tx.blockNumber !== null)
tx.blockNumber = utils.toDecimal(tx.blockNumber); tx.blockNumber = utils.toDecimal(tx.blockNumber);
if(tx.transactionIndex !== null)
tx.transactionIndex = utils.toDecimal(tx.transactionIndex); tx.transactionIndex = utils.toDecimal(tx.transactionIndex);
tx.nonce = utils.toDecimal(tx.nonce); tx.nonce = utils.toDecimal(tx.nonce);
tx.gas = utils.toDecimal(tx.gas); tx.gas = utils.toDecimal(tx.gas);
@ -112,6 +114,7 @@ var outputBlockFormatter = function(block) {
block.gasUsed = utils.toDecimal(block.gasUsed); block.gasUsed = utils.toDecimal(block.gasUsed);
block.size = utils.toDecimal(block.size); block.size = utils.toDecimal(block.size);
block.timestamp = utils.toDecimal(block.timestamp); block.timestamp = utils.toDecimal(block.timestamp);
if(block.number !== null)
block.number = utils.toDecimal(block.number); block.number = utils.toDecimal(block.number);
block.difficulty = utils.toBigNumber(block.difficulty); block.difficulty = utils.toBigNumber(block.difficulty);
@ -135,12 +138,11 @@ var outputBlockFormatter = function(block) {
* @returns {Object} log * @returns {Object} log
*/ */
var outputLogFormatter = function(log) { var outputLogFormatter = function(log) {
if (log === null) { // 'pending' && 'latest' filters are nulls if(log.blockNumber !== null)
return null;
}
log.blockNumber = utils.toDecimal(log.blockNumber); log.blockNumber = utils.toDecimal(log.blockNumber);
if(log.transactionIndex !== null)
log.transactionIndex = utils.toDecimal(log.transactionIndex); log.transactionIndex = utils.toDecimal(log.transactionIndex);
if(log.logIndex !== null)
log.logIndex = utils.toDecimal(log.logIndex); log.logIndex = utils.toDecimal(log.logIndex);
return log; return log;

13
libjsqrc/ethereumjs/lib/web3/function.js

@ -23,6 +23,7 @@
var web3 = require('../web3'); var web3 = require('../web3');
var coder = require('../solidity/coder'); var coder = require('../solidity/coder');
var utils = require('../utils/utils'); var utils = require('../utils/utils');
var formatters = require('./formatters');
var sha3 = require('../utils/sha3'); var sha3 = require('../utils/sha3');
/** /**
@ -46,6 +47,12 @@ SolidityFunction.prototype.extractCallback = function (args) {
} }
}; };
SolidityFunction.prototype.extractDefaultBlock = function (args) {
if (args.length > this._inputTypes.length && !utils.isObject(args[args.length -1])) {
return formatters.inputDefaultBlockNumberFormatter(args.pop()); // modify the args array!
}
};
/** /**
* Should be used to create payload from arguments * Should be used to create payload from arguments
* *
@ -97,15 +104,17 @@ SolidityFunction.prototype.unpackOutput = function (output) {
SolidityFunction.prototype.call = function () { SolidityFunction.prototype.call = function () {
var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; }); var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; });
var callback = this.extractCallback(args); var callback = this.extractCallback(args);
var defaultBlock = this.extractDefaultBlock(args);
var payload = this.toPayload(args); var payload = this.toPayload(args);
if (!callback) { if (!callback) {
var output = web3.eth.call(payload); var output = web3.eth.call(payload, defaultBlock);
return this.unpackOutput(output); return this.unpackOutput(output);
} }
var self = this; var self = this;
web3.eth.call(payload, function (error, output) { web3.eth.call(payload, defaultBlock, function (error, output) {
callback(error, self.unpackOutput(output)); callback(error, self.unpackOutput(output));
}); });
}; };

2
libjsqrc/ethereumjs/lib/web3/httpprovider.js

@ -35,6 +35,7 @@ HttpProvider.prototype.send = function (payload) {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('POST', this.host, false); request.open('POST', this.host, false);
request.setRequestHeader('Content-type','application/json');
try { try {
request.send(JSON.stringify(payload)); request.send(JSON.stringify(payload));
@ -78,6 +79,7 @@ HttpProvider.prototype.sendAsync = function (payload, callback) {
}; };
request.open('POST', this.host, true); request.open('POST', this.host, true);
request.setRequestHeader('Content-type','application/json');
try { try {
request.send(JSON.stringify(payload)); request.send(JSON.stringify(payload));

1
libjsqrc/ethereumjs/lib/web3/property.js

@ -29,7 +29,6 @@ var Property = function (options) {
this.setter = options.setter; this.setter = options.setter;
this.outputFormatter = options.outputFormatter; this.outputFormatter = options.outputFormatter;
this.inputFormatter = options.inputFormatter; this.inputFormatter = options.inputFormatter;
this.params = options.params;
}; };
/** /**

55
libjsqrc/ethereumjs/lib/web3/requestmanager.js

@ -43,9 +43,9 @@ var RequestManager = function (provider) {
arguments.callee._singletonInstance = this; arguments.callee._singletonInstance = this;
this.provider = provider; this.provider = provider;
this.polls = []; this.polls = {};
this.timeout = null; this.timeout = null;
this.poll(); this.isPolling = false;
}; };
/** /**
@ -140,6 +140,11 @@ RequestManager.prototype.sendBatch = function (data, callback) {
*/ */
RequestManager.prototype.setProvider = function (p) { RequestManager.prototype.setProvider = function (p) {
this.provider = p; this.provider = p;
if (this.provider && !this.isPolling) {
this.poll();
this.isPolling = true;
}
}; };
/*jshint maxparams:4 */ /*jshint maxparams:4 */
@ -156,7 +161,7 @@ RequestManager.prototype.setProvider = function (p) {
* @todo cleanup number of params * @todo cleanup number of params
*/ */
RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) { RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) {
this.polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); this.polls['poll_'+ pollId] = {data: data, id: pollId, callback: callback, uninstall: uninstall};
}; };
/*jshint maxparams:3 */ /*jshint maxparams:3 */
@ -167,24 +172,19 @@ RequestManager.prototype.startPolling = function (data, pollId, callback, uninst
* @param {Number} pollId * @param {Number} pollId
*/ */
RequestManager.prototype.stopPolling = function (pollId) { RequestManager.prototype.stopPolling = function (pollId) {
for (var i = this.polls.length; i--;) { delete this.polls['poll_'+ pollId];
var poll = this.polls[i];
if (poll.id === pollId) {
this.polls.splice(i, 1);
}
}
}; };
/** /**
* Should be called to reset polling mechanism of request manager * Should be called to reset the polling mechanism of the request manager
* *
* @method reset * @method reset
*/ */
RequestManager.prototype.reset = function () { RequestManager.prototype.reset = function () {
this.polls.forEach(function (poll) { for (var key in this.polls) {
poll.uninstall(poll.id); this.polls[key].uninstall();
}); }
this.polls = []; this.polls = {};
if (this.timeout) { if (this.timeout) {
clearTimeout(this.timeout); clearTimeout(this.timeout);
@ -199,9 +199,10 @@ RequestManager.prototype.reset = function () {
* @method poll * @method poll
*/ */
RequestManager.prototype.poll = function () { RequestManager.prototype.poll = function () {
/*jshint maxcomplexity: 6 */
this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT); this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT);
if (!this.polls.length) { if (Object.keys(this.polls).length === 0) {
return; return;
} }
@ -210,9 +211,18 @@ RequestManager.prototype.poll = function () {
return; return;
} }
var payload = Jsonrpc.getInstance().toBatchPayload(this.polls.map(function (data) { var pollsData = [];
return data.data; var pollsKeys = [];
})); for (var key in this.polls) {
pollsData.push(this.polls[key].data);
pollsKeys.push(key);
}
if (pollsData.length === 0) {
return;
}
var payload = Jsonrpc.getInstance().toBatchPayload(pollsData);
var self = this; var self = this;
this.provider.sendAsync(payload, function (error, results) { this.provider.sendAsync(payload, function (error, results) {
@ -226,8 +236,15 @@ RequestManager.prototype.poll = function () {
} }
results.map(function (result, index) { results.map(function (result, index) {
result.callback = self.polls[index].callback; var key = pollsKeys[index];
// make sure the filter is still installed after arrival of the request
if (self.polls[key]) {
result.callback = self.polls[key].callback;
return result; return result;
} else
return false;
}).filter(function (result) {
return !!result;
}).filter(function (result) { }).filter(function (result) {
var valid = Jsonrpc.getInstance().isValidResponse(result); var valid = Jsonrpc.getInstance().isValidResponse(result);
if (!valid) { if (!valid) {

4
libjsqrc/ethereumjs/lib/web3/watches.js

@ -29,11 +29,11 @@ var eth = function () {
switch(type) { switch(type) {
case 'latest': case 'latest':
args.pop(); args.shift();
this.params = 0; this.params = 0;
return 'eth_newBlockFilter'; return 'eth_newBlockFilter';
case 'pending': case 'pending':
args.pop(); args.shift();
this.params = 0; this.params = 0;
return 'eth_newPendingTransactionFilter'; return 'eth_newPendingTransactionFilter';
default: default:

2
libjsqrc/ethereumjs/package.js

@ -1,7 +1,7 @@
/* jshint ignore:start */ /* jshint ignore:start */
Package.describe({ Package.describe({
name: 'ethereum:web3', name: 'ethereum:web3',
version: '0.5.0', version: '0.6.0',
summary: 'Ethereum JavaScript API, middleware to talk to a ethreum node over RPC', summary: 'Ethereum JavaScript API, middleware to talk to a ethreum node over RPC',
git: 'https://github.com/ethereum/ethereum.js', git: 'https://github.com/ethereum/ethereum.js',
// By default, Meteor will default to using README.md for documentation. // By default, Meteor will default to using README.md for documentation.

6
libjsqrc/ethereumjs/package.json

@ -1,7 +1,7 @@
{ {
"name": "web3", "name": "web3",
"namespace": "ethereum", "namespace": "ethereum",
"version": "0.5.0", "version": "0.6.0",
"description": "Ethereum JavaScript API, middleware to talk to a ethereum node over RPC", "description": "Ethereum JavaScript API, middleware to talk to a ethereum node over RPC",
"main": "./index.js", "main": "./index.js",
"directories": { "directories": {
@ -17,11 +17,11 @@
}, },
"devDependencies": { "devDependencies": {
"bower": ">=1.3.0", "bower": ">=1.3.0",
"browserify": ">=6.0", "browserify": ">=10.0",
"chai": "^2.1.1", "chai": "^2.1.1",
"coveralls": "^2.11.2", "coveralls": "^2.11.2",
"del": ">=0.1.1", "del": ">=0.1.1",
"exorcist": "^0.1.6", "exorcist": "^0.4.0",
"gulp": ">=3.4.0", "gulp": ">=3.4.0",
"gulp-jshint": ">=1.5.0", "gulp-jshint": ">=1.5.0",
"gulp-rename": ">=1.2.0", "gulp-rename": ">=1.2.0",

55
libjsqrc/ethereumjs/test/contract.js

@ -66,7 +66,7 @@ describe('web3.eth.contract', function () {
provider.injectValidation(function (payload) { provider.injectValidation(function (payload) {
if (step === 0) { if (step === 0) {
step = 1; step = 1;
provider.injectResult(3); provider.injectResult('0x3');
assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, 'eth_newFilter'); assert.equal(payload.method, 'eth_newFilter');
assert.deepEqual(payload.params[0], { assert.deepEqual(payload.params[0], {
@ -105,7 +105,7 @@ describe('web3.eth.contract', function () {
'0000000000000000000000000000000000000000000000000000000000000008' '0000000000000000000000000000000000000000000000000000000000000008'
}]]); }]]);
var r = payload.filter(function (p) { var r = payload.filter(function (p) {
return p.jsonrpc === '2.0' && p.method === 'eth_getFilterChanges' && p.params[0] === 3; return p.jsonrpc === '2.0' && p.method === 'eth_getFilterChanges' && p.params[0] === '0x3';
}); });
assert.equal(r.length > 0, true); assert.equal(r.length > 0, true);
} }
@ -114,7 +114,8 @@ describe('web3.eth.contract', function () {
var contract = web3.eth.contract(desc).at(address); var contract = web3.eth.contract(desc).at(address);
var res = 0; var res = 0;
contract.Changed({from: address}).watch(function(err, result) { var event = contract.Changed({from: address});
event.watch(function(err, result) {
assert.equal(result.args.from, address); assert.equal(result.args.from, address);
assert.equal(result.args.amount, 1); assert.equal(result.args.amount, 1);
assert.equal(result.args.t1, 1); assert.equal(result.args.t1, 1);
@ -133,6 +134,7 @@ describe('web3.eth.contract', function () {
provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032');
var signature = 'balance(address)' var signature = 'balance(address)'
var address = '0x1234567890123456789012345678901234567890'; var address = '0x1234567890123456789012345678901234567890';
provider.injectValidation(function (payload) { provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_call'); assert.equal(payload.method, 'eth_call');
assert.deepEqual(payload.params, [{ assert.deepEqual(payload.params, [{
@ -147,6 +149,28 @@ describe('web3.eth.contract', function () {
assert.deepEqual(new BigNumber(0x32), r); assert.deepEqual(new BigNumber(0x32), r);
}); });
it('should call constant function with default block', function () {
var provider = new FakeHttpProvider();
web3.setProvider(provider);
web3.reset();
provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032');
var signature = 'balance(address)'
var address = '0x1234567890123456789012345678901234567890';
provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_call');
assert.deepEqual(payload.params, [{
data: '0x' + sha3(signature).slice(0, 8) + '0000000000000000000000001234567890123456789012345678901234567890',
to: address
}, '0xb']);
});
var contract = web3.eth.contract(desc).at(address);
var r = contract.balance(address, 11);
assert.deepEqual(new BigNumber(0x32), r);
});
it('should sendTransaction to contract function', function () { it('should sendTransaction to contract function', function () {
var provider = new FakeHttpProvider(); var provider = new FakeHttpProvider();
web3.setProvider(provider); web3.setProvider(provider);
@ -218,6 +242,31 @@ describe('web3.eth.contract', function () {
}); });
it('should explicitly make a call with optional params and defaultBlock', function () {
var provider = new FakeHttpProvider();
web3.setProvider(provider);
web3.reset();
provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032');
var signature = 'balance(address)';
var address = '0x1234567890123456789012345678901234567890';
provider.injectValidation(function (payload) {
assert.equal(payload.method, 'eth_call');
assert.deepEqual(payload.params, [{
data: '0x' + sha3(signature).slice(0, 8) + '0000000000000000000000001234567890123456789012345678901234567890',
to: address,
from: address,
gas: '0xc350'
}, '0xb']);
});
var contract = web3.eth.contract(desc).at(address);
var r = contract.balance.call(address, {from: address, gas: 50000}, 11);
assert.deepEqual(new BigNumber(0x32), r);
});
it('should sendTransaction with optional params', function () { it('should sendTransaction with optional params', function () {
var provider = new FakeHttpProvider(); var provider = new FakeHttpProvider();
web3.setProvider(provider); web3.setProvider(provider);

70
libjsqrc/ethereumjs/test/formatters.outputBlockFormatter.js

@ -8,38 +8,72 @@ describe('formatters', function () {
it('should return the correct value', function () { it('should return the correct value', function () {
assert.deepEqual(formatters.outputBlockFormatter({ assert.deepEqual(formatters.outputBlockFormatter({
hash: '0x34234kjh23kj4234', hash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
parentHash: '0x34234kjh23kj4234', parentHash: '0x83ffb245cfced97ccc5c75253d6960376d6c6dea93647397a543a72fdaea5265',
miner: '0x34234kjh23kj4234', miner: '0xdcc6960376d6c6dea93647383ffb245cfced97cf',
stateRoot: '0x34234kjh23kj4234', stateRoot: '0x54dda68af07643f68739a6e9612ad157a26ae7e2ce81f77842bb5835fbcde583',
sha3Uncles: '0x34234kjh23kj4234', sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
bloom: '0x34234kjh23kj4234', bloom: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
difficulty: '0x3e8', difficulty: '0x3e8',
totalDifficulty: '0x3e8', totalDifficulty: '0x3e8',
number: '0x3e8', number: '0x3e8',
gasLimit: '0x3e8', gasLimit: '0x3e8',
gasUsed: '0x3e8', gasUsed: '0x3e8',
timestamp: '0x3e8', timestamp: '0x3e8',
extraData: '0x34234kjh23kj4234', extraData: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
nonce: '0x34234kjh23kj4234', nonce: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
children: ['0x34234kjh23kj4234'],
size: '0x3e8' size: '0x3e8'
}), { }), {
hash: '0x34234kjh23kj4234', hash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
parentHash: '0x34234kjh23kj4234', parentHash: '0x83ffb245cfced97ccc5c75253d6960376d6c6dea93647397a543a72fdaea5265',
miner: '0x34234kjh23kj4234', miner: '0xdcc6960376d6c6dea93647383ffb245cfced97cf',
stateRoot: '0x34234kjh23kj4234', stateRoot: '0x54dda68af07643f68739a6e9612ad157a26ae7e2ce81f77842bb5835fbcde583',
sha3Uncles: '0x34234kjh23kj4234', sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
bloom: '0x34234kjh23kj4234', bloom: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
difficulty: new BigNumber(1000), difficulty: new BigNumber(1000),
totalDifficulty: new BigNumber(1000), totalDifficulty: new BigNumber(1000),
number: 1000, number: 1000,
gasLimit: 1000, gasLimit: 1000,
gasUsed: 1000, gasUsed: 1000,
timestamp: 1000, timestamp: 1000,
extraData: '0x34234kjh23kj4234', extraData: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
nonce: '0x34234kjh23kj4234', nonce: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
children: ['0x34234kjh23kj4234'], size: 1000
});
});
it('should return the correct value, when null values are present', function () {
assert.deepEqual(formatters.outputBlockFormatter({
hash: null,
parentHash: '0x83ffb245cfced97ccc5c75253d6960376d6c6dea93647397a543a72fdaea5265',
miner: null,
stateRoot: '0x54dda68af07643f68739a6e9612ad157a26ae7e2ce81f77842bb5835fbcde583',
sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
bloom: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
difficulty: '0x3e8',
totalDifficulty: '0x3e8',
number: null,
gasLimit: '0x3e8',
gasUsed: '0x3e8',
timestamp: '0x3e8',
extraData: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
nonce: null,
size: '0x3e8'
}), {
hash: null,
parentHash: '0x83ffb245cfced97ccc5c75253d6960376d6c6dea93647397a543a72fdaea5265',
miner: null,
stateRoot: '0x54dda68af07643f68739a6e9612ad157a26ae7e2ce81f77842bb5835fbcde583',
sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
bloom: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
difficulty: new BigNumber(1000),
totalDifficulty: new BigNumber(1000),
number: null,
gasLimit: 1000,
gasUsed: 1000,
timestamp: 1000,
extraData: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
nonce: null,
size: 1000 size: 1000
}); });
}); });

32
libjsqrc/ethereumjs/test/formatters.outputLogFormatter.js

@ -9,17 +9,37 @@ describe('formatters', function () {
transactionIndex: '0x3e8', transactionIndex: '0x3e8',
logIndex: '0x3e8', logIndex: '0x3e8',
blockNumber: '0x3e8', blockNumber: '0x3e8',
transactionHash: '0x7b2274657374223a2274657374227d', transactionHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
blockHash: '0x7b2274657374223a2274657374227d', blockHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
data: '0x7b2274657374223a2274657374227d', data: '0x7b2274657374223a2274657374227',
topics: ['0x68656c6c6f','0x6d79746f70696373'] topics: ['0x68656c6c6f','0x6d79746f70696373']
}), { }), {
transactionIndex: 1000, transactionIndex: 1000,
logIndex: 1000, logIndex: 1000,
blockNumber: 1000, blockNumber: 1000,
transactionHash: '0x7b2274657374223a2274657374227d', transactionHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
blockHash: '0x7b2274657374223a2274657374227d', blockHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265',
data: '0x7b2274657374223a2274657374227d', data: '0x7b2274657374223a2274657374227',
topics: ['0x68656c6c6f','0x6d79746f70696373']
});
});
it('should return the correct value, when null values are present', function () {
assert.deepEqual(formatters.outputLogFormatter({
transactionIndex: null,
logIndex: null,
blockNumber: null,
transactionHash: null,
blockHash: null,
data: '0x7b2274657374223a2274657374227',
topics: ['0x68656c6c6f','0x6d79746f70696373']
}), {
transactionIndex: null,
logIndex: null,
blockNumber: null,
transactionHash: null,
blockHash: null,
data: '0x7b2274657374223a2274657374227',
topics: ['0x68656c6c6f','0x6d79746f70696373'] topics: ['0x68656c6c6f','0x6d79746f70696373']
}); });
}); });

35
libjsqrc/ethereumjs/test/formatters.outputTransactionFormatter.js

@ -7,7 +7,7 @@ describe('formatters', function () {
it('should return the correct value', function () { it('should return the correct value', function () {
assert.deepEqual(formatters.outputTransactionFormatter({ assert.deepEqual(formatters.outputTransactionFormatter({
input: '0x34234kjh23kj4234', input: '0x3454645634534',
from: '0x00000', from: '0x00000',
to: '0x00000', to: '0x00000',
value: '0x3e8', value: '0x3e8',
@ -16,9 +16,9 @@ describe('formatters', function () {
nonce: '0xb', nonce: '0xb',
transactionIndex: '0x1', transactionIndex: '0x1',
blockNumber: '0x3e8', blockNumber: '0x3e8',
blockHash: '0x34234bf23bf4234' blockHash: '0xc9b9cdc2092a9d6589d96662b1fd6949611163fb3910cf8a173cd060f17702f9'
}), { }), {
input: '0x34234kjh23kj4234', input: '0x3454645634534',
from: '0x00000', from: '0x00000',
to: '0x00000', to: '0x00000',
value: new BigNumber(1000), value: new BigNumber(1000),
@ -26,9 +26,36 @@ describe('formatters', function () {
gasPrice: new BigNumber(1000), gasPrice: new BigNumber(1000),
nonce: 11, nonce: 11,
blockNumber: 1000, blockNumber: 1000,
blockHash: '0x34234bf23bf4234', blockHash: '0xc9b9cdc2092a9d6589d96662b1fd6949611163fb3910cf8a173cd060f17702f9',
transactionIndex: 1 transactionIndex: 1
}); });
}); });
it('should return the correct value, when null values are present', function () {
assert.deepEqual(formatters.outputTransactionFormatter({
input: '0x3454645634534',
from: '0x00000',
to: null,
value: '0x3e8',
gas: '0x3e8',
gasPrice: '0x3e8',
nonce: '0xb',
transactionIndex: null,
blockNumber: null,
blockHash: null
}), {
input: '0x3454645634534',
from: '0x00000',
to: null,
value: new BigNumber(1000),
gas: 1000,
gasPrice: new BigNumber(1000),
nonce: 11,
blockNumber: null,
blockHash: null,
transactionIndex: null
});
});
}); });
}); });

10
libjsqrc/ethereumjs/test/helpers/FakeHttpProvider2.js

@ -15,11 +15,21 @@ FakeHttpProvider2.prototype.injectResultList = function (list) {
FakeHttpProvider2.prototype.getResponse = function () { FakeHttpProvider2.prototype.getResponse = function () {
var result = this.resultList[this.counter]; var result = this.resultList[this.counter];
this.counter++; this.counter++;
// add fallback result value
if(!result)
result = {
result: undefined
};
if (result.type === 'batch') { if (result.type === 'batch') {
this.injectBatchResults(result.result); this.injectBatchResults(result.result);
} else { } else {
this.injectResult(result.result); this.injectResult(result.result);
} }
this.counter = 0;
return this.response; return this.response;
}; };

7
libjsqrc/ethereumjs/test/helpers/FakeXMLHttpRequest.js

@ -6,6 +6,9 @@ var FakeXMLHttpRequest = function () {
this.readyState = 4; this.readyState = 4;
this.onreadystatechange = null; this.onreadystatechange = null;
this.async = false; this.async = false;
this.headers = {
'Content-Type': 'text/plain'
};
}; };
FakeXMLHttpRequest.prototype.open = function (method, host, async) { FakeXMLHttpRequest.prototype.open = function (method, host, async) {
@ -15,6 +18,10 @@ FakeXMLHttpRequest.prototype.open = function (method, host, async) {
this.async = async; this.async = async;
}; };
FakeXMLHttpRequest.prototype.setRequestHeader = function(name, value) {
this.headers[name] = value;
};
FakeXMLHttpRequest.prototype.send = function (payload) { FakeXMLHttpRequest.prototype.send = function (payload) {
assert.equal(typeof payload, 'string'); assert.equal(typeof payload, 'string');
if (this.async) { if (this.async) {

76
libjsqrc/ethereumjs/test/web3.extend.js

@ -0,0 +1,76 @@
var chai = require('chai');
var assert = chai.assert;
var FakeHttpProvider = require('./helpers/FakeHttpProvider');
var web3 = require('../lib/web3');
var tests = [{
properties: [new web3._extend.Property({
name: 'gasPrice',
getter: 'eth_gasPrice',
outputFormatter: web3._extend.formatters.outputBigNumberFormatter
})]
},{
methods: [new web3._extend.Method({
name: 'getBalance',
call: 'eth_getBalance',
params: 2,
inputFormatter: [web3._extend.utils.toAddress, web3._extend.formatters.inputDefaultBlockNumberFormatter],
outputFormatter: web3._extend.formatters.outputBigNumberFormatter
})]
},{
property: 'admin',
properties: [new web3._extend.Property({
name: 'gasPrice',
getter: 'eth_gasPrice',
outputFormatter: web3._extend.formatters.outputBigNumberFormatter
})],
methods: [new web3._extend.Method({
name: 'getBalance',
call: 'eth_getBalance',
params: 2,
inputFormatter: [web3._extend.utils.toAddress, web3._extend.formatters.inputDefaultBlockNumberFormatter],
outputFormatter: web3._extend.formatters.outputBigNumberFormatter
})]
}];
describe('web3', function () {
describe('_extend', function () {
tests.forEach(function (test, index) {
it('test no: ' + index, function () {
web3._extend(test);
if(test.properties)
test.properties.forEach(function(property){
var provider = new FakeHttpProvider();
web3.setProvider(provider);
provider.injectResult('');
provider.injectValidation(function (payload) {
assert.equal(payload.jsonrpc, '2.0');
assert.equal(payload.method, property.getter);
});
if(test.property) {
assert.isObject(web3[test.property][property.name]);
assert.isFunction(web3[test.property]['get'+ property.name.charAt(0).toUpperCase() + property.name.slice(1)]);
} else {
assert.isObject(web3[property.name]);
assert.isFunction(web3['get'+ property.name.charAt(0).toUpperCase() + property.name.slice(1)]);
}
});
if(test.methods)
test.methods.forEach(function(property){
if(test.property)
assert.isFunction(web3[test.property][property.name]);
else
assert.isFunction(web3[property.name]);
});
});
});
});
});

1
libjsqrc/js.qrc

@ -2,6 +2,7 @@
<qresource prefix="/js"> <qresource prefix="/js">
<file>bignumber.min.js</file> <file>bignumber.min.js</file>
<file>setup.js</file> <file>setup.js</file>
<file>admin.js</file>
<file alias="webthree.js">ethereumjs/dist/web3.js</file> <file alias="webthree.js">ethereumjs/dist/web3.js</file>
</qresource> </qresource>
</RCC> </RCC>

26
libsolidity/ArrayUtils.cpp

@ -39,11 +39,6 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
// stack layout: [source_ref] [source_byte_off] [source length] target_ref target_byte_off (top) // stack layout: [source_ref] [source_byte_off] [source length] target_ref target_byte_off (top)
solAssert(_targetType.location() == DataLocation::Storage, ""); solAssert(_targetType.location() == DataLocation::Storage, "");
solAssert(
_sourceType.location() == DataLocation::CallData ||
_sourceType.location() == DataLocation::Storage,
"Given array location not implemented."
);
IntegerType uint256(256); IntegerType uint256(256);
Type const* targetBaseType = _targetType.isByteArray() ? &uint256 : &(*_targetType.getBaseType()); Type const* targetBaseType = _targetType.isByteArray() ? &uint256 : &(*_targetType.getBaseType());
@ -52,6 +47,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
// TODO unroll loop for small sizes // TODO unroll loop for small sizes
bool sourceIsStorage = _sourceType.location() == DataLocation::Storage; bool sourceIsStorage = _sourceType.location() == DataLocation::Storage;
bool fromCalldata = _sourceType.location() == DataLocation::CallData;
bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType; bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType;
bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->getStorageBytes() <= 16; bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->getStorageBytes() <= 16;
bool haveByteOffsetTarget = !directCopy && targetBaseType->getStorageBytes() <= 16; bool haveByteOffsetTarget = !directCopy && targetBaseType->getStorageBytes() <= 16;
@ -71,6 +67,13 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
// retrieve source length // retrieve source length
if (_sourceType.location() != DataLocation::CallData || !_sourceType.isDynamicallySized()) if (_sourceType.location() != DataLocation::CallData || !_sourceType.isDynamicallySized())
retrieveLength(_sourceType); // otherwise, length is already there retrieveLength(_sourceType); // otherwise, length is already there
if (_sourceType.location() == DataLocation::Memory && _sourceType.isDynamicallySized())
{
// increment source pointer to point to data
m_context << eth::Instruction::SWAP1 << u256(0x20);
m_context << eth::Instruction::ADD << eth::Instruction::SWAP1;
}
// stack: target_ref source_ref source_length // stack: target_ref source_ref source_length
m_context << eth::Instruction::DUP3; m_context << eth::Instruction::DUP3;
// stack: target_ref source_ref source_length target_ref // stack: target_ref source_ref source_length target_ref
@ -164,9 +167,9 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
StorageItem(m_context, *sourceBaseType).retrieveValue(SourceLocation(), true); StorageItem(m_context, *sourceBaseType).retrieveValue(SourceLocation(), true);
} }
else if (sourceBaseType->isValueType()) else if (sourceBaseType->isValueType())
CompilerUtils(m_context).loadFromMemoryDynamic(*sourceBaseType, true, true, false); CompilerUtils(m_context).loadFromMemoryDynamic(*sourceBaseType, fromCalldata, true, false);
else else
solAssert(false, "Copying of unknown type requested: " + sourceBaseType->toString()); solAssert(false, "Copying of type " + _sourceType.toString(false) + " to storage not yet supported.");
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] <source_value>... // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] <source_value>...
solAssert( solAssert(
2 + byteOffsetSize + sourceBaseType->getSizeOnStack() <= 16, 2 + byteOffsetSize + sourceBaseType->getSizeOnStack() <= 16,
@ -419,6 +422,10 @@ void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) con
} }
else else
{ {
solAssert(
_arrayType.getBaseType()->getCalldataEncodedSize() > 0,
"Copying nested dynamic arrays not yet implemented."
);
if (!_arrayType.isByteArray()) if (!_arrayType.isByteArray())
m_context << _arrayType.getBaseType()->getCalldataEncodedSize() << eth::Instruction::MUL; m_context << _arrayType.getBaseType()->getCalldataEncodedSize() << eth::Instruction::MUL;
else if (_pad) else if (_pad)
@ -485,6 +492,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const
switch (location) switch (location)
{ {
case DataLocation::CallData: case DataLocation::CallData:
case DataLocation::Memory:
if (!_arrayType.isByteArray()) if (!_arrayType.isByteArray())
{ {
m_context << eth::Instruction::SWAP1; m_context << eth::Instruction::SWAP1;
@ -494,7 +502,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const
if (_arrayType.getBaseType()->isValueType()) if (_arrayType.getBaseType()->isValueType())
CompilerUtils(m_context).loadFromMemoryDynamic( CompilerUtils(m_context).loadFromMemoryDynamic(
*_arrayType.getBaseType(), *_arrayType.getBaseType(),
true, location == DataLocation::CallData,
!_arrayType.isByteArray(), !_arrayType.isByteArray(),
false false
); );
@ -527,8 +535,6 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const
m_context << eth::Instruction::ADD << u256(0); m_context << eth::Instruction::ADD << u256(0);
} }
break; break;
case DataLocation::Memory:
solAssert(false, "Memory lvalues not yet implemented.");
} }
} }

15
libsolidity/Compiler.cpp

@ -163,14 +163,14 @@ void Compiler::appendConstructor(FunctionDefinition const& _constructor)
{ {
CompilerContext::LocationSetter locationSetter(m_context, _constructor); CompilerContext::LocationSetter locationSetter(m_context, _constructor);
// 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; if (!_constructor.getParameters().empty())
for (ASTPointer<VariableDeclaration> const& var: _constructor.getParameters())
argumentSize += var->getType()->getCalldataEncodedSize();
if (argumentSize > 0)
{ {
CompilerUtils(m_context).fetchFreeMemoryPointer(); CompilerUtils(m_context).fetchFreeMemoryPointer();
m_context << u256(argumentSize) << eth::Instruction::DUP1; m_context.appendProgramSize(); // program itself
// CODESIZE is program plus manually added arguments
m_context << eth::Instruction::CODESIZE << eth::Instruction::SUB;
// stack: <memptr> <argument size>
m_context << eth::Instruction::DUP1;
m_context.appendProgramSize(); m_context.appendProgramSize();
m_context << eth::Instruction::DUP4 << eth::Instruction::CODECOPY; m_context << eth::Instruction::DUP4 << eth::Instruction::CODECOPY;
m_context << eth::Instruction::ADD; m_context << eth::Instruction::ADD;
@ -265,8 +265,9 @@ void Compiler::appendCalldataUnpacker(
{ {
solAssert(arrayType.location() == DataLocation::Memory, ""); solAssert(arrayType.location() == DataLocation::Memory, "");
// compute data pointer // compute data pointer
m_context << eth::Instruction::DUP1 << eth::Instruction::MLOAD;
//@todo once we support nested arrays, this offset needs to be dynamic. //@todo once we support nested arrays, this offset needs to be dynamic.
m_context << eth::Instruction::DUP1 << _startOffset << eth::Instruction::ADD; m_context << _startOffset << eth::Instruction::ADD;
m_context << eth::Instruction::SWAP1 << u256(0x20) << eth::Instruction::ADD; m_context << eth::Instruction::SWAP1 << u256(0x20) << eth::Instruction::ADD;
} }
else else

2
libsolidity/CompilerUtils.cpp

@ -135,7 +135,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
m_context << u256(0) << u256(identityContractAddress); m_context << u256(0) << u256(identityContractAddress);
//@TODO do not use ::CALL if less than 32 bytes? //@TODO do not use ::CALL if less than 32 bytes?
//@todo in production, we should not have to pair c_callNewAccountGas. //@todo in production, we should not have to pair c_callNewAccountGas.
m_context << u256(eth::c_callGas + 10 + eth::c_callNewAccountGas) << eth::Instruction::GAS; m_context << u256(eth::c_callGas + 15 + eth::c_callNewAccountGas) << eth::Instruction::GAS;
m_context << eth::Instruction::SUB << eth::Instruction::CALL; m_context << eth::Instruction::SUB << eth::Instruction::CALL;
m_context << eth::Instruction::POP; // ignore return value m_context << eth::Instruction::POP; // ignore return value

13
libsolidity/ExpressionCompiler.cpp

@ -457,6 +457,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
strings(), strings(),
Location::Bare, Location::Bare,
false, false,
nullptr,
true, true,
true true
), ),
@ -724,8 +725,8 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
case DataLocation::Storage: case DataLocation::Storage:
setLValue<StorageArrayLength>(_memberAccess, type); setLValue<StorageArrayLength>(_memberAccess, type);
break; break;
default: case DataLocation::Memory:
solAssert(false, "Unsupported array location."); m_context << eth::Instruction::MLOAD;
break; break;
} }
break; break;
@ -1004,9 +1005,14 @@ void ExpressionCompiler::appendExternalFunctionCall(
_functionType.getReturnParameterTypes().empty() ? _functionType.getReturnParameterTypes().empty() ?
nullptr : nullptr :
_functionType.getReturnParameterTypes().front().get(); _functionType.getReturnParameterTypes().front().get();
unsigned retSize = firstReturnType ? firstReturnType->getCalldataEncodedSize() : 0; unsigned retSize = 0;
if (returnSuccessCondition) if (returnSuccessCondition)
retSize = 0; // return value actually is success condition retSize = 0; // return value actually is success condition
else if (firstReturnType)
{
retSize = firstReturnType->getCalldataEncodedSize();
solAssert(retSize > 0, "Unable to return dynamic type from external call.");
}
// Evaluate arguments. // Evaluate arguments.
TypePointers argumentTypes; TypePointers argumentTypes;
@ -1123,6 +1129,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
//@todo manually update free memory pointer if we accept returning memory-stored objects //@todo manually update free memory pointer if we accept returning memory-stored objects
utils().fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
utils().loadFromMemoryDynamic(*firstReturnType, false, true, false); utils().loadFromMemoryDynamic(*firstReturnType, false, true, false);
} }
} }

40
libsolidity/Types.cpp

@ -822,7 +822,7 @@ string ArrayType::toString(bool _short) const
TypePointer ArrayType::externalType() const TypePointer ArrayType::externalType() const
{ {
if (m_arrayKind != ArrayKind::Ordinary) if (m_arrayKind != ArrayKind::Ordinary)
return shared_from_this(); return this->copyForLocation(DataLocation::CallData, true);
if (!m_baseType->externalType()) if (!m_baseType->externalType())
return TypePointer(); return TypePointer();
if (m_baseType->getCategory() == Category::Array && m_baseType->isDynamicallySized()) if (m_baseType->getCategory() == Category::Array && m_baseType->isDynamicallySized())
@ -903,7 +903,7 @@ MemberList const& ContractType::getMembers() const
for (auto const& it: m_contract.getInterfaceFunctions()) for (auto const& it: m_contract.getInterfaceFunctions())
members.push_back(MemberList::Member( members.push_back(MemberList::Member(
it.second->getDeclaration().getName(), it.second->getDeclaration().getName(),
it.second, it.second->asMemberFunction(),
&it.second->getDeclaration() &it.second->getDeclaration()
)); ));
m_members.reset(new MemberList(members)); m_members.reset(new MemberList(members));
@ -1284,6 +1284,7 @@ MemberList const& FunctionType::getMembers() const
strings(), strings(),
Location::SetValue, Location::SetValue,
false, false,
nullptr,
m_gasSet, m_gasSet,
m_valueSet m_valueSet
) )
@ -1300,6 +1301,7 @@ MemberList const& FunctionType::getMembers() const
strings(), strings(),
Location::SetGas, Location::SetGas,
false, false,
nullptr,
m_gasSet, m_gasSet,
m_valueSet m_valueSet
) )
@ -1404,11 +1406,45 @@ TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) con
m_returnParameterNames, m_returnParameterNames,
m_location, m_location,
m_arbitraryParameters, m_arbitraryParameters,
m_declaration,
m_gasSet || _setGas, m_gasSet || _setGas,
m_valueSet || _setValue m_valueSet || _setValue
); );
} }
FunctionTypePointer FunctionType::asMemberFunction() const
{
TypePointers parameterTypes;
for (auto const& t: m_parameterTypes)
{
auto refType = dynamic_cast<ReferenceType const*>(t.get());
if (refType && refType->location() == DataLocation::CallData)
parameterTypes.push_back(refType->copyForLocation(DataLocation::Memory, false));
else
parameterTypes.push_back(t);
}
//@todo make this more intelligent once we support destructuring assignments
TypePointers returnParameterTypes;
vector<string> returnParameterNames;
if (!m_returnParameterTypes.empty() && m_returnParameterTypes.front()->getCalldataEncodedSize() > 0)
{
returnParameterTypes.push_back(m_returnParameterTypes.front());
returnParameterNames.push_back(m_returnParameterNames.front());
}
return make_shared<FunctionType>(
parameterTypes,
returnParameterTypes,
m_parameterNames,
returnParameterNames,
m_location,
m_arbitraryParameters,
m_declaration,
m_gasSet,
m_valueSet
);
}
vector<string> const FunctionType::getParameterTypeNames() const vector<string> const FunctionType::getParameterTypeNames() const
{ {
vector<string> names; vector<string> names;

10
libsolidity/Types.h

@ -669,6 +669,7 @@ public:
strings _returnParameterNames = strings(), strings _returnParameterNames = strings(),
Location _location = Location::Internal, Location _location = Location::Internal,
bool _arbitraryParameters = false, bool _arbitraryParameters = false,
Declaration const* _declaration = nullptr,
bool _gasSet = false, bool _gasSet = false,
bool _valueSet = false bool _valueSet = false
): ):
@ -679,7 +680,8 @@ public:
m_location(_location), m_location(_location),
m_arbitraryParameters(_arbitraryParameters), m_arbitraryParameters(_arbitraryParameters),
m_gasSet(_gasSet), m_gasSet(_gasSet),
m_valueSet (_valueSet) m_valueSet(_valueSet),
m_declaration(_declaration)
{} {}
TypePointers const& getParameterTypes() const { return m_parameterTypes; } TypePointers const& getParameterTypes() const { return m_parameterTypes; }
@ -733,6 +735,12 @@ public:
/// of the parameters to fals. /// of the parameters to fals.
TypePointer copyAndSetGasOrValue(bool _setGas, bool _setValue) const; TypePointer copyAndSetGasOrValue(bool _setGas, bool _setValue) const;
/// @returns a copy of this function type where all return parameters of dynamic size are
/// removed and the location of reference types is changed from CallData to Memory.
/// This is needed if external functions are called on other contracts, as they cannot return
/// dynamic values.
FunctionTypePointer asMemberFunction() const;
private: private:
static TypePointers parseElementaryTypeVector(strings const& _types); static TypePointers parseElementaryTypeVector(strings const& _types);

BIN
mix/qml/img/edittransaction.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 902 B

BIN
mix/qml/img/edittransaction2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 756 B

BIN
mix/qml/img/edittransaction2@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
mix/qml/img/edittransaction@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
mix/qml/img/newblock.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

BIN
mix/qml/img/newblock@2x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

55
test/TestHelper.cpp

@ -178,7 +178,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptio
{ {
stateOptions.m_bHasBalance = true; stateOptions.m_bHasBalance = true;
if (bigint(o["balance"].get_str()) >= c_max256plus1) if (bigint(o["balance"].get_str()) >= c_max256plus1)
TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") ); BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") );
balance = toInt(o["balance"]); balance = toInt(o["balance"]);
} }
@ -186,7 +186,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptio
{ {
stateOptions.m_bHasNonce = true; stateOptions.m_bHasNonce = true;
if (bigint(o["nonce"].get_str()) >= c_max256plus1) if (bigint(o["nonce"].get_str()) >= c_max256plus1)
TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'nonce' is equal or greater than 2**256") ); BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'nonce' is equal or greater than 2**256") );
nonce = toInt(o["nonce"]); nonce = toInt(o["nonce"]);
} }
@ -230,7 +230,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state)
{ {
//check that every parameter was declared in state object //check that every parameter was declared in state object
if (!stateOptionMap.second.isAllSet()) if (!stateOptionMap.second.isAllSet())
TBOOST_THROW_EXCEPTION(MissingFields() << errinfo_comment("Import State: Missing state fields!")); BOOST_THROW_EXCEPTION(MissingFields() << errinfo_comment("Import State: Missing state fields!"));
} }
} }
@ -246,13 +246,13 @@ void ImportTest::importTransaction(json_spirit::mObject& _o)
assert(_o.count("data") > 0); assert(_o.count("data") > 0);
if (bigint(_o["nonce"].get_str()) >= c_max256plus1) if (bigint(_o["nonce"].get_str()) >= c_max256plus1)
TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'nonce' is equal or greater than 2**256") ); BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'nonce' is equal or greater than 2**256") );
if (bigint(_o["gasPrice"].get_str()) >= c_max256plus1) if (bigint(_o["gasPrice"].get_str()) >= c_max256plus1)
TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasPrice' 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["gasLimit"].get_str()) >= c_max256plus1) if (bigint(_o["gasLimit"].get_str()) >= c_max256plus1)
TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasLimit' 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["value"].get_str()) >= c_max256plus1) if (bigint(_o["value"].get_str()) >= c_max256plus1)
TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'value' is equal or greater than 2**256") ); BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'value' is equal or greater than 2**256") );
m_transaction = _o["to"].get_str().empty() ? 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())) : Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())) :
@ -349,9 +349,9 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost)
{ {
std::string warning = "Check State: Error! Unexpected output: " + m_TestObject["out"].get_str() + " Expected: " + m_TestObject["expectOut"].get_str(); std::string warning = "Check State: Error! Unexpected output: " + m_TestObject["out"].get_str() + " Expected: " + m_TestObject["expectOut"].get_str();
if (Options::get().checkState) if (Options::get().checkState)
BOOST_CHECK_MESSAGE((m_TestObject["out"].get_str() == m_TestObject["expectOut"].get_str()), warning); {TBOOST_CHECK_MESSAGE((m_TestObject["out"].get_str() == m_TestObject["expectOut"].get_str()), warning);}
else else
BOOST_WARN_MESSAGE((m_TestObject["out"].get_str() == m_TestObject["expectOut"].get_str()), warning); TBOOST_WARN_MESSAGE((m_TestObject["out"].get_str() == m_TestObject["expectOut"].get_str()), warning);
m_TestObject.erase(m_TestObject.find("expectOut")); m_TestObject.erase(m_TestObject.find("expectOut"));
} }
@ -533,24 +533,25 @@ void checkOutput(bytes const& _output, json_spirit::mObject& _o)
void checkStorage(map<u256, u256> _expectedStore, map<u256, u256> _resultStore, Address _expectedAddr) void checkStorage(map<u256, u256> _expectedStore, map<u256, u256> _resultStore, Address _expectedAddr)
{ {
_expectedAddr = _expectedAddr; //unsed parametr when macro
for (auto&& expectedStorePair : _expectedStore) for (auto&& expectedStorePair : _expectedStore)
{ {
auto& expectedStoreKey = expectedStorePair.first; auto& expectedStoreKey = expectedStorePair.first;
auto resultStoreIt = _resultStore.find(expectedStoreKey); auto resultStoreIt = _resultStore.find(expectedStoreKey);
if (resultStoreIt == _resultStore.end()) if (resultStoreIt == _resultStore.end())
BOOST_ERROR(_expectedAddr << ": missing store key " << expectedStoreKey); {TBOOST_ERROR(_expectedAddr << ": missing store key " << expectedStoreKey);}
else else
{ {
auto& expectedStoreValue = expectedStorePair.second; auto& expectedStoreValue = expectedStorePair.second;
auto& resultStoreValue = resultStoreIt->second; auto& resultStoreValue = resultStoreIt->second;
BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, _expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue); TBOOST_CHECK_MESSAGE((expectedStoreValue == resultStoreValue), _expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue);
} }
} }
BOOST_CHECK_EQUAL(_resultStore.size(), _expectedStore.size()); TBOOST_CHECK_EQUAL(_resultStore.size(), _expectedStore.size());
for (auto&& resultStorePair: _resultStore) for (auto&& resultStorePair: _resultStore)
{ {
if (!_expectedStore.count(resultStorePair.first)) if (!_expectedStore.count(resultStorePair.first))
BOOST_ERROR(_expectedAddr << ": unexpected store key " << resultStorePair.first); TBOOST_ERROR(_expectedAddr << ": unexpected store key " << resultStorePair.first);
} }
} }
@ -568,14 +569,14 @@ void checkLog(LogEntries _resultLogs, LogEntries _expectedLogs)
void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates) void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates)
{ {
BOOST_REQUIRE_EQUAL(_resultCallCreates.size(), _expectedCallCreates.size()); TBOOST_REQUIRE_EQUAL(_resultCallCreates.size(), _expectedCallCreates.size());
for (size_t i = 0; i < _resultCallCreates.size(); ++i) for (size_t i = 0; i < _resultCallCreates.size(); ++i)
{ {
BOOST_CHECK(_resultCallCreates[i].data() == _expectedCallCreates[i].data()); TBOOST_CHECK((_resultCallCreates[i].data() == _expectedCallCreates[i].data()));
BOOST_CHECK(_resultCallCreates[i].receiveAddress() == _expectedCallCreates[i].receiveAddress()); TBOOST_CHECK((_resultCallCreates[i].receiveAddress() == _expectedCallCreates[i].receiveAddress()));
BOOST_CHECK(_resultCallCreates[i].gas() == _expectedCallCreates[i].gas()); TBOOST_CHECK((_resultCallCreates[i].gas() == _expectedCallCreates[i].gas()));
BOOST_CHECK(_resultCallCreates[i].value() == _expectedCallCreates[i].value()); TBOOST_CHECK((_resultCallCreates[i].value() == _expectedCallCreates[i].value()));
} }
} }
@ -598,7 +599,7 @@ void userDefinedTest(std::function<void(json_spirit::mValue&, bool)> doTests)
cnote << "Testing user defined test: " << filename; cnote << "Testing user defined test: " << filename;
json_spirit::mValue v; json_spirit::mValue v;
string s = contentsString(filename); string s = contentsString(filename);
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); TBOOST_REQUIRE_MESSAGE((s.length() > 0), "Contents of " + filename + " is empty. ");
json_spirit::read_string(s, v); json_spirit::read_string(s, v);
json_spirit::mObject oSingleTest; json_spirit::mObject oSingleTest;
@ -616,11 +617,11 @@ void userDefinedTest(std::function<void(json_spirit::mValue&, bool)> doTests)
} }
catch (Exception const& _e) catch (Exception const& _e)
{ {
BOOST_ERROR("Failed Test with Exception: " << diagnostic_information(_e)); TBOOST_ERROR("Failed Test with Exception: " << diagnostic_information(_e));
} }
catch (std::exception const& _e) catch (std::exception const& _e)
{ {
BOOST_ERROR("Failed Test with Exception: " << _e.what()); TBOOST_ERROR("Failed Test with Exception: " << _e.what());
} }
} }
@ -640,18 +641,18 @@ void executeTests(const string& _name, const string& _testPathAppendix, const bo
json_spirit::mValue v; json_spirit::mValue v;
boost::filesystem::path p(__FILE__); boost::filesystem::path p(__FILE__);
string s = asString(dev::contents(_pathToFiller.string() + "/" + _name + "Filler.json")); string s = asString(dev::contents(_pathToFiller.string() + "/" + _name + "Filler.json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _pathToFiller.string() + "/" + _name + "Filler.json is empty."); TBOOST_REQUIRE_MESSAGE((s.length() > 0), "Contents of " + _pathToFiller.string() + "/" + _name + "Filler.json is empty.");
json_spirit::read_string(s, v); json_spirit::read_string(s, v);
doTests(v, true); doTests(v, true);
writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true)));
} }
catch (Exception const& _e) catch (Exception const& _e)
{ {
BOOST_ERROR("Failed filling test with Exception: " << diagnostic_information(_e)); TBOOST_ERROR("Failed filling test with Exception: " << diagnostic_information(_e));
} }
catch (std::exception const& _e) catch (std::exception const& _e)
{ {
BOOST_ERROR("Failed filling test with Exception: " << _e.what()); TBOOST_ERROR("Failed filling test with Exception: " << _e.what());
} }
} }
@ -660,18 +661,18 @@ void executeTests(const string& _name, const string& _testPathAppendix, const bo
std::cout << "TEST " << _name << ":\n"; std::cout << "TEST " << _name << ":\n";
json_spirit::mValue v; json_spirit::mValue v;
string s = asString(dev::contents(testPath + "/" + _name + ".json")); string s = asString(dev::contents(testPath + "/" + _name + ".json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); TBOOST_REQUIRE_MESSAGE((s.length() > 0), "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?");
json_spirit::read_string(s, v); json_spirit::read_string(s, v);
Listener::notifySuiteStarted(_name); Listener::notifySuiteStarted(_name);
doTests(v, false); doTests(v, false);
} }
catch (Exception const& _e) catch (Exception const& _e)
{ {
BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); TBOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e));
} }
catch (std::exception const& _e) catch (std::exception const& _e)
{ {
BOOST_ERROR("Failed test with Exception: " << _e.what()); TBOOST_ERROR("Failed test with Exception: " << _e.what());
} }
} }

4
test/TestHelper.h

@ -32,21 +32,21 @@
#include <libtestutils/Common.h> #include <libtestutils/Common.h>
#ifdef NOBOOST #ifdef NOBOOST
#define TBOOST_THROW_EXCEPTION(arg) throw dev::Exception();
#define TBOOST_REQUIRE(arg) if(arg == false) throw dev::Exception(); #define TBOOST_REQUIRE(arg) if(arg == false) throw dev::Exception();
#define TBOOST_REQUIRE_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception(); #define TBOOST_REQUIRE_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception();
#define TBOOST_CHECK_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception(); #define TBOOST_CHECK_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception();
#define TBOOST_CHECK(arg) if(arg == false) throw dev::Exception(); #define TBOOST_CHECK(arg) if(arg == false) throw dev::Exception();
#define TBOOST_REQUIRE_MESSAGE(arg1, arg2) if(arg1 == false) throw dev::Exception();
#define TBOOST_CHECK_MESSAGE(arg1, arg2) if(arg1 == false) throw dev::Exception(); #define TBOOST_CHECK_MESSAGE(arg1, arg2) if(arg1 == false) throw dev::Exception();
#define TBOOST_WARN_MESSAGE(arg1, arg2) throw dev::Exception(); #define TBOOST_WARN_MESSAGE(arg1, arg2) throw dev::Exception();
#define TBOOST_ERROR(arg) throw dev::Exception(); #define TBOOST_ERROR(arg) throw dev::Exception();
#else #else
#define TBOOST_THROW_EXCEPTION(arg) BOOST_THROW_EXCEPTION(arg)
#define TBOOST_REQUIRE(arg) BOOST_REQUIRE(arg) #define TBOOST_REQUIRE(arg) BOOST_REQUIRE(arg)
#define TBOOST_REQUIRE_EQUAL(arg1, arg2) BOOST_REQUIRE_EQUAL(arg1, arg2) #define TBOOST_REQUIRE_EQUAL(arg1, arg2) BOOST_REQUIRE_EQUAL(arg1, arg2)
#define TBOOST_CHECK(arg) BOOST_CHECK(arg) #define TBOOST_CHECK(arg) BOOST_CHECK(arg)
#define TBOOST_CHECK_EQUAL(arg1, arg2) BOOST_CHECK_EQUAL(arg1, arg2) #define TBOOST_CHECK_EQUAL(arg1, arg2) BOOST_CHECK_EQUAL(arg1, arg2)
#define TBOOST_CHECK_MESSAGE(arg1, arg2) BOOST_CHECK_MESSAGE(arg1, arg2) #define TBOOST_CHECK_MESSAGE(arg1, arg2) BOOST_CHECK_MESSAGE(arg1, arg2)
#define TBOOST_REQUIRE_MESSAGE(arg1, arg2) BOOST_REQUIRE_MESSAGE(arg1, arg2)
#define TBOOST_WARN_MESSAGE(arg1, arg2) BOOST_WARN_MESSAGE(arg1, arg2) #define TBOOST_WARN_MESSAGE(arg1, arg2) BOOST_WARN_MESSAGE(arg1, arg2)
#define TBOOST_ERROR(arg) BOOST_ERROR(arg) #define TBOOST_ERROR(arg) BOOST_ERROR(arg)
#endif #endif

67
test/fuzzTesting/createRandomTest.cpp

@ -36,8 +36,8 @@ extern std::string const c_testExampleVMTest;
extern std::string const c_testExampleBlockchainTest; extern std::string const c_testExampleBlockchainTest;
//Main Test functinos //Main Test functinos
void fillRandomTest(std::function<void(json_spirit::mValue&, bool)> doTests, std::string const& testString); void fillRandomTest(std::function<void(json_spirit::mValue&, bool)> _doTests, std::string const& _testString, bool _debug = false);
int checkRandomTest(std::function<void(json_spirit::mValue&, bool)> doTests, json_spirit::mValue& value); int checkRandomTest(std::function<void(json_spirit::mValue&, bool)> _doTests, json_spirit::mValue& _value, bool _debug = false);
//Helper Functions //Helper Functions
std::vector<std::string> getTypes(); std::vector<std::string> getTypes();
@ -46,8 +46,12 @@ void parseTestWithTypes(std::string& test);
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
std::string testSuite; std::string testSuite;
std::string testFillString;
json_spirit::mValue testmValue; json_spirit::mValue testmValue;
bool checktest = false; bool checktest = false;
bool filldebug = false;
bool debug = false;
bool filltest = false;
for (auto i = 0; i < argc; ++i) for (auto i = 0; i < argc; ++i)
{ {
auto arg = std::string{argv[i]}; auto arg = std::string{argv[i]};
@ -62,7 +66,7 @@ int main(int argc, char *argv[])
testSuite = ""; testSuite = "";
} }
else else
if (arg == "-checktest" && i + 1 < argc) if ((arg == "-checktest" || arg == "-filltest") && i + 1 < argc)
{ {
std::string s; std::string s;
for (int j = i+1; j < argc; ++j) for (int j = i+1; j < argc; ++j)
@ -72,10 +76,24 @@ int main(int argc, char *argv[])
std::cout << "Error! Content of argument is empty! (Usage -checktest textstream) \n"; std::cout << "Error! Content of argument is empty! (Usage -checktest textstream) \n";
return 1; return 1;
} }
if (arg == "-filltest")
{
testFillString = s;
filltest = true;
}
else
{
read_string(s, testmValue); read_string(s, testmValue);
checktest = true; checktest = true;
} }
} }
else
if (arg == "--debug")
debug = true;
else
if (arg == "--filldebug")
filldebug = true;
}
if (testSuite == "") if (testSuite == "")
{ {
@ -83,28 +101,32 @@ int main(int argc, char *argv[])
return 1; return 1;
} }
else else
{
if (checktest)
std::cout << "Testing: " << testSuite.substr(0, testSuite.length() - 1) << std::endl;
if (testSuite == "BlockChainTests") if (testSuite == "BlockChainTests")
{ {
if (checktest) if (checktest)
return checkRandomTest(dev::test::doBlockchainTests, testmValue); return checkRandomTest(dev::test::doBlockchainTests, testmValue, debug);
else else
fillRandomTest(dev::test::doBlockchainTests, c_testExampleBlockchainTest); fillRandomTest(dev::test::doBlockchainTests, (filltest) ? testFillString : c_testExampleBlockchainTest, filldebug);
} }
else else
if (testSuite == "TransactionTests") if (testSuite == "TransactionTests")
{ {
if (checktest) if (checktest)
return checkRandomTest(dev::test::doTransactionTests, testmValue); return checkRandomTest(dev::test::doTransactionTests, testmValue, debug);
else else
fillRandomTest(dev::test::doTransactionTests, c_testExampleTransactionTest); fillRandomTest(dev::test::doTransactionTests, (filltest) ? testFillString : c_testExampleTransactionTest, filldebug);
} }
else else
if (testSuite == "StateTests") if (testSuite == "StateTests")
{ {
if (checktest) if (checktest)
return checkRandomTest(dev::test::doStateTests, testmValue); return checkRandomTest(dev::test::doStateTests, testmValue, debug);
else else
fillRandomTest(dev::test::doStateTests, c_testExampleStateTest); fillRandomTest(dev::test::doStateTests, (filltest) ? testFillString : c_testExampleStateTest, filldebug);
} }
else else
if (testSuite == "VMTests") if (testSuite == "VMTests")
@ -112,16 +134,17 @@ int main(int argc, char *argv[])
if (checktest) if (checktest)
{ {
dev::eth::VMFactory::setKind(dev::eth::VMKind::JIT); dev::eth::VMFactory::setKind(dev::eth::VMKind::JIT);
return checkRandomTest(dev::test::doVMTests, testmValue); return checkRandomTest(dev::test::doVMTests, testmValue, debug);
} }
else else
fillRandomTest(dev::test::doVMTests, c_testExampleVMTest); fillRandomTest(dev::test::doVMTests, (filltest) ? testFillString : c_testExampleVMTest, filldebug);
}
} }
return 0; return 0;
} }
int checkRandomTest(std::function<void(json_spirit::mValue&, bool)> doTests, json_spirit::mValue& value) int checkRandomTest(std::function<void(json_spirit::mValue&, bool)> _doTests, json_spirit::mValue& _value, bool _debug)
{ {
bool ret = 0; bool ret = 0;
try try
@ -129,15 +152,21 @@ int checkRandomTest(std::function<void(json_spirit::mValue&, bool)> doTests, jso
//redirect all output to the stream //redirect all output to the stream
std::ostringstream strCout; std::ostringstream strCout;
std::streambuf* oldCoutStreamBuf = std::cout.rdbuf(); std::streambuf* oldCoutStreamBuf = std::cout.rdbuf();
if (!_debug)
{
std::cout.rdbuf( strCout.rdbuf() ); std::cout.rdbuf( strCout.rdbuf() );
std::cerr.rdbuf( strCout.rdbuf() ); std::cerr.rdbuf( strCout.rdbuf() );
}
doTests(value, false); _doTests(_value, false);
//restroe output //restroe output
if (!_debug)
{
std::cout.rdbuf(oldCoutStreamBuf); std::cout.rdbuf(oldCoutStreamBuf);
std::cerr.rdbuf(oldCoutStreamBuf); std::cerr.rdbuf(oldCoutStreamBuf);
} }
}
catch (dev::Exception const& _e) catch (dev::Exception const& _e)
{ {
std::cout << "Failed test with Exception: " << diagnostic_information(_e) << std::endl; std::cout << "Failed test with Exception: " << diagnostic_information(_e) << std::endl;
@ -151,21 +180,24 @@ int checkRandomTest(std::function<void(json_spirit::mValue&, bool)> doTests, jso
return ret; return ret;
} }
void fillRandomTest(std::function<void(json_spirit::mValue&, bool)> doTests, std::string const& testString) void fillRandomTest(std::function<void(json_spirit::mValue&, bool)> _doTests, std::string const& _testString, bool _debug)
{ {
//redirect all output to the stream //redirect all output to the stream
std::ostringstream strCout; std::ostringstream strCout;
std::streambuf* oldCoutStreamBuf = std::cout.rdbuf(); std::streambuf* oldCoutStreamBuf = std::cout.rdbuf();
if (!_debug)
{
std::cout.rdbuf( strCout.rdbuf() ); std::cout.rdbuf( strCout.rdbuf() );
std::cerr.rdbuf( strCout.rdbuf() ); std::cerr.rdbuf( strCout.rdbuf() );
}
json_spirit::mValue v; json_spirit::mValue v;
try try
{ {
std::string newTest = testString; std::string newTest = _testString;
parseTestWithTypes(newTest); parseTestWithTypes(newTest);
json_spirit::read_string(newTest, v); json_spirit::read_string(newTest, v);
doTests(v, true); _doTests(v, true);
} }
catch(...) catch(...)
{ {
@ -173,8 +205,11 @@ void fillRandomTest(std::function<void(json_spirit::mValue&, bool)> doTests, std
} }
//restroe output //restroe output
if (!_debug)
{
std::cout.rdbuf(oldCoutStreamBuf); std::cout.rdbuf(oldCoutStreamBuf);
std::cerr.rdbuf(oldCoutStreamBuf); std::cerr.rdbuf(oldCoutStreamBuf);
}
std::cout << json_spirit::write_string(v, true); std::cout << json_spirit::write_string(v, true);
} }

40
test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json

@ -1638,6 +1638,46 @@
} }
}, },
"suicideCoinbase": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "095e7baea6a6c7c4c2dfeb977efac326af552d87"
},
"expect" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1999999999999979496",
"nonce" : "1"
}
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (SUICIDE 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b) }",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "1000000",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "100000",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"suicideCaller": { "suicideCaller": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

2
test/libethereum/state.cpp

@ -80,7 +80,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin)
#if ETH_FATDB #if ETH_FATDB
importer.exportTest(output, theState); importer.exportTest(output, theState);
#else #else
TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("You can not fill tests when FATDB is switched off")); BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("You can not fill tests when FATDB is switched off"));
#endif #endif
} }
else else

4
test/libethereum/transaction.cpp

@ -50,7 +50,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
{ {
Transaction txFromFields(rlpStream.out(), CheckTransaction::Everything); Transaction txFromFields(rlpStream.out(), CheckTransaction::Everything);
if (!txFromFields.signature().isValid()) if (!txFromFields.signature().isValid())
TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") );
o["sender"] = toString(txFromFields.sender()); o["sender"] = toString(txFromFields.sender());
o["transaction"] = ImportTest::makeAllFieldsHex(tObj); o["transaction"] = ImportTest::makeAllFieldsHex(tObj);
@ -94,7 +94,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
RLP rlp(stream); RLP rlp(stream);
txFromRlp = Transaction(rlp.data(), CheckTransaction::Everything); txFromRlp = Transaction(rlp.data(), CheckTransaction::Everything);
if (!txFromRlp.signature().isValid()) if (!txFromRlp.signature().isValid())
TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") );
} }
catch(Exception const& _e) catch(Exception const& _e)
{ {

6
test/libevm/vm.cpp

@ -395,9 +395,9 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
{ {
std::string warning = "Check State: Error! Unexpected output: " + o["out"].get_str() + " Expected: " + o["expectOut"].get_str(); std::string warning = "Check State: Error! Unexpected output: " + o["out"].get_str() + " Expected: " + o["expectOut"].get_str();
if (Options::get().checkState) if (Options::get().checkState)
BOOST_CHECK_MESSAGE((o["out"].get_str() == o["expectOut"].get_str()), warning); {TBOOST_CHECK_MESSAGE((o["out"].get_str() == o["expectOut"].get_str()), warning);}
else else
BOOST_WARN_MESSAGE((o["out"].get_str() == o["expectOut"].get_str()), warning); TBOOST_WARN_MESSAGE((o["out"].get_str() == o["expectOut"].get_str()), warning);
o.erase(o.find("expectOut")); o.erase(o.find("expectOut"));
} }
@ -440,7 +440,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
checkLog(fev.sub.logs, test.sub.logs); checkLog(fev.sub.logs, test.sub.logs);
} }
else // Exception expected else // Exception expected
BOOST_CHECK(vmExceptionOccured); TBOOST_CHECK(vmExceptionOccured);
} }
} }
} }

162
test/libsolidity/SolidityEndToEndTest.cpp

@ -4355,6 +4355,168 @@ BOOST_AUTO_TEST_CASE(accessor_involving_strings)
BOOST_REQUIRE(callContractFunction("data(uint256,uint256)", x, y) == result); BOOST_REQUIRE(callContractFunction("data(uint256,uint256)", x, y) == result);
} }
BOOST_AUTO_TEST_CASE(bytes_in_function_calls)
{
char const* sourceCode = R"(
contract Main {
string public s1;
string public s2;
function set(string _s1, uint x, string _s2) returns (uint) {
s1 = _s1;
s2 = _s2;
return x;
}
function setIndirectFromMemory(string _s1, uint x, string _s2) returns (uint) {
return this.set(_s1, x, _s2);
}
function setIndirectFromCalldata(string _s1, uint x, string _s2) external returns (uint) {
return this.set(_s1, x, _s2);
}
}
)";
compileAndRun(sourceCode, 0, "Main");
string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
string s2("ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ");
vector<size_t> lengthes{0, 31, 64, 65};
for (auto l1: lengthes)
for (auto l2: lengthes)
{
bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1));
bytes dyn2 = encodeArgs(u256(l2), s2.substr(0, l2));
bytes args1 = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn1.size())) + dyn1 + dyn2;
BOOST_REQUIRE(
callContractFunction("setIndirectFromMemory(string,uint256,string)", asString(args1)) ==
encodeArgs(u256(l1))
);
BOOST_CHECK(callContractFunction("s1()") == encodeArgs(0x20) + dyn1);
BOOST_CHECK(callContractFunction("s2()") == encodeArgs(0x20) + dyn2);
// swapped
bytes args2 = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn2.size())) + dyn2 + dyn1;
BOOST_REQUIRE(
callContractFunction("setIndirectFromCalldata(string,uint256,string)", asString(args2)) ==
encodeArgs(u256(l1))
);
BOOST_CHECK(callContractFunction("s1()") == encodeArgs(0x20) + dyn2);
BOOST_CHECK(callContractFunction("s2()") == encodeArgs(0x20) + dyn1);
}
}
BOOST_AUTO_TEST_CASE(return_bytes_internal)
{
char const* sourceCode = R"(
contract Main {
bytes s1;
function doSet(bytes _s1) returns (bytes _r1) {
s1 = _s1;
_r1 = s1;
}
function set(bytes _s1) external returns (uint _r, bytes _r1) {
_r1 = doSet(_s1);
_r = _r1.length;
}
}
)";
compileAndRun(sourceCode, 0, "Main");
string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
vector<size_t> lengthes{0, 31, 64, 65};
for (auto l1: lengthes)
{
bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1));
bytes args1 = encodeArgs(u256(0x20)) + dyn1;
BOOST_REQUIRE(
callContractFunction("set(bytes)", asString(args1)) ==
encodeArgs(u256(l1), u256(0x40)) + dyn1
);
}
}
BOOST_AUTO_TEST_CASE(bytes_index_access_memory)
{
char const* sourceCode = R"(
contract Main {
function f(bytes _s1, uint i1, uint i2, uint i3) returns (byte c1, byte c2, byte c3) {
c1 = _s1[i1];
c2 = intern(_s1, i2);
c3 = internIndirect(_s1)[i3];
}
function intern(bytes _s1, uint i) returns (byte c) {
return _s1[i];
}
function internIndirect(bytes _s1) returns (bytes) {
return _s1;
}
}
)";
compileAndRun(sourceCode, 0, "Main");
string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
bytes dyn1 = encodeArgs(u256(s1.length()), s1);
bytes args1 = encodeArgs(u256(0x80), u256(3), u256(4), u256(5)) + dyn1;
BOOST_REQUIRE(
callContractFunction("f(bytes,uint256,uint256,uint256)", asString(args1)) ==
encodeArgs(string{s1[3]}, string{s1[4]}, string{s1[5]})
);
}
BOOST_AUTO_TEST_CASE(bytes_in_constructors_unpacker)
{
char const* sourceCode = R"(
contract Test {
uint public m_x;
bytes public m_s;
function Test(uint x, bytes s) {
m_x = x;
m_s = s;
}
}
)";
string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
bytes dyn1 = encodeArgs(u256(s1.length()), s1);
u256 x = 7;
bytes args1 = encodeArgs(x, u256(0x40)) + dyn1;
compileAndRun(sourceCode, 0, "Test", args1);
BOOST_REQUIRE(callContractFunction("m_x()") == encodeArgs(x));
BOOST_REQUIRE(callContractFunction("m_s()") == encodeArgs(u256(0x20)) + dyn1);
}
BOOST_AUTO_TEST_CASE(bytes_in_constructors_packer)
{
char const* sourceCode = R"(
contract Base {
uint public m_x;
bytes m_s;
function Base(uint x, bytes s) {
m_x = x;
m_s = s;
}
function part(uint i) returns (byte) {
return m_s[i];
}
}
contract Main is Base {
function Main(bytes s, uint x) Base(x, s){}//f(s)) {}
function f(bytes s) returns (bytes) {
return s;
}
}
contract Creator {
function f(uint x, bytes s) returns (uint r, byte ch) {
var c = new Main(s, x);
r = c.m_x();
ch = c.part(x);
}
}
)";
compileAndRun(sourceCode, 0, "Creator");
string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz");
bytes dyn1 = encodeArgs(u256(s1.length()), s1);
u256 x = 7;
bytes args1 = encodeArgs(x, u256(0x40)) + dyn1;
BOOST_REQUIRE(
callContractFunction("f(uint256,bytes)", asString(args1)) ==
encodeArgs(x, string{s1[unsigned(x)]})
);
}
BOOST_AUTO_TEST_CASE(storage_array_ref) BOOST_AUTO_TEST_CASE(storage_array_ref)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(

13
test/libsolidity/SolidityNameAndTypeResolution.cpp

@ -1987,6 +1987,19 @@ BOOST_AUTO_TEST_CASE(mem_array_assignment_changes_base_type)
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
} }
BOOST_AUTO_TEST_CASE(dynamic_return_types_not_possible)
{
char const* sourceCode = R"(
contract C {
function f(uint) returns (string);
function g() {
var x = this.f(2);
}
}
)";
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

Loading…
Cancel
Save