Browse Source

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

cl-refactor
arkpar 10 years ago
parent
commit
fcf209b716
  1. 2
      alethzero/CMakeLists.txt
  2. 28
      cmake/Findv8.cmake
  3. 19
      eth/main.cpp
  4. 2
      ethconsole/CMakeLists.txt
  5. 22
      ethminer/MinerAux.h
  6. 1
      extdep/getstuff.bat
  7. 3
      libdevcore/Common.h
  8. 2
      libdevcore/FixedHash.h
  9. 2
      libdevcore/Guards.h
  10. 4
      libethash-cl/ethash_cl_miner.cpp
  11. 5
      libethash-cl/ethash_cl_miner.h
  12. 2
      libethcore/Ethash.cpp
  13. 4
      libethcore/Ethash.h
  14. 2
      libethereum/BlockChain.cpp
  15. 3
      libethereum/Client.cpp
  16. 2
      libethereum/Client.h
  17. 2
      libethereum/EthereumHost.cpp
  18. 8
      libjsconsole/CMakeLists.txt
  19. 31
      libjsconsole/JSConsole.h
  20. 2
      libjsengine/CMakeLists.txt
  21. 4
      libjsengine/JSEngine.h
  22. 17
      libjsengine/JSV8Engine.cpp
  23. 1
      libjsengine/JSV8Engine.h
  24. 1
      libjsengine/JSV8Printer.cpp
  25. 26
      libjsengine/PrettyPrint.js
  26. 138
      libsolidity/CompilerUtils.cpp
  27. 7
      libsolidity/CompilerUtils.h
  28. 13
      libsolidity/ExpressionCompiler.cpp
  29. 2
      libsolidity/LValue.cpp
  30. 41
      libsolidity/Types.cpp
  31. 36
      libsolidity/Types.h
  32. 39
      libsolidity/Version.cpp
  33. 36
      libsolidity/Version.h
  34. 2
      mix/CMakeLists.txt
  35. 3
      mix/CodeModel.cpp
  36. 10
      solc/CommandLineInterface.cpp
  37. 1
      test/TestHelper.h
  38. 268
      test/libdevcore/rlp.cpp
  39. 29
      test/libethereum/BlockchainTestsFiller/bcWalletTestFiller.json
  40. 193
      test/libethereum/StateTestsFiller/stWalletTestFiller.json
  41. 45
      test/libsolidity/SolidityEndToEndTest.cpp
  42. 15
      test/libsolidity/SolidityNameAndTypeResolution.cpp
  43. 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 ()

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()

19
eth/main.cpp

@ -266,8 +266,7 @@ enum class OperationMode
{
Node,
Import,
Export,
Rescue
Export
};
enum class Format
@ -1085,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;
@ -1252,11 +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")
mode = OperationMode::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);
@ -1556,12 +1555,6 @@ int main(int argc, char** argv)
}
};
if (mode == OperationMode::Rescue)
{
web3.ethereum()->rescue();
exit(0);
}
if (mode == OperationMode::Export)
{
ofstream fout(filename, std::ofstream::binary);

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)

22
ethminer/MinerAux.h

@ -81,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
{
@ -484,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)
@ -501,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));
@ -553,7 +559,7 @@ private:
unsigned m_localWorkSize = ethash_cl_miner::c_defaultLocalWorkSize;
unsigned m_msPerBatch = ethash_cl_miner::c_defaultMSPerBatch;
#endif
boost::optional<uint64_t> m_currentBlock;
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;

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);

4
libethash-cl/ethash_cl_miner.cpp

@ -149,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;
@ -158,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
{

5
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>
@ -50,7 +49,7 @@ public:
unsigned _msPerBatch,
bool _allowCPU,
unsigned _extraGPUMemory,
boost::optional<uint64_t> _currentBlock
uint64_t _currentBlock
);
bool init(

2
libethcore/Ethash.cpp

@ -416,7 +416,7 @@ bool Ethash::GPUMiner::configureGPU(
unsigned _deviceId,
bool _allowCPU,
unsigned _extraGPUMemory,
boost::optional<uint64_t> _currentBlock
uint64_t _currentBlock
)
{
s_platformId = _platformId;

4
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()); }

2
libethereum/BlockChain.cpp

@ -844,7 +844,7 @@ void BlockChain::rescue(OverlayDB& _db)
cout << "details..." << flush;
BlockDetails bd = details(h);
cout << "state..." << flush;
if (_db.exists(sha3(bi.stateRoot)))
if (_db.exists(bi.stateRoot))
break;
}
catch (...) {}

3
libethereum/Client.cpp

@ -92,6 +92,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);

2
libethereum/Client.h

@ -218,8 +218,6 @@ public:
void setExtraData(bytes const& _extraData) { m_extraData = _extraData; }
/// Rewind to a prior head.
void rewind(unsigned _n) { m_bc.rewind(_n); }
/// Rescue the chain.
void rescue() { m_bc.rescue(m_stateDB); }
protected:
/// InterfaceStub methods

2
libethereum/EthereumHost.cpp

@ -118,7 +118,7 @@ void EthereumHost::doWork()
if (m_syncStart)
{
DEV_GUARDED(x_sync);
DEV_GUARDED(x_sync)
if (!m_sync)
{
time_t now = std::chrono::system_clock::to_time_t(chrono::system_clock::now());

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;
}
}

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:

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)

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