Browse Source

Merge remote-tracking branch 'up/develop' into deploydialog

cl-refactor
yann300 10 years ago
parent
commit
930abbeb11
  1. 2
      alethzero/CMakeLists.txt
  2. 215
      alethzero/DownloadView.cpp
  3. 5
      alethzero/DownloadView.h
  4. 28
      cmake/Findv8.cmake
  5. 15
      eth/main.cpp
  6. 2
      ethconsole/CMakeLists.txt
  7. 4
      ethminer/CMakeLists.txt
  8. 48
      ethminer/MinerAux.h
  9. 12
      exp/CMakeLists.txt
  10. 1
      extdep/getstuff.bat
  11. 3
      libdevcore/Common.h
  12. 2
      libdevcore/FixedHash.h
  13. 2
      libdevcore/Guards.h
  14. 16
      libethash-cl/ethash_cl_miner.cpp
  15. 15
      libethash-cl/ethash_cl_miner.h
  16. 12
      libethcore/Common.h
  17. 5
      libethcore/Ethash.cpp
  18. 10
      libethcore/Ethash.h
  19. 52
      libethereum/BlockChain.cpp
  20. 3
      libethereum/BlockChain.h
  21. 12
      libethereum/BlockChainSync.cpp
  22. 6
      libethereum/BlockChainSync.h
  23. 5
      libethereum/Client.cpp
  24. 25
      libethereum/EthereumHost.cpp
  25. 1
      libethereum/EthereumHost.h
  26. 2
      libethereum/State.cpp
  27. 21
      libethereum/TransactionQueue.cpp
  28. 61
      libethereum/TransactionQueue.h
  29. 8
      libjsconsole/CMakeLists.txt
  30. 31
      libjsconsole/JSConsole.h
  31. 2
      libjsengine/CMakeLists.txt
  32. 4
      libjsengine/JSEngine.h
  33. 17
      libjsengine/JSV8Engine.cpp
  34. 1
      libjsengine/JSV8Engine.h
  35. 1
      libjsengine/JSV8Printer.cpp
  36. 26
      libjsengine/PrettyPrint.js
  37. 138
      libsolidity/CompilerUtils.cpp
  38. 7
      libsolidity/CompilerUtils.h
  39. 13
      libsolidity/ExpressionCompiler.cpp
  40. 2
      libsolidity/LValue.cpp
  41. 41
      libsolidity/Types.cpp
  42. 36
      libsolidity/Types.h
  43. 39
      libsolidity/Version.cpp
  44. 36
      libsolidity/Version.h
  45. 4
      libwhisper/BloomFilter.h
  46. 4
      libwhisper/Message.cpp
  47. 1
      libwhisper/Message.h
  48. 2
      mix/CMakeLists.txt
  49. 3
      mix/CodeModel.cpp
  50. 3
      mix/MixClient.cpp
  51. 10
      solc/CommandLineInterface.cpp
  52. 1
      test/TestHelper.h
  53. 133
      test/fuzzTesting/fuzzHelper.cpp
  54. 268
      test/libdevcore/rlp.cpp
  55. 29
      test/libethereum/BlockchainTestsFiller/bcWalletTestFiller.json
  56. 193
      test/libethereum/StateTestsFiller/stWalletTestFiller.json
  57. 45
      test/libsolidity/SolidityEndToEndTest.cpp
  58. 15
      test/libsolidity/SolidityNameAndTypeResolution.cpp
  59. 6
      test/libsolidity/solidityExecutionFramework.h

2
alethzero/CMakeLists.txt

@ -7,7 +7,7 @@ if (${CMAKE_MAJOR_VERSION} GREATER 2)
cmake_policy(SET CMP0043 OLD)
endif()
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "3.6") AND NOT APPLE)
# Supress warnings for qt headers for clang+ccache
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-inconsistent-missing-override")
endif ()

215
alethzero/DownloadView.cpp

@ -36,10 +36,12 @@ SyncView::SyncView(QWidget* _p): QWidget(_p)
void SyncView::paintEvent(QPaintEvent*)
{
QPainter p(this);
p.fillRect(rect(), Qt::white);
QPainter painter(this);
painter.fillRect(rect(), Qt::white);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setRenderHint(QPainter::HighQualityAntialiasing, true);
if (!m_client)
if (!m_client || !isVisible() || !rect().width() || !rect().height())
return;
DownloadMan const* man = m_client->downloadMan();
@ -55,31 +57,52 @@ void SyncView::paintEvent(QPaintEvent*)
unsigned syncCount = syncUnverified + bqs.unknown - syncFrom;
// best effort guess. assumes there's no forks.
unsigned downloadFrom = m_client->numberFromHash(m_client->isKnown(man->firstBlock()) ? man->firstBlock() : PendingBlockHash);
unsigned downloadCount = sync.blocksTotal;
DownloadMan::Overview overview = man->overview();
unsigned downloadDone = downloadFrom + overview.total;
unsigned downloadFlank = downloadFrom + overview.firstIncomplete;
unsigned downloadPoint = downloadFrom + overview.lastComplete;
unsigned downloadFrom = sync.state == SyncState::Idle ? m_lastSyncFrom : m_client->numberFromHash(m_client->isKnown(man->firstBlock()) ? man->firstBlock() : PendingBlockHash);
unsigned downloadCount = sync.state == SyncState::Idle ? m_lastSyncCount : sync.blocksTotal;
unsigned downloadDone = downloadFrom + (sync.state == SyncState::Idle ? m_lastSyncCount : sync.blocksReceived);
unsigned downloadPoint = downloadFrom + (sync.state == SyncState::Idle ? m_lastSyncCount : man->overview().lastComplete);
unsigned hashFrom = sync.state == SyncState::Hashes ? m_client->numberFromHash(PendingBlockHash) : downloadFrom;
unsigned hashCount = sync.state == SyncState::Hashes ? sync.hashesTotal : downloadCount;
unsigned hashDone = hashFrom + (sync.state == SyncState::Hashes ? sync.hashesReceived : hashCount);
m_lastFrom = min(syncFrom, m_lastFrom);
m_lastTo = max(max(syncFrom + syncCount, hashFrom + hashCount), m_lastTo);
unsigned from = min(min(hashFrom, downloadFrom), min(syncFrom, m_lastFrom));
unsigned count = max(max(hashFrom + hashCount, downloadFrom + downloadCount), max(syncFrom + syncCount, m_lastTo)) - from;
m_lastFrom = (m_lastFrom * 99 + syncFrom * 1) / 100;
m_lastTo = (m_lastTo * 99 + max(syncFrom + syncCount, hashFrom + hashCount) * 1) / 100;
if (!count)
QString labelText = QString("PV%1").arg(sync.protocolVersion);
QColor labelBack = QColor::fromHsv(sync.protocolVersion == 60 ? 30 : sync.protocolVersion == 61 ? 120 : 240, 25, 200);
QColor labelFore = labelBack.darker();
switch (sync.state)
{
m_lastFrom = m_lastTo = (unsigned)-1;
return;
case SyncState::Hashes:
if (!syncCount || !sync.hashesEstimated)
{
m_lastSyncFrom = min(hashFrom, m_lastSyncFrom);
m_lastSyncCount = max(hashFrom + hashCount, m_lastSyncFrom + m_lastSyncCount) - m_lastSyncFrom;
m_wasEstimate = sync.hashesEstimated;
}
break;
case SyncState::Blocks:
if (m_wasEstimate)
{
m_lastSyncFrom = downloadFrom;
m_lastSyncCount = downloadCount;
m_wasEstimate = false;
}
break;
case SyncState::Idle:
if (!syncCount)
{
m_lastSyncFrom = (unsigned)-1;
m_lastSyncCount = 0;
labelBack = QColor::fromHsv(0, 0, 200);
labelFore = Qt::white;
labelText = "Idle";
}
default: break;
}
cnote << "Range " << from << "-" << (from + count) << "(" << hashFrom << "+" << hashCount << "," << downloadFrom << "+" << downloadCount << "," << syncFrom << "+" << syncCount << ")";
unsigned from = min(min(hashFrom, downloadFrom), min(syncFrom, m_lastSyncFrom));
unsigned count = max(max(hashFrom + hashCount, downloadFrom + downloadCount), max(syncFrom + syncCount, m_lastSyncFrom + m_lastSyncCount)) - from;
/* cnote << "Range " << from << "-" << (from + count) << "(" << hashFrom << "+" << hashCount << "," << downloadFrom << "+" << downloadCount << "," << syncFrom << "+" << syncCount << ")";
auto r = [&](unsigned u) {
return toString((u - from) * 100 / count) + "%";
};
@ -89,86 +112,94 @@ void SyncView::paintEvent(QPaintEvent*)
cnote << "Hashes:" << r(hashDone) << " Blocks:" << r(downloadFlank) << r(downloadDone) << r(downloadPoint);
cnote << "Importing:" << r(syncFrom) << r(syncImported) << r(syncImporting) << r(syncVerified) << r(syncVerifying) << r(syncUnverified);
}
float squareSize = min(rect().width(), rect().height());
QPen pen;
pen.setCapStyle(Qt::FlatCap);
pen.setWidthF(squareSize / 20);
*/
float const squareSize = min(rect().width(), rect().height());
auto middleRect = [&](float w, float h) {
return QRectF(rect().width() / 2 - w / 2, rect().height() / 2 - h / 2, w, h);
};
auto middle = [&](float x) {
return QRectF(squareSize / 2 - squareSize / 2 * x, 0 + squareSize / 2 - squareSize / 2 * x, squareSize * x, squareSize * x);
return middleRect(squareSize * x, squareSize * x);
};
auto arcLen = [&](unsigned x) {
return x * -5760.f / count;
auto pieProgress = [&](unsigned h, unsigned s, unsigned v, float row, float thickness, unsigned nfrom, unsigned ncount) {
auto arcLen = [&](unsigned x) {
return x * -5760.f / count;
};
auto arcPos = [&](unsigned x) {
return int(90 * 16.f + arcLen(x - from)) % 5760;
};
painter.setPen(QPen(QColor::fromHsv(h, s, v), squareSize * thickness, Qt::SolidLine, Qt::FlatCap));
painter.setBrush(Qt::NoBrush);
painter.drawArc(middle(0.5 + row / 2), arcPos(nfrom), arcLen(ncount));
};
auto arcPos = [&](unsigned x) {
return int(90 * 16.f + arcLen(x - from)) % 5760;
auto pieProgress2 = [&](unsigned h, unsigned s, unsigned v, float row, float orbit, float thickness, unsigned nfrom, unsigned ncount) {
pieProgress(h, s, v, row - orbit, thickness, nfrom, ncount);
pieProgress(h, s, v, row + orbit, thickness, nfrom, ncount);
};
p.setPen(Qt::NoPen);
p.setBrush(QColor::fromHsv(0, 0, 210));
pen.setWidthF(0.f);
p.drawPie(middle(0.4f), arcPos(from), arcLen(hashDone - from));
auto progress = [&](unsigned h, unsigned s, unsigned v, float size, float thickness, unsigned nfrom, unsigned ncount) {
p.setBrush(Qt::NoBrush);
pen.setColor(QColor::fromHsv(h, s, v));
pen.setWidthF(squareSize * thickness);
p.setPen(pen);
p.drawArc(middle(size), arcPos(nfrom), arcLen(ncount));
auto pieLabel = [&](QString text, float points, QColor fore, QColor back) {
painter.setBrush(QBrush(back));
painter.setFont(QFont("Helvetica", points, QFont::Bold));
QRectF r = painter.boundingRect(middle(1.f), Qt::AlignCenter, text);
r.adjust(-r.width() / 4, -r.height() / 8, r.width() / 4, r.height() / 8);
painter.setPen(QPen(fore, r.height() / 20));
painter.drawRoundedRect(r, r.height() / 4, r.height() / 4);
painter.drawText(r, Qt::AlignCenter, text);
};
progress(0, 50, 170, 0.4f, 0.12f, downloadFlank, downloadPoint - downloadFlank);
progress(0, 0, 150, 0.4f, 0.10f, from, downloadDone - from);
progress(0, 0, 230, 0.7f, 0.090f, from, syncUnverified - from);
progress(60, 25, 210, 0.7f, 0.08f, from, syncVerifying - from);
progress(120, 25, 190, 0.7f, 0.07f, from, syncVerified - from);
progress(0, 0, 220, 0.9f, 0.02f, from, count);
progress(0, 0, 100, 0.9f, 0.04f, from, syncFrom - from);
progress(0, 50, 100, 0.9f, 0.08f, syncFrom, syncImporting - syncFrom);
return;
double ratio = (double)rect().width() / rect().height();
if (ratio < 1)
ratio = 1 / ratio;
double n = min(16.0, min(rect().width(), rect().height()) / ceil(sqrt(man->chainSize() / ratio)));
float lineHeight = painter.boundingRect(rect(), Qt::AlignTop | Qt::AlignHCenter, "Ay").height();
auto hProgress = [&](unsigned h, unsigned s, unsigned v, float row, float thickness, unsigned nfrom, unsigned ncount) {
QRectF r = rect();
painter.setPen(QPen(QColor::fromHsv(h, s, v), r.height() * thickness * 3, Qt::SolidLine, Qt::FlatCap));
painter.setBrush(Qt::NoBrush);
auto y = row * (r.height() - lineHeight) + lineHeight;
painter.drawLine(QPointF((nfrom - from) * r.width() / count, y), QPointF((nfrom + ncount - from) * r.width() / count, y));
};
auto hProgress2 = [&](unsigned h, unsigned s, unsigned v, float row, float orbit, float thickness, unsigned nfrom, unsigned ncount) {
hProgress(h, s, v, row - orbit * 3, thickness, nfrom, ncount);
hProgress(h, s, v, row + orbit * 3, thickness, nfrom, ncount);
};
auto hLabel = [&](QString text, float points, QColor fore, QColor back) {
painter.setBrush(QBrush(back));
painter.setFont(QFont("Helvetica", points, QFont::Bold));
QRectF r = painter.boundingRect(rect(), Qt::AlignTop | Qt::AlignHCenter, text);
r.adjust(-r.width() / 4, r.height() / 8, r.width() / 4, 3 * r.height() / 8);
painter.setPen(QPen(fore, r.height() / 20));
painter.drawRoundedRect(r, r.height() / 4, r.height() / 4);
painter.drawText(r, Qt::AlignCenter, text);
};
// QSizeF area(rect().width() / floor(rect().width() / n), rect().height() / floor(rect().height() / n));
QSizeF area(n, n);
QPointF pos(0, 0);
function<void(unsigned h, unsigned s, unsigned v, float row, float thickness, unsigned nfrom, unsigned ncount)> progress;
function<void(unsigned h, unsigned s, unsigned v, float row, float orbit, float thickness, unsigned nfrom, unsigned ncount)> progress2;
function<void(QString text, float points, QColor fore, QColor back)> label;
if (rect().width() / rect().height() > 5)
{
progress = hProgress;
progress2 = hProgress2;
label = hLabel;
}
else if (rect().height() / rect().width() > 5)
{
}
else
{
progress = pieProgress;
progress2 = pieProgress2;
label = pieLabel;
}
auto bg = man->blocksGot();
unsigned subCount = man->subCount();
if (subCount == 0)
return;
unsigned dh = 360 / subCount;
for (unsigned i = bg.all().first, ei = bg.all().second; i < ei; ++i)
if (sync.state != SyncState::Idle)
{
int s = -2;
if (bg.contains(i))
s = -1;
else
{
unsigned h = 0;
man->foreachSub([&](DownloadSub const& sub)
{
if (sub.askedContains(i))
s = h;
h++;
});
}
if (s == -2)
p.fillRect(QRectF(QPointF(pos) + QPointF(3 * area.width() / 8, 3 * area.height() / 8), area / 4), Qt::black);
else if (s == -1)
p.fillRect(QRectF(QPointF(pos) + QPointF(1 * area.width() / 8, 1 * area.height() / 8), area * 3 / 4), Qt::black);
else
p.fillRect(QRectF(QPointF(pos) + QPointF(1 * area.width() / 8, 1 * area.height() / 8), area * 3 / 4), QColor::fromHsv(s * dh, 64, 128));
pos.setX(pos.x() + n);
if (pos.x() >= rect().width() - n)
pos = QPoint(0, pos.y() + n);
progress(0, 0, 220, 0.4f, 0.02f, from, hashDone - from); // Download rail
progress(240, 25, 170, 0.4f, 0.02f, downloadDone, downloadPoint - downloadDone); // Latest download point
progress(240, 50, 120, 0.4f, 0.04f, from, downloadDone - from); // Downloaded
}
progress(0, 0, 220, 0.8f, 0.01f, from, count); // Sync rail
progress(0, 0, 170, 0.8f, 0.02f, from, syncUnverified - from); // Verification rail
progress2(60, 25, 170, 0.8f, 0.06f, 0.005f, from, syncVerifying - from); // Verifying.
progress2(120, 25, 170, 0.8f, 0.06f, 0.005f, from, syncVerified - from); // Verified.
progress(120, 50, 120, 0.8f, 0.05f, from, syncFrom - from); // Imported.
progress(0, 0, 120, 0.8f, 0.02f, syncFrom, syncImporting - syncFrom); // Importing.
if (sync.state != SyncState::Idle || (sync.state == SyncState::Idle && !syncCount))
label(labelText, 11, labelFore, labelBack);
}

5
alethzero/DownloadView.h

@ -50,6 +50,7 @@ protected:
private:
dev::eth::Client const* m_client = nullptr;
unsigned m_lastFrom = (unsigned)-1;
unsigned m_lastTo = (unsigned)-1;
unsigned m_lastSyncFrom = (unsigned)-1;
unsigned m_lastSyncCount = 0;
bool m_wasEstimate = false;
};

28
cmake/Findv8.cmake

@ -31,12 +31,32 @@ set(V8_LIBRARIES ${V8_LIBRARY})
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
find_library(
V8_LIBRARY_DEBUG
NAMES v8d
DOC "v8 debug library"
V8_LIBRARY
NAMES v8_base
DOC "v8 base library"
)
find_library(
V8_NO_SNAPSHOT_LIBRARY
NAMES v8_nosnapshot
DOC "v8 nosnapshot library"
)
set(V8_LIBRARIES optimized ${V8_LIBRARIES} debug ${V8_LIBRARY_DEBUG})
set(V8_LIBRARIES ${V8_LIBRARY} ${V8_NO_SNAPSHOT_LIBRARY})
find_library(
V8_LIBRARY_DEBUG
NAMES v8_based
DOC "v8 base library"
)
find_library(
V8_NO_SNAPSHOT_LIBRARY_DEBUG
NAMES v8_nosnapshotd
DOC "v8 nosnapshot library"
)
set(V8_LIBRARIES "ws2_32" "winmm" optimized ${V8_LIBRARIES} debug ${V8_LIBRARY_DEBUG} ${V8_NO_SNAPSHOT_LIBRARY_DEBUG})
endif()

15
eth/main.cpp

@ -75,12 +75,8 @@ void interactiveHelp()
<< "Commands:" << endl
<< " netstart <port> Starts the network subsystem on a specific port." << endl
<< " netstop Stops the network subsystem." << endl
<< " jsonstart <port> Starts the JSON-RPC server." << endl
<< " 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
<< " minestop Stops mining." << endl
<< " mineforce <enable> Forces mining, even when there are no transactions." << endl
@ -135,6 +131,7 @@ void help()
#endif
<< " -K,--kill First kill the blockchain." << endl
<< " -R,--rebuild Rebuild the blockchain from the existing database." << endl
<< " --rescue Attempt to rescue a corrupt database." << endl
<< " --genesis-nonce <nonce> Set the Genesis Nonce to the given hex nonce." << endl
<< " -s,--import-secret <secret> Import a secret key into the key store and use as the default." << endl
<< " -S,--import-session-secret <secret> Import a secret key into the key store and use as the default for this session only." << endl
@ -1087,7 +1084,7 @@ int main(int argc, char** argv)
#endif
string jsonAdmin;
bool upnp = true;
WithExisting killChain = WithExisting::Trust;
WithExisting withExisting = WithExisting::Trust;
bool jit = false;
string sentinel;
@ -1254,9 +1251,11 @@ int main(int argc, char** argv)
return -1;
}
else if (arg == "-K" || arg == "--kill-blockchain" || arg == "--kill")
killChain = WithExisting::Kill;
withExisting = WithExisting::Kill;
else if (arg == "-R" || arg == "--rebuild")
killChain = WithExisting::Verify;
withExisting = WithExisting::Verify;
else if (arg == "-R" || arg == "--rescue")
withExisting = WithExisting::Rescue;
else if ((arg == "-c" || arg == "--client-name") && i + 1 < argc)
{
if (arg == "-c")
@ -1534,7 +1533,7 @@ int main(int argc, char** argv)
dev::WebThreeDirect web3(
WebThreeDirect::composeClientVersion("++eth", clientName),
dbPath,
killChain,
withExisting,
nodeMode == NodeMode::Full ? set<string>{"eth"/*, "shh"*/} : set<string>(),
netPrefs,
&nodesState);

2
ethconsole/CMakeLists.txt

@ -13,9 +13,7 @@ set(EXECUTABLE ethconsole)
file(GLOB HEADERS "*.h")
add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES})
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)

4
ethminer/CMakeLists.txt

@ -9,6 +9,9 @@ if (JSONRPC)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
endif()
if (ETHASHCL)
include_directories(${OpenCL_INCLUDE_DIRS})
endif ()
set(EXECUTABLE ethminer)
@ -40,4 +43,3 @@ if (APPLE)
else()
eth_install_executable(${EXECUTABLE})
endif()

48
ethminer/MinerAux.h

@ -40,6 +40,9 @@
#include <libethcore/ProofOfWork.h>
#include <libethcore/EthashAux.h>
#include <libethcore/Farm.h>
#if ETH_ETHASHCL || !ETH_TRUE
#include <libethash-cl/ethash_cl_miner.h>
#endif
#if ETH_JSONRPC || !ETH_TRUE
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include <jsonrpccpp/server/connectors/httpserver.h>
@ -78,6 +81,12 @@ inline std::string credits()
}
class BadArgument: public Exception {};
struct MiningChannel: public LogChannel
{
static const char* name() { return EthGreen "miner"; }
static const int verbosity = 2;
};
#define minelog clog(MiningChannel)
class MinerCLI
{
@ -128,6 +137,7 @@ public:
cerr << "Bad " << arg << " option: " << argv[i] << endl;
BOOST_THROW_EXCEPTION(BadArgument());
}
#if ETH_ETHASHCL || !ETH_TRUE
else if (arg == "--cl-global-work" && i + 1 < argc)
try {
m_globalWorkSizeMultiplier = stol(argv[++i]);
@ -155,6 +165,7 @@ public:
cerr << "Bad " << arg << " option: " << argv[i] << endl;
BOOST_THROW_EXCEPTION(BadArgument());
}
#endif
else if (arg == "--list-devices")
m_shouldListDevices = true;
else if (arg == "--allow-opencl-cpu")
@ -292,6 +303,7 @@ public:
ProofOfWork::CPUMiner::setNumInstances(m_miningThreads);
else if (m_minerType == MinerType::GPU)
{
#if ETH_ETHASHCL || !ETH_TRUE
if (!ProofOfWork::GPUMiner::configureGPU(
m_localWorkSize,
m_globalWorkSizeMultiplier,
@ -304,6 +316,10 @@ public:
))
exit(1);
ProofOfWork::GPUMiner::setNumInstances(m_miningThreads);
#else
cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl;
exit(1);
#endif
}
if (mode == OperationMode::DAGInit)
doInitDAG(m_initDAG);
@ -344,10 +360,12 @@ public:
<< " --allow-opencl-cpu Allows CPU to be considered as an OpenCL device if the OpenCL platform supports it." << endl
<< " --list-devices List the detected OpenCL devices and exit." << endl
<< " --current-block Let the miner know the current block number at configuration time. Will help determine DAG size and required GPU memory." << endl
#if ETH_ETHASHCL || !ETH_TRUE
<< " --cl-extragpu-mem Set the memory (in MB) you believe your GPU requires for stuff other than mining. Windows rendering e.t.c.." << endl
<< " --cl-local-work Set the OpenCL local work size. Default is " << toString(dev::eth::Ethash::defaultLocalWorkSize) << endl
<< " --cl-global-work Set the OpenCL global work size as a multiple of the local work size. Default is " << toString(dev::eth::Ethash::defaultGlobalWorkSizeMultiplier) << " * " << toString(dev::eth::Ethash::defaultLocalWorkSize) << endl
<< " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(dev::eth::Ethash::defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl
<< " --cl-local-work Set the OpenCL local work size. Default is " << toString(ethash_cl_miner::c_defaultLocalWorkSize) << endl
<< " --cl-global-work Set the OpenCL global work size as a multiple of the local work size. Default is " << toString(ethash_cl_miner::c_defaultGlobalWorkSizeMultiplier) << " * " << toString(ethash_cl_miner::c_defaultLocalWorkSize) << endl
<< " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(ethash_cl_miner::c_defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl
#endif
;
}
@ -472,14 +490,14 @@ private:
for (unsigned i = 0; !completed; ++i)
{
if (current)
cnote << "Mining on PoWhash" << current.headerHash << ": " << f.miningProgress();
minelog << "Mining on PoWhash" << current.headerHash << ": " << f.miningProgress();
else
cnote << "Getting work package...";
minelog << "Getting work package...";
Json::Value v = rpc.eth_getWork();
h256 hh(v[0].asString());
h256 newSeedHash(v[1].asString());
if (current.seedHash != newSeedHash)
cnote << "Grabbing DAG for" << newSeedHash;
minelog << "Grabbing DAG for" << newSeedHash;
if (!(dag = EthashAux::full(newSeedHash, true, [&](unsigned _pc){ cout << "\rCreating DAG. " << _pc << "% done..." << flush; return 0; })))
BOOST_THROW_EXCEPTION(DAGCreationFailure());
if (m_precompute)
@ -489,10 +507,10 @@ private:
current.headerHash = hh;
current.seedHash = newSeedHash;
current.boundary = h256(fromHex(v[2].asString()), h256::AlignRight);
cnote << "Got work package:";
cnote << " Header-hash:" << current.headerHash.hex();
cnote << " Seedhash:" << current.seedHash.hex();
cnote << " Target: " << h256(current.boundary).hex();
minelog << "Got work package:";
minelog << " Header-hash:" << current.headerHash.hex();
minelog << " Seedhash:" << current.seedHash.hex();
minelog << " Target: " << h256(current.boundary).hex();
f.setWork(current);
}
this_thread::sleep_for(chrono::milliseconds(_recheckPeriod));
@ -536,10 +554,12 @@ private:
unsigned m_miningThreads = UINT_MAX;
bool m_shouldListDevices = false;
bool m_clAllowCPU = false;
unsigned m_globalWorkSizeMultiplier = dev::eth::Ethash::defaultGlobalWorkSizeMultiplier;
unsigned m_localWorkSize = dev::eth::Ethash::defaultLocalWorkSize;
unsigned m_msPerBatch = dev::eth::Ethash::defaultMSPerBatch;
boost::optional<uint64_t> m_currentBlock;
#if ETH_ETHASHCL || !ETH_TRUE
unsigned m_globalWorkSizeMultiplier = ethash_cl_miner::c_defaultGlobalWorkSizeMultiplier;
unsigned m_localWorkSize = ethash_cl_miner::c_defaultLocalWorkSize;
unsigned m_msPerBatch = ethash_cl_miner::c_defaultMSPerBatch;
#endif
uint64_t m_currentBlock = 0;
// default value is 350MB of GPU memory for other stuff (windows system rendering, e.t.c.)
unsigned m_extraGPUMemory = 350000000;

12
exp/CMakeLists.txt

@ -6,6 +6,9 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${DB_INCLUDE_DIRS})
if (ETHASHCL)
include_directories(${OpenCL_INCLUDE_DIRS})
endif ()
set(EXECUTABLE exp)
@ -27,11 +30,6 @@ target_link_libraries(${EXECUTABLE} p2p)
if (ETHASHCL)
target_link_libraries(${EXECUTABLE} ethash-cl)
target_link_libraries(${EXECUTABLE} ethash)
target_link_libraries(${EXECUTABLE} OpenCL)
target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES})
endif()
install( TARGETS ${EXECUTABLE} DESTINATION bin)
install( TARGETS ${EXECUTABLE} DESTINATION bin)

1
extdep/getstuff.bat

@ -14,6 +14,7 @@ call :download leveldb 1.2
call :download microhttpd 0.9.2
call :download qt 5.4.1
call :download miniupnpc 1.9
call :download v8 3.15.9
goto :EOF

3
libdevcore/Common.h

@ -189,7 +189,7 @@ private:
/// Scope guard for invariant check in a class derived from HasInvariants.
#if ETH_DEBUG
#define DEV_INVARIANT_CHECK { ::dev::InvariantChecker __dev_invariantCheck(this, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__); }
#define DEV_INVARIANT_CHECK ::dev::InvariantChecker __dev_invariantCheck(this, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__)
#else
#define DEV_INVARIANT_CHECK (void)0;
#endif
@ -240,6 +240,7 @@ enum class WithExisting: int
{
Trust = 0,
Verify,
Rescue,
Kill
};

2
libdevcore/FixedHash.h

@ -106,6 +106,8 @@ public:
FixedHash& operator&=(FixedHash const& _c) { for (unsigned i = 0; i < N; ++i) m_data[i] &= _c.m_data[i]; return *this; }
FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; }
FixedHash operator~() const { FixedHash ret; for (unsigned i = 0; i < N; ++i) ret[i] = ~m_data[i]; return ret; }
// Big-endian increment.
FixedHash& operator++() { for (unsigned i = size; i > 0 && !++m_data[--i]; ) {} return *this; }
/// @returns true if all one-bits in @a _c are set in this object.

2
libdevcore/Guards.h

@ -95,7 +95,7 @@ using SpinGuard = std::lock_guard<SpinLock>;
* Mutex m;
* int d;
* ...
* ETH_(m)
* ETH_GUARDED(m)
* {
* for (auto d = 50; d > 25; --d)
* foo(d);

16
libethash-cl/ethash_cl_miner.cpp

@ -33,7 +33,6 @@
#include <vector>
#include <libethash/util.h>
#include <libethash/ethash.h>
#include <libethcore/Ethash.h>
#include <libethash/internal.h>
#include "ethash_cl_miner.h"
#include "ethash_cl_miner_kernel.h"
@ -50,7 +49,10 @@
#undef max
using namespace std;
using namespace dev::eth;
unsigned const ethash_cl_miner::c_defaultLocalWorkSize = 64;
unsigned const ethash_cl_miner::c_defaultGlobalWorkSizeMultiplier = 4096; // * CL_DEFAULT_LOCAL_WORK_SIZE
unsigned const ethash_cl_miner::c_defaultMSPerBatch = 0;
// TODO: If at any point we can use libdevcore in here then we should switch to using a LogChannel
#define ETHCL_LOG(_contents) cout << "[OPENCL]:" << _contents << endl
@ -147,7 +149,7 @@ bool ethash_cl_miner::configureGPU(
unsigned _msPerBatch,
bool _allowCPU,
unsigned _extraGPUMemory,
boost::optional<uint64_t> _currentBlock
uint64_t _currentBlock
)
{
s_workgroupSize = _localWorkSize;
@ -156,7 +158,7 @@ bool ethash_cl_miner::configureGPU(
s_allowCPU = _allowCPU;
s_extraRequiredGPUMem = _extraGPUMemory;
// by default let's only consider the DAG of the first epoch
uint64_t dagSize = _currentBlock ? ethash_get_datasize(*_currentBlock) : 1073739904U;
uint64_t dagSize = ethash_get_datasize(_currentBlock);
uint64_t requiredSize = dagSize + _extraGPUMemory;
return searchForAllDevices(_platformId, [&requiredSize](cl::Device const _device) -> bool
{
@ -183,9 +185,9 @@ bool ethash_cl_miner::configureGPU(
bool ethash_cl_miner::s_allowCPU = false;
unsigned ethash_cl_miner::s_extraRequiredGPUMem;
unsigned ethash_cl_miner::s_msPerBatch = Ethash::defaultMSPerBatch;
unsigned ethash_cl_miner::s_workgroupSize = Ethash::defaultLocalWorkSize;
unsigned ethash_cl_miner::s_initialGlobalWorkSize = Ethash::defaultGlobalWorkSizeMultiplier * Ethash::defaultLocalWorkSize;
unsigned ethash_cl_miner::s_msPerBatch = ethash_cl_miner::c_defaultMSPerBatch;
unsigned ethash_cl_miner::s_workgroupSize = ethash_cl_miner::c_defaultLocalWorkSize;
unsigned ethash_cl_miner::s_initialGlobalWorkSize = ethash_cl_miner::c_defaultGlobalWorkSizeMultiplier * ethash_cl_miner::c_defaultLocalWorkSize;
bool ethash_cl_miner::searchForAllDevices(function<bool(cl::Device const&)> _callback)
{

15
libethash-cl/ethash_cl_miner.h

@ -1,6 +1,6 @@
#pragma once
#define __CL_ENABLE_EXCEPTIONS
#define __CL_ENABLE_EXCEPTIONS
#define CL_USE_DEPRECATED_OPENCL_2_0_APIS
#if defined(__clang__)
@ -12,7 +12,6 @@
#include "cl.hpp"
#endif
#include <boost/optional.hpp>
#include <time.h>
#include <functional>
#include <libethash/ethash.h>
@ -20,7 +19,7 @@
class ethash_cl_miner
{
private:
enum { c_maxSearchResults = 63, c_bufferCount = 2, c_hashBatchSize = 1024, c_searchBatchSize = 1024 * 16 };
enum { c_maxSearchResults = 63, c_bufferCount = 2, c_hashBatchSize = 1024 };
public:
struct search_hook
@ -50,7 +49,7 @@ public:
unsigned _msPerBatch,
bool _allowCPU,
unsigned _extraGPUMemory,
boost::optional<uint64_t> _currentBlock
uint64_t _currentBlock
);
bool init(
@ -65,6 +64,14 @@ public:
void hash_chunk(uint8_t* _ret, uint8_t const* _header, uint64_t _nonce, unsigned _count);
void search_chunk(uint8_t const*_header, uint64_t _target, search_hook& _hook);
/* -- default values -- */
/// Default value of the local work size. Also known as workgroup size.
static unsigned const c_defaultLocalWorkSize;
/// Default value of the global work size as a multiplier of the local work size
static unsigned const c_defaultGlobalWorkSizeMultiplier;
/// Default value of the milliseconds per global work size (per batch)
static unsigned const c_defaultMSPerBatch;
private:
static std::vector<cl::Device> getDevices(std::vector<cl::Platform> const& _platforms, unsigned _platformId);

12
libethcore/Common.h

@ -157,7 +157,8 @@ public:
~Signal()
{
for (auto const& h : m_fire)
h.second->reset();
if (auto l = h.second.lock())
l->reset();
}
std::shared_ptr<HandlerAux> add(Callback const& _h)
@ -168,10 +169,15 @@ public:
return h;
}
void operator()(Args&... _args) { for (auto const& f: m_fire) f.second->fire(std::forward<Args>(_args)...); }
void operator()(Args&... _args)
{
for (auto const& f: m_fire)
if (auto h = f.second.lock())
h->fire(std::forward<Args>(_args)...);
}
private:
std::map<unsigned, std::shared_ptr<typename Signal::HandlerAux>> m_fire;
std::map<unsigned, std::weak_ptr<typename Signal::HandlerAux>> m_fire;
};
template<class... Args> using Handler = std::shared_ptr<typename Signal<Args...>::HandlerAux>;

5
libethcore/Ethash.cpp

@ -54,9 +54,6 @@ namespace dev
namespace eth
{
const unsigned Ethash::defaultLocalWorkSize = 64;
const unsigned Ethash::defaultGlobalWorkSizeMultiplier = 512; // * CL_DEFAULT_LOCAL_WORK_SIZE
const unsigned Ethash::defaultMSPerBatch = 0;
const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage();
std::string Ethash::name()
@ -419,7 +416,7 @@ bool Ethash::GPUMiner::configureGPU(
unsigned _deviceId,
bool _allowCPU,
unsigned _extraGPUMemory,
boost::optional<uint64_t> _currentBlock
uint64_t _currentBlock
)
{
s_platformId = _platformId;

10
libethcore/Ethash.h

@ -88,7 +88,7 @@ public:
static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); }
static std::string platformInfo();
static void listDevices() {}
static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, boost::optional<uint64_t>) { return false; }
static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; }
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, std::thread::hardware_concurrency()); }
protected:
void kickOff() override
@ -125,7 +125,7 @@ public:
unsigned _deviceId,
bool _allowCPU,
unsigned _extraGPUMemory,
boost::optional<uint64_t> _currentBlock
uint64_t _currentBlock
);
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_instances, getNumDevices()); }
@ -150,12 +150,6 @@ public:
#else
using GPUMiner = CPUMiner;
#endif
/// Default value of the local work size. Also known as workgroup size.
static const unsigned defaultLocalWorkSize;
/// Default value of the global work size as a multiplier of the local work size
static const unsigned defaultGlobalWorkSizeMultiplier;
/// Default value of the milliseconds per global work size (per batch)
static const unsigned defaultMSPerBatch;
};
}

52
libethereum/BlockChain.cpp

@ -192,6 +192,8 @@ unsigned BlockChain::open(std::string const& _path, WithExisting _we)
}
}
m_writeOptions.sync = true;
if (_we != WithExisting::Verify && !details(m_genesisHash))
{
// Insert details of genesis block.
@ -799,6 +801,56 @@ void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end)
}
}
void BlockChain::rescue(OverlayDB& _db)
{
cout << "Rescuing database..." << endl;
unsigned u = 1;
while (true)
{
try {
if (isKnown(numberHash(u)))
u *= 2;
else
break;
}
catch (...)
{
break;
}
}
unsigned l = u / 2;
cout << "Finding last likely block number..." << endl;
while (u - l > 1)
{
unsigned m = (u + l) / 2;
cout << " " << m << flush;
if (isKnown(numberHash(m)))
l = m;
else
u = m;
}
cout << " lowest is " << l << endl;
for (;; --l)
{
h256 h = numberHash(l);
cout << "Checking validity of " << l << " (" << h << ")..." << flush;
try
{
cout << "block..." << flush;
BlockInfo bi = info(h);
cout << "details..." << flush;
BlockDetails bd = details(h);
cout << "state..." << flush;
if (_db.exists(bi.stateRoot))
break;
}
catch (...) {}
}
cout << "OK." << endl;
rewind(l);
}
void BlockChain::rewind(unsigned _newHead)
{
DEV_WRITE_GUARDED(x_lastBlockHash)

3
libethereum/BlockChain.h

@ -218,6 +218,9 @@ public:
/// Alter the head of the chain to some prior block along it.
void rewind(unsigned _newHead);
/// Rescue the database.
void rescue(OverlayDB& _db);
/** @returns a tuple of:
* - an vector of hashes of all blocks between @a _from and @a _to, all blocks are ordered first by a number of
* blocks that are parent-to-child, then two sibling blocks, then a number of blocks that are child-to-parent;

12
libethereum/BlockChainSync.cpp

@ -296,10 +296,16 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer, RLP con
case ImportResult::FutureTimeUnknown:
case ImportResult::UnknownParent:
{
logNewBlock(h);
clog(NetMessageDetail) << "Received block with no known parent. Resyncing...";
resetSyncFor(_peer, h, _r[1].toInt<u256>());
u256 totalDifficulty = _r[1].toInt<u256>();
if (totalDifficulty > _peer->m_totalDifficulty)
{
clog(NetMessageDetail) << "Received block with no known parent. Resyncing...";
resetSyncFor(_peer, h, totalDifficulty);
}
break;
}
default:;
}
@ -1164,9 +1170,9 @@ SyncStatus PV61Sync::status() const
{
RecursiveGuard l(x_sync);
SyncStatus res = PV60Sync::status();
res.protocolVersion = 61;
if (m_state == SyncState::Hashes && isPV61Syncing())
{
res.protocolVersion = 61;
res.hashesReceived = 0;
for (auto const& d : m_readyChainMap)
res.hashesReceived += d.second.size();

6
libethereum/BlockChainSync.h

@ -58,6 +58,9 @@ public:
/// @returns true is Sync is in progress
virtual bool isSyncing() const = 0;
/// Restart sync
virtual void restartSync() = 0;
/// Called by peer to report status
virtual void onPeerStatus(std::shared_ptr<EthereumPeer> _peer);
@ -92,9 +95,6 @@ protected:
/// Resume downloading after witing state
virtual void continueSync() = 0;
/// Restart sync
virtual void restartSync() = 0;
/// Called after all blocks have been donloaded
virtual void completeSync() = 0;

5
libethereum/Client.cpp

@ -67,7 +67,7 @@ static const Addresses c_canaries =
Address("4bb7e8ae99b645c2b7860b8f3a2328aae28bd80a"), // gav
Address("1baf27b88c48dd02b744999cf3522766929d2b2a"), // vitalik
Address("a8edb1ac2c86d3d9d78f96cd18001f60df29e52c"), // jeff
Address("60d11b58744784dc97f878f7e3749c0f1381a004") // christoph
Address("ace7813896a84d3f5f80223916a5353ab16e46e6") // christoph
};
VersionChecker::VersionChecker(string const& _dbPath)
@ -90,6 +90,9 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _gp, std::string c
m_preMine(m_stateDB, BaseState::CanonGenesis),
m_postMine(m_stateDB)
{
if (_forceAction == WithExisting::Rescue)
m_bc.rescue(m_stateDB);
m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30);
m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue);
m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue);

25
libethereum/EthereumHost.cpp

@ -88,6 +88,7 @@ void EthereumHost::reset()
if (m_sync)
m_sync->abortSync();
m_sync.reset();
m_syncStart = 0;
m_latestBlockSent = h256();
Guard tl(x_transactions);
@ -115,6 +116,21 @@ void EthereumHost::doWork()
foreachPeer([](std::shared_ptr<EthereumPeer> _p) { _p->tick(); return true; });
if (m_syncStart)
{
DEV_GUARDED(x_sync)
if (!m_sync)
{
time_t now = std::chrono::system_clock::to_time_t(chrono::system_clock::now());
if (now - m_syncStart > 10)
{
m_sync.reset(new PV60Sync(*this));
m_syncStart = 0;
m_sync->restartSync();
}
}
}
// return netChange;
// TODO: Figure out what to do with netChange.
(void)netChange;
@ -259,7 +275,14 @@ BlockChainSync* EthereumHost::sync()
pv61 = true;
return !pv61;
});
m_sync.reset(pv61 ? new PV61Sync(*this) : new PV60Sync(*this));
if (pv61)
{
m_syncStart = 0;
m_sync.reset(new PV61Sync(*this));
}
else if (!m_syncStart)
m_syncStart = std::chrono::system_clock::to_time_t(chrono::system_clock::now());
return m_sync.get();
}

1
libethereum/EthereumHost.h

@ -138,6 +138,7 @@ private:
mutable Mutex x_transactions;
DownloadMan m_man;
std::unique_ptr<BlockChainSync> m_sync;
std::atomic<time_t> m_syncStart = { 0 };
};
}

2
libethereum/State.cpp

@ -1212,7 +1212,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per
uncommitToMine();
// OK - transaction looks valid - execute.
u256 startGasUsed = e.gasUsed();
u256 startGasUsed = gasUsed();
#if ETH_PARANOIA
ctrace << "Executing" << e.t() << "on" << h;
ctrace << toHex(e.t().rlp());

21
libethereum/TransactionQueue.cpp

@ -36,12 +36,12 @@ TransactionQueue::TransactionQueue(unsigned _limit, unsigned _futureLimit):
m_limit(_limit),
m_futureLimit(_futureLimit)
{
unsigned verifierThreads = std::max(thread::hardware_concurrency(), 3U) - 2U;
for (unsigned i = 0; i < verifierThreads; ++i)
m_verifiers.emplace_back([=](){
setThreadName("txcheck" + toString(i));
this->verifierBody();
});
unsigned verifierThreads = std::max(thread::hardware_concurrency(), 3U) - 2U;
for (unsigned i = 0; i < verifierThreads; ++i)
m_verifiers.emplace_back([=](){
setThreadName("txcheck" + toString(i));
this->verifierBody();
});
}
TransactionQueue::~TransactionQueue()
@ -68,6 +68,9 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, IfDropped _
try
{
// Check validity of _transactionRLP as a transaction. To do this we just deserialise and attempt to determine the sender.
// If it doesn't work, the signature is bad.
// The transaction's nonce may yet be invalid (or, it could be "valid" but we may be missing a marginally older transaction).
t = Transaction(_transactionRLP, CheckTransaction::Everything);
UpgradeGuard ul(l);
ir = manageImport_WITH_LOCK(h, t);
@ -99,7 +102,6 @@ ImportResult TransactionQueue::import(Transaction const& _transaction, IfDropped
ImportResult ret;
{
UpgradableGuard l(m_lock);
// TODO: keep old transactions around and check in State for nonce validity
auto ir = check_WITH_LOCK(h, _ik);
if (ir != ImportResult::Success)
return ir;
@ -132,11 +134,7 @@ ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transactio
{
try
{
// Check validity of _transactionRLP as a transaction. To do this we just deserialise and attempt to determine the sender.
// If it doesn't work, the signature is bad.
// The transaction's nonce may yet be invalid (or, it could be "valid" but we may be missing a marginally older transaction).
assert(_h == _transaction.sha3());
// Remove any prior transaction with the same nonce but a lower gas price.
// Bomb out if there's a prior transaction with higher gas price.
auto cs = m_currentByAddressAndNonce.find(_transaction.from());
@ -263,7 +261,6 @@ unsigned TransactionQueue::waiting(Address const& _a) const
void TransactionQueue::setFuture(h256 const& _txHash)
{
// cdebug << "txQ::setFuture" << _t.first;
WriteGuard l(m_lock);
auto it = m_currentByHash.find(_txHash);
if (it == m_currentByHash.end())

61
libethereum/TransactionQueue.h

@ -42,39 +42,84 @@ struct TransactionQueueChannel: public LogChannel { static const char* name(); s
struct TransactionQueueTraceChannel: public LogChannel { static const char* name(); static const int verbosity = 7; };
#define ctxq dev::LogOutputStream<dev::eth::TransactionQueueTraceChannel, true>()
enum class IfDropped { Ignore, Retry };
/// Import transaction policy
enum class IfDropped
{
Ignore, ///< Don't import transaction that was previously dropped.
Retry ///< Import transaction even if it was dropped before.
};
/**
* @brief A queue of Transactions, each stored as RLP.
* Maintains a transaction queue sorted by nonce diff and gas price
* Maintains a transaction queue sorted by nonce diff and gas price.
* @threadsafe
*/
class TransactionQueue
{
public:
/// @brief TransactionQueue
/// @param _limit Maximum number of pending transactions in the queue
/// @param _futureLimit Maximum number of future nonce transactions
/// @param _limit Maximum number of pending transactions in the queue.
/// @param _futureLimit Maximum number of future nonce transactions.
TransactionQueue(unsigned _limit = 1024, unsigned _futureLimit = 1024);
~TransactionQueue();
/// Add transaction to the queue to be verified and imported.
/// @param _data RLP encoded transaction data.
/// @param _nodeId Optional network identified of a node transaction comes from.
void enqueue(RLP const& _data, h512 const& _nodeId);
/// Verify and add transaction to the queue synchronously.
/// @param _tx RLP encoded transaction data.
/// @param _ik Set to Retry to force re-addinga transaction that was previously dropped.
/// @returns Import result code.
ImportResult import(bytes const& _tx, IfDropped _ik = IfDropped::Ignore) { return import(&_tx, _ik); }
/// Verify and add transaction to the queue synchronously.
/// @param _tx Trasnaction data.
/// @param _ik Set to Retry to force re-addinga transaction that was previously dropped.
/// @returns Import result code.
ImportResult import(Transaction const& _tx, IfDropped _ik = IfDropped::Ignore);
/// Remove transaction from the queue
/// @param _txHash Trasnaction hash
void drop(h256 const& _txHash);
/// Get number of pending transactions for account.
/// @returns Pending transaction count.
unsigned waiting(Address const& _a) const;
/// Get top transactions from the queue. Returned transactions are not removed from the queue automatically.
/// @param _limit Max number of transactions to return.
/// @returns up to _limit transactions ordered by nonce and gas price.
Transactions topTransactions(unsigned _limit) const;
/// Get a hash set of transactions in the queue
/// @returns A hash set of all transactions in the queue
h256Hash knownTransactions() const;
/// Get max nonce for an account
/// @returns Max transaction nonce for account in the queue
u256 maxNonce(Address const& _a) const;
/// Mark transaction as future. It wont be retured in topTransactions list until a transaction with a preceeding nonce is imported or marked with dropGood
/// @param _t Transaction hash
void setFuture(h256 const& _t);
/// Drop a trasnaction from the list if exists and move following future trasnactions to current (if any)
/// @param _t Transaction hash
void dropGood(Transaction const& _t);
/// Clear the queue
void clear();
/// Register a handler that will be called once there is a new transaction imported
template <class T> Handler<> onReady(T const& _t) { return m_onReady.add(_t); }
/// Register a handler that will be called once asynchronous verification is comeplte an transaction has been imported
template <class T> Handler<ImportResult, h256 const&, h512 const&> onImport(T const& _t) { return m_onImport.add(_t); }
private:
/// Verified and imported transaction
struct VerifiedTransaction
{
VerifiedTransaction(Transaction const& _t): transaction(_t) {}
@ -83,9 +128,10 @@ private:
VerifiedTransaction(VerifiedTransaction const&) = delete;
VerifiedTransaction& operator=(VerifiedTransaction const&) = delete;
Transaction transaction;
Transaction transaction; ///< Transaction data
};
/// Trasnaction pending verification
struct UnverifiedTransaction
{
UnverifiedTransaction() {}
@ -96,13 +142,14 @@ private:
UnverifiedTransaction(UnverifiedTransaction const&) = delete;
UnverifiedTransaction& operator=(UnverifiedTransaction const&) = delete;
bytes transaction;
h512 nodeId;
bytes transaction; ///< RLP encoded transaction data
h512 nodeId; ///< Network Id of the peer transaction comes from
};
struct PriorityCompare
{
TransactionQueue& queue;
/// Compare transaction by nonce height and gas price.
bool operator()(VerifiedTransaction const& _first, VerifiedTransaction const& _second) const
{
u256 const& height1 = _first.transaction.nonce() - queue.m_currentByAddressAndNonce[_first.transaction.sender()].begin()->first;

8
libjsconsole/CMakeLists.txt

@ -12,7 +12,9 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ${V8_INCLUDE_DIRS})
include_directories(BEFORE ..)
include_directories(${READLINE_INCLUDE_DIRS})
if (READLINE_FOUND)
include_directories(${READLINE_INCLUDE_DIRS})
endif()
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
include_directories(${CURL_INCLUDE_DIRS})
@ -24,7 +26,9 @@ add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
target_link_libraries(${EXECUTABLE} jsengine)
target_link_libraries(${EXECUTABLE} devcore)
target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
if (READLINE_FOUND)
target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES})
endif()
target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_SERVER_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES})

31
libjsconsole/JSConsole.h

@ -23,9 +23,11 @@
#pragma once
#include <libdevcore/Log.h>
// TODO! make readline optional!
#if ETH_READLINE
#include <readline/readline.h>
#include <readline/history.h>
#endif
namespace dev
{
@ -42,18 +44,35 @@ public:
void readExpression() const
{
std::string cmd = "";
g_logPost = [](std::string const& a, char const*) { std::cout << "\r \r" << a << std::endl << std::flush; rl_forced_update_display(); };
g_logPost = [](std::string const& a, char const*)
{
std::cout << "\r \r" << a << std::endl << std::flush;
#if ETH_READLINE
rl_forced_update_display();
#endif
};
bool isEmpty = true;
int openBrackets = 0;
do {
std::string rl;
#if ETH_READLINE
char* buff = readline(promptForIndentionLevel(openBrackets).c_str());
isEmpty = !(buff && *buff);
isEmpty = !buff;
if (!isEmpty)
{
cmd += std::string(buff);
cmd += " ";
rl = std::string(buff);
free(buff);
}
#else
std::cout << promptForIndentionLevel(openBrackets) << std::flush;
std::getline(std::cin, rl);
isEmpty = rl.length() == 0;
#endif
if (!isEmpty)
{
cmd += rl;
cmd += " ";
int open = std::count(cmd.begin(), cmd.end(), '{');
open += std::count(cmd.begin(), cmd.end(), '(');
int closed = std::count(cmd.begin(), cmd.end(), '}');
@ -64,7 +83,9 @@ public:
if (!isEmpty)
{
#if ETH_READLINE
add_history(cmd.c_str());
#endif
auto value = m_engine.eval(cmd.c_str());
std::string result = m_printer.prettyPrint(value).cstr();
std::cout << result << std::endl;

2
libjsengine/CMakeLists.txt

@ -21,6 +21,8 @@ include(EthUtils)
eth_add_resources("${CMAKE_CURRENT_SOURCE_DIR}/JSResources.cmake" "JSRES")
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS} ${JSRES})
add_dependencies(${EXECUTABLE} BuildInfo.h)
# macos brew version of v8 needs to be compiled with libstdc++
# it also needs to be dynamic library
# xcode needs libstdc++ to be explicitly set as it's attribute

4
libjsengine/JSEngine.h

@ -29,7 +29,11 @@ namespace eth
{
class JSException: public std::exception {};
#if defined(_MSC_VER)
class JSPrintException: public JSException { char const* what() const { return "Cannot print expression!"; } };
#else
class JSPrintException: public JSException { char const* what() const noexcept { return "Cannot print expression!"; } };
#endif
class JSString
{

17
libjsengine/JSV8Engine.cpp

@ -23,6 +23,10 @@
#include <memory>
#include "JSV8Engine.h"
#include "libjsengine/JSEngineResources.hpp"
#include "BuildInfo.h"
#define TO_STRING_HELPER(s) #s
#define TO_STRING(s) TO_STRING_HELPER(s)
using namespace std;
using namespace dev;
@ -87,15 +91,6 @@ void reportException(v8::TryCatch* _tryCatch)
}
}
class JSV8Env
{
public:
~JSV8Env()
{
v8::V8::Dispose();
}
};
class JSV8Scope
{
public:
@ -124,8 +119,6 @@ private:
}
}
JSV8Env JSV8Engine::s_env = JSV8Env();
JSString JSV8Value::toString() const
{
if (m_value.IsEmpty())
@ -141,6 +134,7 @@ JSString JSV8Value::toString() const
JSV8Engine::JSV8Engine(): m_scope(new JSV8Scope())
{
JSEngineResources resources;
eval("env = typeof(env) === 'undefined' ? {} : env; env.os = '" TO_STRING(ETH_BUILD_PLATFORM) "'");
string common = resources.loadResourceAsString("common");
string web3 = resources.loadResourceAsString("web3");
string admin = resources.loadResourceAsString("admin");
@ -157,7 +151,6 @@ JSV8Engine::~JSV8Engine()
JSV8Value JSV8Engine::eval(char const* _cstr) const
{
v8::HandleScope handleScope;
v8::TryCatch tryCatch;
v8::Local<v8::String> source = v8::String::New(_cstr);
v8::Local<v8::String> name(v8::String::New("(shell)"));

1
libjsengine/JSV8Engine.h

@ -56,7 +56,6 @@ public:
v8::Handle<v8::Context> const& context() const;
private:
static JSV8Env s_env;
JSV8Scope* m_scope;
};

1
libjsengine/JSV8Printer.cpp

@ -37,7 +37,6 @@ JSV8Printer::JSV8Printer(JSV8Engine const& _engine): m_engine(_engine)
JSString JSV8Printer::prettyPrint(JSV8Value const& _value) const
{
v8::HandleScope handleScope;
v8::Local<v8::String> pp = v8::String::New("prettyPrint");
v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(m_engine.context()->Global()->Get(pp));
v8::Local<v8::Value> values[1] = {v8::Local<v8::Value>::New(_value.value())};

26
libjsengine/PrettyPrint.js

@ -1,4 +1,14 @@
var prettyPrint = (function () {
var onlyDecentPlatform = function (x) {
return env.os.indexOf('Windows') === -1 ? x : '';
};
var color_red = onlyDecentPlatform('\033[31m');
var color_green = onlyDecentPlatform('\033[32m');
var color_pink = onlyDecentPlatform('\033[35m');
var color_white = onlyDecentPlatform('\033[0m');
var color_blue = onlyDecentPlatform('\033[30m');
function pp(object, indent) {
try {
JSON.stringify(object)
@ -16,13 +26,13 @@ var prettyPrint = (function () {
}
str += " ]";
} else if (object instanceof Error) {
str += "\033[31m" + "Error:\033[0m " + object.message;
str += color_red + "Error: " + color_white + object.message;
} else if (object === null) {
str += "\033[1m\033[30m" + "null";
str += color_blue + "null";
} else if(typeof(object) === "undefined") {
str += "\033[1m\033[30m" + object;
str += color_blue + object;
} else if (isBigNumber(object)) {
str += "\033[32m'" + object.toString(10) + "'";
str += color_green + object.toString(10) + "'";
} else if(typeof(object) === "object") {
str += "{\n";
indent += " ";
@ -41,15 +51,15 @@ var prettyPrint = (function () {
});
str += indent.substr(2, indent.length) + "}";
} else if(typeof(object) === "string") {
str += "\033[32m'" + object + "'";
str += color_green + object + "'";
} else if(typeof(object) === "number") {
str += "\033[31m" + object;
str += color_red + object;
} else if(typeof(object) === "function") {
str += "\033[35m[Function]";
str += color_pink + "[Function]";
} else {
str += object;
}
str += "\033[0m";
str += color_white;
return str;
}
var redundantFields = [

138
libsolidity/CompilerUtils.cpp

@ -113,6 +113,16 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
solAssert(ref->location() == DataLocation::Memory, "");
storeInMemoryDynamic(IntegerType(256), _padToWordBoundaries);
}
else if (auto str = dynamic_cast<StringLiteralType const*>(&_type))
{
m_context << eth::Instruction::DUP1;
storeStringData(bytesConstRef(str->value()));
if (_padToWordBoundaries)
m_context << u256(((str->value().size() + 31) / 32) * 32);
else
m_context << u256(str->value().size());
m_context << eth::Instruction::ADD;
}
else
{
unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries);
@ -169,7 +179,8 @@ void CompilerUtils::encodeToMemory(
TypePointer type = targetType;
if (
_givenTypes[i]->dataStoredIn(DataLocation::Storage) ||
_givenTypes[i]->dataStoredIn(DataLocation::CallData)
_givenTypes[i]->dataStoredIn(DataLocation::CallData) ||
_givenTypes[i]->getCategory() == Type::Category::StringLiteral
)
type = _givenTypes[i]; // delay conversion
else
@ -192,36 +203,48 @@ void CompilerUtils::encodeToMemory(
solAssert(!!targetType, "Externalable type expected.");
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
{
solAssert(_givenTypes[i]->getCategory() == Type::Category::Array, "Unknown dynamic type.");
auto const& arrayType = dynamic_cast<ArrayType const&>(*_givenTypes[i]);
// copy tail pointer (=mem_end - mem_start) to memory
m_context << eth::dupInstruction(2 + dynPointers) << eth::Instruction::DUP2;
m_context << eth::Instruction::SUB;
m_context << eth::dupInstruction(2 + dynPointers - thisDynPointer);
m_context << eth::Instruction::MSTORE;
// now copy the array
copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType.getSizeOnStack());
// stack: ... <end_of_mem> <value...>
// copy length to memory
m_context << eth::dupInstruction(1 + arrayType.getSizeOnStack());
if (arrayType.location() == DataLocation::CallData)
m_context << eth::Instruction::DUP2; // length is on stack
else if (arrayType.location() == DataLocation::Storage)
m_context << eth::Instruction::DUP3 << eth::Instruction::SLOAD;
// stack: ... <end_of_mem>
if (_givenTypes[i]->getCategory() == Type::Category::StringLiteral)
{
auto const& strType = dynamic_cast<StringLiteralType const&>(*_givenTypes[i]);
m_context << u256(strType.value().size());
storeInMemoryDynamic(IntegerType(256), true);
// stack: ... <end_of_mem'>
storeInMemoryDynamic(strType, _padToWordBoundaries);
}
else
{
solAssert(arrayType.location() == DataLocation::Memory, "");
m_context << eth::Instruction::DUP2 << eth::Instruction::MLOAD;
solAssert(_givenTypes[i]->getCategory() == Type::Category::Array, "Unknown dynamic type.");
auto const& arrayType = dynamic_cast<ArrayType const&>(*_givenTypes[i]);
// now copy the array
copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType.getSizeOnStack());
// stack: ... <end_of_mem> <value...>
// copy length to memory
m_context << eth::dupInstruction(1 + arrayType.getSizeOnStack());
if (arrayType.location() == DataLocation::CallData)
m_context << eth::Instruction::DUP2; // length is on stack
else if (arrayType.location() == DataLocation::Storage)
m_context << eth::Instruction::DUP3 << eth::Instruction::SLOAD;
else
{
solAssert(arrayType.location() == DataLocation::Memory, "");
m_context << eth::Instruction::DUP2 << eth::Instruction::MLOAD;
}
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
storeInMemoryDynamic(IntegerType(256), true);
// stack: ... <end_of_mem> <value...> <end_of_mem''>
// copy the new memory pointer
m_context << eth::swapInstruction(arrayType.getSizeOnStack() + 1) << eth::Instruction::POP;
// stack: ... <end_of_mem''> <value...>
// copy data part
ArrayUtils(m_context).copyArrayToMemory(arrayType, _padToWordBoundaries);
// stack: ... <end_of_mem'''>
}
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
storeInMemoryDynamic(IntegerType(256), true);
// stack: ... <end_of_mem> <value...> <end_of_mem''>
// copy the new memory pointer
m_context << eth::swapInstruction(arrayType.getSizeOnStack() + 1) << eth::Instruction::POP;
// stack: ... <end_of_mem''> <value...>
// copy data part
ArrayUtils(m_context).copyArrayToMemory(arrayType, _padToWordBoundaries);
// stack: ... <end_of_mem'''>
thisDynPointer++;
}
@ -269,22 +292,22 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
// conversion from bytes to integer. no need to clean the high bit
// only to shift right because of opposite alignment
IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType);
m_context << (u256(1) << (256 - typeOnStack.getNumBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
if (targetIntegerType.getNumBits() < typeOnStack.getNumBytes() * 8)
convertType(IntegerType(typeOnStack.getNumBytes() * 8), _targetType, _cleanupNeeded);
m_context << (u256(1) << (256 - typeOnStack.numBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
if (targetIntegerType.getNumBits() < typeOnStack.numBytes() * 8)
convertType(IntegerType(typeOnStack.numBytes() * 8), _targetType, _cleanupNeeded);
}
else
{
// clear lower-order bytes for conversion to shorter bytes - we always clean
solAssert(targetTypeCategory == Type::Category::FixedBytes, "Invalid type conversion requested.");
FixedBytesType const& targetType = dynamic_cast<FixedBytesType const&>(_targetType);
if (targetType.getNumBytes() < typeOnStack.getNumBytes())
if (targetType.numBytes() < typeOnStack.numBytes())
{
if (targetType.getNumBytes() == 0)
if (targetType.numBytes() == 0)
m_context << eth::Instruction::DUP1 << eth::Instruction::XOR;
else
{
m_context << (u256(1) << (256 - targetType.getNumBytes() * 8));
m_context << (u256(1) << (256 - targetType.numBytes() * 8));
m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2;
m_context << eth::Instruction::DIV << eth::Instruction::MUL;
}
@ -306,9 +329,9 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
// only to shift left because of opposite alignment
FixedBytesType const& targetBytesType = dynamic_cast<FixedBytesType const&>(_targetType);
if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
if (targetBytesType.getNumBytes() * 8 > typeOnStack->getNumBits())
if (targetBytesType.numBytes() * 8 > typeOnStack->getNumBits())
cleanHigherOrderBits(*typeOnStack);
m_context << (u256(1) << (256 - targetBytesType.getNumBytes() * 8)) << eth::Instruction::MUL;
m_context << (u256(1) << (256 - targetBytesType.numBytes() * 8)) << eth::Instruction::MUL;
}
else if (targetTypeCategory == Type::Category::Enum)
// just clean
@ -340,6 +363,37 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
}
}
break;
case Type::Category::StringLiteral:
{
auto const& literalType = dynamic_cast<StringLiteralType const&>(_typeOnStack);
string const& value = literalType.value();
bytesConstRef data(value);
if (targetTypeCategory == Type::Category::FixedBytes)
{
solAssert(data.size() <= 32, "");
m_context << h256::Arith(h256(data, h256::AlignLeft));
}
else if (targetTypeCategory == Type::Category::Array)
{
auto const& arrayType = dynamic_cast<ArrayType const&>(_targetType);
solAssert(arrayType.isByteArray(), "");
u256 storageSize(32 + ((data.size() + 31) / 32) * 32);
m_context << storageSize;
allocateMemory();
// stack: mempos
m_context << eth::Instruction::DUP1 << u256(data.size());
storeInMemoryDynamic(IntegerType(256));
// stack: mempos datapos
storeStringData(data);
break;
}
else
solAssert(
false,
"Invalid conversion from string literal to " + _targetType.toString(false) + " requested."
);
break;
}
case Type::Category::Array:
{
solAssert(targetTypeCategory == stackTypeCategory, "");
@ -606,6 +660,28 @@ void CompilerUtils::computeHashStatic()
m_context << u256(32) << u256(0) << eth::Instruction::SHA3;
}
void CompilerUtils::storeStringData(bytesConstRef _data)
{
//@todo provide both alternatives to the optimiser
// stack: mempos
if (_data.size() <= 128)
{
for (unsigned i = 0; i < _data.size(); i += 32)
{
m_context << h256::Arith(h256(_data.cropped(i), h256::AlignLeft));
storeInMemoryDynamic(IntegerType(256));
}
m_context << eth::Instruction::POP;
}
else
{
// stack: mempos mempos_data
m_context.appendData(_data.toBytes());
m_context << u256(_data.size()) << eth::Instruction::SWAP2;
m_context << eth::Instruction::CODECOPY;
}
}
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
{
unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);

7
libsolidity/CompilerUtils.h

@ -148,7 +148,12 @@ private:
/// Address of the precompiled identity contract.
static const unsigned identityContractAddress;
//// Appends code that cleans higher-order bits for integer types.
/// Stores the given string in memory.
/// Stack pre: mempos
/// Stack post:
void storeStringData(bytesConstRef _data);
/// Appends code that cleans higher-order bits for integer types.
void cleanHigherOrderBits(IntegerType const& _typeOnStack);
/// Prepares the given type for storing in memory by shifting it if necessary.

13
libsolidity/ExpressionCompiler.cpp

@ -158,6 +158,11 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
utils().convertType(*type, *_assignment.getType());
type = _assignment.getType();
}
else
{
utils().convertType(*type, *type->mobileType());
type = type->mobileType();
}
_assignment.getLeftHandSide().accept(*this);
solAssert(!!m_currentLValue, "LValue not retrieved.");
@ -898,13 +903,15 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
void ExpressionCompiler::endVisit(Literal const& _literal)
{
CompilerContext::LocationSetter locationSetter(m_context, _literal);
switch (_literal.getType()->getCategory())
TypePointer type = _literal.getType();
switch (type->getCategory())
{
case Type::Category::IntegerConstant:
case Type::Category::Bool:
case Type::Category::FixedBytes:
m_context << _literal.getType()->literalValue(&_literal);
m_context << type->literalValue(&_literal);
break;
case Type::Category::StringLiteral:
break; // will be done during conversion
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer, boolean and string literals implemented for now."));
}

2
libsolidity/LValue.cpp

@ -209,7 +209,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
// stack: value storage_ref cleared_value multiplier value
if (m_dataType.getCategory() == Type::Category::FixedBytes)
m_context
<< (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(m_dataType).getNumBytes()))
<< (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(m_dataType).numBytes()))
<< eth::Instruction::SWAP1 << eth::Instruction::DIV;
else if (
m_dataType.getCategory() == Type::Category::Integer &&

41
libsolidity/Types.cpp

@ -212,8 +212,7 @@ TypePointer Type::forLiteral(Literal const& _literal)
case Token::Number:
return make_shared<IntegerConstantType>(_literal);
case Token::StringLiteral:
//@todo put larger strings into dynamic strings
return FixedBytesType::smallestTypeForLiteral(_literal.getValue());
return make_shared<StringLiteralType>(_literal);
default:
return shared_ptr<Type>();
}
@ -378,7 +377,7 @@ bool IntegerConstantType::isImplicitlyConvertibleTo(Type const& _convertTo) cons
else if (_convertTo.getCategory() == Category::FixedBytes)
{
FixedBytesType const& fixedBytes = dynamic_cast<FixedBytesType const&>(_convertTo);
return fixedBytes.getNumBytes() * 8 >= getIntegerType()->getNumBits();
return fixedBytes.numBytes() * 8 >= getIntegerType()->getNumBits();
}
else
return false;
@ -530,6 +529,33 @@ shared_ptr<IntegerType const> IntegerConstantType::getIntegerType() const
);
}
StringLiteralType::StringLiteralType(Literal const& _literal):
m_value(_literal.getValue())
{
}
bool StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
if (auto fixedBytes = dynamic_cast<FixedBytesType const*>(&_convertTo))
return size_t(fixedBytes->numBytes()) >= m_value.size();
else if (auto arrayType = dynamic_cast<ArrayType const*>(&_convertTo))
return arrayType->isByteArray();
else
return false;
}
bool StringLiteralType::operator==(const Type& _other) const
{
if (_other.getCategory() != getCategory())
return false;
return m_value == dynamic_cast<StringLiteralType const&>(_other).m_value;
}
TypePointer StringLiteralType::mobileType() const
{
return make_shared<ArrayType>(DataLocation::Memory, true);
}
shared_ptr<FixedBytesType> FixedBytesType::smallestTypeForLiteral(string const& _literal)
{
if (_literal.length() <= 32)
@ -590,15 +616,6 @@ bool FixedBytesType::operator==(Type const& _other) const
return other.m_bytes == m_bytes;
}
u256 FixedBytesType::literalValue(const Literal* _literal) const
{
solAssert(_literal, "");
u256 value = 0;
for (char c: _literal->getValue())
value = (value << 8) | byte(c);
return value << ((32 - _literal->getValue().length()) * 8);
}
bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
// conversion to integer is fine, but not to address

36
libsolidity/Types.h

@ -131,7 +131,7 @@ class Type: private boost::noncopyable, public std::enable_shared_from_this<Type
public:
enum class Category
{
Integer, IntegerConstant, Bool, Real, Array,
Integer, IntegerConstant, StringLiteral, Bool, Real, Array,
FixedBytes, Contract, Struct, Function, Enum,
Mapping, Void, TypeType, Modifier, Magic
};
@ -311,6 +311,37 @@ private:
bigint m_value;
};
/**
* Literal string, can be converted to bytes, bytesX or string.
*/
class StringLiteralType: public Type
{
public:
virtual Category getCategory() const override { return Category::StringLiteral; }
explicit StringLiteralType(Literal const& _literal);
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override
{
return TypePointer();
}
virtual bool operator==(Type const& _other) const override;
virtual bool canBeStored() const override { return false; }
virtual bool canLiveOutsideStorage() const override { return false; }
virtual unsigned getSizeOnStack() const override { return 0; }
virtual std::string toString(bool) const override { return "literal_string \"" + m_value + "\""; }
virtual TypePointer mobileType() const override;
std::string const& value() const { return m_value; }
private:
std::string m_value;
};
/**
* Bytes type with fixed length of up to 32 bytes.
*/
@ -336,10 +367,9 @@ public:
virtual bool isValueType() const override { return true; }
virtual std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
virtual u256 literalValue(Literal const* _literal) const override;
virtual TypePointer externalType() const override { return shared_from_this(); }
int getNumBytes() const { return m_bytes; }
int numBytes() const { return m_bytes; }
private:
int m_bytes;

39
libsolidity/Version.cpp

@ -0,0 +1,39 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2015
* Versioning.
*/
#include <libsolidity/Version.h>
#include <string>
#include <BuildInfo.h>
#include <libdevcore/Common.h>
using namespace dev;
using namespace dev::solidity;
using namespace std;
char const* dev::solidity::VersionNumber = "0.1.0";
extern string const dev::solidity::VersionString =
string(dev::solidity::VersionNumber) +
"-" +
string(DEV_QUOTED(ETH_COMMIT_HASH)).substr(0, 8) +
(ETH_CLEAN_REPO ? "" : "*") +
"/" DEV_QUOTED(ETH_BUILD_TYPE) "-" DEV_QUOTED(ETH_BUILD_PLATFORM);

36
libsolidity/Version.h

@ -0,0 +1,36 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2015
* Versioning.
*/
#pragma once
#include <string>
namespace dev
{
namespace solidity
{
extern char const* VersionNumber;
extern std::string const VersionString;
}
}

4
libwhisper/BloomFilter.h

@ -88,7 +88,7 @@ template <unsigned N>
bool TopicBloomFilterBase<N>::isBitSet(FixedHash<N> const& _h, unsigned _index)
{
unsigned iByte = _index / 8;
unsigned iBit = _index & 0x7;
unsigned iBit = _index % 8;
return (_h[iByte] & c_powerOfTwoBitMmask[iBit]) != 0;
}
@ -96,7 +96,7 @@ template <unsigned N>
void TopicBloomFilterBase<N>::setBit(FixedHash<N>& _h, unsigned _index)
{
unsigned iByte = _index / 8;
unsigned iBit = _index & 0x7;
unsigned iBit = _index % 8;
_h[iByte] |= c_powerOfTwoBitMmask[iBit];
}

4
libwhisper/Message.cpp

@ -170,7 +170,7 @@ void Envelope::proveWork(unsigned _ms)
chrono::high_resolution_clock::time_point then = chrono::high_resolution_clock::now() + chrono::milliseconds(_ms);
while (chrono::high_resolution_clock::now() < then)
// do it rounds of 1024 for efficiency
for (unsigned i = 0; i < 1024; ++i)
for (unsigned i = 0; i < 1024; ++i, ++d[1])
{
auto fbs = dev::sha3(chuck).firstBitSet();
if (fbs > bestBitSet)
@ -178,8 +178,6 @@ void Envelope::proveWork(unsigned _ms)
bestBitSet = fbs;
m_nonce = (h256::Arith)d[1];
}
incrementHash(d[1]);
}
}

1
libwhisper/Message.h

@ -81,7 +81,6 @@ public:
void proveWork(unsigned _ms);
bool matchesBloomFilter(TopicBloomFilterHash const& f) const;
static void incrementHash(h256& _h) { for (unsigned i = h256::size; i > 0 && !++_h[--i]; ) {} }
private:
Envelope(unsigned _exp, unsigned _ttl, AbridgedTopics const& _topic): m_expiry(_exp), m_ttl(_ttl), m_topic(_topic) {}

2
mix/CMakeLists.txt

@ -15,7 +15,7 @@ include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(${Boost_INCLUDE_DIRS})
include_directories(BEFORE ..)
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "3.6") AND NOT APPLE)
# Supress warnings for qt headers for clang+ccache
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-inconsistent-missing-override")
endif ()

3
mix/CodeModel.cpp

@ -562,7 +562,7 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type)
{
FixedBytesType const* b = dynamic_cast<FixedBytesType const*>(_type);
r.type = SolidityType::Type::Bytes;
r.size = static_cast<unsigned>(b->getNumBytes());
r.size = static_cast<unsigned>(b->numBytes());
}
break;
case Type::Category::Contract:
@ -608,6 +608,7 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type)
break;
case Type::Category::Function:
case Type::Category::IntegerConstant:
case Type::Category::StringLiteral:
case Type::Category::Magic:
case Type::Category::Mapping:
case Type::Category::Modifier:

3
mix/MixClient.cpp

@ -314,7 +314,8 @@ pair<h256, Address> MixClient::submitTransaction(eth::TransactionSkeleton const&
{
WriteGuard l(x_state);
TransactionSkeleton ts = _ts;
ts.nonce = m_state.transactionsFrom(toAddress(_secret));
ts.from = toAddress(_secret);
ts.nonce = m_state.transactionsFrom(ts.from);
eth::Transaction t(ts, _secret);
executeTransaction(t, m_state, false, _gasAuto, _secret);
return make_pair(t.sha3(), toAddress(ts.from, ts.nonce));

10
solc/CommandLineInterface.cpp

@ -35,6 +35,7 @@
#include <libdevcore/CommonIO.h>
#include <libevmcore/Instruction.h>
#include <libevmcore/Params.h>
#include <libsolidity/Version.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/ASTPrinter.h>
@ -81,9 +82,12 @@ static set<string> const g_combinedJsonArgs{
static void version()
{
cout << "solc, the solidity compiler commandline interface " << dev::Version << endl
<< " by Christian <c@ethdev.com> and Lefteris <lefteris@ethdev.com>, (c) 2014." << endl
<< "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl;
cout <<
"solc, the solidity compiler commandline interface" <<
endl <<
"Version: " <<
dev::solidity::VersionString <<
endl;
exit(0);
}

1
test/TestHelper.h

@ -188,6 +188,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin);
void doStateTests(json_spirit::mValue& v, bool _fillin);
void doVMTests(json_spirit::mValue& v, bool _fillin);
void doBlockchainTests(json_spirit::mValue& _v, bool _fillin);
void doRlpTests(json_spirit::mValue& v, bool _fillin);
template<typename mapType>
void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs)

133
test/fuzzTesting/fuzzHelper.cpp

@ -74,7 +74,7 @@ std::string RandomCode::generate(int _maxOpNumber, RandomCodeOptions _options)
uint8_t opcode = weightsDefined ? randOpCodeWeight() : randOpCodeGen();
dev::eth::InstructionInfo info = dev::eth::instructionInfo((dev::eth::Instruction) opcode);
if (info.name.find_first_of("INVALID_INSTRUCTION") > 0)
if (info.name.find("INVALID_INSTRUCTION") != std::string::npos)
{
//Byte code is yet not implemented
if (_options.useUndefinedOpCodes == false)
@ -85,12 +85,12 @@ std::string RandomCode::generate(int _maxOpNumber, RandomCodeOptions _options)
}
else
{
if (info.name.find_first_of("PUSH") > 0)
if (info.name.find("PUSH") != std::string::npos)
code += toCompactHex(opcode);
code += fillArguments((dev::eth::Instruction) opcode, _options);
}
if (info.name.find_first_of("PUSH") <= 0)
if (info.name.find("PUSH") == std::string::npos)
{
std::string byte = toCompactHex(opcode);
code += (byte == "") ? "00" : byte;
@ -149,113 +149,34 @@ std::string RandomCode::fillArguments(dev::eth::Instruction _opcode, RandomCodeO
if (smart)
{
switch (_opcode)
//PUSH1 ... PUSH32
if (dev::eth::Instruction::PUSH1 <= _opcode && _opcode <= dev::eth::Instruction::PUSH32)
{
case dev::eth::Instruction::PUSH1: code += rndByteSequence(1); break;
case dev::eth::Instruction::PUSH2: code += rndByteSequence(2); break;
case dev::eth::Instruction::PUSH3: code += rndByteSequence(3); break;
case dev::eth::Instruction::PUSH4: code += rndByteSequence(4); break;
case dev::eth::Instruction::PUSH5: code += rndByteSequence(5); break;
case dev::eth::Instruction::PUSH6: code += rndByteSequence(6); break;
case dev::eth::Instruction::PUSH7: code += rndByteSequence(7); break;
case dev::eth::Instruction::PUSH8: code += rndByteSequence(8); break;
case dev::eth::Instruction::PUSH9: code += rndByteSequence(9); break;
case dev::eth::Instruction::PUSH10: code += rndByteSequence(10); break;
case dev::eth::Instruction::PUSH11: code += rndByteSequence(11); break;
case dev::eth::Instruction::PUSH12: code += rndByteSequence(12); break;
case dev::eth::Instruction::PUSH13: code += rndByteSequence(13); break;
case dev::eth::Instruction::PUSH14: code += rndByteSequence(14); break;
case dev::eth::Instruction::PUSH15: code += rndByteSequence(15); break;
case dev::eth::Instruction::PUSH16: code += rndByteSequence(16); break;
case dev::eth::Instruction::PUSH17: code += rndByteSequence(17); break;
case dev::eth::Instruction::PUSH18: code += rndByteSequence(18); break;
case dev::eth::Instruction::PUSH19: code += rndByteSequence(19); break;
case dev::eth::Instruction::PUSH20: code += rndByteSequence(20); break;
case dev::eth::Instruction::PUSH21: code += rndByteSequence(21); break;
case dev::eth::Instruction::PUSH22: code += rndByteSequence(22); break;
case dev::eth::Instruction::PUSH23: code += rndByteSequence(23); break;
case dev::eth::Instruction::PUSH24: code += rndByteSequence(24); break;
case dev::eth::Instruction::PUSH25: code += rndByteSequence(25); break;
case dev::eth::Instruction::PUSH26: code += rndByteSequence(26); break;
case dev::eth::Instruction::PUSH27: code += rndByteSequence(27); break;
case dev::eth::Instruction::PUSH28: code += rndByteSequence(28); break;
case dev::eth::Instruction::PUSH29: code += rndByteSequence(29); break;
case dev::eth::Instruction::PUSH30: code += rndByteSequence(30); break;
case dev::eth::Instruction::PUSH31: code += rndByteSequence(31); break;
case dev::eth::Instruction::PUSH32: code += rndByteSequence(32); break;
case dev::eth::Instruction::SWAP1:
case dev::eth::Instruction::SWAP2:
case dev::eth::Instruction::SWAP3:
case dev::eth::Instruction::SWAP4:
case dev::eth::Instruction::SWAP5:
case dev::eth::Instruction::SWAP6:
case dev::eth::Instruction::SWAP7:
case dev::eth::Instruction::SWAP8:
case dev::eth::Instruction::SWAP9:
case dev::eth::Instruction::SWAP10:
case dev::eth::Instruction::SWAP11:
case dev::eth::Instruction::SWAP12:
case dev::eth::Instruction::SWAP13:
case dev::eth::Instruction::SWAP14:
case dev::eth::Instruction::SWAP15:
case dev::eth::Instruction::SWAP16:
case dev::eth::Instruction::DUP1:
case dev::eth::Instruction::DUP2:
case dev::eth::Instruction::DUP3:
case dev::eth::Instruction::DUP4:
case dev::eth::Instruction::DUP5:
case dev::eth::Instruction::DUP6:
case dev::eth::Instruction::DUP7:
case dev::eth::Instruction::DUP8:
case dev::eth::Instruction::DUP9:
case dev::eth::Instruction::DUP10:
case dev::eth::Instruction::DUP11:
case dev::eth::Instruction::DUP12:
case dev::eth::Instruction::DUP13:
case dev::eth::Instruction::DUP14:
case dev::eth::Instruction::DUP15:
case dev::eth::Instruction::DUP16:
int times;
switch (_opcode)
{
case dev::eth::Instruction::DUP1: times = 1; break;
case dev::eth::Instruction::SWAP1:
case dev::eth::Instruction::DUP2: times = 2; break;
case dev::eth::Instruction::SWAP2:
case dev::eth::Instruction::DUP3: times = 3; break;
case dev::eth::Instruction::SWAP3:
case dev::eth::Instruction::DUP4: times = 4; break;
case dev::eth::Instruction::SWAP4:
case dev::eth::Instruction::DUP5: times = 5; break;
case dev::eth::Instruction::SWAP5:
case dev::eth::Instruction::DUP6: times = 6; break;
case dev::eth::Instruction::SWAP6:
case dev::eth::Instruction::DUP7: times = 7; break;
case dev::eth::Instruction::SWAP7:
case dev::eth::Instruction::DUP8: times = 8; break;
case dev::eth::Instruction::SWAP8:
case dev::eth::Instruction::DUP9: times = 9; break;
case dev::eth::Instruction::SWAP9:
case dev::eth::Instruction::DUP10: times = 10; break;
case dev::eth::Instruction::SWAP10:
case dev::eth::Instruction::DUP11: times = 11; break;
case dev::eth::Instruction::SWAP11:
case dev::eth::Instruction::DUP12: times = 12; break;
case dev::eth::Instruction::SWAP12:
case dev::eth::Instruction::DUP13: times = 13; break;
case dev::eth::Instruction::SWAP13:
case dev::eth::Instruction::DUP14: times = 14; break;
case dev::eth::Instruction::SWAP14:
case dev::eth::Instruction::DUP15: times = 15; break;
case dev::eth::Instruction::SWAP15:
case dev::eth::Instruction::DUP16: times = 16; break;
case dev::eth::Instruction::SWAP16: times = 17; break;
default: times = 1;
}
code += rndByteSequence(int(_opcode) - int(dev::eth::Instruction::PUSH1) + 1);
return code;
}
//SWAP1 ... SWAP16 || DUP1 ... DUP16
bool isSWAP = (dev::eth::Instruction::SWAP1 <= _opcode && _opcode <= dev::eth::Instruction::SWAP16);
bool isDUP = (dev::eth::Instruction::DUP1 <= _opcode && _opcode <= dev::eth::Instruction::DUP16);
if (isSWAP || isDUP)
{
int times = 0;
if (isSWAP)
times = int(_opcode) - int(dev::eth::Instruction::SWAP1) + 2;
else
if (isDUP)
times = int(_opcode) - int(dev::eth::Instruction::DUP1) + 1;
for (int i = 0; i < times; i ++)
code += getPushCode(randUniIntGen() % 32);
break;
return code;
}
switch (_opcode)
{
case dev::eth::Instruction::CREATE:
//(CREATE value mem1 mem2)
code += getPushCode(randUniIntGen() % 128); //memlen1

268
test/libdevcore/rlp.cpp

@ -40,8 +40,125 @@ namespace js = json_spirit;
namespace dev
{
namespace test
{
static void buildRLP(js::mValue& _v, RLPStream& _rlp)
{
void buildRLP(js::mValue& _v, RLPStream& _rlp);
void checkRLPAgainstJson(js::mValue& v, RLP& u);
enum class RlpType
{
Valid,
Invalid,
Test
};
void doRlpTests(json_spirit::mValue& v, bool _fillin)
{
for (auto& i: v.get_obj())
{
js::mObject& o = i.second.get_obj();
if (test::Options::get().singleTest && test::Options::get().singleTestName != i.first)
{
o.clear();
continue;
}
cout << " " << i.first << endl;
TBOOST_REQUIRE((o.count("out") > 0));
TBOOST_REQUIRE((!o["out"].is_null()));
if (_fillin)
{
try
{
bytes payloadToDecode = fromHex(o["out"].get_str());
RLP payload(payloadToDecode);
if (payload.isEmpty())
BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Decoded Empty RLP!"));
o["in"] = "VALID";
}
catch (Exception const& _e)
{
cnote << "Exception: " << diagnostic_information(_e);
o["in"] = "INVALID";
}
catch (std::exception const& _e)
{
cnote << "rlp exception: " << _e.what();
o["in"] = "INVALID";
}
}
else
{
//Check Encode
TBOOST_REQUIRE((o.count("in") > 0));
RlpType rlpType = RlpType::Test;
if (o["in"].type() == js::str_type)
{
if (o["in"].get_str() == "INVALID")
rlpType = RlpType::Invalid;
else if (o["in"].get_str() == "VALID")
rlpType = RlpType::Valid;
}
if (rlpType == RlpType::Test)
{
RLPStream s;
dev::test::buildRLP(o["in"], s);
string computedText = toHex(s.out());
string expectedText(o["out"].get_str());
transform(expectedText.begin(), expectedText.end(), expectedText.begin(), ::tolower );
stringstream msg;
msg << "Encoding Failed: expected: " << expectedText << std::endl;
msg << " But Computed: " << computedText;
TBOOST_CHECK_MESSAGE(
(expectedText == computedText),
msg.str()
);
}
//Check Decode
// Uses the same test cases as encoding but in reverse.
// We read into the string of hex values, convert to bytes,
// and then compare the output structure to the json of the
// input object.
bool was_exception = false;
js::mValue& inputData = o["in"];
try
{
bytes payloadToDecode = fromHex(o["out"].get_str());
RLP payload(payloadToDecode);
if (rlpType == RlpType::Test)
dev::test::checkRLPAgainstJson(inputData, payload);
}
catch (Exception const& _e)
{
cnote << "Exception: " << diagnostic_information(_e);
was_exception = true;
}
catch (exception const& _e)
{
cnote << "rlp exception: " << _e.what();
was_exception = true;
}
//Expect exception as input is INVALID
if (rlpType == RlpType::Invalid && was_exception)
continue;
//Check that there was an exception as input is INVALID
if (rlpType == RlpType::Invalid && !was_exception)
TBOOST_ERROR("Expected RLP Exception as rlp should be invalid!");
//input is VALID check that there was no exceptions
if (was_exception)
TBOOST_ERROR("Unexpected RLP Exception!");
}
}
}
void buildRLP(js::mValue& _v, RLPStream& _rlp)
{
if (_v.type() == js::array_type)
{
@ -62,67 +179,46 @@ namespace dev
}
}
static void getRLPTestCases(js::mValue& v)
{
string testPath = getTestPath();
testPath += "/BasicTests";
string s = contentsString(testPath + "/rlptest.json");
BOOST_REQUIRE_MESSAGE( s.length() > 0,
"Contents of 'rlptest.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v);
}
static void checkRLPTestCase(js::mObject& o)
{
BOOST_REQUIRE( o.count("in") > 0 );
BOOST_REQUIRE( o.count("out") > 0 );
BOOST_REQUIRE(!o["out"].is_null());
}
static void checkRLPAgainstJson(js::mValue& v, RLP& u)
void checkRLPAgainstJson(js::mValue& v, RLP& u)
{
if ( v.type() == js::str_type )
{
const std::string& expectedText = v.get_str();
const string& expectedText = v.get_str();
if ( !expectedText.empty() && expectedText.front() == '#' )
{
// Deal with bigint instead of a raw string
std::string bigIntStr = expectedText.substr(1,expectedText.length()-1);
std::stringstream bintStream(bigIntStr);
string bigIntStr = expectedText.substr(1,expectedText.length()-1);
stringstream bintStream(bigIntStr);
bigint val;
bintStream >> val;
BOOST_CHECK( !u.isList() );
BOOST_CHECK( !u.isNull() );
BOOST_CHECK( u ); // operator bool()
BOOST_CHECK(u == val);
TBOOST_CHECK(( !u.isList() ));
TBOOST_CHECK(( !u.isNull() ));
TBOOST_CHECK(( u == val ));
}
else
{
BOOST_CHECK( !u.isList() );
BOOST_CHECK( !u.isNull() );
BOOST_CHECK( u.isData() );
BOOST_CHECK( u );
BOOST_CHECK( u.size() == expectedText.length() );
BOOST_CHECK(u == expectedText);
TBOOST_CHECK(( !u.isList() ));
TBOOST_CHECK(( !u.isNull() ));
TBOOST_CHECK(( u.isData() ));
TBOOST_CHECK(( u.size() == expectedText.length() ));
TBOOST_CHECK(( u == expectedText ));
}
}
else if ( v.type() == js::int_type )
{
const int expectedValue = v.get_int();
BOOST_CHECK( u.isInt() );
BOOST_CHECK( !u.isList() );
BOOST_CHECK( !u.isNull() );
BOOST_CHECK( u ); // operator bool()
BOOST_CHECK(u == expectedValue);
TBOOST_CHECK(( u.isInt() ));
TBOOST_CHECK(( !u.isList() ));
TBOOST_CHECK(( !u.isNull() ));
TBOOST_CHECK(( u == expectedValue ));
}
else if ( v.type() == js::array_type )
{
BOOST_CHECK( u.isList() );
BOOST_CHECK( !u.isInt() );
BOOST_CHECK( !u.isData() );
TBOOST_CHECK(( u.isList() ));
TBOOST_CHECK(( !u.isInt() ));
TBOOST_CHECK(( !u.isData() ));
js::mArray& arr = v.get_array();
BOOST_CHECK( u.itemCount() == arr.size() );
TBOOST_CHECK(( u.itemCount() == arr.size() ));
unsigned i;
for( i = 0; i < arr.size(); i++ )
{
@ -132,71 +228,59 @@ namespace dev
}
else
{
BOOST_ERROR("Invalid Javascript object!");
TBOOST_ERROR("Invalid Javascript object!");
}
}
}
}
BOOST_AUTO_TEST_SUITE(BasicTests)
BOOST_AUTO_TEST_SUITE(RlpTests)
BOOST_AUTO_TEST_CASE(rlp_encoding_test)
BOOST_AUTO_TEST_CASE(invalidRLPtest)
{
cnote << "Testing RLP Encoding...";
js::mValue v;
dev::test::getRLPTestCases(v);
for (auto& i: v.get_obj())
{
js::mObject& o = i.second.get_obj();
cnote << i.first;
dev::test::checkRLPTestCase(o);
RLPStream s;
dev::test::buildRLP(o["in"], s);
std::string expectedText(o["out"].get_str());
std::transform(expectedText.begin(), expectedText.end(), expectedText.begin(), ::tolower );
const std::string& computedText = toHex(s.out());
std::stringstream msg;
msg << "Encoding Failed: expected: " << expectedText << std::endl;
msg << " But Computed: " << computedText;
BOOST_CHECK_MESSAGE(
expectedText == computedText,
msg.str()
);
}
dev::test::executeTests("invalidRLPTest", "/RLPTests", dev::test::getFolder(__FILE__) + "/RLPTestsFiller", dev::test::doRlpTests);
}
BOOST_AUTO_TEST_CASE(rlptest)
{
dev::test::executeTests("rlptest", "/RLPTests", dev::test::getFolder(__FILE__) + "/RLPTestsFiller", dev::test::doRlpTests);
}
BOOST_AUTO_TEST_CASE(rlp_decoding_test)
BOOST_AUTO_TEST_CASE(rlpRandom)
{
cnote << "Testing RLP decoding...";
// Uses the same test cases as encoding but in reverse.
// We read into the string of hex values, convert to bytes,
// and then compare the output structure to the json of the
// input object.
js::mValue v;
dev::test::getRLPTestCases(v);
for (auto& i: v.get_obj())
{
js::mObject& o = i.second.get_obj();
cnote << i.first;
dev::test::checkRLPTestCase(o);
test::Options::get();
js::mValue& inputData = o["in"];
bytes payloadToDecode = fromHex(o["out"].get_str());
string testPath = dev::test::getTestPath();
testPath += "/RLPTests/RandomRLPTests";
RLP payload(payloadToDecode);
vector<boost::filesystem::path> testFiles;
boost::filesystem::directory_iterator iterator(testPath);
for(; iterator != boost::filesystem::directory_iterator(); ++iterator)
if (boost::filesystem::is_regular_file(iterator->path()) && iterator->path().extension() == ".json")
testFiles.push_back(iterator->path());
dev::test::checkRLPAgainstJson(inputData, payload);
for (auto& path: testFiles)
{
try
{
cnote << "Testing ..." << path.filename();
json_spirit::mValue v;
string s = asString(dev::contents(path.string()));
TBOOST_REQUIRE_MESSAGE((s.length() > 0), "Content of " + path.string() + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?");
json_spirit::read_string(s, v);
test::Listener::notifySuiteStarted(path.filename().string());
dev::test::doRlpTests(v, false);
}
catch (Exception const& _e)
{
TBOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e));
}
catch (std::exception const& _e)
{
TBOOST_ERROR("Failed test with Exception: " << _e.what());
}
}
}
BOOST_AUTO_TEST_SUITE_END()

29
test/libethereum/BlockchainTestsFiller/bcWalletTestFiller.json

File diff suppressed because one or more lines are too long

193
test/libethereum/StateTestsFiller/stWalletTestFiller.json

File diff suppressed because one or more lines are too long

45
test/libsolidity/SolidityEndToEndTest.cpp

@ -564,20 +564,6 @@ BOOST_AUTO_TEST_CASE(strings)
BOOST_CHECK(callContractFunction("pipeThrough(bytes2,bool)", string("\0\x02", 2), true) == encodeArgs(string("\0\x2", 2), true));
}
BOOST_AUTO_TEST_CASE(empty_string_on_stack)
{
char const* sourceCode = R"(
contract test {
function run() external returns(bytes2 ret) {
var y = "";
ret = y;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("run()") == encodeArgs(byte(0x00)));
}
BOOST_AUTO_TEST_CASE(inc_dec_operators)
{
char const* sourceCode = R"(
@ -5001,6 +4987,37 @@ BOOST_AUTO_TEST_CASE(struct_named_constructor)
BOOST_CHECK(callContractFunction("s()") == encodeArgs(u256(1), true));
}
BOOST_AUTO_TEST_CASE(literal_strings)
{
char const* sourceCode = R"(
contract Test {
string public long;
string public medium;
string public short;
string public empty;
function f() returns (string) {
long = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
medium = "01234567890123456789012345678901234567890123456789012345678901234567890123456789";
short = "123";
empty = "";
return "Hello, World!";
}
}
)";
compileAndRun(sourceCode, 0, "Test");
string longStr = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
string medium = "01234567890123456789012345678901234567890123456789012345678901234567890123456789";
string shortStr = "123";
string hello = "Hello, World!";
BOOST_CHECK(callContractFunction("f()") == encodeDyn(hello));
BOOST_CHECK(callContractFunction("long()") == encodeDyn(longStr));
BOOST_CHECK(callContractFunction("medium()") == encodeDyn(medium));
BOOST_CHECK(callContractFunction("short()") == encodeDyn(shortStr));
BOOST_CHECK(callContractFunction("empty()") == encodeDyn(string()));
}
BOOST_AUTO_TEST_SUITE_END()
}

15
test/libsolidity/SolidityNameAndTypeResolution.cpp

@ -283,7 +283,7 @@ BOOST_AUTO_TEST_CASE(large_string_literal)
char const* text = "contract test {\n"
" function f() { var x = \"123456789012345678901234567890123\"; }"
"}\n";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(balance)
@ -2097,6 +2097,19 @@ BOOST_AUTO_TEST_CASE(struct_named_constructor)
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode));
}
BOOST_AUTO_TEST_CASE(literal_strings)
{
char const* text = R"(
contract Foo {
function f() {
string memory long = "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
string memory short = "123";
}
}
)";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_SUITE_END()
}

6
test/libsolidity/solidityExecutionFramework.h

@ -145,6 +145,12 @@ public:
{
return bytes();
}
//@todo might be extended in the future
template <class Arg>
static bytes encodeDyn(Arg const& _arg)
{
return encodeArgs(u256(0x20), u256(_arg.size()), _arg);
}
private:
template <class CppFunction, class... Args>

Loading…
Cancel
Save