Browse Source

Merge remote-tracking branch 'upstream/develop' into evmjit

cl-refactor
Paweł Bylica 10 years ago
parent
commit
970ec93516
  1. 14
      CMakeLists.txt
  2. 2
      alethzero/CMakeLists.txt
  3. 14
      alethzero/Main.ui
  4. 230
      alethzero/MainWin.cpp
  5. 4
      cmake/EthDependencies.cmake
  6. 123
      eth/main.cpp
  7. 8
      libdevcore/Exceptions.h
  8. 2
      libdevcrypto/TrieDB.h
  9. 47
      libethcore/BlockInfo.cpp
  10. 21
      libethcore/BlockInfo.h
  11. 46
      libethcore/Exceptions.cpp
  12. 14
      libethcore/Exceptions.h
  13. 4
      libethereum/BlockChain.cpp
  14. 1
      libethereum/BlockChain.h
  15. 2
      libethereum/BlockQueue.cpp
  16. 72
      libethereum/Client.cpp
  17. 37
      libethereum/Client.h
  18. 8
      libethereum/Executive.cpp
  19. 33
      libethereum/State.cpp
  20. 31
      libethereum/State.h
  21. 10
      libevmcore/Assembly.cpp
  22. 11
      libevmcore/Assembly.h
  23. 253
      libsolidity/ArrayUtils.cpp
  24. 5
      libsolidity/ArrayUtils.h
  25. 45
      libsolidity/Compiler.cpp
  26. 38
      libsolidity/CompilerContext.cpp
  27. 18
      libsolidity/CompilerContext.h
  28. 8
      libsolidity/CompilerUtils.cpp
  29. 3
      libsolidity/CompilerUtils.h
  30. 38
      libsolidity/ExpressionCompiler.cpp
  31. 1
      libsolidity/LValue.cpp
  32. 5
      libsolidity/Types.cpp
  33. 14
      libsolidity/Types.h
  34. 2
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  35. 89
      mix/ClientModel.cpp
  36. 2
      mix/ClientModel.h
  37. 111
      mix/CodeModel.cpp
  38. 31
      mix/CodeModel.h
  39. 7
      mix/DebuggingStateWrapper.cpp
  40. 45
      mix/DebuggingStateWrapper.h
  41. 2
      mix/MixClient.cpp
  42. 74
      mix/qml/CallStack.qml
  43. 193
      mix/qml/Debugger.qml
  44. 4
      mix/qml/StatusPane.qml
  45. 69
      mix/qml/StorageView.qml
  46. 31
      mix/qml/js/Debugger.js
  47. 2
      mix/res.qrc
  48. 169
      rlp/main.cpp
  49. 12
      test/SolidityABIJSON.cpp
  50. 99
      test/SolidityEndToEndTest.cpp
  51. 10
      test/SolidityExpressionCompiler.cpp
  52. 6
      test/SolidityInterface.cpp
  53. 119
      test/SolidityNameAndTypeResolution.cpp
  54. 12
      test/SolidityNatspecJSON.cpp
  55. 146
      test/SolidityParser.cpp
  56. 53
      test/TestHelper.h
  57. 13
      test/blockchain.cpp
  58. 2
      test/dagger.cpp
  59. 16
      test/solidityExecutionFramework.h
  60. 176
      test/stTransactionTestFiller.json
  61. 196
      test/vmArithmeticTestFiller.json

14
CMakeLists.txt

@ -120,8 +120,12 @@ cmake_policy(SET CMP0015 NEW)
createDefaultCacheConfig()
configureProject()
# Force chromium.
set (ETH_HAVE_WEBENGINE 1)
message(STATUS "CMAKE_VERSION: ${CMAKE_VERSION}")
message("-- VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}; JSONRPC: ${JSONRPC}; EVMJIT: ${EVMJIT}; FATDB: ${FATDB}")
message("-- VMTRACE: ${VMTRACE}; PARANOIA: ${PARANOIA}; HEADLESS: ${HEADLESS}; JSONRPC: ${JSONRPC}; EVMJIT: ${EVMJIT}; FATDB: ${FATDB}; CHROMIUM: ${ETH_HAVE_WEBENGINE}")
# Default TARGET_PLATFORM to "linux".
@ -200,8 +204,12 @@ if (NOT JUSTTESTS)
add_subdirectory(libnatspec)
add_subdirectory(libjsqrc)
add_subdirectory(alethzero)
add_subdirectory(third)
if (ETH_HAVE_WEBENGINE)
add_subdirectory(alethzero)
# add_subdirectory(third) // reenable once not qtwebkit.
endif()
add_subdirectory(mix)
endif()

2
alethzero/CMakeLists.txt

@ -41,8 +41,6 @@ add_dependencies(${EXECUTABLE} BuildInfo.h)
target_link_libraries(${EXECUTABLE} Qt5::Core)
target_link_libraries(${EXECUTABLE} Qt5::Widgets)
target_link_libraries(${EXECUTABLE} Qt5::WebKit)
target_link_libraries(${EXECUTABLE} Qt5::WebKitWidgets)
target_link_libraries(${EXECUTABLE} Qt5::WebEngine)
target_link_libraries(${EXECUTABLE} Qt5::WebEngineWidgets)
target_link_libraries(${EXECUTABLE} webthree)

14
alethzero/Main.ui

@ -807,13 +807,7 @@
<number>0</number>
</property>
<item>
<widget class="QWebView" name="jsConsole">
<property name="url">
<url>
<string>about:blank</string>
</url>
</property>
</widget>
<widget class="QWebEngineView" name="jsConsole" native="true"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
@ -1668,11 +1662,6 @@ font-size: 14pt</string>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>QWebView</class>
<extends>QWidget</extends>
<header>QtWebKitWidgets/QWebView</header>
</customwidget>
<customwidget>
<class>MiningView</class>
<extends>QWidget</extends>
@ -1702,7 +1691,6 @@ font-size: 14pt</string>
<tabstop>log</tabstop>
<tabstop>post</tabstop>
<tabstop>verbosity</tabstop>
<tabstop>jsConsole</tabstop>
<tabstop>tabWidget</tabstop>
<tabstop>urlEdit</tabstop>
<tabstop>idealPeers</tabstop>

230
alethzero/MainWin.cpp

@ -26,6 +26,7 @@
#include <boost/asio.hpp>
#pragma GCC diagnostic ignored "-Wpedantic"
//pragma GCC diagnostic ignored "-Werror=pedantic"
#include <QtNetwork/QNetworkReply>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QMessageBox>
@ -120,7 +121,6 @@ Main::Main(QWidget *parent) :
QtWebEngine::initialize();
setWindowFlags(Qt::Window);
ui->setupUi(this);
QtWebEngine::initialize();
g_logPost = [=](string const& s, char const* c)
{
simpleDebugOut(s, c);
@ -372,28 +372,6 @@ void Main::load(QString _s)
{
QString contents = QString::fromStdString(dev::asString(dev::contents(_s.toStdString())));
ui->webView->page()->runJavaScript(contents);
/*
QFile fin(_s);
if (!fin.open(QFile::ReadOnly))
return;
QString line;
while (!fin.atEnd())
{
QString l = QString::fromUtf8(fin.readLine());
line.append(l);
if (line.count('"') % 2)
{
line.chop(1);
}
else if (line.endsWith("\\\n"))
line.chop(2);
else
{
ui->webView->page()->currentFrame()->evaluateJavaScript(line);
//eval(line);
line.clear();
}
}*/
}
void Main::on_newTransaction_triggered()
@ -472,37 +450,17 @@ static Public stringToPublic(QString const& _a)
return Public();
}
//static Address g_newNameReg;
QString Main::pretty(dev::Address _a) const
{
/* static map<Address, QString> s_memos;
if (!s_memos.count(_a))
{*/
// if (!g_newNameReg)
auto g_newNameReg = getNameReg();
if (g_newNameReg)
{
QString s = QString::fromStdString(toString(abiOut<string32>(ethereum()->call(g_newNameReg, abiIn("nameOf(address)", _a)))));
// s_memos[_a] = s;
if (s.size())
return s;
}
/* }
else
if (s_memos[_a].size())
return s_memos[_a];*/
auto g_newNameReg = getNameReg();
if (g_newNameReg)
{
QString s = QString::fromStdString(toString(abiOut<string32>(ethereum()->call(g_newNameReg, abiIn("nameOf(address)", _a)))));
if (s.size())
return s;
}
h256 n;
/*
if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
n = ethereum()->stateAt(nameReg, (u160)(_a));
if (!n)
n = ethereum()->stateAt(m_nameReg, (u160)(_a));
*/
return fromRaw(n);
}
@ -527,41 +485,13 @@ Address Main::fromString(QString const& _n) const
if (_n == "(Create Contract)")
return Address();
/* static map<QString, Address> s_memos;
if (!s_memos.count(_n))
{*/
// if (!g_newNameReg)
auto g_newNameReg = getNameReg();
if (g_newNameReg)
{
Address a = abiOut<Address>(ethereum()->call(g_newNameReg, abiIn("addressOf(string32)", ::fromString(_n.toStdString()))));
// s_memos[_n] = a;
if (a)
return a;
}
/* }
else
if (s_memos[_n])
return s_memos[_n];
string sn = _n.toStdString();
if (sn.size() > 32)
sn.resize(32);
h256 n;
memcpy(n.data(), sn.data(), sn.size());
memset(n.data() + sn.size(), 0, 32 - sn.size());
if (_n.size())
auto g_newNameReg = getNameReg();
if (g_newNameReg)
{
if (h160 nameReg = (u160)ethereum()->stateAt(c_config, 0))
if (h256 a = ethereum()->stateAt(nameReg, n))
return right160(a);
if (h256 a = ethereum()->stateAt(m_nameReg, n))
return right160(a);
}*/
Address a = abiOut<Address>(ethereum()->call(g_newNameReg, abiIn("addressOf(string32)", ::fromString(_n.toStdString()))));
if (a)
return a;
}
if (_n.size() == 40)
{
try
@ -595,13 +525,6 @@ QString Main::lookup(QString const& _a) const
h256 n;
memcpy(n.data(), sn.data(), sn.size());
/* string sn2 = _a.toStdString();
if (sn2.size() > 32)
sn2 = sha3(sn2, false);
h256 n2;
memcpy(n2.data(), sn2.data(), sn2.size());
*/
h256 ret;
// TODO: fix with the new DNSreg contract
// if (h160 dnsReg = (u160)ethereum()->stateAt(c_config, 4, 0))
@ -1038,31 +961,6 @@ void Main::refreshBlockCount()
ui->blockCount->setText(QString("%6 #%1 @%3 T%2 PV%4 D%5").arg(d.number).arg(toLog2(d.totalDifficulty)).arg(toLog2(diff)).arg(c_protocolVersion).arg(c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet"));
}
static bool blockMatch(string const& _f, BlockDetails const& _b, h256 _h, CanonBlockChain const& _bc)
{
try
{
if (_f.size() > 1 && _f.size() < 10 && _f[0] == '#' && stoul(_f.substr(1)) == _b.number)
return true;
}
catch (...) {}
if (toHex(_h.ref()).find(_f) != string::npos)
return true;
BlockInfo bi(_bc.block(_h));
string info = toHex(bi.stateRoot.ref()) + " " + toHex(bi.coinbaseAddress.ref()) + " " + toHex(bi.transactionsRoot.ref()) + " " + toHex(bi.sha3Uncles.ref());
if (info.find(_f) != string::npos)
return true;
return false;
}
static bool transactionMatch(string const& _f, Transaction const& _t)
{
string info = toHex(_t.receiveAddress().ref()) + " " + toHex(_t.sha3().ref()) + " " + toHex(_t.sha3(eth::WithoutSignature).ref()) + " " + toHex(_t.sender().ref());
if (info.find(_f) != string::npos)
return true;
return false;
}
void Main::on_turboMining_triggered()
{
ethereum()->setTurboMining(ui->turboMining->isChecked());
@ -1072,55 +970,81 @@ void Main::refreshBlockChain()
{
cwatch << "refreshBlockChain()";
QByteArray oldSelected = ui->blocks->count() ? ui->blocks->currentItem()->data(Qt::UserRole).toByteArray() : QByteArray();
ui->blocks->clear();
// TODO: keep the same thing highlighted.
// TODO: refactor into MVC
// TODO: use get by hash/number
// TODO: transactions, log addresses, log topics
string filter = ui->blockChainFilter->text().toLower().toStdString();
auto const& bc = ethereum()->blockChain();
unsigned i = (ui->showAll->isChecked() || !filter.empty()) ? (unsigned)-1 : 10;
for (auto h = bc.currentHash(); bc.details(h) && i; h = bc.details(h).parent, --i)
{
auto d = bc.details(h);
auto bm = blockMatch(filter, d, h, bc);
if (bm)
QStringList filters = ui->blockChainFilter->text().toLower().split(QRegExp("\\s+"), QString::SkipEmptyParts);
h256Set blocks;
for (QString f: filters)
if (f.size() == 64)
{
QListWidgetItem* blockItem = new QListWidgetItem(QString("#%1 %2").arg(d.number).arg(h.abridged().c_str()), ui->blocks);
auto hba = QByteArray((char const*)h.data(), h.size);
blockItem->setData(Qt::UserRole, hba);
if (oldSelected == hba)
blockItem->setSelected(true);
h256 h(f.toStdString());
if (bc.isKnown(h))
blocks.insert(h);
}
else if (f.toLongLong() <= bc.number())
blocks.insert(bc.numberHash(u256(f.toLongLong())));
/*else if (f.size() == 40)
{
Address h(f[0]);
if (bc.(h))
blocks.insert(h);
}*/
QByteArray oldSelected = ui->blocks->count() ? ui->blocks->currentItem()->data(Qt::UserRole).toByteArray() : QByteArray();
ui->blocks->clear();
auto showBlock = [&](h256 const& h) {
auto d = bc.details(h);
QListWidgetItem* blockItem = new QListWidgetItem(QString("#%1 %2").arg(d.number).arg(h.abridged().c_str()), ui->blocks);
auto hba = QByteArray((char const*)h.data(), h.size);
blockItem->setData(Qt::UserRole, hba);
if (oldSelected == hba)
blockItem->setSelected(true);
int n = 0;
auto b = bc.block(h);
for (auto const& i: RLP(b)[1])
{
Transaction t(i.data(), CheckSignature::Sender);
if (bm || transactionMatch(filter, t))
{
QString s = t.receiveAddress() ?
QString(" %2 %5> %3: %1 [%4]")
.arg(formatBalance(t.value()).c_str())
.arg(render(t.safeSender()))
.arg(render(t.receiveAddress()))
.arg((unsigned)t.nonce())
.arg(ethereum()->codeAt(t.receiveAddress()).size() ? '*' : '-') :
QString(" %2 +> %3: %1 [%4]")
.arg(formatBalance(t.value()).c_str())
.arg(render(t.safeSender()))
.arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce())))))
.arg((unsigned)t.nonce());
QListWidgetItem* txItem = new QListWidgetItem(s, ui->blocks);
auto hba = QByteArray((char const*)h.data(), h.size);
txItem->setData(Qt::UserRole, hba);
txItem->setData(Qt::UserRole + 1, n);
if (oldSelected == hba)
txItem->setSelected(true);
}
QString s = t.receiveAddress() ?
QString(" %2 %5> %3: %1 [%4]")
.arg(formatBalance(t.value()).c_str())
.arg(render(t.safeSender()))
.arg(render(t.receiveAddress()))
.arg((unsigned)t.nonce())
.arg(ethereum()->codeAt(t.receiveAddress()).size() ? '*' : '-') :
QString(" %2 +> %3: %1 [%4]")
.arg(formatBalance(t.value()).c_str())
.arg(render(t.safeSender()))
.arg(render(right160(sha3(rlpList(t.safeSender(), t.nonce())))))
.arg((unsigned)t.nonce());
QListWidgetItem* txItem = new QListWidgetItem(s, ui->blocks);
auto hba = QByteArray((char const*)h.data(), h.size);
txItem->setData(Qt::UserRole, hba);
txItem->setData(Qt::UserRole + 1, n);
if (oldSelected == hba)
txItem->setSelected(true);
n++;
}
if (h == bc.genesisHash())
break;
};
if (filters.empty())
{
unsigned i = ui->showAll->isChecked() ? (unsigned)-1 : 10;
for (auto h = bc.currentHash(); bc.details(h) && i; h = bc.details(h).parent, --i)
{
showBlock(h);
if (h == bc.genesisHash())
break;
}
}
else
for (auto const& h: blocks)
showBlock(h);
if (!ui->blocks->currentItem())
ui->blocks->setCurrentRow(0);

4
cmake/EthDependencies.cmake

@ -120,8 +120,8 @@ if (NOT HEADLESS)
find_package (Qt5Qml REQUIRED)
find_package (Qt5Network REQUIRED)
find_package (Qt5Widgets REQUIRED)
find_package (Qt5WebKit REQUIRED)
find_package (Qt5WebKitWidgets REQUIRED)
find_package (Qt5WebEngine REQUIRED)
find_package (Qt5WebEngineWidgets REQUIRED)
# we need to find path to macdeployqt on mac
if (APPLE)

123
eth/main.cpp

@ -74,6 +74,9 @@ void interactiveHelp()
<< " jsonstop Stops the JSON-RPC server." << endl
<< " connect <addr> <port> Connects to a specific peer." << endl
<< " verbosity (<level>) Gets or sets verbosity level." << endl
<< " setetherprice <p> Resets the ether price." << endl
<< " setpriority <p> Resets the transaction priority." << endl
<< " minestart Starts mining." << endl
<< " minestart Starts mining." << endl
<< " minestop Stops mining." << endl
<< " mineforce <enable> Forces mining, even when there are no transactions." << endl
@ -85,12 +88,12 @@ void interactiveHelp()
<< " send Execute a given transaction with current secret." << endl
<< " contract Create a new contract with current secret." << endl
<< " peers List the peers that are connected" << endl
<< " listAccounts List the accounts on the network." << endl
<< " listContracts List the contracts on the network." << endl
<< " setSecret <secret> Set the secret to the hex secret key." <<endl
<< " setAddress <addr> Set the coinbase (mining payout) address." <<endl
<< " exportConfig <path> Export the config (.RLP) to the path provided." <<endl
<< " importConfig <path> Import the config (.RLP) from the path provided." <<endl
<< " listaccounts List the accounts on the network." << endl
<< " listcontracts List the contracts on the network." << endl
<< " setsecret <secret> Set the secret to the hex secret key." <<endl
<< " setaddress <addr> Set the coinbase (mining payout) address." <<endl
<< " exportconfig <path> Export the config (.RLP) to the path provided." <<endl
<< " importconfig <path> Import the config (.RLP) from the path provided." <<endl
<< " inspect <contract> Dumps a contract to <APPDATA>/<contract>.evm." << endl
<< " dumptrace <block> <index> <filename> <format> Dumps a transaction trace" << endl << "to <filename>. <format> should be one of pretty, standard, standard+." << endl
<< " dumpreceipt <block> <index> Dumps a transation receipt." << endl
@ -104,9 +107,11 @@ void help()
<< "Options:" << endl
<< " -a,--address <addr> Set the coinbase (mining payout) address to addr (default: auto)." << endl
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (Default: 15)." << endl
<< " -c,--client-name <name> Add a name to your client's version string (default: blank)." << endl
<< " -d,--db-path <path> Load database from path (default: ~/.ethereum " << endl
<< " <APPDATA>/Etherum or Library/Application Support/Ethereum)." << endl
<< " -e,--ether-price <n> Set the ether price in the reference unit e.g. ¢ (Default: 30.679)." << endl
<< " -f,--force-mining Mine even when there are no transaction to mine (Default: off)" << endl
<< " -h,--help Show this help message and exit." << endl
<< " -i,--interactive Enter interactive mode (default: non-interactive)." << endl
@ -115,11 +120,12 @@ void help()
<< " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: 8080)." << endl
#endif
<< " -l,--listen <port> Listen on the given port for incoming connected (default: 30303)." << endl
<< " -L,--local-networking Use peers whose addresses are local." << endl
<< " -m,--mining <on/off/number> Enable mining, optionally for a specified number of blocks (Default: off)" << endl
<< " -n,--upnp <on/off> Use upnp for NAT (default: on)." << endl
<< " -L,--local-networking Use peers whose addresses are local." << endl
<< " -o,--mode <full/peer> Start a full node or a peer node (Default: full)." << endl
<< " -p,--port <port> Connect to remote port (default: 30303)." << endl
<< " -P,--priority <0 - 100> Default % priority of a transaction (default: 50)." << endl
<< " -r,--remote <host> Connect to remote host (default: none)." << endl
<< " -s,--secret <secretkeyhex> Set the secret key for use with send command (default: auto)." << endl
<< " -t,--miners <number> Number of mining threads to start (Default: " << thread::hardware_concurrency() << ")" << endl
@ -128,7 +134,7 @@ void help()
<< " -x,--peers <number> Attempt to connect to given number of peers (Default: 5)." << endl
<< " -V,--version Show the version and exit." << endl
#if ETH_EVMJIT
<< " --jit Use EVM JIT (default: off)." << endl
<< " --jit Use EVM JIT (default: off)." << endl
#endif
;
exit(0);
@ -212,6 +218,9 @@ int main(int argc, char** argv)
bool structuredLogging = false;
string structuredLoggingFormat = "%Y-%m-%dT%H:%M:%S";
string clientName;
TransactionPriority priority = TransactionPriority::Medium;
double etherPrice = 30.679;
double blockFees = 15.0;
// Init defaults
Defaults::get();
@ -289,6 +298,48 @@ int main(int argc, char** argv)
structuredLogging = true;
else if ((arg == "-d" || arg == "--path" || arg == "--db-path") && i + 1 < argc)
dbPath = argv[++i];
else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc)
{
try {
blockFees = stof(argv[++i]);
}
catch (...) {
cerr << "Bad " << arg << " option: " << argv[++i] << endl;
return -1;
}
}
else if ((arg == "-e" || arg == "--ether-price") && i + 1 < argc)
{
try {
etherPrice = stof(argv[++i]);
}
catch (...) {
cerr << "Bad " << arg << " option: " << argv[++i] << endl;
return -1;
}
}
else if ((arg == "-P" || arg == "--priority") && i + 1 < argc)
{
string m = boost::to_lower_copy(string(argv[++i]));
if (m == "lowest")
priority = TransactionPriority::Lowest;
else if (m == "low")
priority = TransactionPriority::Low;
else if (m == "medium" || m == "mid" || m == "default" || m == "normal")
priority = TransactionPriority::Medium;
else if (m == "high")
priority = TransactionPriority::High;
else if (m == "highest")
priority = TransactionPriority::Highest;
else
try {
priority = (TransactionPriority)(max(0, min(100, stoi(m))) * 8 / 100);
}
catch (...) {
cerr << "Unknown " << arg << " option: " << m << endl;
return -1;
}
}
else if ((arg == "-m" || arg == "--mining") && i + 1 < argc)
{
string m = argv[++i];
@ -301,7 +352,7 @@ int main(int argc, char** argv)
mining = stoi(m);
}
catch (...) {
cerr << "Unknown -m/--mining option: " << m << endl;
cerr << "Unknown " << arg << " option: " << m << endl;
return -1;
}
}
@ -373,10 +424,12 @@ int main(int argc, char** argv)
miners
);
web3.setIdealPeerCount(peers);
std::shared_ptr<eth::BasicGasPricer> gasPricer = make_shared<eth::BasicGasPricer>(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000));
eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr;
StructuredLogger::starting(clientImplString, dev::Version);
if (c)
{
c->setGasPricer(gasPricer);
c->setForceMining(forceMining);
c->setAddress(coinbase);
}
@ -435,6 +488,7 @@ int main(int argc, char** argv)
istringstream iss(l);
string cmd;
iss >> cmd;
boost::to_lower(cmd);
if (cmd == "netstart")
{
iss >> netPrefs.listenPort;
@ -466,6 +520,42 @@ int main(int argc, char** argv)
iss >> enable;
c->setForceMining(isTrue(enable));
}
else if (c && cmd == "setblockfees")
{
iss >> blockFees;
gasPricer->setRefBlockFees(u256(blockFees * 1000));
cout << "Block fees: " << blockFees << endl;
}
else if (c && cmd == "setetherprice")
{
iss >> etherPrice;
gasPricer->setRefPrice(u256(double(ether / 1000) / etherPrice));
cout << "ether Price: " << etherPrice << endl;
}
else if (c && cmd == "setpriority")
{
string m;
iss >> m;
boost::to_lower(m);
if (m == "lowest")
priority = TransactionPriority::Lowest;
else if (m == "low")
priority = TransactionPriority::Low;
else if (m == "medium" || m == "mid" || m == "default" || m == "normal")
priority = TransactionPriority::Medium;
else if (m == "high")
priority = TransactionPriority::High;
else if (m == "highest")
priority = TransactionPriority::Highest;
else
try {
priority = (TransactionPriority)(max(0, min(100, stoi(m))) * 8 / 100);
}
catch (...) {
cerr << "Unknown priority: " << m << endl;
}
cout << "Priority: " << (int)priority << "/8" << endl;
}
else if (cmd == "verbosity")
{
if (iss.peek() != -1)
@ -536,6 +626,9 @@ int main(int argc, char** argv)
iss >> hexAddr >> amount >> gasPrice >> gas >> sechex >> sdata;
if (!gasPrice)
gasPrice = gasPricer->bid(priority);
cnote << "Data:";
cnote << sdata;
bytes data = dev::eth::parseData(sdata);
@ -582,7 +675,7 @@ int main(int argc, char** argv)
else
cwarn << "Require parameters: transact ADDRESS AMOUNT GASPRICE GAS SECRET DATA";
}
else if (c && cmd == "listContracts")
else if (c && cmd == "listcontracts")
{
auto acs =c->addresses();
string ss;
@ -593,7 +686,7 @@ int main(int argc, char** argv)
cout << ss << endl;
}
}
else if (c && cmd == "listAccounts")
else if (c && cmd == "listaccounts")
{
auto acs =c->addresses();
string ss;
@ -809,7 +902,7 @@ int main(int argc, char** argv)
}
}
}
else if (cmd == "setSecret")
else if (cmd == "setsecret")
{
if (iss.peek() != -1)
{
@ -820,7 +913,7 @@ int main(int argc, char** argv)
else
cwarn << "Require parameter: setSecret HEXSECRETKEY";
}
else if (cmd == "setAddress")
else if (cmd == "setaddress")
{
if (iss.peek() != -1)
{
@ -848,7 +941,7 @@ int main(int argc, char** argv)
else
cwarn << "Require parameter: setAddress HEXADDRESS";
}
else if (cmd == "exportConfig")
else if (cmd == "exportconfig")
{
if (iss.peek() != -1)
{
@ -861,7 +954,7 @@ int main(int argc, char** argv)
else
cwarn << "Require parameter: exportConfig PATH";
}
else if (cmd == "importConfig")
else if (cmd == "importconfig")
{
if (iss.peek() != -1)
{

8
libdevcore/Exceptions.h

@ -33,8 +33,8 @@ namespace dev
// base class for all exceptions
struct Exception: virtual std::exception, virtual boost::exception
{
Exception(std::string _message = {}) : m_message(std::move(_message)) {}
const char* what() const noexcept override { return m_message.c_str(); }
Exception(std::string _message = {}): m_message(std::move(_message)) {}
const char* what() const noexcept override { return m_message.empty() ? std::exception::what() : m_message.c_str(); }
private:
std::string m_message;
@ -57,5 +57,9 @@ using errinfo_wrongAddress = boost::error_info<struct tag_address, std::string>;
using errinfo_comment = boost::error_info<struct tag_comment, std::string>;
using errinfo_required = boost::error_info<struct tag_required, bigint>;
using errinfo_got = boost::error_info<struct tag_got, bigint>;
using errinfo_min = boost::error_info<struct tag_min, bigint>;
using errinfo_max = boost::error_info<struct tag_max, bigint>;
using RequirementError = boost::tuple<errinfo_required, errinfo_got>;
using errinfo_hash256 = boost::error_info<struct tag_hash, h256>;
using HashMismatchError = boost::tuple<errinfo_hash256, errinfo_hash256>;
}

2
libdevcrypto/TrieDB.h

@ -417,7 +417,7 @@ public:
void insert(bytesConstRef _key, bytesConstRef _value) { Super::insert(_key, _value); m_secure.insert(_key, _value); syncRoot(); }
void remove(bytesConstRef _key) { Super::remove(_key); m_secure.remove(_key); syncRoot(); }
std::set<h256> leftOvers(std::ostream* = nullptr) const { return {}; }
std::set<h256> leftOvers(std::ostream* = nullptr) const { return std::set<h256>{}; }
bool check(bool) const { return m_secure.check(false) && Super::check(false); }
private:

47
libethcore/BlockInfo.cpp

@ -35,9 +35,9 @@ BlockInfo::BlockInfo(): timestamp(Invalid256)
{
}
BlockInfo::BlockInfo(bytesConstRef _block, bool _checkNonce)
BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s)
{
populate(_block, _checkNonce);
populate(_block, _s);
}
void BlockInfo::setEmpty()
@ -61,10 +61,10 @@ void BlockInfo::setEmpty()
hash = headerHash(WithNonce);
}
BlockInfo BlockInfo::fromHeader(bytesConstRef _block)
BlockInfo BlockInfo::fromHeader(bytesConstRef _block, Strictness _s)
{
BlockInfo ret;
ret.populateFromHeader(RLP(_block));
ret.populateFromHeader(RLP(_block), _s);
return ret;
}
@ -89,7 +89,7 @@ h256 BlockInfo::headerHash(bytesConstRef _block)
return sha3(RLP(_block)[0].data());
}
void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce)
void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s)
{
hash = dev::sha3(_header.data());
@ -121,35 +121,38 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce)
}
// check it hashes according to proof of work or that it's the genesis block.
if (_checkNonce && parentHash && !ProofOfWork::verify(*this))
BOOST_THROW_EXCEPTION(InvalidBlockNonce(headerHash(WithoutNonce), nonce, difficulty));
if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this))
BOOST_THROW_EXCEPTION(InvalidBlockNonce() << errinfo_hash256(headerHash(WithoutNonce)) << errinfo_nonce(nonce) << errinfo_difficulty(difficulty));
if (gasUsed > gasLimit)
BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) );
if (_s != CheckNothing)
{
if (gasUsed > gasLimit)
BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) );
if (difficulty < c_minimumDifficulty)
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) );
if (difficulty < c_minimumDifficulty)
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) );
if (gasLimit < c_minGasLimit)
BOOST_THROW_EXCEPTION(InvalidGasLimit(gasLimit, c_minGasLimit, c_minGasLimit) << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) );
if (gasLimit < c_minGasLimit)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) );
if (number && extraData.size() > c_maximumExtraDataSize)
BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size())));
if (number && extraData.size() > c_maximumExtraDataSize)
BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size())));
}
}
void BlockInfo::populate(bytesConstRef _block, bool _checkNonce)
void BlockInfo::populate(bytesConstRef _block, Strictness _s)
{
RLP root(_block);
RLP header = root[0];
if (!header.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat(0, header.data()) << errinfo_comment("block header needs to be a list"));
populateFromHeader(header, _checkNonce);
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString()));
populateFromHeader(header, _s);
if (!root[1].isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat(1, root[1].data()));
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString()));
if (!root[2].isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat(2, root[2].data()));
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString()));
}
void BlockInfo::verifyInternals(bytesConstRef _block) const
@ -171,7 +174,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
++i;
}
if (transactionsRoot != t.root())
BOOST_THROW_EXCEPTION(InvalidTransactionsHash(t.root(), transactionsRoot));
BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(t.root(), transactionsRoot));
if (sha3Uncles != sha3(root[2].data()))
BOOST_THROW_EXCEPTION(InvalidUnclesHash());
@ -217,7 +220,7 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const
if (gasLimit < _parent.gasLimit * (c_gasLimitBoundDivisor - 1) / c_gasLimitBoundDivisor ||
gasLimit > _parent.gasLimit * (c_gasLimitBoundDivisor + 1) / c_gasLimitBoundDivisor)
BOOST_THROW_EXCEPTION(InvalidGasLimit(gasLimit, _parent.gasLimit * (c_gasLimitBoundDivisor - 1) / c_gasLimitBoundDivisor, _parent.gasLimit * (c_gasLimitBoundDivisor + 1) / c_gasLimitBoundDivisor));
BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit * (c_gasLimitBoundDivisor - 1) / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit * (c_gasLimitBoundDivisor + 1) / c_gasLimitBoundDivisor));
if (seedHash != calculateSeedHash(_parent))
BOOST_THROW_EXCEPTION(InvalidSeedHash());

21
libethcore/BlockInfo.h

@ -36,6 +36,13 @@ enum IncludeNonce
WithNonce = 1
};
enum Strictness
{
CheckEverything,
IgnoreNonce,
CheckNothing
};
/** @brief Encapsulation of a block header.
* Class to contain all of a block header's data. It is able to parse a block header and populate
* from some given RLP block serialisation with the static fromHeader(), through the method
@ -79,14 +86,14 @@ public:
Nonce nonce;
BlockInfo();
explicit BlockInfo(bytes const& _block): BlockInfo(&_block) {}
explicit BlockInfo(bytesConstRef _block, bool _checkNonce = true);
explicit BlockInfo(bytes const& _block, Strictness _s = CheckEverything): BlockInfo(&_block, _s) {}
explicit BlockInfo(bytesConstRef _block, Strictness _s = CheckEverything);
static h256 headerHash(bytes const& _block) { return headerHash(&_block); }
static h256 headerHash(bytesConstRef _block);
static BlockInfo fromHeader(bytes const& _block) { return fromHeader(bytesConstRef(&_block)); }
static BlockInfo fromHeader(bytesConstRef _block);
static BlockInfo fromHeader(bytes const& _block, Strictness _s = CheckEverything) { return fromHeader(bytesConstRef(&_block), _s); }
static BlockInfo fromHeader(bytesConstRef _block, Strictness _s = CheckEverything);
explicit operator bool() const { return timestamp != Invalid256; }
@ -113,9 +120,9 @@ public:
void setEmpty();
void populateFromHeader(RLP const& _header, bool _checkNonce = true);
void populate(bytesConstRef _block, bool _checkNonce = true);
void populate(bytes const& _block, bool _checkNonce = true) { populate(&_block, _checkNonce); }
void populateFromHeader(RLP const& _header, Strictness _s = CheckEverything);
void populate(bytesConstRef _block, Strictness _s = CheckEverything);
void populate(bytes const& _block, Strictness _s = CheckEverything) { populate(&_block, _s); }
void verifyInternals(bytesConstRef _block) const;
void verifyParent(BlockInfo const& _parent) const;
void populateFromParent(BlockInfo const& parent);

46
libethcore/Exceptions.cpp

@ -1,46 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Exceptions.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Exceptions.h"
#include <boost/thread.hpp>
#include <libdevcore/CommonIO.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
InvalidBlockFormat::InvalidBlockFormat(int _f, bytesConstRef _d):
Exception("Invalid block format: Bad field " + toString(_f) + " (" + toHex(_d) + ")"), f(_f), d(_d.toBytes()) {}
UncleInChain::UncleInChain(h256Set _uncles, h256 _block):
Exception("Uncle in block already mentioned: Uncles " + toString(_uncles) + " (" + _block.abridged() + ")"), uncles(_uncles), block(_block) {}
InvalidTransactionsHash::InvalidTransactionsHash(h256 _head, h256 _real):
Exception("Invalid transactions hash: header says: " + toHex(_head.ref()) + " block is:" + toHex(_real.ref())), head(_head), real(_real) {}
InvalidGasLimit::InvalidGasLimit(u256 _provided, u256 _n, u256 _x):
Exception("Invalid gas limit (provided: " + toString(provided) + " minimum:" + toString(minimum) + " max:" + toString(maximum) + ")"), provided(_provided), minimum(_n), maximum(_x) {}
InvalidNonce::InvalidNonce(u256 _required, u256 _candidate):
Exception("Invalid nonce (r: " + toString(_required) + " c:" + toString(_candidate) + ")"), required(_required), candidate(_candidate) {}
InvalidBlockNonce::InvalidBlockNonce(h256 _h, Nonce _n, u256 _d):
Exception("Invalid nonce (h: " + toString(h) + " n:" + toString(n) + " d:" + toString(d) + ")"), h(_h), n(_n), d(_d) {}

14
libethcore/Exceptions.h

@ -33,6 +33,8 @@ namespace eth
using errinfo_name = boost::error_info<struct tag_field, std::string>;
using errinfo_field = boost::error_info<struct tag_field, int>;
using errinfo_data = boost::error_info<struct tag_data, std::string>;
using errinfo_nonce = boost::error_info<struct tag_nonce, h64>;
using errinfo_difficulty = boost::error_info<struct tag_difficulty, u256>;
using BadFieldError = boost::tuple<errinfo_field, errinfo_data>;
struct DatabaseAlreadyOpen: virtual dev::Exception {};
@ -45,27 +47,27 @@ struct FeeTooSmall: virtual dev::Exception {};
struct TooMuchGasUsed: virtual dev::Exception {};
struct ExtraDataTooBig: virtual dev::Exception {};
struct InvalidSignature: virtual dev::Exception {};
class InvalidBlockFormat: virtual public dev::Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d); int f; bytes d; };
class InvalidBlockFormat: virtual public dev::Exception {};
struct InvalidUnclesHash: virtual dev::Exception {};
struct InvalidUncle: virtual dev::Exception {};
struct TooManyUncles: virtual dev::Exception {};
struct UncleTooOld: virtual dev::Exception {};
class UncleInChain: virtual public dev::Exception { public: UncleInChain(h256Set _uncles, h256 _block); h256Set uncles; h256 block; };
class UncleInChain: virtual public dev::Exception {};
struct DuplicateUncleNonce: virtual dev::Exception {};
struct InvalidStateRoot: virtual dev::Exception {};
struct InvalidGasUsed: virtual dev::Exception {};
class InvalidTransactionsHash: virtual public dev::Exception { public: InvalidTransactionsHash(h256 _head, h256 _real); h256 head; h256 real; };
class InvalidTransactionsHash: virtual public dev::Exception {};
struct InvalidTransaction: virtual dev::Exception {};
struct InvalidDifficulty: virtual dev::Exception {};
struct InvalidSeedHash: virtual dev::Exception {};
class InvalidGasLimit: virtual public dev::Exception { public: InvalidGasLimit(u256 _provided, u256 _n, u256 _x); u256 provided; u256 minimum; u256 maximum; };
class InvalidGasLimit: virtual public dev::Exception {};
struct InvalidTransactionGasUsed: virtual dev::Exception {};
struct InvalidTransactionsStateRoot: virtual dev::Exception {};
struct InvalidReceiptsStateRoot: virtual dev::Exception {};
struct InvalidTimestamp: virtual dev::Exception {};
struct InvalidLogBloom: virtual dev::Exception {};
class InvalidNonce: virtual public dev::Exception { public: InvalidNonce(u256 _required, u256 _candidate); u256 required; u256 candidate; };
class InvalidBlockNonce: virtual public dev::Exception { public: InvalidBlockNonce(h256 _h, Nonce _n, u256 _d); h256 h; Nonce n; u256 d; };
class InvalidNonce: virtual public dev::Exception {};
class InvalidBlockNonce: virtual public dev::Exception {};
struct InvalidParentHash: virtual dev::Exception {};
struct InvalidNumber: virtual dev::Exception {};
struct InvalidContractAddress: virtual public dev::Exception {};

4
libethereum/BlockChain.cpp

@ -243,7 +243,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
RLP blockRLP(_block);
if (!blockRLP.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat(0, blockRLP.data()) << errinfo_comment("block header needs to be a list"));
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, blockRLP.data().toString()));
bi.populate(&_block);
bi.verifyInternals(&_block);
@ -547,7 +547,7 @@ void BlockChain::garbageCollect(bool _force)
}
}
m_cacheUsage.pop_back();
m_cacheUsage.push_front({});
m_cacheUsage.push_front(std::set<CacheID>{});
}
void BlockChain::checkConsistency()

1
libethereum/BlockChain.h

@ -26,6 +26,7 @@
#include <leveldb/db.h>
#pragma warning(pop)
#include <deque>
#include <chrono>
#include <libdevcore/Log.h>
#include <libdevcore/Exceptions.h>

2
libethereum/BlockQueue.cpp

@ -107,7 +107,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
void BlockQueue::tick(BlockChain const& _bc)
{
unsigned t = time(0);
for (auto i = m_future.begin(); i != m_future.end() && i->first < time(0); ++i)
for (auto i = m_future.begin(); i != m_future.end() && i->first < t; ++i)
import(&(i->second), _bc);
WriteGuard l(m_lock);

72
libethereum/Client.cpp

@ -60,14 +60,84 @@ void VersionChecker::setOk()
}
}
void BasicGasPricer::update(BlockChain const& _bc)
{
unsigned c = 0;
h256 p = _bc.currentHash();
m_gasPerBlock = _bc.info(p).gasLimit;
map<u256, unsigned> dist;
unsigned total = 0;
while (c < 1000 && p)
{
BlockInfo bi = _bc.info(p);
if (bi.transactionsRoot != EmptyTrie)
{
auto bb = _bc.block(p);
RLP r(bb);
BlockReceipts brs(_bc.receipts(bi.hash));
for (unsigned i = 0; i < r[1].size(); ++i)
{
auto gu = brs.receipts[i].gasUsed();
dist[Transaction(r[1][i].data(), CheckSignature::None).gasPrice()] += (unsigned)brs.receipts[i].gasUsed();
total += (unsigned)gu;
}
}
p = bi.parentHash;
++c;
}
if (total > 0)
{
unsigned t = 0;
unsigned q = 1;
m_octiles[0] = dist.begin()->first;
for (auto const& i: dist)
{
for (; t <= total * q / 8 && t + i.second > total * q / 8; ++q)
m_octiles[q] = i.first;
if (q > 7)
break;
}
m_octiles[8] = dist.rbegin()->first;
}
}
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, bool _forceClean, u256 _networkId, int _miners):
Worker("eth"),
m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean),
m_gp(new TrivialGasPricer),
m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(Address(), m_stateDB),
m_postMine(Address(), m_stateDB)
{
m_gp->update(m_bc);
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
if (_miners > -1)
setMiningThreads(_miners);
else
setMiningThreads();
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
m_vc.setOk();
doWork();
startWorking();
}
Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _gp, std::string const& _dbPath, bool _forceClean, u256 _networkId, int _miners):
Worker("eth"),
m_vc(_dbPath),
m_bc(_dbPath, !m_vc.ok() || _forceClean),
m_gp(_gp),
m_stateDB(State::openDB(_dbPath, !m_vc.ok() || _forceClean)),
m_preMine(Address(), m_stateDB),
m_postMine(Address(), m_stateDB)
{
m_gp->update(m_bc);
m_host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
if (_miners > -1)
@ -592,7 +662,7 @@ void Client::doWork()
// returns h256s as blooms, once for each transaction.
cwork << "postSTATE <== TQ";
TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq);
TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp);
if (newPendingReceipts.size())
{
for (size_t i = 0; i < newPendingReceipts.size(); i++)

37
libethereum/Client.h

@ -160,6 +160,26 @@ private:
State m_state;
};
class BasicGasPricer: public GasPricer
{
public:
explicit BasicGasPricer(u256 _weiPerRef, u256 _refsPerBlock): m_weiPerRef(_weiPerRef), m_refsPerBlock(_refsPerBlock) {}
void setRefPrice(u256 _weiPerRef) { m_weiPerRef = _weiPerRef; }
void setRefBlockFees(u256 _refsPerBlock) { m_refsPerBlock = _refsPerBlock; }
u256 ask(State const&) const override { return m_weiPerRef * m_refsPerBlock / m_gasPerBlock; }
u256 bid(TransactionPriority _p = TransactionPriority::Medium) const override { return m_octiles[(int)_p] > 0 ? m_octiles[(int)_p] : (m_weiPerRef * m_refsPerBlock / m_gasPerBlock); }
void update(BlockChain const& _bc) override;
private:
u256 m_weiPerRef;
u256 m_refsPerBlock;
u256 m_gasPerBlock = 1000000;
std::array<u256, 9> m_octiles;
};
/**
* @brief Main API hub for interfacing with Ethereum.
*/
@ -177,9 +197,21 @@ public:
int _miners = -1
);
explicit Client(
p2p::Host* _host,
std::shared_ptr<GasPricer> _gpForAdoption, // pass it in with new.
std::string const& _dbPath = std::string(),
bool _forceClean = false,
u256 _networkId = 0,
int _miners = -1
);
/// Destructor.
virtual ~Client();
/// Resets the gas pricer to some other object.
void setGasPricer(std::shared_ptr<GasPricer> _gp) { m_gp = _gp; }
/// Submits the given message-call transaction.
virtual void transact(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo);
@ -352,6 +384,7 @@ private:
CanonBlockChain m_bc; ///< Maintains block database.
TransactionQueue m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
std::shared_ptr<GasPricer> m_gp; ///< The gas pricer.
mutable SharedMutex x_stateDB; ///< Lock on the state DB, effectively a lock on m_postMine.
OverlayDB m_stateDB; ///< Acts as the central point for the state database, so multiple States can share it.
@ -368,7 +401,9 @@ private:
bool m_paranoia = false; ///< Should we be paranoid about our state?
bool m_turboMining = false; ///< Don't squander all of our time mining actually just sleeping.
bool m_forceMining = false; ///< Mine even when there are no transactions pending?
bool m_verifyOwnBlocks = true; ///< Shoudl be verify blocks that we mined?
bool m_verifyOwnBlocks = true; ///< Should be verify blocks that we mined?
mutable Mutex m_filterLock;
std::map<h256, InstalledFilter> m_filters;

8
libethereum/Executive.cpp

@ -66,7 +66,7 @@ bool Executive::setup()
if (m_t.nonce() != nonceReq)
{
clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce();
BOOST_THROW_EXCEPTION(InvalidNonce(nonceReq, m_t.nonce()));
BOOST_THROW_EXCEPTION(InvalidNonce() << RequirementError((bigint)nonceReq, (bigint)m_t.nonce()));
}
// Check gas cost is enough.
@ -176,7 +176,7 @@ OnOpFunc Executive::simpleTrace()
o << endl << " STACK" << endl;
for (auto i: vm.stack())
o << (h256)i << endl;
o << " MEMORY" << endl << (vm.memory().size() > 1000) ? " mem size greater than 1000 bytes " : memDump(vm.memory());
o << " MEMORY" << endl << ((vm.memory().size() > 1000) ? " mem size greater than 1000 bytes " : memDump(vm.memory()));
o << " STORAGE" << endl;
for (auto const& i: ext.state().storage(ext.myAddress))
o << showbase << hex << i.first << ": " << i.second << endl;
@ -236,6 +236,10 @@ bool Executive::go(OnOpFunc const& _onOp)
void Executive::finalize()
{
// Accumulate refunds for suicides.
if (m_ext)
m_ext->sub.refunds += c_suicideRefundGas * m_ext->sub.suicides.size();
// SSTORE refunds...
// must be done before the miner gets the fees.
if (m_ext)

33
libethereum/State.cpp

@ -400,7 +400,7 @@ bool State::cull(TransactionQueue& _tq) const
return ret;
}
TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged)
TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, bool* o_transactionQueueChanged)
{
// TRANSACTIONS
TransactionReceipts ret;
@ -414,20 +414,27 @@ TransactionReceipts State::sync(BlockChain const& _bc, TransactionQueue& _tq, bo
for (auto const& i: ts)
if (!m_transactionSet.count(i.first))
{
// don't have it yet! Execute it now.
try
{
uncommitToMine();
// boost::timer t;
execute(lh, i.second);
ret.push_back(m_receipts.back());
_tq.noteGood(i);
++goodTxs;
// cnote << "TX took:" << t.elapsed() * 1000;
Transaction t(i.second, CheckSignature::Sender);
if (t.gasPrice() >= _gp.ask(*this))
{
// don't have it yet! Execute it now.
uncommitToMine();
// boost::timer t;
execute(lh, i.second);
ret.push_back(m_receipts.back());
_tq.noteGood(i);
++goodTxs;
// cnote << "TX took:" << t.elapsed() * 1000;
}
}
catch (InvalidNonce const& in)
{
if (in.required > in.candidate)
bigint const* req = boost::get_error_info<errinfo_required>(in);
bigint const* got = boost::get_error_info<errinfo_got>(in);
if (*req > *got)
{
// too old
_tq.drop(i.first);
@ -462,7 +469,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
// m_currentBlock is assumed to be prepopulated and reset.
#if !ETH_RELEASE
BlockInfo bi(_block, _checkNonce);
BlockInfo bi(_block, _checkNonce ? CheckEverything : IgnoreNonce);
assert(m_previousBlock.hash == bi.parentHash);
assert(m_currentBlock.parentHash == bi.parentHash);
assert(rootHash() == m_previousBlock.stateRoot);
@ -472,7 +479,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
BOOST_THROW_EXCEPTION(InvalidParentHash());
// Populate m_currentBlock with the correct values.
m_currentBlock.populate(_block, _checkNonce);
m_currentBlock.populate(_block, _checkNonce ? CheckEverything : IgnoreNonce);
m_currentBlock.verifyInternals(_block);
// cnote << "playback begins:" << m_state.root();
@ -554,7 +561,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
for (auto const& i: rlp[2])
{
if (knownUncles.count(sha3(i.data())))
BOOST_THROW_EXCEPTION(UncleInChain(knownUncles, sha3(i.data()) ));
BOOST_THROW_EXCEPTION(UncleInChain() << errinfo_comment("Uncle in block already mentioned") << errinfo_data(toString(knownUncles)) << errinfo_hash256(sha3(i.data())) );
BlockInfo uncle = BlockInfo::fromHeader(i.data());
if (nonces.count(uncle.nonce))

31
libethereum/State.h

@ -47,6 +47,7 @@ namespace eth
{
class BlockChain;
class State;
struct StateChat: public LogChannel { static const char* name() { return "-S-"; } static const int verbosity = 4; };
struct StateTrace: public LogChannel { static const char* name() { return "=S="; } static const int verbosity = 7; };
@ -55,6 +56,33 @@ struct StateSafeExceptions: public LogChannel { static const char* name() { retu
enum class BaseState { Empty, CanonGenesis };
enum class TransactionPriority
{
Lowest = 0,
Low = 2,
Medium = 4,
High = 6,
Highest = 8
};
class GasPricer
{
public:
GasPricer() {}
virtual u256 ask(State const&) const = 0;
virtual u256 bid(TransactionPriority _p = TransactionPriority::Medium) const = 0;
virtual void update(BlockChain const&) {}
};
class TrivialGasPricer: public GasPricer
{
protected:
u256 ask(State const&) const override { return 10 * szabo; }
u256 bid(TransactionPriority = TransactionPriority::Medium) const override { return 10 * szabo; }
};
/**
* @brief Model of the current state of the ledger.
* Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block).
@ -147,10 +175,11 @@ public:
/// @returns a list of receipts one for each transaction placed from the queue into the state.
/// @a o_transactionQueueChanged boolean pointer, the value of which will be set to true if the transaction queue
/// changed and the pointer is non-null
TransactionReceipts sync(BlockChain const& _bc, TransactionQueue& _tq, bool* o_transactionQueueChanged = nullptr);
TransactionReceipts sync(BlockChain const& _bc, TransactionQueue& _tq, GasPricer const& _gp, bool* o_transactionQueueChanged = nullptr);
/// Like sync but only operate on _tq, killing the invalid/old ones.
bool cull(TransactionQueue& _tq) const;
/// Returns the last few block hashes of the current chain.
LastHashes getLastHashes(BlockChain const& _bc, unsigned _n) const;
/// Execute a given transaction.

10
libevmcore/Assembly.cpp

@ -199,7 +199,6 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix, StringMap con
_out << _prefix << ".code:" << endl;
for (AssemblyItem const& i: m_items)
{
string sourceLine = getLocationFromSources(_sourceCodes, i.getLocation());
_out << _prefix;
switch (i.m_type)
{
@ -239,7 +238,7 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix, StringMap con
default:
BOOST_THROW_EXCEPTION(InvalidOpcode());
}
_out << string("\t\t") << sourceLine << endl;
_out << string("\t\t") << getLocationFromSources(_sourceCodes, i.getLocation()) << endl;
}
if (!m_data.empty() || !m_subs.empty())
@ -251,17 +250,18 @@ ostream& Assembly::streamRLP(ostream& _out, string const& _prefix, StringMap con
for (auto const& i: m_subs)
{
_out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << endl;
i.second.streamRLP(_out, _prefix + " ");
i.second.streamRLP(_out, _prefix + " ", _sourceCodes);
}
}
return _out;
}
AssemblyItem const& Assembly::append(AssemblyItem const& _i, SourceLocation const& _location)
AssemblyItem const& Assembly::append(AssemblyItem const& _i)
{
m_deposit += _i.deposit();
m_items.push_back(_i);
m_items.back().setLocation(_location);
if (m_items.back().getLocation().isEmpty() && !m_currentSourceLocation.isEmpty())
m_items.back().setLocation(m_currentSourceLocation);
return back();
}

11
libevmcore/Assembly.h

@ -88,9 +88,9 @@ public:
AssemblyItem append() { return append(newTag()); }
void append(Assembly const& _a);
void append(Assembly const& _a, int _deposit);
AssemblyItem const& append(AssemblyItem const& _i, SourceLocation const& _location = SourceLocation());
AssemblyItem const& append(std::string const& _data, SourceLocation const& _location = SourceLocation()) { return append(newPushString(_data), _location); }
AssemblyItem const& append(bytes const& _data, SourceLocation const& _location = SourceLocation()) { return append(newData(_data), _location); }
AssemblyItem const& append(AssemblyItem const& _i);
AssemblyItem const& append(std::string const& _data) { return append(newPushString(_data)); }
AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); }
AssemblyItem appendSubSize(Assembly const& _a) { auto ret = newSub(_a); append(newPushSubSize(ret.data())); return ret; }
/// Pushes the final size of the current assembly itself. Use this when the code is modified
/// after compilation and CODESIZE is not an option.
@ -119,6 +119,9 @@ public:
void adjustDeposit(int _adjustment) { m_deposit += _adjustment; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); }
void setDeposit(int _deposit) { m_deposit = _deposit; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); }
/// Changes the source location used for each appended item.
void setSourceLocation(SourceLocation const& _location) { m_currentSourceLocation = _location; }
bytes assemble() const;
Assembly& optimise(bool _enable);
std::ostream& streamRLP(std::ostream& _out, std::string const& _prefix = "", const StringMap &_sourceCodes = StringMap()) const;
@ -137,6 +140,8 @@ protected:
int m_deposit = 0;
int m_baseDeposit = 0;
int m_totalDeposit = 0;
SourceLocation m_currentSourceLocation;
};
inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a)

253
libsolidity/ArrayUtils.cpp

@ -37,140 +37,120 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
// stack layout: [source_ref] target_ref (top)
// need to leave target_ref on the stack at the end
solAssert(_targetType.getLocation() == ArrayType::Location::Storage, "");
solAssert(
_sourceType.getLocation() == ArrayType::Location::CallData ||
_sourceType.getLocation() == ArrayType::Location::Storage,
"Given array location not implemented."
);
IntegerType uint256(256);
Type const* targetBaseType = _targetType.isByteArray() ? &uint256 : &(*_targetType.getBaseType());
Type const* sourceBaseType = _sourceType.isByteArray() ? &uint256 : &(*_sourceType.getBaseType());
switch (_sourceType.getLocation())
{
case ArrayType::Location::CallData:
{
solAssert(_targetType.isByteArray(), "Non byte arrays not yet implemented here.");
solAssert(_sourceType.isByteArray(), "Non byte arrays not yet implemented here.");
// This also assumes that after "length" we only have zeros, i.e. it cannot be used to
// slice a byte array from calldata.
// stack: source_offset source_len target_ref
// fetch old length and convert to words
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
convertLengthToSize(_targetType);
// stack here: source_offset source_len target_ref target_length_words
// actual array data is stored at SHA3(storage_offset)
m_context << eth::Instruction::DUP2;
CompilerUtils(m_context).computeHashStatic();
// compute target_data_end
m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2 << eth::Instruction::ADD
<< eth::Instruction::SWAP1;
// stack here: source_offset source_len target_ref target_data_end target_data_ref
// store length (in bytes)
m_context << eth::Instruction::DUP4 << eth::Instruction::DUP1 << eth::Instruction::DUP5
<< eth::Instruction::SSTORE;
// jump to end if length is zero
m_context << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
// add length to source offset
m_context << eth::Instruction::DUP5 << eth::Instruction::DUP5 << eth::Instruction::ADD;
// stack now: source_offset source_len target_ref target_data_end target_data_ref source_end
// store start offset
m_context << eth::Instruction::DUP6;
// stack now: source_offset source_len target_ref target_data_end target_data_ref source_end calldata_offset
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart
// copy from calldata and store
<< eth::Instruction::DUP1 << eth::Instruction::CALLDATALOAD
<< eth::Instruction::DUP4 << eth::Instruction::SSTORE
// increment target_data_ref by 1
<< eth::Instruction::SWAP2 << u256(1) << eth::Instruction::ADD
// increment calldata_offset by 32
<< eth::Instruction::SWAP2 << u256(32) << eth::Instruction::ADD
// check for loop condition
<< eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::GT;
m_context.appendConditionalJumpTo(copyLoopStart);
m_context << eth::Instruction::POP << eth::Instruction::POP;
m_context << copyLoopEnd;
// this copies source to target and also clears target if it was larger
// now clear leftover bytes of the old value
// stack now: source_offset source_len target_ref target_data_end target_data_ref
clearStorageLoop(IntegerType(256));
// stack now: source_offset source_len target_ref target_data_end
// TODO unroll loop for small sizes
m_context << eth::Instruction::POP << eth::Instruction::SWAP2
// stack: source_ref [source_length] target_ref
// store target_ref
for (unsigned i = _sourceType.getSizeOnStack(); i > 0; --i)
m_context << eth::swapInstruction(i);
if (_sourceType.getLocation() != ArrayType::Location::CallData || !_sourceType.isDynamicallySized())
retrieveLength(_sourceType); // otherwise, length is already there
// stack: target_ref source_ref source_length
m_context << eth::Instruction::DUP3;
// stack: target_ref source_ref source_length target_ref
retrieveLength(_targetType);
// stack: target_ref source_ref source_length target_ref target_length
if (_targetType.isDynamicallySized())
// store new target length
m_context << eth::Instruction::DUP3 << eth::Instruction::DUP3 << eth::Instruction::SSTORE;
if (sourceBaseType->getCategory() == Type::Category::Mapping)
{
solAssert(targetBaseType->getCategory() == Type::Category::Mapping, "");
solAssert(_sourceType.getLocation() == ArrayType::Location::Storage, "");
// nothing to copy
m_context
<< eth::Instruction::POP << eth::Instruction::POP
<< eth::Instruction::POP << eth::Instruction::POP;
break;
return;
}
case ArrayType::Location::Storage:
{
// this copies source to target and also clears target if it was larger
solAssert(sourceBaseType->getStorageSize() == targetBaseType->getStorageSize(),
"Copying with different storage sizes not yet implemented.");
// stack: source_ref target_ref
// store target_ref
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;
// stack: target_ref source_ref target_ref
// fetch lengthes
retrieveLength(_targetType);
m_context << eth::Instruction::SWAP2;
// stack: target_ref target_len target_ref source_ref
retrieveLength(_sourceType);
// stack: target_ref target_len target_ref source_ref source_len
if (_targetType.isDynamicallySized())
// store new target length
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::SSTORE;
// compute hashes (data positions)
m_context << eth::Instruction::SWAP2;
if (_targetType.isDynamicallySized())
CompilerUtils(m_context).computeHashStatic();
m_context << eth::Instruction::SWAP1;
if (_sourceType.isDynamicallySized())
CompilerUtils(m_context).computeHashStatic();
// stack: target_ref target_len source_len target_data_pos source_data_pos
m_context << eth::Instruction::DUP4;
convertLengthToSize(_sourceType);
m_context << eth::Instruction::DUP4;
convertLengthToSize(_sourceType);
// stack: target_ref target_len source_len target_data_pos source_data_pos target_size source_size
// @todo we might be able to go without a third counter
m_context << u256(0);
// stack: target_ref target_len source_len target_data_pos source_data_pos target_size source_size counter
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart;
// check for loop condition
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3
<< eth::Instruction::GT << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
// copy
m_context << eth::Instruction::DUP4 << eth::Instruction::DUP2 << eth::Instruction::ADD;
StorageItem(m_context, *sourceBaseType).retrieveValue(SourceLocation(), true);
m_context << eth::dupInstruction(5 + sourceBaseType->getSizeOnStack())
<< eth::dupInstruction(2 + sourceBaseType->getSizeOnStack()) << eth::Instruction::ADD;
StorageItem(m_context, *targetBaseType).storeValue(*sourceBaseType, SourceLocation(), true);
// increment
m_context << targetBaseType->getStorageSize() << eth::Instruction::ADD;
m_context.appendJumpTo(copyLoopStart);
m_context << copyLoopEnd;
// compute hashes (data positions)
m_context << eth::Instruction::SWAP1;
if (_targetType.isDynamicallySized())
CompilerUtils(m_context).computeHashStatic();
// stack: target_ref source_ref source_length target_length target_data_pos
m_context << eth::Instruction::SWAP1;
convertLengthToSize(_targetType);
m_context << eth::Instruction::DUP2 << eth::Instruction::ADD;
// stack: target_ref source_ref source_length target_data_pos target_data_end
m_context << eth::Instruction::SWAP3;
// stack: target_ref target_data_end source_length target_data_pos source_ref
// skip copying if source length is zero
m_context << eth::Instruction::DUP3 << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
// zero-out leftovers in target
// stack: target_ref target_len source_len target_data_pos source_data_pos target_size source_size counter
// add counter to target_data_pos
m_context << eth::Instruction::DUP5 << eth::Instruction::ADD
<< eth::Instruction::SWAP5 << eth::Instruction::POP;
// stack: target_ref target_len target_data_pos_updated target_data_pos source_data_pos target_size source_size
// add size to target_data_pos to get target_data_end
m_context << eth::Instruction::POP << eth::Instruction::DUP3 << eth::Instruction::ADD
<< eth::Instruction::SWAP4
<< eth::Instruction::POP << eth::Instruction::POP << eth::Instruction::POP;
// stack: target_ref target_data_end target_data_pos_updated
clearStorageLoop(*targetBaseType);
if (_sourceType.getLocation() == ArrayType::Location::Storage && _sourceType.isDynamicallySized())
CompilerUtils(m_context).computeHashStatic();
// stack: target_ref target_data_end source_length target_data_pos source_data_pos
m_context << eth::Instruction::SWAP2;
convertLengthToSize(_sourceType);
m_context << eth::Instruction::DUP3 << eth::Instruction::ADD;
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart;
// check for loop condition
m_context
<< eth::Instruction::DUP3 << eth::Instruction::DUP2
<< eth::Instruction::GT << eth::Instruction::ISZERO;
m_context.appendConditionalJumpTo(copyLoopEnd);
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end
// copy
if (sourceBaseType->getCategory() == Type::Category::Array)
{
m_context << eth::Instruction::DUP3 << eth::Instruction::DUP3;
copyArrayToStorage(
dynamic_cast<ArrayType const&>(*targetBaseType),
dynamic_cast<ArrayType const&>(*sourceBaseType)
);
m_context << eth::Instruction::POP;
break;
}
default:
solAssert(false, "Given byte array location not implemented.");
else
{
m_context << eth::Instruction::DUP3;
if (_sourceType.getLocation() == ArrayType::Location::Storage)
StorageItem(m_context, *sourceBaseType).retrieveValue(SourceLocation(), true);
else if (sourceBaseType->isValueType())
CompilerUtils(m_context).loadFromMemoryDynamic(*sourceBaseType, true, true, false);
else
solAssert(false, "Copying of unknown type requested: " + sourceBaseType->toString());
m_context << eth::dupInstruction(2 + sourceBaseType->getSizeOnStack());
StorageItem(m_context, *targetBaseType).storeValue(*sourceBaseType, SourceLocation(), true);
}
// increment source
m_context
<< eth::Instruction::SWAP2
<< (_sourceType.getLocation() == ArrayType::Location::Storage ?
sourceBaseType->getStorageSize() :
sourceBaseType->getCalldataEncodedSize())
<< eth::Instruction::ADD
<< eth::Instruction::SWAP2;
// increment target
m_context
<< eth::Instruction::SWAP1
<< targetBaseType->getStorageSize()
<< eth::Instruction::ADD
<< eth::Instruction::SWAP1;
m_context.appendJumpTo(copyLoopStart);
m_context << copyLoopEnd;
// zero-out leftovers in target
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end
m_context << eth::Instruction::POP << eth::Instruction::SWAP1 << eth::Instruction::POP;
// stack: target_ref target_data_end target_data_pos_updated
clearStorageLoop(*targetBaseType);
m_context << eth::Instruction::POP;
}
void ArrayUtils::clearArray(ArrayType const& _type) const
@ -178,7 +158,7 @@ void ArrayUtils::clearArray(ArrayType const& _type) const
solAssert(_type.getLocation() == ArrayType::Location::Storage, "");
if (_type.isDynamicallySized())
clearDynamicArray(_type);
else if (_type.getLength() == 0)
else if (_type.getLength() == 0 || _type.getBaseType()->getCategory() == Type::Category::Mapping)
m_context << eth::Instruction::POP;
else if (_type.getLength() < 5) // unroll loop for small arrays @todo choose a good value
{
@ -272,6 +252,11 @@ void ArrayUtils::resizeDynamicArray(const ArrayType& _type) const
void ArrayUtils::clearStorageLoop(Type const& _type) const
{
if (_type.getCategory() == Type::Category::Mapping)
{
m_context << eth::Instruction::POP;
return;
}
// stack: end_pos pos
eth::AssemblyItem loopStart = m_context.newTag();
m_context << loopStart;
@ -290,13 +275,25 @@ void ArrayUtils::clearStorageLoop(Type const& _type) const
m_context << eth::Instruction::POP;
}
void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType) const
void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) const
{
if (_arrayType.isByteArray())
m_context << u256(31) << eth::Instruction::ADD
<< u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
else if (_arrayType.getBaseType()->getStorageSize() > 1)
m_context << _arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL;
if (_arrayType.getLocation() == ArrayType::Location::Storage)
{
if (_arrayType.isByteArray())
m_context << u256(31) << eth::Instruction::ADD
<< u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
else if (_arrayType.getBaseType()->getStorageSize() > 1)
m_context << _arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL;
}
else
{
if (!_arrayType.isByteArray())
m_context << _arrayType.getBaseType()->getCalldataEncodedSize() << eth::Instruction::MUL;
else if (_pad)
m_context << u256(31) << eth::Instruction::ADD
<< u256(32) << eth::Instruction::DUP1
<< eth::Instruction::SWAP2 << eth::Instruction::DIV << eth::Instruction::MUL;
}
}
void ArrayUtils::retrieveLength(ArrayType const& _arrayType) const

5
libsolidity/ArrayUtils.h

@ -60,10 +60,11 @@ public:
/// Stack pre: end_ref start_ref
/// Stack post: end_ref
void clearStorageLoop(Type const& _type) const;
/// Converts length to size (multiplies by size on stack), rounds up for byte arrays.
/// Converts length to size (number of storage slots or calldata/memory bytes).
/// if @a _pad then add padding to multiples of 32 bytes for calldata/memory.
/// Stack pre: length
/// Stack post: size
void convertLengthToSize(ArrayType const& _arrayType) const;
void convertLengthToSize(ArrayType const& _arrayType, bool _pad = false) const;
/// Retrieves the length (number of elements) of the array ref on the stack. This also
/// works for statically-sized arrays.
/// Stack pre: reference

45
libsolidity/Compiler.cpp

@ -132,7 +132,7 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
void Compiler::appendBaseConstructor(FunctionDefinition const& _constructor)
{
CompilerContext::LocationSetter locationSetter(m_context, &_constructor);
CompilerContext::LocationSetter locationSetter(m_context, _constructor);
FunctionType constructorType(_constructor);
if (!constructorType.getParameterTypes().empty())
{
@ -146,11 +146,11 @@ void Compiler::appendBaseConstructor(FunctionDefinition const& _constructor)
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
unsigned argumentSize = 0;
for (ASTPointer<VariableDeclaration> const& var: _constructor.getParameters())
argumentSize += CompilerUtils::getPaddedSize(var->getType()->getCalldataEncodedSize());
argumentSize += var->getType()->getCalldataEncodedSize();
if (argumentSize > 0)
{
@ -192,10 +192,12 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
for (auto const& it: interfaceFunctions)
{
FunctionTypePointer const& functionType = it.second;
solAssert(functionType->hasDeclaration(), "");
CompilerContext::LocationSetter locationSetter(m_context, functionType->getDeclaration());
m_context << callDataUnpackerEntryPoints.at(it.first);
eth::AssemblyItem returnTag = m_context.pushNewTag();
appendCalldataUnpacker(functionType->getParameterTypes());
m_context.appendJumpTo(m_context.getFunctionEntryLabel(it.second->getDeclaration()));
m_context.appendJumpTo(m_context.getFunctionEntryLabel(functionType->getDeclaration()));
m_context << returnTag;
appendReturnValuePacker(functionType->getReturnParameterTypes());
}
@ -208,8 +210,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
bigint parameterHeadEnd = offset;
for (TypePointer const& type: _typeParameters)
parameterHeadEnd += type->isDynamicallySized() ? 32 :
CompilerUtils::getPaddedSize(type->getCalldataEncodedSize());
parameterHeadEnd += type->isDynamicallySized() ? 32 : type->getCalldataEncodedSize();
solAssert(parameterHeadEnd <= numeric_limits<unsigned>::max(), "Arguments too large.");
unsigned stackHeightOfPreviousDynamicArgument = 0;
@ -228,8 +229,8 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
// Retrieve data start offset by adding length to start offset of previous dynamic type
unsigned stackDepth = m_context.getStackHeight() - stackHeightOfPreviousDynamicArgument;
m_context << eth::dupInstruction(stackDepth) << eth::dupInstruction(stackDepth);
ArrayUtils(m_context).convertLengthToSize(*previousDynamicType);
m_context << u256(32) << eth::Instruction::MUL << eth::Instruction::ADD;
ArrayUtils(m_context).convertLengthToSize(*previousDynamicType, true);
m_context << eth::Instruction::ADD;
}
else
m_context << u256(parameterHeadEnd);
@ -240,7 +241,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
else
{
m_context << u256(offset);
offset += CompilerUtils::getPaddedSize(type->getCalldataEncodedSize());
offset += type->getCalldataEncodedSize();
}
break;
default:
@ -287,7 +288,7 @@ void Compiler::initializeStateVariables(ContractDefinition const& _contract)
bool Compiler::visit(VariableDeclaration const& _variableDeclaration)
{
solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration.");
CompilerContext::LocationSetter locationSetter(m_context, &_variableDeclaration);
CompilerContext::LocationSetter locationSetter(m_context, _variableDeclaration);
m_context.startFunction(_variableDeclaration);
m_breakTags.clear();
@ -301,7 +302,7 @@ bool Compiler::visit(VariableDeclaration const& _variableDeclaration)
bool Compiler::visit(FunctionDefinition const& _function)
{
CompilerContext::LocationSetter locationSetter(m_context, &_function);
CompilerContext::LocationSetter locationSetter(m_context, _function);
//@todo to simplify this, the calling convention could by changed such that
// caller puts: [retarg0] ... [retargm] [return address] [arg0] ... [argn]
// although note that this reduces the size of the visible stack
@ -376,7 +377,7 @@ bool Compiler::visit(FunctionDefinition const& _function)
for (VariableDeclaration const* localVariable: _function.getLocalVariables())
m_context.removeVariable(*localVariable);
m_context.adjustStackOffset(-c_returnValuesSize);
m_context.adjustStackOffset(-(int)c_returnValuesSize);
if (!_function.isConstructor())
m_context << eth::Instruction::JUMP;
return false;
@ -385,7 +386,7 @@ bool Compiler::visit(FunctionDefinition const& _function)
bool Compiler::visit(IfStatement const& _ifStatement)
{
StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, &_ifStatement);
CompilerContext::LocationSetter locationSetter(m_context, _ifStatement);
compileExpression(_ifStatement.getCondition());
eth::AssemblyItem trueTag = m_context.appendConditionalJump();
if (_ifStatement.getFalseStatement())
@ -402,7 +403,7 @@ bool Compiler::visit(IfStatement const& _ifStatement)
bool Compiler::visit(WhileStatement const& _whileStatement)
{
StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, &_whileStatement);
CompilerContext::LocationSetter locationSetter(m_context, _whileStatement);
eth::AssemblyItem loopStart = m_context.newTag();
eth::AssemblyItem loopEnd = m_context.newTag();
m_continueTags.push_back(loopStart);
@ -428,7 +429,7 @@ bool Compiler::visit(WhileStatement const& _whileStatement)
bool Compiler::visit(ForStatement const& _forStatement)
{
StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, &_forStatement);
CompilerContext::LocationSetter locationSetter(m_context, _forStatement);
eth::AssemblyItem loopStart = m_context.newTag();
eth::AssemblyItem loopEnd = m_context.newTag();
m_continueTags.push_back(loopStart);
@ -465,7 +466,7 @@ bool Compiler::visit(ForStatement const& _forStatement)
bool Compiler::visit(Continue const& _continueStatement)
{
CompilerContext::LocationSetter locationSetter(m_context, &_continueStatement);
CompilerContext::LocationSetter locationSetter(m_context, _continueStatement);
if (!m_continueTags.empty())
m_context.appendJumpTo(m_continueTags.back());
return false;
@ -473,7 +474,7 @@ bool Compiler::visit(Continue const& _continueStatement)
bool Compiler::visit(Break const& _breakStatement)
{
CompilerContext::LocationSetter locationSetter(m_context, &_breakStatement);
CompilerContext::LocationSetter locationSetter(m_context, _breakStatement);
if (!m_breakTags.empty())
m_context.appendJumpTo(m_breakTags.back());
return false;
@ -481,7 +482,7 @@ bool Compiler::visit(Break const& _breakStatement)
bool Compiler::visit(Return const& _return)
{
CompilerContext::LocationSetter locationSetter(m_context, &_return);
CompilerContext::LocationSetter locationSetter(m_context, _return);
//@todo modifications are needed to make this work with functions returning multiple values
if (Expression const* expression = _return.getExpression())
{
@ -500,7 +501,7 @@ bool Compiler::visit(Return const& _return)
bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationStatement)
{
StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, &_variableDeclarationStatement);
CompilerContext::LocationSetter locationSetter(m_context, _variableDeclarationStatement);
if (Expression const* expression = _variableDeclarationStatement.getExpression())
{
compileExpression(*expression, _variableDeclarationStatement.getDeclaration().getType());
@ -513,7 +514,7 @@ bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationSta
bool Compiler::visit(ExpressionStatement const& _expressionStatement)
{
StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, &_expressionStatement);
CompilerContext::LocationSetter locationSetter(m_context, _expressionStatement);
Expression const& expression = _expressionStatement.getExpression();
compileExpression(expression);
CompilerUtils(m_context).popStackElement(*expression.getType());
@ -524,7 +525,7 @@ bool Compiler::visit(ExpressionStatement const& _expressionStatement)
bool Compiler::visit(PlaceholderStatement const& _placeholderStatement)
{
StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, &_placeholderStatement);
CompilerContext::LocationSetter locationSetter(m_context, _placeholderStatement);
++m_modifierDepth;
appendModifierOrFunctionCode();
--m_modifierDepth;
@ -551,7 +552,7 @@ void Compiler::appendModifierOrFunctionCode()
}
ModifierDefinition const& modifier = m_context.getFunctionModifier(modifierInvocation->getName()->getName());
CompilerContext::LocationSetter locationSetter(m_context, &modifier);
CompilerContext::LocationSetter locationSetter(m_context, modifier);
solAssert(modifier.getParameters().size() == modifierInvocation->getArguments().size(), "");
for (unsigned i = 0; i < modifier.getParameters().size(); ++i)
{

38
libsolidity/CompilerContext.cpp

@ -63,13 +63,13 @@ void CompilerContext::addVariable(VariableDeclaration const& _declaration,
void CompilerContext::removeVariable(VariableDeclaration const& _declaration)
{
solAssert(m_localVariables.count(&_declaration), "");
solAssert(!!m_localVariables.count(&_declaration), "");
m_localVariables.erase(&_declaration);
}
void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration)
{
LocationSetter locationSetter(*this, &_declaration);
LocationSetter locationSetter(*this, _declaration);
addVariable(_declaration);
int const size = _declaration.getType()->getSizeOnStack();
for (int i = 0; i < size; ++i)
@ -182,34 +182,7 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node)
stack<ASTNode const*> newStack;
newStack.push(_node);
std::swap(m_visitedNodes, newStack);
}
CompilerContext& CompilerContext::operator<<(eth::AssemblyItem const& _item)
{
solAssert(!m_visitedNodes.empty(), "No node on the visited stack");
m_asm.append(_item, m_visitedNodes.top()->getLocation());
return *this;
}
CompilerContext& CompilerContext::operator<<(eth::Instruction _instruction)
{
solAssert(!m_visitedNodes.empty(), "No node on the visited stack");
m_asm.append(_instruction, m_visitedNodes.top()->getLocation());
return *this;
}
CompilerContext& CompilerContext::operator<<(u256 const& _value)
{
solAssert(!m_visitedNodes.empty(), "No node on the visited stack");
m_asm.append(_value, m_visitedNodes.top()->getLocation());
return *this;
}
CompilerContext& CompilerContext::operator<<(bytes const& _data)
{
solAssert(!m_visitedNodes.empty(), "No node on the visited stack");
m_asm.append(_data, m_visitedNodes.top()->getLocation());
return *this;
updateSourceLocation();
}
vector<ContractDefinition const*>::const_iterator CompilerContext::getSuperContract(ContractDefinition const& _contract) const
@ -220,5 +193,10 @@ vector<ContractDefinition const*>::const_iterator CompilerContext::getSuperContr
return ++it;
}
void CompilerContext::updateSourceLocation()
{
m_asm.setSourceLocation(m_visitedNodes.empty() ? SourceLocation() : m_visitedNodes.top()->getLocation());
}
}
}

18
libsolidity/CompilerContext.h

@ -108,15 +108,15 @@ public:
/// Resets the stack of visited nodes with a new stack having only @c _node
void resetVisitedNodes(ASTNode const* _node);
/// Pops the stack of visited nodes
void popVisitedNodes() { m_visitedNodes.pop(); }
void popVisitedNodes() { m_visitedNodes.pop(); updateSourceLocation(); }
/// Pushes an ASTNode to the stack of visited nodes
void pushVisitedNodes(ASTNode const* _node) { m_visitedNodes.push(_node); }
void pushVisitedNodes(ASTNode const* _node) { m_visitedNodes.push(_node); updateSourceLocation(); }
/// Append elements to the current instruction list and adjust @a m_stackOffset.
CompilerContext& operator<<(eth::AssemblyItem const& _item);
CompilerContext& operator<<(eth::Instruction _instruction);
CompilerContext& operator<<(u256 const& _value);
CompilerContext& operator<<(bytes const& _data);
CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm.append(_item); return *this; }
CompilerContext& operator<<(eth::Instruction _instruction) { m_asm.append(_instruction); return *this; }
CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; }
CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; }
eth::Assembly const& getAssembly() const { return m_asm; }
/// @arg _sourceCodes is the map of input files to source code strings
@ -130,12 +130,14 @@ public:
class LocationSetter: public ScopeGuard
{
public:
LocationSetter(CompilerContext& _compilerContext, ASTNode const* _node):
ScopeGuard(std::bind(&CompilerContext::popVisitedNodes, _compilerContext)) { _compilerContext.pushVisitedNodes(_node); }
LocationSetter(CompilerContext& _compilerContext, ASTNode const& _node):
ScopeGuard([&]{ _compilerContext.popVisitedNodes(); }) { _compilerContext.pushVisitedNodes(&_node); }
};
private:
std::vector<ContractDefinition const*>::const_iterator getSuperContract(const ContractDefinition &_contract) const;
/// Updates source location set in the assembly.
void updateSourceLocation();
eth::Assembly m_asm;
/// Magic global variables like msg, tx or this, distinguished by type.

8
libsolidity/CompilerUtils.cpp

@ -92,7 +92,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
}
else
{
solAssert(type.getLocation() == ArrayType::Location::Storage, "Memory byte arrays not yet implemented.");
solAssert(type.getLocation() == ArrayType::Location::Storage, "Memory arrays not yet implemented.");
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
// stack here: memory_offset storage_offset length_bytes
// jump to end if length is zero
@ -177,8 +177,7 @@ void CompilerUtils::computeHashStatic(Type const& _type, bool _padToWordBoundari
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
{
unsigned _encodedSize = _type.getCalldataEncodedSize();
unsigned numBytes = _padToWordBoundaries ? getPaddedSize(_encodedSize) : _encodedSize;
unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);
bool leftAligned = _type.getCategory() == Type::Category::String;
if (numBytes == 0)
m_context << eth::Instruction::POP << u256(0);
@ -202,8 +201,7 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const
{
unsigned _encodedSize = _type.getCalldataEncodedSize();
unsigned numBytes = _padToWordBoundaries ? getPaddedSize(_encodedSize) : _encodedSize;
unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);
bool leftAligned = _type.getCategory() == Type::Category::String;
if (numBytes == 0)
m_context << eth::Instruction::POP;

3
libsolidity/CompilerUtils.h

@ -71,9 +71,6 @@ public:
/// Stack pre: memory_offset value...
/// Stack post: (memory_offset+length)
void storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries = true);
/// @returns _size rounded up to the next multiple of 32 (the number of bytes occupied in the
/// padded calldata)
static unsigned getPaddedSize(unsigned _size) { return ((_size + 31) / 32) * 32; }
/// Moves the value that is at the top of the stack to a stack variable.
void moveToStackVariable(VariableDeclaration const& _variable);

38
libsolidity/ExpressionCompiler.cpp

@ -48,7 +48,7 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
if (!_varDecl.getValue())
return;
solAssert(!!_varDecl.getValue()->getType(), "Type information not available.");
CompilerContext::LocationSetter locationSetter(m_context, &_varDecl);
CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
_varDecl.getValue()->accept(*this);
appendTypeConversion(*_varDecl.getValue()->getType(), *_varDecl.getType(), true);
@ -57,7 +57,7 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
{
CompilerContext::LocationSetter locationSetter(m_context, &_varDecl);
CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
FunctionType accessorType(_varDecl);
unsigned length = 0;
@ -74,7 +74,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
{
// move offset to memory
CompilerUtils(m_context).storeInMemory(length);
unsigned argLen = CompilerUtils::getPaddedSize(paramType->getCalldataEncodedSize());
unsigned argLen = paramType->getCalldataEncodedSize();
length -= argLen;
m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3;
@ -204,7 +204,7 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
bool ExpressionCompiler::visit(Assignment const& _assignment)
{
CompilerContext::LocationSetter locationSetter(m_context, &_assignment);
CompilerContext::LocationSetter locationSetter(m_context, _assignment);
_assignment.getRightHandSide().accept(*this);
if (_assignment.getType()->isValueType())
appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType());
@ -237,7 +237,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
{
CompilerContext::LocationSetter locationSetter(m_context, &_unaryOperation);
CompilerContext::LocationSetter locationSetter(m_context, _unaryOperation);
//@todo type checking and creating code for an operator should be in the same place:
// the operator should know how to convert itself and to which types it applies, so
// put this code together with "Type::acceptsBinary/UnaryOperator" into a class that
@ -307,7 +307,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
{
CompilerContext::LocationSetter locationSetter(m_context, &_binaryOperation);
CompilerContext::LocationSetter locationSetter(m_context, _binaryOperation);
Expression const& leftExpression = _binaryOperation.getLeftExpression();
Expression const& rightExpression = _binaryOperation.getRightExpression();
Type const& commonType = _binaryOperation.getCommonType();
@ -354,7 +354,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
CompilerContext::LocationSetter locationSetter(m_context, &_functionCall);
CompilerContext::LocationSetter locationSetter(m_context, _functionCall);
using Location = FunctionType::Location;
if (_functionCall.isTypeConversion())
{
@ -572,7 +572,7 @@ bool ExpressionCompiler::visit(NewExpression const&)
void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
{
CompilerContext::LocationSetter locationSetter(m_context, &_memberAccess);
CompilerContext::LocationSetter locationSetter(m_context, _memberAccess);
ASTString const& member = _memberAccess.getMemberName();
switch (_memberAccess.getExpression().getType()->getCategory())
{
@ -707,7 +707,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
{
CompilerContext::LocationSetter locationSetter(m_context, &_indexAccess);
CompilerContext::LocationSetter locationSetter(m_context, _indexAccess);
_indexAccess.getBaseExpression().accept(*this);
Type const& baseType = *_indexAccess.getBaseExpression().getType();
@ -782,8 +782,9 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
else
{
u256 elementSize =
location == ArrayType::Location::Storage ? arrayType.getBaseType()->getStorageSize() :
CompilerUtils::getPaddedSize(arrayType.getBaseType()->getCalldataEncodedSize());
location == ArrayType::Location::Storage ?
arrayType.getBaseType()->getStorageSize() :
arrayType.getBaseType()->getCalldataEncodedSize();
solAssert(elementSize != 0, "Invalid element size.");
if (elementSize > 1)
m_context << elementSize << eth::Instruction::MUL;
@ -801,8 +802,8 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
switch (location)
{
case ArrayType::Location::CallData:
// no lvalue
CompilerUtils(m_context).loadFromMemoryDynamic(*arrayType.getBaseType(), true, true, false);
if (arrayType.getBaseType()->isValueType())
CompilerUtils(m_context).loadFromMemoryDynamic(*arrayType.getBaseType(), true, true, false);
break;
case ArrayType::Location::Storage:
setLValueToStorageItem(_indexAccess);
@ -820,6 +821,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
void ExpressionCompiler::endVisit(Identifier const& _identifier)
{
CompilerContext::LocationSetter locationSetter(m_context, _identifier);
Declaration const* declaration = _identifier.getReferencedDeclaration();
if (MagicVariableDeclaration const* magicVar = dynamic_cast<MagicVariableDeclaration const*>(declaration))
{
@ -852,6 +854,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
void ExpressionCompiler::endVisit(Literal const& _literal)
{
CompilerContext::LocationSetter locationSetter(m_context, _literal);
switch (_literal.getType()->getCategory())
{
case Type::Category::IntegerConstant:
@ -1021,7 +1024,7 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
//@todo only return the first return value for now
Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr :
_functionType.getReturnParameterTypes().front().get();
unsigned retSize = firstType ? CompilerUtils::getPaddedSize(firstType->getCalldataEncodedSize()) : 0;
unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0;
m_context << u256(retSize) << u256(0);
if (bare)
@ -1051,8 +1054,9 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
if (_functionType.gasSet())
m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos));
else
// send all gas except for the 21 needed to execute "SUB" and "CALL"
m_context << u256(_functionType.valueSet() ? 6741 : 41) << eth::Instruction::GAS << eth::Instruction::SUB;
// send all gas except the amount needed to execute "SUB" and "CALL"
// @todo this retains too much gas for now, needs to be fine-tuned.
m_context << u256(50 + (_functionType.valueSet() ? 9000 : 0)) << eth::Instruction::GAS << eth::Instruction::SUB;
m_context << eth::Instruction::CALL;
auto tag = m_context.appendConditionalJump();
m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0.
@ -1083,7 +1087,7 @@ void ExpressionCompiler::appendArgumentsCopyToMemory(
appendTypeConversion(*_arguments[i]->getType(), *expectedType, true);
bool pad = _padToWordBoundaries;
// Do not pad if the first argument has exactly four bytes
if (i == 0 && pad && _padExceptionIfFourBytes && expectedType->getCalldataEncodedSize() == 4)
if (i == 0 && pad && _padExceptionIfFourBytes && expectedType->getCalldataEncodedSize(false) == 4)
pad = false;
appendTypeMoveToMemory(*expectedType, pad);
}

1
libsolidity/LValue.cpp

@ -212,6 +212,7 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
}
else
{
solAssert(m_dataType.isValueType(), "Clearing of unsupported type requested: " + m_dataType.toString());
if (m_size == 0 && _removeReference)
m_context << eth::Instruction::POP;
else if (m_size == 1)

5
libsolidity/Types.cpp

@ -589,11 +589,12 @@ bool ArrayType::operator==(Type const& _other) const
return isDynamicallySized() || getLength() == other.getLength();
}
unsigned ArrayType::getCalldataEncodedSize() const
unsigned ArrayType::getCalldataEncodedSize(bool _padded) const
{
if (isDynamicallySized())
return 0;
bigint size = bigint(getLength()) * (isByteArray() ? 1 : getBaseType()->getCalldataEncodedSize());
bigint size = bigint(getLength()) * (isByteArray() ? 1 : getBaseType()->getCalldataEncodedSize(_padded));
size = ((size + 31) / 32) * 32;
solAssert(size <= numeric_limits<unsigned>::max(), "Array size does not fit unsigned.");
return unsigned(size);
}

14
libsolidity/Types.h

@ -120,8 +120,10 @@ public:
/// @returns number of bytes used by this type when encoded for CALL, or 0 if the encoding
/// is not a simple big-endian encoding or the type cannot be stored in calldata.
/// Note that irrespective of this size, each calldata element is padded to a multiple of 32 bytes.
virtual unsigned getCalldataEncodedSize() const { return 0; }
/// If @a _padded then it is assumed that each element is padded to a multiple of 32 bytes.
virtual unsigned getCalldataEncodedSize(bool _padded) const { (void)_padded; return 0; }
/// Convenience version of @see getCalldataEncodedSize(bool)
unsigned getCalldataEncodedSize() const { return getCalldataEncodedSize(true); }
/// @returns true if the type is dynamically encoded in calldata
virtual bool isDynamicallySized() const { return false; }
/// @returns number of bytes required to hold this value in storage.
@ -176,7 +178,7 @@ public:
virtual bool operator==(Type const& _other) const override;
virtual unsigned getCalldataEncodedSize() const override { return m_bits / 8; }
virtual unsigned getCalldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : m_bits / 8; }
virtual bool isValueType() const override { return true; }
virtual MemberList const& getMembers() const { return isAddress() ? AddressMemberList : EmptyMemberList; }
@ -247,7 +249,7 @@ public:
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool operator==(Type const& _other) const override;
virtual unsigned getCalldataEncodedSize() const override { return m_bytes; }
virtual unsigned getCalldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
virtual bool isValueType() const override { return true; }
virtual std::string toString() const override { return "string" + dev::toString(m_bytes); }
@ -271,7 +273,7 @@ public:
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
virtual unsigned getCalldataEncodedSize() const { return 1; }
virtual unsigned getCalldataEncodedSize(bool _padded) const { return _padded ? 32 : 1; }
virtual bool isValueType() const override { return true; }
virtual std::string toString() const override { return "bool"; }
@ -302,7 +304,7 @@ public:
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(const Type& _other) const override;
virtual unsigned getCalldataEncodedSize() const override;
virtual unsigned getCalldataEncodedSize(bool _padded) const override;
virtual bool isDynamicallySized() const { return m_hasDynamicLength; }
virtual u256 getStorageSize() const override;
virtual unsigned getSizeOnStack() const override;

2
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -710,7 +710,7 @@ std::string WebThreeStubServerBase::eth_transact(Json::Value const& _json)
if (t.creation)
ret = toJS(right160(sha3(rlpList(t.from, client()->countAt(t.from)))));;
if (!t.gasPrice)
t.gasPrice = 10 * dev::eth::szabo;
t.gasPrice = 10 * dev::eth::szabo; // TODO: should be determined by user somehow.
if (!t.gas)
t.gas = min<u256>(client()->gasLimitRemaining(), client()->balanceAt(t.from) / t.gasPrice);

89
mix/ClientModel.cpp

@ -37,7 +37,6 @@
#include "QVariableDefinition.h"
#include "ContractCallDataEncoder.h"
#include "CodeModel.h"
#include "ClientModel.h"
#include "QEther.h"
#include "Web3Server.h"
#include "ClientModel.h"
@ -318,19 +317,28 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
QDebugData* debugData = new QDebugData();
QQmlEngine::setObjectOwnership(debugData, QQmlEngine::JavaScriptOwnership);
QList<QCode*> codes;
QList<QHash<int, int>> codeMaps;
QList<AssemblyItems> codeItems;
QList<CompiledContract const*> contracts;
for (MachineCode const& code: _t.executionCode)
{
codes.push_back(QMachineState::getHumanReadableCode(debugData, code.address, code.code));
QHash<int, int> codeMap;
codes.push_back(QMachineState::getHumanReadableCode(debugData, code.address, code.code, codeMap));
codeMaps.push_back(std::move(codeMap));
//try to resolve contract for source level debugging
auto nameIter = m_contractNames.find(code.address);
if (nameIter != m_contractNames.end())
{
CompiledContract const& compilerRes = m_context->codeModel()->contract(nameIter->second);
eth::AssemblyItems assemblyItems = !_t.isConstructor() ? compilerRes.assemblyItems() : compilerRes.constructorAssemblyItems();
QVariantList locations;
for (eth::AssemblyItem const& item: assemblyItems)
locations.push_back(QVariant::fromValue(new QSourceLocation(debugData, item.getLocation().start, item.getLocation().end)));
codes.back()->setLocations(compilerRes.documentId(), std::move(locations));
codes.back()->setDocument(compilerRes.documentId());
codeItems.push_back(std::move(assemblyItems));
contracts.push_back(&compilerRes);
}
else
{
codeItems.push_back(AssemblyItems());
contracts.push_back(nullptr);
}
}
@ -339,18 +347,77 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
data.push_back(QMachineState::getDebugCallData(debugData, d));
QVariantList states;
QStringList solCallStack;
std::map<int, SolidityDeclaration> solLocals; //<stack pos, declaration>
QList<int> returnStack;
unsigned prevInstructionIndex = 0;
for (MachineState const& s: _t.machineStates)
states.append(QVariant::fromValue(new QMachineState(debugData, s, codes[s.codeIndex], data[s.dataIndex])));
{
int instructionIndex = codeMaps[s.codeIndex][static_cast<unsigned>(s.curPC)];
QSolState* solState = nullptr;
if (!codeItems[s.codeIndex].empty() && contracts[s.codeIndex])
{
CompiledContract const* contract = contracts[s.codeIndex];
AssemblyItem const& instruction = codeItems[s.codeIndex][instructionIndex];
debugData->setStates(std::move(states));
if (instruction.type() == dev::eth::Push && !instruction.data())
{
//register new local variable initialization
auto localIter = contract->locals().find(LocationPair(instruction.getLocation().start, instruction.getLocation().end));
if (localIter != contract->locals().end())
solLocals[s.stack.size()] = localIter.value();
}
//QList<QVariableDefinition*> returnParameters;
//returnParameters = encoder.decode(f->returnParameters(), debuggingContent.returnValue);
if (instruction.type() == dev::eth::Tag) //TODO: use annotations
{
//track calls into functions
auto functionIter = contract->functions().find(LocationPair(instruction.getLocation().start, instruction.getLocation().end));
if (functionIter != contract->functions().end())
{
QString functionName = functionIter.value();
solCallStack.push_back(functionName);
returnStack.push_back(prevInstructionIndex + 1);
}
else if (!returnStack.empty() && instructionIndex == returnStack.back())
{
returnStack.pop_back();
solCallStack.pop_back();
}
}
//format solidity context values
QStringList locals;
for(auto l: solLocals)
if (l.first < (int)s.stack.size())
locals.push_back(l.second.name + "\t" + formatValue(l.second.type, s.stack[l.first]));
QStringList storage;
for(auto st: s.storage)
{
if (st.first < std::numeric_limits<unsigned>::max())
{
auto storageIter = contract->storage().find(static_cast<unsigned>(st.first));
if (storageIter != contract->storage().end())
storage.push_back(storageIter.value().name + "\t" + formatValue(storageIter.value().type, st.second));
}
}
prevInstructionIndex = instructionIndex;
solState = new QSolState(debugData, storage, solCallStack, locals, instruction.getLocation().start, instruction.getLocation().end);
}
states.append(QVariant::fromValue(new QMachineState(debugData, instructionIndex, s, codes[s.codeIndex], data[s.dataIndex], solState)));
}
//collect states for last transaction
debugData->setStates(std::move(states));
debugDataReady(debugData);
}
QString ClientModel::formatValue(SolidityType const&, dev::u256 const& _value)
{
return QString::fromStdString(prettyU256(_value));
}
void ClientModel::emptyRecord()
{
debugDataReady(new QDebugData());

2
mix/ClientModel.h

@ -41,6 +41,7 @@ class QEther;
class QDebugData;
class MixClient;
class QVariableDefinition;
struct SolidityType;
/// Backend transaction config class
struct TransactionSettings
@ -198,6 +199,7 @@ private:
void onNewTransaction();
void onStateReset();
void showDebuggerForTransaction(ExecutionResult const& _t);
QString formatValue(SolidityType const& _type, dev::u256 const& _value);
AppContext* m_context;
std::atomic<bool> m_running;

111
mix/CodeModel.cpp

@ -25,7 +25,10 @@
#include <QDebug>
#include <QApplication>
#include <QtQml>
#include <libdevcore/Common.h>
#include <libevmcore/SourceLocation.h>
#include <libsolidity/AST.h>
#include <libsolidity/ASTVisitor.h>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/SourceReferenceFormatter.h>
#include <libsolidity/InterfaceHandler.h>
@ -43,6 +46,91 @@ using namespace dev::mix;
const std::set<std::string> c_predefinedContracts =
{ "Config", "Coin", "CoinReg", "coin", "service", "owned", "mortal", "NameReg", "named", "std", "configUser" };
namespace
{
using namespace dev::solidity;
class CollectDeclarationsVisitor: public ASTConstVisitor
{
public:
CollectDeclarationsVisitor(QHash<LocationPair, QString>* _functions, QHash<LocationPair, SolidityDeclaration>* _locals, QHash<unsigned, SolidityDeclaration>* _storage):
m_functions(_functions), m_locals(_locals), m_storage(_storage), m_functionScope(false), m_storageSlot(0) {}
private:
QHash<LocationPair, QString>* m_functions;
QHash<LocationPair, SolidityDeclaration>* m_locals;
QHash<unsigned, SolidityDeclaration>* m_storage;
bool m_functionScope;
uint m_storageSlot;
LocationPair nodeLocation(ASTNode const& _node)
{
return LocationPair(_node.getLocation().start, _node.getLocation().end);
}
SolidityType nodeType(Type const* _type)
{
if (!_type)
return SolidityType { SolidityType::Type::UnsignedInteger, 32 };
switch (_type->getCategory())
{
case Type::Category::Integer:
{
IntegerType const* it = dynamic_cast<IntegerType const*>(_type);
unsigned size = it->getNumBits() / 8;
SolidityType::Type typeCode = it->isAddress() ? SolidityType::Type::Address : it->isHash() ? SolidityType::Type::Hash : it->isSigned() ? SolidityType::Type::SignedInteger : SolidityType::Type::UnsignedInteger;
return SolidityType { typeCode, size };
}
case Type::Category::Bool:
return SolidityType { SolidityType::Type::Bool, _type->getSizeOnStack() * 32 };
case Type::Category::String:
{
StaticStringType const* s = dynamic_cast<StaticStringType const*>(_type);
return SolidityType { SolidityType::Type::String, static_cast<unsigned>(s->getNumBytes()) };
}
case Type::Category::Contract:
return SolidityType { SolidityType::Type::Address, _type->getSizeOnStack() * 32 };
case Type::Category::Array:
case Type::Category::Enum:
case Type::Category::Function:
case Type::Category::IntegerConstant:
case Type::Category::Magic:
case Type::Category::Mapping:
case Type::Category::Modifier:
case Type::Category::Real:
case Type::Category::Struct:
case Type::Category::TypeType:
case Type::Category::Void:
default:
return SolidityType { SolidityType::Type::UnsignedInteger, 32 };
}
}
virtual bool visit(FunctionDefinition const& _node)
{
m_functions->insert(nodeLocation(_node), QString::fromStdString(_node.getName()));
m_functionScope = true;
return true;
}
virtual void endVisit(FunctionDefinition const&)
{
m_functionScope = false;
}
virtual bool visit(VariableDeclaration const& _node)
{
SolidityDeclaration decl;
decl.type = nodeType(_node.getType().get());
decl.name = QString::fromStdString(_node.getName());
if (m_functionScope)
m_locals->insert(nodeLocation(_node), decl);
else
m_storage->insert(m_storageSlot++, decl);
return true;
}
};
}
void BackgroundWorker::queueCodeChange(int _jobId)
{
m_model->runCompilationJob(_jobId);
@ -52,18 +140,23 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler
QObject(nullptr),
m_sourceHash(qHash(_source))
{
auto const& contractDefinition = _compiler.getContractDefinition(_contractName.toStdString());
std::string name = _contractName.toStdString();
auto const& contractDefinition = _compiler.getContractDefinition(name);
m_contract.reset(new QContractDefinition(&contractDefinition));
QQmlEngine::setObjectOwnership(m_contract.get(), QQmlEngine::CppOwnership);
m_bytes = _compiler.getBytecode(_contractName.toStdString());
m_assemblyItems = _compiler.getRuntimeAssemblyItems(_contractName.toStdString());
m_constructorAssemblyItems = _compiler.getAssemblyItems(_contractName.toStdString());
m_assemblyItems = _compiler.getRuntimeAssemblyItems(name);
m_constructorAssemblyItems = _compiler.getAssemblyItems(name);
dev::solidity::InterfaceHandler interfaceHandler;
m_contractInterface = QString::fromStdString(*interfaceHandler.getABIInterface(contractDefinition));
if (m_contractInterface.isEmpty())
m_contractInterface = "[]";
if (contractDefinition.getLocation().sourceName.get())
m_documentId = QString::fromStdString(*contractDefinition.getLocation().sourceName);
CollectDeclarationsVisitor visitor(&m_functions, &m_locals, &m_storage);
contractDefinition.accept(visitor);
}
QString CompiledContract::codeHex() const
@ -121,12 +214,11 @@ void CodeModel::reset(QVariantMap const& _documents)
void CodeModel::registerCodeChange(QString const& _documentId, QString const& _code)
{
{
Guard l(x_contractMap);
CompiledContract* contract = m_contractMap.value(_documentId);
if (contract != nullptr && contract->m_sourceHash == qHash(_code))
return;
CompiledContract* contract = contractByDocumentId(_documentId);
if (contract != nullptr && contract->m_sourceHash == qHash(_code))
return;
{
Guard pl(x_pendingContracts);
m_pendingContracts[_documentId] = _code;
}
@ -196,7 +288,8 @@ void CodeModel::runCompilationJob(int _jobId)
if (c_predefinedContracts.count(n) != 0)
continue;
QString name = QString::fromStdString(n);
auto sourceIter = m_pendingContracts.find(name);
QString sourceName = QString::fromStdString(*cs.getContractDefinition(n).getLocation().sourceName);
auto sourceIter = m_pendingContracts.find(sourceName);
QString source = sourceIter != m_pendingContracts.end() ? sourceIter->second : QString();
CompiledContract* contract = new CompiledContract(cs, name, source);
QQmlEngine::setObjectOwnership(contract, QQmlEngine::CppOwnership);

31
mix/CodeModel.h

@ -64,6 +64,29 @@ private:
CodeModel* m_model;
};
using LocationPair = QPair<int, int>;
struct SolidityType
{
enum class Type //TODO: arrays and structs
{
SignedInteger,
UnsignedInteger,
Hash,
Bool,
Address,
String,
};
Type type;
unsigned size; //bytes
};
struct SolidityDeclaration
{
QString name;
SolidityType type;
};
///Compilation result model. Contains all the compiled contract data required by UI
class CompiledContract: public QObject
{
@ -93,6 +116,10 @@ public:
/// @returns contract source Id
QString documentId() const { return m_documentId; }
QHash<LocationPair, QString> const& functions() const { return m_functions; }
QHash<LocationPair, SolidityDeclaration> const& locals() const { return m_locals; }
QHash<unsigned, SolidityDeclaration> const& storage() const { return m_storage; }
private:
uint m_sourceHash;
std::shared_ptr<QContractDefinition> m_contract;
@ -102,11 +129,13 @@ private:
QString m_documentId;
eth::AssemblyItems m_assemblyItems;
eth::AssemblyItems m_constructorAssemblyItems;
QHash<LocationPair, QString> m_functions;
QHash<LocationPair, SolidityDeclaration> m_locals;
QHash<unsigned, SolidityDeclaration> m_storage;
friend class CodeModel;
};
using ContractMap = QHash<QString, CompiledContract*>;
/// Code compilation model. Compiles contracts in background an provides compiled contract data

7
mix/DebuggingStateWrapper.cpp

@ -69,7 +69,7 @@ namespace
}
}
QCode* QMachineState::getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code)
QCode* QMachineState::getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code, QHash<int, int>& o_codeMap)
{
QVariantList codeStr;
for (unsigned i = 0; i <= _code.size(); ++i)
@ -80,14 +80,15 @@ QCode* QMachineState::getHumanReadableCode(QObject* _owner, const Address& _addr
QString s = QString::fromStdString(instructionInfo((Instruction)b).name);
std::ostringstream out;
out << std::hex << std::setw(4) << std::setfill('0') << i;
int line = i;
int offset = i;
if (b >= (byte)Instruction::PUSH1 && b <= (byte)Instruction::PUSH32)
{
unsigned bc = getPushNumber((Instruction)b);
s = "PUSH 0x" + QString::fromStdString(toHex(bytesConstRef(&_code[i + 1], bc)));
i += bc;
}
codeStr.append(QVariant::fromValue(new QInstruction(_owner, QString::fromStdString(out.str()) + " " + s, line)));
o_codeMap[offset] = codeStr.size();
codeStr.append(QVariant::fromValue(new QInstruction(_owner, QString::fromStdString(out.str()) + " " + s)));
}
catch (...)
{

45
mix/DebuggingStateWrapper.h

@ -26,12 +26,12 @@
#include <boost/asio.hpp>
#include <QStringList>
#include <QMap>
#include <QHash>
#include <libdevcore/Common.h>
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include "MachineStates.h"
#include "QVariableDefinition.h"
#include "MixClient.h"
#include "QBigInt.h"
namespace dev
@ -46,32 +46,39 @@ class QInstruction: public QObject
{
Q_OBJECT
Q_PROPERTY(QString line MEMBER m_line CONSTANT)
Q_PROPERTY(int processIndex MEMBER m_processIndex CONSTANT)
public:
QInstruction(QObject* _owner, QString _line, int _processIndex): QObject(_owner), m_line(_line), m_processIndex(_processIndex) {}
QInstruction(QObject* _owner, QString _line): QObject(_owner), m_line(_line) {}
private:
QString m_line;
int m_processIndex;
};
class QSourceLocation: public QObject
/**
* @brief Solidity state
*/
class QSolState: public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList storage MEMBER m_storage CONSTANT)
Q_PROPERTY(QStringList callStack MEMBER m_callStack CONSTANT)
Q_PROPERTY(QStringList locals MEMBER m_locals CONSTANT)
Q_PROPERTY(int start MEMBER m_start CONSTANT)
Q_PROPERTY(int end MEMBER m_end CONSTANT)
public:
QSourceLocation(QObject* _owner, int _start, int _end): QObject(_owner), m_start(_start), m_end(_end) {}
QSolState(QObject* _parent, QStringList const& _storage, QStringList const& _callStack, QStringList const& _locals, int _start, int _end):
QObject(_parent), m_storage(_storage), m_callStack(_callStack), m_locals(_locals), m_start(_start), m_end(_end)
{ }
private:
QStringList m_storage;
QStringList m_callStack;
QStringList m_locals;
int m_start;
int m_end;
};
/**
* @brief Shared container for lines
*/
@ -79,19 +86,17 @@ class QCode: public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantList instructions MEMBER m_instructions CONSTANT)
Q_PROPERTY(QVariantList locations MEMBER m_locations CONSTANT)
Q_PROPERTY(QString address MEMBER m_address CONSTANT)
Q_PROPERTY(QString documentId MEMBER m_document CONSTANT)
public:
QCode(QObject* _owner, QString const& _address, QVariantList&& _instrunctions): QObject(_owner), m_instructions(_instrunctions), m_address(_address) {}
void setLocations(QString const& _document, QVariantList&& _locations) { m_document = _document; m_locations = _locations; }
void setDocument(QString const& _documentId) { m_document = _documentId; }
private:
QVariantList m_instructions;
QString m_address;
QString m_document;
QVariantList m_locations;
};
/**
@ -133,6 +138,7 @@ class QMachineState: public QObject
Q_OBJECT
Q_PROPERTY(int step READ step CONSTANT)
Q_PROPERTY(int curPC READ curPC CONSTANT)
Q_PROPERTY(int instructionIndex MEMBER m_instructionIndex CONSTANT)
Q_PROPERTY(QBigInt* gasCost READ gasCost CONSTANT)
Q_PROPERTY(QBigInt* gas READ gas CONSTANT)
Q_PROPERTY(QString instruction READ instruction CONSTANT)
@ -146,10 +152,11 @@ class QMachineState: public QObject
Q_PROPERTY(QVariantList levels READ levels CONSTANT)
Q_PROPERTY(unsigned codeIndex READ codeIndex CONSTANT)
Q_PROPERTY(unsigned dataIndex READ dataIndex CONSTANT)
Q_PROPERTY(QObject* solidity MEMBER m_solState CONSTANT)
public:
QMachineState(QObject* _owner, MachineState const& _state, QCode* _code, QCallData* _callData):
QObject(_owner), m_state(_state), m_code(_code), m_callData(_callData) {}
QMachineState(QObject* _owner, int _instructionIndex, MachineState const& _state, QCode* _code, QCallData* _callData, QSolState* _solState):
QObject(_owner), m_instructionIndex(_instructionIndex), m_state(_state), m_code(_code), m_callData(_callData), m_solState(_solState) { }
/// Get the step of this machine states.
int step() { return (int)m_state.steps; }
/// Get the proccessed code index.
@ -168,7 +175,7 @@ public:
QStringList debugStorage();
/// Get memory.
QVariantList debugMemory();
/// get end of debug information.
/// Get end of debug information.
QString endOfDebug();
/// Get the new memory size.
QBigInt* newMemSize();
@ -177,18 +184,18 @@ public:
/// Get all previous steps.
QVariantList levels();
/// Get the current processed machine state.
MachineState state() { return m_state; }
/// Set the current processed machine state.
void setState(MachineState _state) { m_state = _state; }
MachineState const& state() const { return m_state; }
/// Convert all machine states in human readable code.
static QCode* getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code);
static QCode* getHumanReadableCode(QObject* _owner, const Address& _address, const bytes& _code, QHash<int, int>& o_codeMap);
/// Convert call data into human readable form
static QCallData* getDebugCallData(QObject* _owner, bytes const& _data);
private:
int m_instructionIndex;
MachineState m_state;
QCode* m_code;
QCallData* m_callData;
QSolState* m_solState;
};
}

2
mix/MixClient.cpp

@ -41,7 +41,7 @@ namespace mix
{
const Secret c_defaultUserAccountSecret = Secret("cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074");
const u256 c_mixGenesisDifficulty = (u256) 1 << 4;
const u256 c_mixGenesisDifficulty = c_minimumDifficulty; //TODO: make it lower for Mix somehow
class MixBlockChain: public dev::eth::BlockChain
{

74
mix/qml/CallStack.qml

@ -0,0 +1,74 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import "."
DebugInfoList
{
id: callStack
collapsible: true
title : qsTr("Call Stack")
enableSelection: true
itemDelegate:
Item {
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "#4A90E2"
visible: styleData.selected;
}
RowLayout
{
id: row
anchors.fill: parent
Rectangle
{
color: "#f7f7f7"
Layout.fillWidth: true
Layout.minimumWidth: 30
Layout.maximumWidth: 30
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
font.family: "monospace"
anchors.leftMargin: 5
color: "#4a4a4a"
text: styleData.row;
font.pointSize: DebuggerPaneStyle.general.basicFontSize
width: parent.width - 5
elide: Text.ElideRight
}
}
Rectangle
{
color: "transparent"
Layout.fillWidth: true
Layout.minimumWidth: parent.width - 30
Layout.maximumWidth: parent.width - 30
Text {
anchors.leftMargin: 5
width: parent.width - 5
wrapMode: Text.NoWrap
anchors.left: parent.left
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: styleData.value;
elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize
}
}
}
Rectangle {
anchors.top: row.bottom
width: parent.width;
height: 1;
color: "#cccccc"
anchors.bottom: parent.bottom
}
}
}

193
mix/qml/Debugger.qml

@ -29,6 +29,7 @@ Rectangle {
onAssemblyModeChanged:
{
Debugger.updateMode();
machineStates.updateHeight();
}
function displayCompilationErrorIfAny()
@ -90,6 +91,9 @@ Rectangle {
property alias memoryDumpHeightSettings: memoryRect.height
property alias callDataHeightSettings: callDataRect.height
property alias transactionLogVisible: transactionLog.visible
property alias solCallStackHeightSettings: solStackRect.height
property alias solStorageHeightSettings: solStorageRect.height
property alias solLocalsHeightSettings: solLocalsRect.height
}
Rectangle
@ -183,8 +187,12 @@ Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
function updateHeight() {
statesLayout.height = buttonRow.childrenRect.height + assemblyCodeRow.childrenRect.height +
callStackRect.childrenRect.height + storageRect.childrenRect.height + memoryRect.childrenRect.height + callDataRect.childrenRect.height + 120;
var h = buttonRow.childrenRect.height;
if (assemblyMode)
h += assemblyCodeRow.childrenRect.height + callStackRect.childrenRect.height + storageRect.childrenRect.height + memoryRect.childrenRect.height + callDataRect.childrenRect.height;
else
h += solStackRect.childrenRect.height + solLocalsRect.childrenRect.height + solStorageRect.childrenRect.height;
statesLayout.height = h + 120;
}
Component.onCompleted: updateHeight();
@ -546,83 +554,66 @@ Rectangle {
Rectangle
{
id: callStackRect;
id: solStackRect;
color: "transparent"
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
DebugInfoList
{
id: callStack
collapsible: true
visible: !assemblyMode
CallStack {
anchors.fill: parent
title : qsTr("Call Stack")
enableSelection: true
onRowActivated: Debugger.displayFrame(index);
itemDelegate:
Item {
anchors.fill: parent
id: solCallStack
}
}
Rectangle {
anchors.fill: parent
color: "#4A90E2"
visible: styleData.selected;
}
Rectangle
{
id: solLocalsRect;
color: "transparent"
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
visible: !assemblyMode
StorageView {
title : qsTr("Locals")
anchors.fill: parent
id: solLocals
}
}
RowLayout
{
id: row
anchors.fill: parent
Rectangle
{
color: "#f7f7f7"
Layout.fillWidth: true
Layout.minimumWidth: 30
Layout.maximumWidth: 30
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
font.family: "monospace"
anchors.leftMargin: 5
color: "#4a4a4a"
text: styleData.row;
font.pointSize: DebuggerPaneStyle.general.basicFontSize
width: parent.width - 5
elide: Text.ElideRight
}
}
Rectangle
{
color: "transparent"
Layout.fillWidth: true
Layout.minimumWidth: parent.width - 30
Layout.maximumWidth: parent.width - 30
Text {
anchors.leftMargin: 5
width: parent.width - 5
wrapMode: Text.NoWrap
anchors.left: parent.left
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: styleData.value;
elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize
}
}
}
Rectangle
{
id: solStorageRect;
color: "transparent"
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
visible: !assemblyMode
StorageView {
title : qsTr("Members")
anchors.fill: parent
id: solStorage
}
}
Rectangle {
anchors.top: row.bottom
width: parent.width;
height: 1;
color: "#cccccc"
anchors.bottom: parent.bottom
}
}
Rectangle
{
id: callStackRect;
color: "transparent"
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
visible: assemblyMode
CallStack {
anchors.fill: parent
id: callStack
onRowActivated: Debugger.displayFrame(index);
}
}
Rectangle
{
id: storageRect
@ -631,68 +622,10 @@ Rectangle {
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
DebugInfoList
{
id: storage
visible: assemblyMode
StorageView {
anchors.fill: parent
collapsible: true
title : qsTr("Storage")
itemDelegate:
Item {
anchors.fill: parent
RowLayout
{
id: row
anchors.fill: parent
Rectangle
{
color: "#f7f7f7"
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
Layout.maximumWidth: parent.width / 2
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
font.family: "monospace"
anchors.leftMargin: 5
color: "#4a4a4a"
text: styleData.value.split('\t')[0];
font.pointSize: DebuggerPaneStyle.general.basicFontSize
width: parent.width - 5
elide: Text.ElideRight
}
}
Rectangle
{
color: "transparent"
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
Layout.maximumWidth: parent.width / 2
Text {
maximumLineCount: 1
clip: true
anchors.leftMargin: 5
width: parent.width - 5
wrapMode: Text.WrapAnywhere
anchors.left: parent.left
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: styleData.value.split('\t')[1];
elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize
}
}
}
Rectangle {
anchors.top: row.bottom
width: parent.width;
height: 1;
color: "#cccccc"
anchors.bottom: parent.bottom
}
}
id: storage
}
}
@ -704,6 +637,7 @@ Rectangle {
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
visible: assemblyMode
DebugInfoList {
id: memoryDump
anchors.fill: parent
@ -726,6 +660,7 @@ Rectangle {
Layout.minimumHeight: 25
Layout.maximumHeight: 800
onHeightChanged: machineStates.updateHeight();
visible: assemblyMode
DebugInfoList {
id: callDataDump
anchors.fill: parent

4
mix/qml/StatusPane.qml

@ -159,8 +159,8 @@ Rectangle {
color: "transparent"
width: 100
height: parent.height
anchors.top: statusHeader.top
anchors.right: statusHeader.right
anchors.top: parent.top
anchors.right: parent.right
RowLayout
{
anchors.fill: parent

69
mix/qml/StorageView.qml

@ -0,0 +1,69 @@
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import "."
DebugInfoList
{
id: storage
collapsible: true
title : qsTr("Storage")
itemDelegate:
Item {
anchors.fill: parent
RowLayout
{
id: row
anchors.fill: parent
Rectangle
{
color: "#f7f7f7"
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
Layout.maximumWidth: parent.width / 2
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
font.family: "monospace"
anchors.leftMargin: 5
color: "#4a4a4a"
text: styleData.value.split('\t')[0];
font.pointSize: DebuggerPaneStyle.general.basicFontSize
width: parent.width - 5
elide: Text.ElideRight
}
}
Rectangle
{
color: "transparent"
Layout.fillWidth: true
Layout.minimumWidth: parent.width / 2
Layout.maximumWidth: parent.width / 2
Text {
maximumLineCount: 1
clip: true
anchors.leftMargin: 5
width: parent.width - 5
wrapMode: Text.WrapAnywhere
anchors.left: parent.left
font.family: "monospace"
anchors.verticalCenter: parent.verticalCenter
color: "#4a4a4a"
text: styleData.value.split('\t')[1];
elide: Text.ElideRight
font.pointSize: DebuggerPaneStyle.general.basicFontSize
}
}
}
Rectangle {
anchors.top: row.bottom
width: parent.width;
height: 1;
color: "#cccccc"
anchors.bottom: parent.bottom
}
}
}

31
mix/qml/js/Debugger.js

@ -4,7 +4,6 @@
var currentSelectedState = null;
var currentDisplayedState = null;
var debugData = null;
var codeMap = null;
var locations = [];
var locationMap = {};
var breakpoints = {};
@ -56,7 +55,7 @@ function initLocations()
for (var i = 0; i < debugData.states.length - 1; i++) {
var code = debugData.states[i].code;
var location = code.documentId ? code.locations[codeStr(i)] : nullLocation;
var location = code.documentId ? debugData.states[i].solidity : nullLocation;
if (location.start !== prevLocation.start || location.end !== prevLocation.end || code.documentId !== prevLocation.documentId)
{
prevLocation = { start: location.start, end: location.end, documentId: code.documentId, state: i };
@ -65,6 +64,7 @@ function initLocations()
locationMap[i] = locations.length - 1;
}
locations.push({ start: -1, end: -1, documentId: code.documentId, state: i });
locationMap[debugData.states.length - 1] = locations.length - 1;
}
@ -93,12 +93,10 @@ function initSlider()
function setupInstructions(stateIndex)
{
var instructions = debugData.states[stateIndex].code.instructions;
codeMap = {};
statesList.model.clear();
for (var i = 0; i < instructions.length; i++) {
for (var i = 0; i < instructions.length; i++)
statesList.model.append(instructions[i]);
codeMap[instructions[i].processIndex] = i;
}
callDataDump.listModel = debugData.states[stateIndex].callData.items;
}
@ -129,14 +127,14 @@ function display(stateIndex)
setupInstructions(stateIndex);
if (debugData.states[stateIndex].dataIndex !== debugData.states[currentDisplayedState].dataIndex)
setupCallData(stateIndex);
var codeLine = codeStr(stateIndex);
var state = debugData.states[stateIndex];
var codeLine = state.instructionIndex;
highlightSelection(codeLine);
completeCtxInformation(state);
currentDisplayedState = stateIndex;
var docId = debugData.states[stateIndex].code.documentId;
if (docId)
debugExecuteLocation(docId, locations[locationMap[stateIndex]]);
debugExecuteLocation(docId, debugData.states[stateIndex].solidity);
}
function displayFrame(frameIndex)
@ -183,12 +181,6 @@ function selectState(stateIndex)
statesSlider.value = stateIndex;
}
function codeStr(stateIndex)
{
var state = debugData.states[stateIndex];
return codeMap[state.curPC];
}
function highlightSelection(index)
{
statesList.positionViewAtRow(index, ListView.Center);
@ -206,6 +198,15 @@ function completeCtxInformation(state)
stack.listModel = state.debugStack;
storage.listModel = state.debugStorage;
memoryDump.listModel = state.debugMemory;
if (state.solidity) {
solLocals.listModel = state.solidity.locals;
solStorage.listModel = state.solidity.storage;
solCallStack.listModel = state.solidity.callStack;
} else {
solLocals.listModel = [];
solStorage.listModel = [];
solCallStack.listModel = [];
}
}
function isCallInstruction(index)
@ -229,7 +230,7 @@ function breakpointHit(i)
{
var bpLocations = breakpoints[debugData.states[i].code.documentId];
if (bpLocations) {
var location = locations[locationMap[i]];
var location = debugData.states[i].solidity;
if (location.start >= 0 && location.end >= location.start)
for (var b = 0; b < bpLocations.length; b++)
if (locationsIntersect(location, bpLocations[b]))

2
mix/res.qrc

@ -103,6 +103,8 @@
<file>qml/img/available_updates.png</file>
<file>qml/DeploymentDialog.qml</file>
<file>qml/img/search_filled.png</file>
<file>qml/StorageView.qml</file>
<file>qml/CallStack.qml</file>
<file>qml/img/help.png</file>
<file>qml/img/openedfolder.png</file>
<file>qml/img/b64.png</file>

169
rlp/main.cpp

@ -22,11 +22,13 @@
#include <fstream>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include "../test/JsonSpiritHeaders.h"
#include <libdevcore/CommonIO.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/SHA3.h>
using namespace std;
using namespace dev;
namespace js = json_spirit;
void help()
{
@ -42,6 +44,7 @@ void help()
<< " --force-hex Force all data to be rendered as raw hex." << endl
<< " -l,--list-archive List the items in the RLP list by hash and size." << endl
<< " -e,--extract-archive Extract all items in the RLP list, named by hash." << endl
<< " -c,--create Given a simplified JSON string, output the RLP." << endl
<< "General options:" << endl
<< " -L,--lenience Try not to bomb out early if possible." << endl
<< " -x,--hex,--base-16 Treat input RLP as hex encoded data." << endl
@ -63,6 +66,7 @@ enum class Mode {
ListArchive,
ExtractArchive,
Render,
Create
};
enum class Encoding {
@ -74,6 +78,10 @@ enum class Encoding {
bool isAscii(string const& _s)
{
// Always hex-encode anything beginning with 0x to avoid ambiguity.
if (_s.size() >= 2 && _s.substr(0, 2) == "0x")
return false;
for (char c: _s)
if (c < 32)
return false;
@ -87,6 +95,7 @@ public:
{
string indent = " ";
bool hexInts = false;
bool hexPrefix = true;
bool forceString = true;
bool escapeAll = false;
bool forceHex = false;
@ -100,14 +109,14 @@ public:
m_out << "null";
else if (_d.isInt())
if (m_prefs.hexInts)
m_out << toHex(toCompactBigEndian(_d.toInt<bigint>(RLP::LaisezFaire), 1), 1);
m_out << (m_prefs.hexPrefix ? "0x" : "") << toHex(toCompactBigEndian(_d.toInt<bigint>(RLP::LaisezFaire), 1), 1);
else
m_out << _d.toInt<bigint>(RLP::LaisezFaire);
else if (_d.isData())
if (m_prefs.forceString || (!m_prefs.forceHex && isAscii(_d.toString())))
m_out << escaped(_d.toString(), m_prefs.escapeAll);
else
m_out << toHex(_d.data());
m_out << (m_prefs.hexPrefix ? "0x" : "") << toHex(_d.data());
else if (_d.isList())
{
m_out << "[";
@ -147,6 +156,8 @@ int main(int argc, char** argv)
help();
else if (arg == "-r" || arg == "--render")
mode = Mode::Render;
else if (arg == "-c" || arg == "--create")
mode = Mode::Create;
else if ((arg == "-i" || arg == "--indent") && argc > i)
prefs.indent = argv[++i];
else if (arg == "--hex-ints")
@ -183,48 +194,53 @@ int main(int argc, char** argv)
in.push_back((byte)i);
else
in = contents(inputFile);
if (encoding == Encoding::Auto)
bytes b;
if (mode != Mode::Create)
{
encoding = Encoding::Hex;
for (char b: in)
if (b != '\n' && b != ' ' && b != '\t')
{
if (encoding == Encoding::Hex && (b < '0' || b > '9' ) && (b < 'a' || b > 'f' ) && (b < 'A' || b > 'F' ))
{
cerr << "'" << b << "':" << (int)b << endl;
encoding = Encoding::Base64;
}
if (encoding == Encoding::Base64 && (b < '0' || b > '9' ) && (b < 'a' || b > 'z' ) && (b < 'A' || b > 'Z' ) && b != '+' && b != '/')
if (encoding == Encoding::Auto)
{
encoding = Encoding::Hex;
for (char b: in)
if (b != '\n' && b != ' ' && b != '\t')
{
encoding = Encoding::Binary;
break;
if (encoding == Encoding::Hex && (b < '0' || b > '9' ) && (b < 'a' || b > 'f' ) && (b < 'A' || b > 'F' ))
{
cerr << "'" << b << "':" << (int)b << endl;
encoding = Encoding::Base64;
}
if (encoding == Encoding::Base64 && (b < '0' || b > '9' ) && (b < 'a' || b > 'z' ) && (b < 'A' || b > 'Z' ) && b != '+' && b != '/')
{
encoding = Encoding::Binary;
break;
}
}
}
}
bytes b;
switch (encoding)
{
case Encoding::Hex:
{
string s = asString(in);
boost::algorithm::replace_all(s, " ", "");
boost::algorithm::replace_all(s, "\n", "");
boost::algorithm::replace_all(s, "\t", "");
b = fromHex(s);
break;
}
case Encoding::Base64:
{
string s = asString(in);
boost::algorithm::replace_all(s, " ", "");
boost::algorithm::replace_all(s, "\n", "");
boost::algorithm::replace_all(s, "\t", "");
b = fromBase64(s);
break;
}
default:
swap(b, in);
break;
}
switch (encoding)
{
case Encoding::Hex:
{
string s = asString(in);
boost::algorithm::replace_all(s, " ", "");
boost::algorithm::replace_all(s, "\n", "");
boost::algorithm::replace_all(s, "\t", "");
b = fromHex(s);
break;
}
case Encoding::Base64:
{
string s = asString(in);
boost::algorithm::replace_all(s, " ", "");
boost::algorithm::replace_all(s, "\n", "");
boost::algorithm::replace_all(s, "\t", "");
b = fromBase64(s);
break;
}
default:
swap(b, in);
break;
}
}
try
@ -281,6 +297,77 @@ int main(int argc, char** argv)
cout << endl;
break;
}
case Mode::Create:
{
vector<js::mValue> v(1);
try {
js::read_string(asString(in), v[0]);
}
catch (...)
{
cerr << "Error: Invalid format; bad JSON." << endl;
exit(1);
}
RLPStream out;
while (!v.empty())
{
auto vb = v.back();
v.pop_back();
switch (vb.type())
{
case js::array_type:
{
js::mArray a = vb.get_array();
out.appendList(a.size());
for (int i = a.size() - 1; i >= 0; --i)
v.push_back(a[i]);
break;
}
case js::str_type:
{
string const& s = vb.get_str();
if (s.size() >= 2 && s.substr(0, 2) == "0x")
out << fromHex(s);
else
{
// assume it's a normal JS escaped string.
bytes ss;
ss.reserve(s.size());
for (unsigned i = 0; i < s.size(); ++i)
if (s[i] == '\\' && i + 1 < s.size())
{
if (s[++i] == 'x' && i + 2 < s.size())
ss.push_back(fromHex(s.substr(i, 2))[0]);
}
else if (s[i] != '\\')
ss.push_back((byte)s[i]);
out << ss;
}
break;
}
case js::int_type:
out << vb.get_int();
break;
default:
cerr << "ERROR: Unsupported type in JSON." << endl;
if (!lenience)
exit(1);
}
}
switch (encoding)
{
case Encoding::Hex: case Encoding::Auto:
cout << toHex(out.out()) << endl;
break;
case Encoding::Base64:
cout << toBase64(&out.out()) << endl;
break;
case Encoding::Binary:
cout.write((char const*)out.out().data(), out.out().size());
break;
}
break;
}
default:;
}
}

12
test/SolidityABIJSON.cpp

@ -20,7 +20,7 @@
* Unit tests for the solidity compiler JSON Interface output.
*/
#include <boost/test/unit_test.hpp>
#include "TestHelper.h"
#include <libsolidity/CompilerStack.h>
#include <json/json.h>
#include <libdevcore/Exceptions.h>
@ -39,15 +39,7 @@ public:
void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString)
{
try
{
m_compilerStack.parse(_code);
}
catch(boost::exception const& _e)
{
auto msg = std::string("Parsing contract failed with: ") + boost::diagnostic_information(_e);
BOOST_FAIL(msg);
}
ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parse(_code), "Parsing contract failed");
std::string generatedInterfaceString = m_compilerStack.getMetadata("", DocumentationType::ABIInterface);
Json::Value generatedInterface;
m_reader.parse(generatedInterfaceString, generatedInterface);

99
test/SolidityEndToEndTest.cpp

@ -3008,6 +3008,105 @@ BOOST_AUTO_TEST_CASE(bytes_index_access)
BOOST_CHECK(callContractFunction("storageWrite()") == encodeArgs(0x193));
}
BOOST_AUTO_TEST_CASE(array_copy_calldata_storage)
{
char const* sourceCode = R"(
contract c {
uint[9] m_data;
uint[] m_data_dyn;
uint8[][] m_byte_data;
function store(uint[9] a, uint8[3][] b) external returns (uint8) {
m_data = a;
m_data_dyn = a;
m_byte_data = b;
return b[3][1]; // note that access and declaration are reversed to each other
}
function retrieve() returns (uint a, uint b, uint c, uint d, uint e, uint f, uint g) {
a = m_data.length;
b = m_data[7];
c = m_data_dyn.length;
d = m_data_dyn[7];
e = m_byte_data.length;
f = m_byte_data[3].length;
g = m_byte_data[3][1];
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("store(uint256[9],uint8[3][])", encodeArgs(
21, 22, 23, 24, 25, 26, 27, 28, 29, // a
4, // size of b
1, 2, 3, // b[0]
11, 12, 13, // b[1]
21, 22, 23, // b[2]
31, 32, 33 // b[3]
)) == encodeArgs(32));
BOOST_CHECK(callContractFunction("retrieve()") == encodeArgs(
9, 28, 9, 28,
4, 3, 32));
}
BOOST_AUTO_TEST_CASE(array_copy_nested_array)
{
char const* sourceCode = R"(
contract c {
uint[4][] a;
uint[5][] b;
uint[][] c;
function test(uint[2][] d) external returns (uint) {
a = d;
b = a;
c = b;
return c[1][1] | c[1][2] | c[1][3] | c[1][4];
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test(uint256[2][])", encodeArgs(
3,
7, 8,
9, 10,
11, 12
)) == encodeArgs(10));
}
BOOST_AUTO_TEST_CASE(array_copy_including_mapping)
{
char const* sourceCode = R"(
contract c {
mapping(uint=>uint)[90][] large;
mapping(uint=>uint)[3][] small;
function test() returns (uint r) {
large.length = small.length = 7;
large[3][2][0] = 2;
large[1] = large[3];
small[3][2][0] = 2;
small[1] = small[2];
r = ((
small[3][2][0] * 0x100 |
small[1][2][0]) * 0x100 |
large[3][2][0]) * 0x100 |
large[1][2][0];
delete small;
delete large;
}
function clear() returns (uint r) {
large.length = small.length = 7;
small[3][2][0] = 0;
large[3][2][0] = 0;
small.length = large.length = 0;
return 7;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(0x02000200));
// storage is not empty because we cannot delete the mappings
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("clear()") == encodeArgs(7));
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base)
{
char const* sourceCode = R"(

10
test/SolidityExpressionCompiler.cpp

@ -30,7 +30,7 @@
#include <libsolidity/CompilerContext.h>
#include <libsolidity/ExpressionCompiler.h>
#include <libsolidity/AST.h>
#include <boost/test/unit_test.hpp>
#include "TestHelper.h"
using namespace std;
@ -72,8 +72,8 @@ private:
Expression* m_expression;
};
Declaration const& resolveDeclaration(vector<string> const& _namespacedName,
NameAndTypeResolver const& _resolver)
Declaration const& resolveDeclaration(
vector<string> const& _namespacedName, NameAndTypeResolver const& _resolver)
{
Declaration const* declaration = nullptr;
// bracers are required, cause msvc couldnt handle this macro in for statement
@ -112,13 +112,13 @@ bytes compileFirstExpression(const string& _sourceCode, vector<vector<string>> _
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));
ETH_TEST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract), "Resolving names failed");
inheritanceHierarchy = vector<ContractDefinition const*>(1, contract);
}
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
BOOST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract));
ETH_TEST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract), "Checking type Requirements failed");
}
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))

6
test/SolidityInterface.cpp

@ -20,7 +20,7 @@
* Unit tests for generating source interfaces for Solidity contracts.
*/
#include <boost/test/unit_test.hpp>
#include "TestHelper.h"
#include <libsolidity/CompilerStack.h>
#include <libsolidity/AST.h>
@ -42,9 +42,9 @@ public:
ContractDefinition const& checkInterface(string const& _code, string const& _contractName = "")
{
m_code = _code;
BOOST_REQUIRE_NO_THROW(m_compilerStack.parse(_code));
ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parse(_code), "Parsing failed");
m_interface = m_compilerStack.getMetadata("", DocumentationType::ABISolidityInterface);
BOOST_REQUIRE_NO_THROW(m_reCompiler.parse(m_interface));
ETH_TEST_REQUIRE_NO_THROW(m_reCompiler.parse(m_interface), "Interface parsing failed");
return m_reCompiler.getContractDefinition(_contractName);
}

119
test/SolidityNameAndTypeResolution.cpp

@ -28,7 +28,7 @@
#include <libsolidity/Parser.h>
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Exceptions.h>
#include <boost/test/unit_test.hpp>
#include "TestHelper.h"
using namespace std;
@ -58,30 +58,6 @@ ASTPointer<SourceUnit> parseTextAndResolveNames(std::string const& _source)
return sourceUnit;
}
ASTPointer<SourceUnit> parseTextAndResolveNamesWithChecks(std::string const& _source)
{
Parser parser;
ASTPointer<SourceUnit> sourceUnit;
try
{
sourceUnit = parser.parse(std::make_shared<Scanner>(CharStream(_source)));
NameAndTypeResolver resolver({});
resolver.registerDeclarations(*sourceUnit);
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
resolver.resolveNamesAndTypes(*contract);
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
resolver.checkTypeRequirements(*contract);
}
catch(boost::exception const& _e)
{
auto msg = std::string("Parsing text and resolving names failed with: \n") + boost::diagnostic_information(_e);
BOOST_FAIL(msg);
}
return sourceUnit;
}
static ContractDefinition const* retrieveContract(ASTPointer<SourceUnit> _source, unsigned index)
{
ContractDefinition* contract;
@ -109,7 +85,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
" uint256 stateVariable1;\n"
" function fun(uint256 arg1) { var x; uint256 y; }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(double_stateVariable_declaration)
@ -144,7 +120,7 @@ BOOST_AUTO_TEST_CASE(name_shadowing)
" uint256 variable;\n"
" function f() { uint32 variable ; }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(name_references)
@ -153,7 +129,7 @@ BOOST_AUTO_TEST_CASE(name_references)
" uint256 variable;\n"
" function f(uint256 arg) returns (uint out) { f(variable); test; out; }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(undeclared_name)
@ -171,7 +147,7 @@ BOOST_AUTO_TEST_CASE(reference_to_later_declaration)
" function g() { f(); }"
" function f() { }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(struct_definition_directly_recursive)
@ -209,7 +185,7 @@ BOOST_AUTO_TEST_CASE(struct_definition_recursion_via_mapping)
" mapping(uint => MyStructName1) x;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(type_inference_smoke_test)
@ -217,7 +193,7 @@ BOOST_AUTO_TEST_CASE(type_inference_smoke_test)
char const* text = "contract test {\n"
" function f(uint256 arg1, uint32 arg2) returns (bool ret) { var x = arg1 + arg2 == 8; ret = x; }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(type_checking_return)
@ -225,7 +201,7 @@ BOOST_AUTO_TEST_CASE(type_checking_return)
char const* text = "contract test {\n"
" function f() returns (bool r) { return 1 >= 2; }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(type_checking_return_wrong_number)
@ -250,7 +226,7 @@ BOOST_AUTO_TEST_CASE(type_checking_function_call)
" function f() returns (bool r) { return g(12, true) == 3; }\n"
" function g(uint256 a, bool b) returns (uint256 r) { }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(type_conversion_for_comparison)
@ -258,7 +234,7 @@ BOOST_AUTO_TEST_CASE(type_conversion_for_comparison)
char const* text = "contract test {\n"
" function f() { uint32(2) == int64(2); }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(type_conversion_for_comparison_invalid)
@ -274,7 +250,7 @@ BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion)
char const* text = "contract test {\n"
" function f() returns (int256 r) { var x = int256(uint32(2)); return x; }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(large_string_literal)
@ -292,7 +268,7 @@ BOOST_AUTO_TEST_CASE(balance)
" uint256 x = address(0).balance;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(balance_invalid)
@ -332,7 +308,7 @@ BOOST_AUTO_TEST_CASE(assignment_to_struct)
" data = a;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(returns_in_constructor)
@ -356,7 +332,7 @@ BOOST_AUTO_TEST_CASE(forward_function_reference)
" if (First(2).fun() == true) return 1;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(comparison_bitop_precedence)
@ -366,7 +342,7 @@ BOOST_AUTO_TEST_CASE(comparison_bitop_precedence)
" return 1 & 2 == 8 & 9 && 1 ^ 2 < 4 | 6;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(function_canonical_signature)
@ -423,7 +399,7 @@ BOOST_AUTO_TEST_CASE(inheritance_basic)
function f() { baseMember = 7; }
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(inheritance_diamond_basic)
@ -436,7 +412,7 @@ BOOST_AUTO_TEST_CASE(inheritance_diamond_basic)
function g() { f(); rootFunction(); }
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(cyclic_inheritance)
@ -492,7 +468,7 @@ BOOST_AUTO_TEST_CASE(complex_inheritance)
contract B { function f() {} function g() returns (uint8 r) {} }
contract C is A, B { }
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(constructor_visibility)
@ -502,7 +478,7 @@ BOOST_AUTO_TEST_CASE(constructor_visibility)
contract A { function A() { } }
contract B is A { function f() { A x = A(0); } }
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(overriding_constructor)
@ -512,7 +488,7 @@ BOOST_AUTO_TEST_CASE(overriding_constructor)
contract A { function A() { } }
contract B is A { function A() returns (uint8 r) {} }
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(missing_base_constructor_arguments)
@ -541,7 +517,7 @@ BOOST_AUTO_TEST_CASE(implicit_derived_to_base_conversion)
function f() { A a = B(1); }
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(implicit_base_to_derived_conversion)
@ -564,7 +540,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation)
modifier mod2(string7 a) { while (a == "1234567") _ }
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(invalid_function_modifier_type)
@ -587,7 +563,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation_parameters)
modifier mod2(string7 a) { while (a == "1234567") _ }
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables)
@ -598,7 +574,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables)
modifier mod(uint a) { if (a > 0) _ }
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(legal_modifier_override)
@ -607,7 +583,7 @@ BOOST_AUTO_TEST_CASE(legal_modifier_override)
contract A { modifier mod(uint a) {} }
contract B is A { modifier mod(uint a) {} }
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(illegal_modifier_override)
@ -661,7 +637,7 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors)
ASTPointer<SourceUnit> source;
ContractDefinition const* contract;
BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text));
ETH_TEST_CHECK_NO_THROW(source = parseTextAndResolveNames(text), "Parsing and Resolving names failed");
BOOST_REQUIRE((contract = retrieveContract(source, 0)) != nullptr);
FunctionTypePointer function = retrieveFunctionBySignature(contract, "foo()");
BOOST_REQUIRE(function && function->hasDeclaration());
@ -711,7 +687,7 @@ BOOST_AUTO_TEST_CASE(private_state_variable)
ASTPointer<SourceUnit> source;
ContractDefinition const* contract;
BOOST_CHECK_NO_THROW(source = parseTextAndResolveNamesWithChecks(text));
ETH_TEST_CHECK_NO_THROW(source = parseTextAndResolveNames(text), "Parsing and Resolving names failed");
BOOST_CHECK((contract = retrieveContract(source, 0)) != nullptr);
FunctionTypePointer function;
function = retrieveFunctionBySignature(contract, "foo()");
@ -729,7 +705,7 @@ BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor)
"contract Child is Parent{\n"
" function foo() returns (uint256) { return Parent.m_aMember; }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(base_class_state_variable_internal_member)
@ -740,7 +716,7 @@ BOOST_AUTO_TEST_CASE(base_class_state_variable_internal_member)
"contract Child is Parent{\n"
" function foo() returns (uint256) { return Parent.m_aMember; }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(state_variable_member_of_wrong_class1)
@ -780,7 +756,7 @@ BOOST_AUTO_TEST_CASE(fallback_function)
function() { x = 2; }
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(fallback_function_with_arguments)
@ -817,7 +793,7 @@ BOOST_AUTO_TEST_CASE(fallback_function_inheritance)
function() { x = 2; }
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(event)
@ -827,7 +803,7 @@ BOOST_AUTO_TEST_CASE(event)
event e(uint indexed a, string3 indexed s, bool indexed b);
function f() { e(2, "abc", true); }
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(event_too_many_indexed)
@ -847,7 +823,7 @@ BOOST_AUTO_TEST_CASE(event_call)
event e(uint a, string3 indexed s, bool indexed b);
function f() { e(2, "abc", true); }
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(event_inheritance)
@ -859,7 +835,7 @@ BOOST_AUTO_TEST_CASE(event_inheritance)
contract c is base {
function f() { e(2, "abc", true); }
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(multiple_events_argument_clash)
@ -869,7 +845,7 @@ BOOST_AUTO_TEST_CASE(multiple_events_argument_clash)
event e1(uint a, uint e1, uint e2);
event e2(uint a, uint e1, uint e2);
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(access_to_default_function_visibility)
@ -881,7 +857,7 @@ BOOST_AUTO_TEST_CASE(access_to_default_function_visibility)
contract d {
function g() { c(0).f(); }
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(access_to_internal_function)
@ -917,7 +893,7 @@ BOOST_AUTO_TEST_CASE(access_to_internal_state_variable)
contract d {
function g() { c(0).a(); }
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(error_count_in_named_args)
@ -963,7 +939,7 @@ BOOST_AUTO_TEST_CASE(empty_name_input_parameter)
function f(uint){
}
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(empty_name_return_parameter)
@ -973,7 +949,7 @@ BOOST_AUTO_TEST_CASE(empty_name_return_parameter)
function f() returns(bool){
}
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one)
@ -984,7 +960,7 @@ BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one)
return k;
}
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(empty_name_return_parameter_with_named_one)
@ -1014,7 +990,8 @@ BOOST_AUTO_TEST_CASE(overflow_caused_by_ether_units)
}
uint256 a;
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCodeFine));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCodeFine),
"Parsing and Resolving names failed");
char const* sourceCode = R"(
contract c {
function c ()
@ -1056,7 +1033,7 @@ BOOST_AUTO_TEST_CASE(enum_member_access)
ActionChoices choices;
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(enum_invalid_member_access)
@ -1088,7 +1065,7 @@ BOOST_AUTO_TEST_CASE(enum_explicit_conversion_is_okay)
uint64 b;
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(int_to_enum_explicit_conversion_is_okay)
@ -1105,7 +1082,7 @@ BOOST_AUTO_TEST_CASE(int_to_enum_explicit_conversion_is_okay)
ActionChoices b;
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(enum_implicit_conversion_is_not_okay)
@ -1225,7 +1202,7 @@ BOOST_AUTO_TEST_CASE(test_for_bug_override_function_with_bytearray_type)
function f(bytes _a) external returns (uint256 r) {r = 42;}
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(sourceCode));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode), "Parsing and Name Resolving failed");
}
BOOST_AUTO_TEST_CASE(array_with_nonconstant_length)
@ -1267,7 +1244,7 @@ BOOST_AUTO_TEST_CASE(array_copy_with_different_types_conversion_possible)
uint8[] b;
function f() { a = b; }
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types_static_dynamic)
@ -1278,7 +1255,7 @@ BOOST_AUTO_TEST_CASE(array_copy_with_different_types_static_dynamic)
uint8[80] b;
function f() { a = b; }
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
ETH_TEST_CHECK_NO_THROW(parseTextAndResolveNames(text), "Parsing and Name Resolving Failed");
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types_dynamic_static)

12
test/SolidityNatspecJSON.cpp

@ -20,7 +20,7 @@
* Unit tests for the solidity compiler JSON Interface output.
*/
#include <boost/test/unit_test.hpp>
#include "TestHelper.h"
#include <json/json.h>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/Exceptions.h>
@ -43,15 +43,7 @@ public:
bool _userDocumentation)
{
std::string generatedDocumentationString;
try
{
m_compilerStack.parse(_code);
}
catch(boost::exception const& _e)
{
auto msg = std::string("Parsing contract failed with: ") + boost::diagnostic_information(_e);
BOOST_FAIL(msg);
}
ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parse(_code), "Parsing failed");
if (_userDocumentation)
generatedDocumentationString = m_compilerStack.getMetadata("", DocumentationType::NatspecUser);

146
test/SolidityParser.cpp

@ -26,7 +26,7 @@
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/Exceptions.h>
#include <boost/test/unit_test.hpp>
#include "TestHelper.h"
using namespace std;
@ -50,22 +50,6 @@ ASTPointer<ContractDefinition> parseText(std::string const& _source)
return ASTPointer<ContractDefinition>();
}
ASTPointer<ContractDefinition> parseTextExplainError(std::string const& _source)
{
try
{
return parseText(_source);
}
catch (Exception const& exception)
{
// LTODO: Print the error in a kind of a better way?
// In absence of CompilerStack we can't use SourceReferenceFormatter
cout << "Exception while parsing: " << diagnostic_information(exception);
// rethrow to signal test failure
throw exception;
}
}
static void checkFunctionNatspec(ASTPointer<FunctionDefinition> _function,
std::string const& _expectedDoc)
{
@ -84,7 +68,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
char const* text = "contract test {\n"
" uint256 stateVariable1;\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
}
BOOST_AUTO_TEST_CASE(missing_variable_name_in_declaration)
@ -103,7 +87,7 @@ BOOST_AUTO_TEST_CASE(empty_function)
" returns (int id)\n"
" { }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
}
BOOST_AUTO_TEST_CASE(no_function_params)
@ -112,7 +96,7 @@ BOOST_AUTO_TEST_CASE(no_function_params)
" uint256 stateVar;\n"
" function functionName() {}\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
}
BOOST_AUTO_TEST_CASE(single_function_param)
@ -121,7 +105,7 @@ BOOST_AUTO_TEST_CASE(single_function_param)
" uint256 stateVar;\n"
" function functionName(hash hashin) returns (hash hashout) {}\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed.");
}
BOOST_AUTO_TEST_CASE(missing_parameter_name_in_named_args)
@ -151,9 +135,9 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation)
" /// This is a test function\n"
" function functionName(hash hashin) returns (hash hashout) {}\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
checkFunctionNatspec(function, "This is a test function");
}
@ -166,9 +150,9 @@ BOOST_AUTO_TEST_CASE(function_normal_comments)
" // We won't see this comment\n"
" function functionName(hash hashin) returns (hash hashout) {}\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr,
"Should not have gotten a Natspecc comment for this function");
}
@ -188,20 +172,20 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation)
" /// This is test function 4\n"
" function functionName4(hash hashin) returns (hash hashout) {}\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
checkFunctionNatspec(function, "This is test function 1");
BOOST_REQUIRE_NO_THROW(function = functions.at(1));
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(1), "Failed to retrieve function");
checkFunctionNatspec(function, "This is test function 2");
BOOST_REQUIRE_NO_THROW(function = functions.at(2));
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(2), "Failed to retrieve function");
BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr,
"Should not have gotten natspec comment for functionName3()");
BOOST_REQUIRE_NO_THROW(function = functions.at(3));
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(3), "Failed to retrieve function");
checkFunctionNatspec(function, "This is test function 4");
}
@ -215,10 +199,10 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation)
" /// and it has 2 lines\n"
" function functionName1(hash hashin) returns (hash hashout) {}\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
checkFunctionNatspec(function, "This is a test function\n"
" and it has 2 lines");
}
@ -240,13 +224,13 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body)
" /// and it has 2 lines\n"
" function fun(hash hashin) returns (hash hashout) {}\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
checkFunctionNatspec(function, "fun1 description");
BOOST_REQUIRE_NO_THROW(function = functions.at(1));
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(1), "Failed to retrieve function");
checkFunctionNatspec(function, "This is a test function\n"
" and it has 2 lines");
}
@ -266,10 +250,10 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature)
" string name = \"Solidity\";"
" }\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
BOOST_CHECK_MESSAGE(!function->getDocumentation(),
"Shouldn't get natspec docstring for this function");
}
@ -289,10 +273,10 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature)
" string name = \"Solidity\";"
" }\n"
"}\n";
BOOST_REQUIRE_NO_THROW(contract = parseText(text));
ETH_TEST_REQUIRE_NO_THROW(contract = parseText(text), "Parsing failed");
auto functions = contract->getDefinedFunctions();
BOOST_REQUIRE_NO_THROW(function = functions.at(0));
ETH_TEST_REQUIRE_NO_THROW(function = functions.at(0), "Failed to retrieve function");
BOOST_CHECK_MESSAGE(!function->getDocumentation(),
"Shouldn't get natspec docstring for this function");
}
@ -306,7 +290,7 @@ BOOST_AUTO_TEST_CASE(struct_definition)
" uint256 count;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(mapping)
@ -314,7 +298,7 @@ BOOST_AUTO_TEST_CASE(mapping)
char const* text = "contract test {\n"
" mapping(address => string) names;\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(mapping_in_struct)
@ -326,7 +310,7 @@ BOOST_AUTO_TEST_CASE(mapping_in_struct)
" mapping(hash => test_struct) self_reference;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(mapping_to_mapping_in_struct)
@ -337,7 +321,7 @@ BOOST_AUTO_TEST_CASE(mapping_to_mapping_in_struct)
" mapping (uint64 => mapping (hash => uint)) complex_mapping;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(variable_definition)
@ -350,7 +334,7 @@ BOOST_AUTO_TEST_CASE(variable_definition)
" customtype varname;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(variable_definition_with_initialization)
@ -364,7 +348,7 @@ BOOST_AUTO_TEST_CASE(variable_definition_with_initialization)
" customtype varname;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(variable_definition_in_function_parameter)
@ -408,7 +392,7 @@ BOOST_AUTO_TEST_CASE(operator_expression)
" uint256 x = (1 + 4) || false && (1 - 12) + -9;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(complex_expression)
@ -418,7 +402,7 @@ BOOST_AUTO_TEST_CASE(complex_expression)
" uint256 x = (1 + 4).member(++67)[a/=9] || true;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(exp_expression)
@ -429,7 +413,7 @@ BOOST_AUTO_TEST_CASE(exp_expression)
uint256 x = 3 ** a;
}
})";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(while_loop)
@ -439,7 +423,7 @@ BOOST_AUTO_TEST_CASE(while_loop)
" while (true) { uint256 x = 1; break; continue; } x = 9;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(for_loop_vardef_initexpr)
@ -450,7 +434,7 @@ BOOST_AUTO_TEST_CASE(for_loop_vardef_initexpr)
" { uint256 x = i; break; continue; }\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextExplainError(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(for_loop_simple_initexpr)
@ -462,7 +446,7 @@ BOOST_AUTO_TEST_CASE(for_loop_simple_initexpr)
" { uint256 x = i; break; continue; }\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextExplainError(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(for_loop_simple_noexpr)
@ -474,7 +458,7 @@ BOOST_AUTO_TEST_CASE(for_loop_simple_noexpr)
" { uint256 x = i; break; continue; }\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextExplainError(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(for_loop_single_stmt_body)
@ -486,7 +470,7 @@ BOOST_AUTO_TEST_CASE(for_loop_single_stmt_body)
" continue;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextExplainError(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(if_statement)
@ -496,7 +480,7 @@ BOOST_AUTO_TEST_CASE(if_statement)
" if (a >= 8) return 2; else { var b = 7; }\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(else_if_statement)
@ -506,7 +490,7 @@ BOOST_AUTO_TEST_CASE(else_if_statement)
" if (a < 0) b = 0x67; else if (a == 0) b = 0x12; else b = 0x78;\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion)
@ -518,7 +502,7 @@ BOOST_AUTO_TEST_CASE(statement_starting_with_type_conversion)
" uint64[](3);\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(type_conversion_to_dynamic_array)
@ -528,7 +512,7 @@ BOOST_AUTO_TEST_CASE(type_conversion_to_dynamic_array)
" var x = uint64[](3);\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(import_directive)
@ -539,7 +523,7 @@ BOOST_AUTO_TEST_CASE(import_directive)
" uint64(2);\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(multiple_contracts)
@ -554,7 +538,7 @@ BOOST_AUTO_TEST_CASE(multiple_contracts)
" uint64(2);\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(multiple_contracts_and_imports)
@ -572,7 +556,7 @@ BOOST_AUTO_TEST_CASE(multiple_contracts_and_imports)
" }\n"
"}\n"
"import \"ghi\";\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(contract_inheritance)
@ -587,7 +571,7 @@ BOOST_AUTO_TEST_CASE(contract_inheritance)
" uint64(2);\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(contract_multiple_inheritance)
@ -602,7 +586,7 @@ BOOST_AUTO_TEST_CASE(contract_multiple_inheritance)
" uint64(2);\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(contract_multiple_inheritance_with_arguments)
@ -617,7 +601,7 @@ BOOST_AUTO_TEST_CASE(contract_multiple_inheritance_with_arguments)
" uint64(2);\n"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(placeholder_in_function_context)
@ -628,7 +612,7 @@ BOOST_AUTO_TEST_CASE(placeholder_in_function_context)
" return _ + 1;"
" }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(modifier)
@ -636,7 +620,7 @@ BOOST_AUTO_TEST_CASE(modifier)
char const* text = "contract c {\n"
" modifier mod { if (msg.sender == 0) _ }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(modifier_arguments)
@ -644,7 +628,7 @@ BOOST_AUTO_TEST_CASE(modifier_arguments)
char const* text = "contract c {\n"
" modifier mod(uint a) { if (msg.sender == a) _ }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(modifier_invocation)
@ -654,7 +638,7 @@ BOOST_AUTO_TEST_CASE(modifier_invocation)
" modifier mod2 { if (msg.sender == 2) _ }\n"
" function f() mod1(7) mod2 { }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(fallback_function)
@ -662,7 +646,7 @@ BOOST_AUTO_TEST_CASE(fallback_function)
char const* text = "contract c {\n"
" function() { }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(event)
@ -671,7 +655,7 @@ BOOST_AUTO_TEST_CASE(event)
contract c {
event e();
})";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(event_arguments)
@ -680,7 +664,7 @@ BOOST_AUTO_TEST_CASE(event_arguments)
contract c {
event e(uint a, string32 s);
})";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(event_arguments_indexed)
@ -689,7 +673,7 @@ BOOST_AUTO_TEST_CASE(event_arguments_indexed)
contract c {
event e(uint a, string32 indexed s, bool indexed b);
})";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(visibility_specifiers)
@ -705,7 +689,7 @@ BOOST_AUTO_TEST_CASE(visibility_specifiers)
function f_public() public {}
function f_internal() internal {}
})";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers)
@ -733,7 +717,7 @@ BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations)
uint256 c;
uint256 d;
})";
BOOST_CHECK_NO_THROW(parseTextExplainError(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations_in_expressions)
@ -746,7 +730,7 @@ BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations_in_expression
}
uint256 a;
})";
BOOST_CHECK_NO_THROW(parseTextExplainError(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(enum_valid_declaration)
@ -760,7 +744,7 @@ BOOST_AUTO_TEST_CASE(enum_valid_declaration)
}
uint256 a;
})";
BOOST_CHECK_NO_THROW(parseTextExplainError(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(empty_enum_declaration)
@ -769,7 +753,7 @@ BOOST_AUTO_TEST_CASE(empty_enum_declaration)
contract c {
enum foo { }
})";
BOOST_CHECK_NO_THROW(parseTextExplainError(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(malformed_enum_declaration)
@ -787,7 +771,7 @@ BOOST_AUTO_TEST_CASE(external_function)
contract c {
function x() external {}
})";
BOOST_CHECK_NO_THROW(parseTextExplainError(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(external_variable)
@ -808,7 +792,7 @@ BOOST_AUTO_TEST_CASE(arrays_in_storage)
struct x { uint[2**20] b; y[0] c; }
struct y { uint d; mapping(uint=>x)[] e; }
})";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(arrays_in_events)
@ -817,7 +801,7 @@ BOOST_AUTO_TEST_CASE(arrays_in_events)
contract c {
event e(uint[10] a, string7[8] indexed b, c[3] x);
})";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(arrays_in_expressions)
@ -826,7 +810,7 @@ BOOST_AUTO_TEST_CASE(arrays_in_expressions)
contract c {
function f() { c[10] a = 7; uint8[10 * 2] x; }
})";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_CASE(multi_arrays)
@ -835,7 +819,7 @@ BOOST_AUTO_TEST_CASE(multi_arrays)
contract c {
mapping(uint => mapping(uint => int8)[8][][9])[] x;
})";
BOOST_CHECK_NO_THROW(parseText(text));
ETH_TEST_CHECK_NO_THROW(parseText(text), "Parsing failed");
}
BOOST_AUTO_TEST_SUITE_END()

53
test/TestHelper.h

@ -44,6 +44,59 @@ void connectClients(Client& c1, Client& c2);
namespace test
{
/// Make sure that no Exception is thrown during testing. If one is thrown show its info and fail the test.
/// Our version of BOOST_REQUIRE_NO_THROW()
/// @param _statenent The statement for which to make sure no exceptions are thrown
/// @param _message A message to act as a prefix to the expression's error information
#define ETH_TEST_REQUIRE_NO_THROW(_statement, _message) \
do \
{ \
try \
{ \
BOOST_TEST_PASSPOINT(); \
_statement; \
} \
catch (boost::exception const& _e) \
{ \
auto msg = std::string(_message " due to an exception thrown by " \
BOOST_STRINGIZE(_statement) "\n") + boost::diagnostic_information(_e); \
BOOST_CHECK_IMPL(false, msg, REQUIRE, CHECK_MSG); \
} \
catch (...) \
{ \
BOOST_CHECK_IMPL(false, "Unknown exception thrown by " \
BOOST_STRINGIZE(_statement), REQUIRE, CHECK_MSG); \
} \
} \
while (0)
/// Check if an Exception is thrown during testing. If one is thrown show its info and continue the test
/// Our version of BOOST_CHECK_NO_THROW()
/// @param _statement The statement for which to make sure no exceptions are thrown
/// @param _message A message to act as a prefix to the expression's error information
#define ETH_TEST_CHECK_NO_THROW(_statement, _message) \
do \
{ \
try \
{ \
BOOST_TEST_PASSPOINT(); \
_statement; \
} \
catch (boost::exception const& _e) \
{ \
auto msg = std::string(_message " due to an exception thrown by " \
BOOST_STRINGIZE(_statement) "\n") + boost::diagnostic_information(_e); \
BOOST_CHECK_IMPL(false, msg, CHECK, CHECK_MSG); \
} \
catch (...) \
{ \
BOOST_CHECK_IMPL(false, "Unknown exception thrown by " \
BOOST_STRINGIZE(_statement), CHECK, CHECK_MSG ); \
} \
} \
while (0)
class ImportTest
{
public:

13
test/blockchain.cpp

@ -87,6 +87,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
// get txs
TransactionQueue txs;
TrivialGasPricer gp;
BOOST_REQUIRE(blObj.count("transactions"));
for (auto const& txObj: blObj["transactions"].get_array())
{
@ -131,7 +132,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
try
{
state.sync(bc);
state.sync(bc,txs);
state.sync(bc, txs, gp);
state.commitToMine(bc);
MineInfo info;
for (info.completed = false; !info.completed; info = state.mine()) {}
@ -281,7 +282,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
BlockInfo blockHeaderFromFields;
const bytes c_rlpBytesBlockHeader = createBlockRLPFromFields(tObj);
const RLP c_blockHeaderRLP(c_rlpBytesBlockHeader);
blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, false);
blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, IgnoreNonce);
BlockInfo blockFromRlp = bc.info();
@ -381,7 +382,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
BlockInfo uncleBlockHeader;
try
{
uncleBlockHeader.populateFromHeader(c_uRLP, true);
uncleBlockHeader.populateFromHeader(c_uRLP);
}
catch(...)
{
@ -395,7 +396,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
for (auto const& uRLP: root[2])
{
BlockInfo uBl;
uBl.populateFromHeader(uRLP, true);
uBl.populateFromHeader(uRLP);
uBlHsFromRlp.push_back(uBl);
}
@ -538,7 +539,7 @@ void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj)
// take the blockheader as is
const bytes c_blockRLP = createBlockRLPFromFields(_blObj["blockHeader"].get_obj());
const RLP c_bRLP(c_blockRLP);
_current_BlockHeader.populateFromHeader(c_bRLP, false);
_current_BlockHeader.populateFromHeader(c_bRLP, IgnoreNonce);
}
}
@ -551,7 +552,7 @@ BlockInfo constructBlock(mObject& _o)
// construct genesis block
const bytes c_blockRLP = createBlockRLPFromFields(_o);
const RLP c_bRLP(c_blockRLP);
ret.populateFromHeader(c_bRLP, false);
ret.populateFromHeader(c_bRLP, IgnoreNonce);
}
catch (Exception const& _e)
{

2
test/dagger.cpp

@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(basic_test)
cnote << i.first;
js::mObject& o = i.second.get_obj();
vector<pair<string, string>> ss;
BlockInfo header = BlockInfo::fromHeader(fromHex(o["header"].get_str()));
BlockInfo header = BlockInfo::fromHeader(fromHex(o["header"].get_str()), CheckNothing);
h256 headerHash(o["header_hash"].get_str());
Nonce nonce(o["nonce"].get_str());
BOOST_REQUIRE_EQUAL(headerHash, header.headerHash(WithoutNonce));

16
test/solidityExecutionFramework.h

@ -25,7 +25,7 @@
#include <string>
#include <tuple>
#include <boost/test/unit_test.hpp>
#include "TestHelper.h"
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include <libsolidity/CompilerStack.h>
@ -46,16 +46,8 @@ public:
bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "")
{
dev::solidity::CompilerStack compiler(m_addStandardSources);
try
{
compiler.addSource("", _sourceCode);
compiler.compile(m_optimize);
}
catch(boost::exception const& _e)
{
auto msg = std::string("Compiling contract failed with: ") + boost::diagnostic_information(_e);
BOOST_FAIL(msg);
}
compiler.addSource("", _sourceCode);
ETH_TEST_REQUIRE_NO_THROW(compiler.compile(m_optimize), "Compiling contract failed");
bytes code = compiler.getBytecode(_contractName);
sendMessage(code, true, _value);
@ -178,7 +170,7 @@ protected:
Address m_contractAddress;
eth::State m_state;
u256 const m_gasPrice = 100 * eth::szabo;
u256 const m_gas = 1000000;
u256 const m_gas = 100000000;
bytes m_output;
eth::LogEntries m_logs;
};

176
test/stTransactionTestFiller.json

@ -30,6 +30,37 @@
}
},
"EmptyTransaction2" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "1000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000",
"code" : "",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "",
"gasLimit" : "22000",
"gasPrice" : "",
"nonce" : "",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "",
"value" : ""
}
},
"TransactionSendingToEmpty" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
@ -236,6 +267,100 @@
}
},
"InternalCallHittingGasLimit2" : {
"env" : {
"currentCoinbase" : "2adf5374fce5edbc8e2a8697c15331677e6ebf0b",
"currentDifficulty" : "45678256",
"currentGasLimit" : "47766",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000",
"code" : "",
"nonce" : "0",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0",
"code" : "{ (CALL 25000 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b 1 0 0 0 0) }",
"nonce" : "0",
"storage" : {
}
},
"c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0",
"code" : "{[[1]]55}",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "",
"gasLimit" : "47766",
"gasPrice" : "1",
"nonce" : "",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
}
},
"InternalCallHittingGasLimitSuccess" : {
"env" : {
"currentCoinbase" : "2adf5374fce5edbc8e2a8697c15331677e6ebf0b",
"currentDifficulty" : "45678256",
"currentGasLimit" : "220000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000000",
"code" : "",
"nonce" : "0",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0",
"code" : "{ (CALL 25000 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b 1 0 0 0 0) }",
"nonce" : "0",
"storage" : {
}
},
"c94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0",
"code" : "{[[1]]55}",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "",
"gasLimit" : "150000",
"gasPrice" : "1",
"nonce" : "",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10"
}
},
"TransactionFromCoinbaseHittingBlockGasLimit" : {
"env" : {
"currentCoinbase" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
@ -584,7 +709,7 @@
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000",
"balance" : "1000000",
"code" : "",
"nonce" : "0",
"storage" : {
@ -811,7 +936,7 @@
}
},
"TransactionCosts555" : {
"TransactionDataCosts652" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
@ -916,7 +1041,7 @@
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "33000",
"balance" : "133000",
"code" : "",
"nonce" : "0",
"storage" : {
@ -927,7 +1052,7 @@
{
"data" : "0x3240349548983454",
"gasLimit" : "32600",
"gasPrice" : "1",
"gasPrice" : "0",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
@ -1089,7 +1214,7 @@
"transaction" :
{
"data" : "0x602280600c6000396000f30060e060020a600035048063f8a8fd6d14601457005b601a6020565b60006000f35b56",
"gasLimit" : "25000",
"gasLimit" : "23679",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
@ -1098,7 +1223,7 @@
}
},
"CreateTransactionWorking" : {
"CreateTransactionSuccess" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
@ -1166,5 +1291,44 @@
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "100"
}
},
"CreateMessageSuccess" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "1000000000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "400000",
"code" : "",
"nonce" : "0",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0",
"code" : "{(MSTORE 0 0x600c600055) (CREATE 0 27 5)}",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"data" : "",
"gasLimit" : "131882",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "100"
}
}
}

196
test/vmArithmeticTestFiller.json

@ -3535,7 +3535,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3555,7 +3555,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3563,7 +3563,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3583,7 +3583,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3591,7 +3591,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3611,7 +3611,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3619,7 +3619,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3639,7 +3639,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3647,7 +3647,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3667,7 +3667,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3675,7 +3675,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3695,7 +3695,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3703,7 +3703,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3723,7 +3723,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3731,7 +3731,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3751,7 +3751,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3759,7 +3759,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "100000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3779,7 +3779,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "10000000"
}
},
@ -3787,7 +3787,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3807,7 +3807,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3815,7 +3815,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3835,7 +3835,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3843,7 +3843,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3863,7 +3863,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3871,7 +3871,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3891,7 +3891,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3899,7 +3899,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3919,7 +3919,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3927,7 +3927,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3947,7 +3947,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3955,7 +3955,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -3975,7 +3975,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -3983,7 +3983,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4003,7 +4003,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4011,7 +4011,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4031,7 +4031,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4039,7 +4039,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4059,7 +4059,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4067,7 +4067,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4087,7 +4087,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4095,7 +4095,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4115,7 +4115,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4123,7 +4123,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4143,7 +4143,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4151,7 +4151,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4171,7 +4171,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4179,7 +4179,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4199,7 +4199,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4207,7 +4207,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4227,7 +4227,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4235,7 +4235,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4255,7 +4255,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4263,7 +4263,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4283,7 +4283,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4291,7 +4291,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4311,7 +4311,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4319,7 +4319,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4339,7 +4339,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4347,7 +4347,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4367,7 +4367,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4375,7 +4375,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4395,7 +4395,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4403,7 +4403,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4423,7 +4423,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4431,7 +4431,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4451,7 +4451,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4459,7 +4459,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4479,7 +4479,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4487,7 +4487,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4507,7 +4507,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4515,7 +4515,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4535,7 +4535,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4543,7 +4543,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4563,7 +4563,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4571,7 +4571,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4591,7 +4591,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4599,7 +4599,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4619,7 +4619,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4627,7 +4627,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4647,7 +4647,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4655,7 +4655,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4675,7 +4675,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4683,7 +4683,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4703,7 +4703,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4711,7 +4711,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4731,7 +4731,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4739,7 +4739,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4759,7 +4759,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4767,7 +4767,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4787,7 +4787,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4795,7 +4795,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4815,7 +4815,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4823,7 +4823,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4843,7 +4843,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4851,7 +4851,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4871,7 +4871,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
},
@ -4879,7 +4879,7 @@
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentGasLimit" : "10000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
@ -4899,7 +4899,7 @@
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "100000"
"gas" : "1000000"
}
}
}

Loading…
Cancel
Save