Browse Source

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

cl-refactor
Gav Wood 10 years ago
parent
commit
3ded0bbcdc
  1. 17
      CMakeLists.txt
  2. 1
      eth/main.cpp
  3. 9
      extdep/getstuff.bat
  4. 6
      libdevcore/Log.cpp
  5. 8
      libdevcore/Log.h
  6. 4
      libdevcrypto/Common.cpp
  7. 31
      libethash-cl/ethash_cl_miner.cpp
  8. 2
      libethcore/Ethash.cpp
  9. 11
      libsolidity/AST.cpp
  10. 11
      libsolidity/AST.h
  11. 17
      libsolidity/ASTJsonConverter.cpp
  12. 5
      libsolidity/ASTJsonConverter.h
  13. 4
      libsolidity/Compiler.h
  14. 4
      libsolidity/CompilerContext.h
  15. 9
      libsolidity/CompilerStack.cpp
  16. 5
      libsolidity/CompilerStack.h
  17. 7
      libsolidity/CompilerUtils.cpp
  18. 2
      libsolidity/CompilerUtils.h
  19. 14
      libsolidity/DeclarationContainer.cpp
  20. 112
      libsolidity/ExpressionCompiler.cpp
  21. 18
      libsolidity/ExpressionCompiler.h
  22. 12
      libsolidity/Types.cpp
  23. 29
      libsolidity/Types.h
  24. 8
      mix/ClientModel.cpp
  25. 7
      mix/qml/Debugger.qml
  26. 96
      mix/qml/QAddressView.qml
  27. 9
      mix/qml/StateDialog.qml
  28. 31
      mix/qml/StructView.qml
  29. 14
      mix/qml/TransactionDialog.qml
  30. 1
      mix/res.qrc
  31. 1
      mix/test/qml/TestMain.qml
  32. 44
      mix/test/qml/js/TestDebugger.js
  33. 2
      mix/test/qml/js/TestTutorial.js
  34. 7
      solc/CMakeLists.txt
  35. 100
      solc/CommandLineInterface.cpp
  36. 1
      solc/CommandLineInterface.h
  37. 124
      solc/jsonCompiler.cpp
  38. 2
      test/TestHelper.cpp
  39. 8
      test/fuzzTesting/CMakeLists.txt
  40. 84
      test/libsolidity/SolidityEndToEndTest.cpp

17
CMakeLists.txt

@ -1,10 +1,22 @@
# cmake global # cmake global
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 2.8.12)
project(ethereum)
set(CMAKE_AUTOMOC ON)
# link_directories interprate relative paths with respect to CMAKE_CURRENT_SOURCE_DIR
cmake_policy(SET CMP0015 NEW)
# let cmake autolink dependencies on windows # let cmake autolink dependencies on windows
# it's specified globally, cause qt libraries requires that on windows and they are also found globally # it's specified globally, cause qt libraries requires that on windows and they are also found globally
cmake_policy(SET CMP0020 NEW) cmake_policy(SET CMP0020 NEW)
project(ethereum) # 3.1 and above
if ((${CMAKE_MAJOR_VERSION} GREATER 2) AND (${CMAKE_MINOR_VERSION} GREATER 0))
# implicitly dereference variables (deprecated in 3.1)
cmake_policy(SET CMP0054 NEW)
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
@ -124,9 +136,6 @@ endfunction()
###################################################################################################### ######################################################################################################
set(CMAKE_AUTOMOC ON)
cmake_policy(SET CMP0015 NEW)
# Clear invalid option # Clear invalid option
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release") if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
if (PARANOID) if (PARANOID)

1
eth/main.cpp

@ -612,6 +612,7 @@ int main(int argc, char** argv)
else if (arg == "--opencl-device" && i + 1 < argc) else if (arg == "--opencl-device" && i + 1 < argc)
try { try {
openclDevice = stol(argv[++i]); openclDevice = stol(argv[++i]);
miningThreads = 1;
} }
catch (...) catch (...)
{ {

9
extdep/getstuff.bat

@ -24,10 +24,10 @@ set eth_version=%2
cd download cd download
if not exist %eth_name%-%eth_version%.tar.gz ( if not exist %eth_name%-%eth_version%.tar.gz (
bitsadmin /cancel %eth_name%-%eth_version%.tar.gz for /f "tokens=2 delims={}" %%g in ('bitsadmin /create %eth_name%-%eth_version%.tar.gz') do (
bitsadmin /create %eth_name%-%eth_version%.tar.gz bitsadmin /transfer {%%g} /download /priority normal %eth_server%/%eth_name%-%eth_version%.tar.gz %cd%\%eth_name%-%eth_version%.tar.gz
bitsadmin /transfer %eth_name%-%eth_version%.tar.gz /download /priority normal %eth_server%/%eth_name%-%eth_version%.tar.gz %cd%\%eth_name%-%eth_version%.tar.gz bitsadmin /cancel {%%g}
bitsadmin /cancel %eth_name%-%eth_version%.tar.gz )
) )
if not exist %eth_name%-%eth_version% cmake -E tar -zxvf %eth_name%-%eth_version%.tar.gz if not exist %eth_name%-%eth_version% cmake -E tar -zxvf %eth_name%-%eth_version%.tar.gz
cmake -E copy_directory %eth_name%-%eth_version% ..\install\windows cmake -E copy_directory %eth_name%-%eth_version% ..\install\windows
@ -35,3 +35,4 @@ cmake -E copy_directory %eth_name%-%eth_version% ..\install\windows
cd .. cd ..
goto :EOF goto :EOF

6
libdevcore/Log.cpp

@ -24,6 +24,7 @@
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#include <boost/asio/ip/tcp.hpp>
#include "Guards.h" #include "Guards.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -69,6 +70,11 @@ LogOutputStreamBase::LogOutputStreamBase(char const* _id, std::type_info const*
} }
} }
void LogOutputStreamBase::append(boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> const& _t)
{
m_sstr << EthNavyUnder "tcp://" << _t << EthReset;
}
/// Associate a name with each thread for nice logging. /// Associate a name with each thread for nice logging.
struct ThreadLocalLogName struct ThreadLocalLogName
{ {

8
libdevcore/Log.h

@ -26,7 +26,6 @@
#include <ctime> #include <ctime>
#include <chrono> #include <chrono>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include <boost/asio.hpp>
#include "vector_ref.h" #include "vector_ref.h"
#include "Common.h" #include "Common.h"
#include "CommonIO.h" #include "CommonIO.h"
@ -34,6 +33,8 @@
#include "FixedHash.h" #include "FixedHash.h"
#include "Terminal.h" #include "Terminal.h"
namespace boost { namespace asio { namespace ip { template<class T>class basic_endpoint; class tcp; } } }
namespace dev namespace dev
{ {
@ -127,6 +128,7 @@ public:
void append(std::string const& _t) { m_sstr << EthGreen "\"" + _t + "\"" EthReset; } void append(std::string const& _t) { m_sstr << EthGreen "\"" + _t + "\"" EthReset; }
void append(bytes const& _t) { m_sstr << EthYellow "%" << toHex(_t) << EthReset; } void append(bytes const& _t) { m_sstr << EthYellow "%" << toHex(_t) << EthReset; }
void append(bytesConstRef _t) { m_sstr << EthYellow "%" << toHex(_t) << EthReset; } void append(bytesConstRef _t) { m_sstr << EthYellow "%" << toHex(_t) << EthReset; }
void append(boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> const& _t);
template <class T> void append(std::vector<T> const& _t) template <class T> void append(std::vector<T> const& _t)
{ {
m_sstr << EthWhite "[" EthReset; m_sstr << EthWhite "[" EthReset;
@ -174,10 +176,6 @@ public:
{ {
m_sstr << toString(_t); m_sstr << toString(_t);
} }
template <class T> void append(boost::asio::ip::tcp::endpoint const& _t)
{
m_sstr << EthNavyUnder "tcp://" << _t << EthReset;
}
protected: protected:
bool m_autospacing = false; bool m_autospacing = false;

4
libdevcrypto/Common.cpp

@ -39,7 +39,9 @@ bool dev::SignatureStruct::isValid() const
{ {
if (v > 1 || if (v > 1 ||
r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") || r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") ||
s >= h256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f")) s >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") ||
s < h256("0x01") ||
r < h256("0x01"))
return false; return false;
return true; return true;
} }

31
libethash-cl/ethash_cl_miner.cpp

@ -24,6 +24,7 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <iostream>
#include <assert.h> #include <assert.h>
#include <queue> #include <queue>
#include <vector> #include <vector>
@ -43,6 +44,8 @@
#undef min #undef min
#undef max #undef max
using namespace std;
static void add_definition(std::string& source, char const* id, unsigned value) static void add_definition(std::string& source, char const* id, unsigned value)
{ {
char buf[256]; char buf[256];
@ -63,7 +66,7 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic
cl::Platform::get(&platforms); cl::Platform::get(&platforms);
if (platforms.empty()) if (platforms.empty())
{ {
debugf("No OpenCL platforms found.\n"); cout << "No OpenCL platforms found." << endl;
return std::string(); return std::string();
} }
@ -73,7 +76,7 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic
platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty()) if (devices.empty())
{ {
debugf("No OpenCL devices found.\n"); cout << "No OpenCL devices found." << endl;
return std::string(); return std::string();
} }
@ -91,7 +94,7 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId)
cl::Platform::get(&platforms); cl::Platform::get(&platforms);
if (platforms.empty()) if (platforms.empty())
{ {
debugf("No OpenCL platforms found.\n"); cout << "No OpenCL platforms found." << endl;
return 0; return 0;
} }
@ -100,7 +103,7 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId)
platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty()) if (devices.empty())
{ {
debugf("No OpenCL devices found.\n"); cout << "No OpenCL devices found." << endl;
return 0; return 0;
} }
return devices.size(); return devices.size();
@ -124,7 +127,7 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function<void(void*
cl::Platform::get(&platforms); cl::Platform::get(&platforms);
if (platforms.empty()) if (platforms.empty())
{ {
debugf("No OpenCL platforms found.\n"); cout << "No OpenCL platforms found." << endl;
return false; return false;
} }
@ -132,31 +135,25 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function<void(void*
_platformId = std::min<unsigned>(_platformId, platforms.size() - 1); _platformId = std::min<unsigned>(_platformId, platforms.size() - 1);
fprintf(stderr, "Using platform: %s\n", platforms[_platformId].getInfo<CL_PLATFORM_NAME>().c_str()); cout << "Using platform: " << platforms[_platformId].getInfo<CL_PLATFORM_NAME>().c_str() << endl;
// get GPU device of the default platform // get GPU device of the default platform
std::vector<cl::Device> devices; std::vector<cl::Device> devices;
platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty()) if (devices.empty())
{ {
debugf("No OpenCL devices found.\n"); cout << "No OpenCL devices found." << endl;
return false; return false;
} }
// use default device // use selected device
cl::Device& device = devices[std::min<unsigned>(_deviceId, devices.size() - 1)]; cl::Device& device = devices[std::min<unsigned>(_deviceId, devices.size() - 1)];
for (unsigned n = 0; n < devices.size(); ++n)
{
auto version = devices[n].getInfo<CL_DEVICE_VERSION>();
auto name = devices[n].getInfo<CL_DEVICE_NAME>();
fprintf(stderr, "%s %d: %s (%s)\n", n == _deviceId ? "USING " : " ", n, name.c_str(), version.c_str());
}
std::string device_version = device.getInfo<CL_DEVICE_VERSION>(); std::string device_version = device.getInfo<CL_DEVICE_VERSION>();
fprintf(stderr, "Using device: %s (%s)\n", device.getInfo<CL_DEVICE_NAME>().c_str(),device_version.c_str()); cout << "Using device: " << device.getInfo<CL_DEVICE_NAME>().c_str() << "(" << device_version.c_str() << ")" << endl;
if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0) if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0)
{ {
debugf("OpenCL 1.0 is not supported.\n"); cout << "OpenCL 1.0 is not supported." << endl;
return false; return false;
} }
if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0) if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0)
@ -190,7 +187,7 @@ bool ethash_cl_miner::init(ethash_params const& params, std::function<void(void*
} }
catch (cl::Error err) catch (cl::Error err)
{ {
debugf("%s\n", program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str()); cout << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str();
return false; return false;
} }
m_hash_kernel = cl::Kernel(program, "ethash_hash"); m_hash_kernel = cl::Kernel(program, "ethash_hash");

2
libethcore/Ethash.cpp

@ -311,7 +311,7 @@ void Ethash::GPUMiner::workLoop()
auto p = EthashAux::params(m_minerSeed); auto p = EthashAux::params(m_minerSeed);
auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); }; auto cb = [&](void* d) { EthashAux::full(m_minerSeed, bytesRef((byte*)d, p.full_size)); };
unsigned device = instances() > 0 ? index() : s_deviceId; unsigned device = instances() > 1 ? index() : s_deviceId;
m_miner->init(p, cb, 32, s_platformId, device); m_miner->init(p, cb, 32, s_platformId, device);
} }

11
libsolidity/AST.cpp

@ -450,14 +450,11 @@ void FunctionDefinition::checkTypeRequirements()
{ {
if (!var->getType()->canLiveOutsideStorage()) if (!var->getType()->canLiveOutsideStorage())
BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage.")); BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage."));
// todo delete when will be implemented arrays as parameter type in internal functions
if (getVisibility() == Visibility::Public && var->getType()->getCategory() == Type::Category::Array)
BOOST_THROW_EXCEPTION(var->createTypeError("Arrays only implemented for external functions."));
if (getVisibility() >= Visibility::Public && !(var->getType()->externalType())) if (getVisibility() >= Visibility::Public && !(var->getType()->externalType()))
{ BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed for public and external functions."));
// todo delete when will be implemented arrays as parameter type in internal functions
if (getVisibility() == Visibility::Public && var->getType()->getCategory() == Type::Category::Array)
BOOST_THROW_EXCEPTION(var->createTypeError("Arrays only implemented for external functions."));
else
BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed for public and external functions."));
}
} }
for (ASTPointer<ModifierInvocation> const& modifier: m_functionModifiers) for (ASTPointer<ModifierInvocation> const& modifier: m_functionModifiers)
modifier->checkTypeRequirements(isConstructor() ? modifier->checkTypeRequirements(isConstructor() ?

11
libsolidity/AST.h

@ -143,8 +143,8 @@ public:
ASTString const& getName() const { return *m_name; } ASTString const& getName() const { return *m_name; }
Visibility getVisibility() const { return m_visibility == Visibility::Default ? getDefaultVisibility() : m_visibility; } Visibility getVisibility() const { return m_visibility == Visibility::Default ? getDefaultVisibility() : m_visibility; }
bool isPublic() const { return getVisibility() >= Visibility::Public; } bool isPublic() const { return getVisibility() >= Visibility::Public; }
bool isVisibleInContract() const { return getVisibility() != Visibility::External; } virtual bool isVisibleInContract() const { return getVisibility() != Visibility::External; }
virtual bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Internal; } bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Internal; }
/// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope.
/// Available only after name and type resolution step. /// Available only after name and type resolution step.
@ -156,7 +156,7 @@ public:
/// contract types. /// contract types.
virtual TypePointer getType(ContractDefinition const* m_currentContract = nullptr) const = 0; virtual TypePointer getType(ContractDefinition const* m_currentContract = nullptr) const = 0;
virtual bool isLValue() const { return false; } virtual bool isLValue() const { return false; }
virtual bool isPartOfExternalInterface() const { return false; }; virtual bool isPartOfExternalInterface() const { return false; }
protected: protected:
virtual Visibility getDefaultVisibility() const { return Visibility::Public; } virtual Visibility getDefaultVisibility() const { return Visibility::Public; }
@ -443,10 +443,9 @@ public:
ASTPointer<ParameterList> const& getReturnParameterList() const { return m_returnParameters; } ASTPointer<ParameterList> const& getReturnParameterList() const { return m_returnParameters; }
Block const& getBody() const { return *m_body; } Block const& getBody() const { return *m_body; }
virtual bool isVisibleInDerivedContracts() const override virtual bool isVisibleInContract() const override
{ {
return !isConstructor() && !getName().empty() && isVisibleInContract() && return Declaration::isVisibleInContract() && !isConstructor() && !getName().empty();
getVisibility() >= Visibility::Internal;
} }
virtual TypePointer getType(ContractDefinition const*) const override; virtual TypePointer getType(ContractDefinition const*) const override;
virtual bool isPartOfExternalInterface() const override { return isPublic() && !m_isConstructor && !getName().empty(); } virtual bool isPartOfExternalInterface() const override { return isPublic() && !m_isConstructor && !getName().empty(); }

17
libsolidity/ASTJsonConverter.cpp

@ -78,10 +78,16 @@ ASTJsonConverter::ASTJsonConverter(ASTNode const& _ast): m_ast(&_ast)
void ASTJsonConverter::print(ostream& _stream) void ASTJsonConverter::print(ostream& _stream)
{ {
m_ast->accept(*this); process();
_stream << m_astJson; _stream << m_astJson;
} }
Json::Value const& ASTJsonConverter::json()
{
process();
return m_astJson;
}
bool ASTJsonConverter::visit(ImportDirective const& _node) bool ASTJsonConverter::visit(ImportDirective const& _node)
{ {
addJsonNode("Import", { make_pair("file", _node.getIdentifier())}); addJsonNode("Import", { make_pair("file", _node.getIdentifier())});
@ -460,9 +466,16 @@ void ASTJsonConverter::endVisit(Literal const&)
{ {
} }
void ASTJsonConverter::process()
{
if (!processed)
m_ast->accept(*this);
processed = true;
}
string ASTJsonConverter::getType(Expression const& _expression) string ASTJsonConverter::getType(Expression const& _expression)
{ {
return (_expression.getType()) ? _expression.getType()->toString() : "Unknown"; return (_expression.getType()) ? _expression.getType()->toString() : "Unknown";
} }
} }

5
libsolidity/ASTJsonConverter.h

@ -44,6 +44,7 @@ public:
ASTJsonConverter(ASTNode const& _ast); ASTJsonConverter(ASTNode const& _ast);
/// Output the json representation of the AST to _stream. /// Output the json representation of the AST to _stream.
void print(std::ostream& _stream); void print(std::ostream& _stream);
Json::Value const& json();
bool visit(ImportDirective const& _node) override; bool visit(ImportDirective const& _node) override;
bool visit(ContractDefinition const& _node) override; bool visit(ContractDefinition const& _node) override;
@ -114,6 +115,7 @@ public:
void endVisit(Literal const&) override; void endVisit(Literal const&) override;
private: private:
void process();
void addKeyValue(Json::Value& _obj, std::string const& _key, std::string const& _val); void addKeyValue(Json::Value& _obj, std::string const& _key, std::string const& _val);
void addJsonNode(std::string const& _nodeName, void addJsonNode(std::string const& _nodeName,
std::initializer_list<std::pair<std::string const, std::string const>> _list, std::initializer_list<std::pair<std::string const, std::string const>> _list,
@ -123,8 +125,9 @@ private:
{ {
solAssert(!m_jsonNodePtrs.empty(), "Uneven json nodes stack. Internal error."); solAssert(!m_jsonNodePtrs.empty(), "Uneven json nodes stack. Internal error.");
m_jsonNodePtrs.pop(); m_jsonNodePtrs.pop();
}; }
bool processed = false;
Json::Value m_astJson; Json::Value m_astJson;
std::stack<Json::Value*> m_jsonNodePtrs; std::stack<Json::Value*> m_jsonNodePtrs;
std::string m_source; std::string m_source;

4
libsolidity/Compiler.h

@ -43,9 +43,9 @@ public:
bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);}
/// @arg _sourceCodes is the map of input files to source code strings /// @arg _sourceCodes is the map of input files to source code strings
/// @arg _inJsonFromat shows whether the out should be in Json format /// @arg _inJsonFromat shows whether the out should be in Json format
void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const Json::Value streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const
{ {
m_context.streamAssembly(_stream, _sourceCodes, _inJsonFormat); return m_context.streamAssembly(_stream, _sourceCodes, _inJsonFormat);
} }
/// @returns Assembly items of the normal compiler context /// @returns Assembly items of the normal compiler context
eth::AssemblyItems const& getAssemblyItems() const { return m_context.getAssembly().getItems(); } eth::AssemblyItems const& getAssemblyItems() const { return m_context.getAssembly().getItems(); }

4
libsolidity/CompilerContext.h

@ -123,9 +123,9 @@ public:
eth::Assembly const& getAssembly() const { return m_asm; } eth::Assembly const& getAssembly() const { return m_asm; }
/// @arg _sourceCodes is the map of input files to source code strings /// @arg _sourceCodes is the map of input files to source code strings
/// @arg _inJsonFormat shows whether the out should be in Json format /// @arg _inJsonFormat shows whether the out should be in Json format
void streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const Json::Value streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const
{ {
m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat); return m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat);
} }
bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); } bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); }

9
libsolidity/CompilerStack.cpp

@ -184,13 +184,16 @@ dev::h256 CompilerStack::getContractCodeHash(string const& _contractName) const
return dev::sha3(getRuntimeBytecode(_contractName)); return dev::sha3(getRuntimeBytecode(_contractName));
} }
void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const Json::Value CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const
{ {
Contract const& contract = getContract(_contractName); Contract const& contract = getContract(_contractName);
if (contract.compiler) if (contract.compiler)
contract.compiler->streamAssembly(_outStream, _sourceCodes, _inJsonFormat); return contract.compiler->streamAssembly(_outStream, _sourceCodes, _inJsonFormat);
else else
{
_outStream << "Contract not fully implemented" << endl; _outStream << "Contract not fully implemented" << endl;
return Json::Value();
}
} }
string const& CompilerStack::getInterface(string const& _contractName) const string const& CompilerStack::getInterface(string const& _contractName) const
@ -264,7 +267,7 @@ void CompilerStack::reset(bool _keepSources)
{ {
m_sources.clear(); m_sources.clear();
if (m_addStandardSources) if (m_addStandardSources)
addSources(StandardSources); addSources(StandardSources, true);
} }
m_globalContext.reset(); m_globalContext.reset();
m_sourceOrder.clear(); m_sourceOrder.clear();

5
libsolidity/CompilerStack.h

@ -28,6 +28,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <json/json.h>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h> #include <libdevcore/FixedHash.h>
@ -104,7 +105,7 @@ public:
/// @arg _sourceCodes is the map of input files to source code strings /// @arg _sourceCodes is the map of input files to source code strings
/// @arg _inJsonFromat shows whether the out should be in Json format /// @arg _inJsonFromat shows whether the out should be in Json format
/// Prerequisite: Successful compilation. /// Prerequisite: Successful compilation.
void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const; Json::Value streamAssembly(std::ostream& _outStream, std::string const& _contractName = "", StringMap _sourceCodes = StringMap(), bool _inJsonFormat = false) const;
/// Returns a string representing the contract interface in JSON. /// Returns a string representing the contract interface in JSON.
/// Prerequisite: Successful call to parse or compile. /// Prerequisite: Successful call to parse or compile.
@ -140,7 +141,7 @@ private:
std::shared_ptr<SourceUnit> ast; std::shared_ptr<SourceUnit> ast;
std::string interface; std::string interface;
bool isLibrary = false; bool isLibrary = false;
void reset() { scanner.reset(); ast.reset(); interface.clear(); isLibrary = false;} void reset() { scanner.reset(); ast.reset(); interface.clear(); }
}; };
struct Contract struct Contract

7
libsolidity/CompilerUtils.cpp

@ -155,6 +155,13 @@ void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
m_context << eth::dupInstruction(_stackDepth); m_context << eth::dupInstruction(_stackDepth);
} }
void CompilerUtils::moveToStackTop(unsigned _stackDepth)
{
solAssert(_stackDepth <= 15, "Stack too deep.");
for (unsigned i = 0; i < _stackDepth; ++i)
m_context << eth::swapInstruction(1 + i);
}
void CompilerUtils::popStackElement(Type const& _type) void CompilerUtils::popStackElement(Type const& _type)
{ {
popStackSlots(_type.getSizeOnStack()); popStackSlots(_type.getSizeOnStack());

2
libsolidity/CompilerUtils.h

@ -77,6 +77,8 @@ public:
/// Copies an item that occupies @a _itemSize stack slots from a stack depth of @a _stackDepth /// Copies an item that occupies @a _itemSize stack slots from a stack depth of @a _stackDepth
/// to the top of the stack. /// to the top of the stack.
void copyToStackTop(unsigned _stackDepth, unsigned _itemSize); void copyToStackTop(unsigned _stackDepth, unsigned _itemSize);
/// Moves a single stack element (with _stackDepth items on top of it) to the top of the stack.
void moveToStackTop(unsigned _stackDepth);
/// Removes the current value from the top of the stack. /// Removes the current value from the top of the stack.
void popStackElement(Type const& _type); void popStackElement(Type const& _type);
/// Removes element from the top of the stack _amount times. /// Removes element from the top of the stack _amount times.

14
libsolidity/DeclarationContainer.cpp

@ -37,19 +37,25 @@ bool DeclarationContainer::registerDeclaration(Declaration const& _declaration,
if (_update) if (_update)
{ {
solAssert(!dynamic_cast<FunctionDefinition const*>(&_declaration), "Attempt to update function definition."); solAssert(!dynamic_cast<FunctionDefinition const*>(&_declaration), "Attempt to update function definition.");
m_declarations[name].clear(); m_declarations.erase(name);
m_invisibleDeclarations[name].clear(); m_invisibleDeclarations.erase(name);
} }
else else
{ {
vector<Declaration const*> declarations;
if (m_declarations.count(name))
declarations += m_declarations.at(name);
if (m_invisibleDeclarations.count(name))
declarations += m_invisibleDeclarations.at(name);
if (dynamic_cast<FunctionDefinition const*>(&_declaration)) if (dynamic_cast<FunctionDefinition const*>(&_declaration))
{ {
// check that all other declarations with the same name are functions // check that all other declarations with the same name are functions
for (auto&& declaration: m_invisibleDeclarations[name] + m_declarations[name])
for (Declaration const* declaration: declarations)
if (!dynamic_cast<FunctionDefinition const*>(declaration)) if (!dynamic_cast<FunctionDefinition const*>(declaration))
return false; return false;
} }
else if (m_declarations.count(name) > 0 || m_invisibleDeclarations.count(name) > 0) else if (!declarations.empty())
return false; return false;
} }

112
libsolidity/ExpressionCompiler.cpp

@ -531,9 +531,12 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
break; break;
case Location::SHA3: case Location::SHA3:
{ {
m_context << u256(0); // we might compute a sha as part of argumentsAppendCopyToMemory, this is only a hack
appendArgumentsCopyToMemory(arguments, TypePointers(), function.padArguments()); // and should be removed once we have a real free memory pointer
m_context << u256(0) << eth::Instruction::SHA3; m_context << u256(0x40);
appendArgumentsCopyToMemory(arguments, TypePointers(), function.padArguments(), false, true);
m_context << u256(0x40) << eth::Instruction::SWAP1 << eth::Instruction::SUB;
m_context << u256(0x40) << eth::Instruction::SHA3;
break; break;
} }
case Location::Log0: case Location::Log0:
@ -574,11 +577,19 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
} }
solAssert(numIndexed <= 4, "Too many indexed arguments."); solAssert(numIndexed <= 4, "Too many indexed arguments.");
// Copy all non-indexed arguments to memory (data) // Copy all non-indexed arguments to memory (data)
m_context << u256(0); // Memory position is only a hack and should be removed once we have free memory pointer.
m_context << u256(0x40);
vector<ASTPointer<Expression const>> nonIndexedArgs;
TypePointers nonIndexedTypes;
for (unsigned arg = 0; arg < arguments.size(); ++arg) for (unsigned arg = 0; arg < arguments.size(); ++arg)
if (!event.getParameters()[arg]->isIndexed()) if (!event.getParameters()[arg]->isIndexed())
appendExpressionCopyToMemory(*function.getParameterTypes()[arg], *arguments[arg]); {
m_context << u256(0) << eth::logInstruction(numIndexed); nonIndexedArgs.push_back(arguments[arg]);
nonIndexedTypes.push_back(function.getParameterTypes()[arg]);
}
appendArgumentsCopyToMemory(nonIndexedArgs, nonIndexedTypes);
m_context << u256(0x40) << eth::Instruction::SWAP1 << eth::Instruction::SUB;
m_context << u256(0x40) << eth::logInstruction(numIndexed);
break; break;
} }
case Location::BlockHash: case Location::BlockHash:
@ -1046,8 +1057,14 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
// For bare call, activate "4 byte pad exception": If the first argument has exactly 4 bytes, // For bare call, activate "4 byte pad exception": If the first argument has exactly 4 bytes,
// do not pad it to 32 bytes. // do not pad it to 32 bytes.
appendArgumentsCopyToMemory(_arguments, _functionType.getParameterTypes(), // If the function takes arbitrary parameters, copy dynamic length data in place.
_functionType.padArguments(), bare); appendArgumentsCopyToMemory(
_arguments,
_functionType.getParameterTypes(),
_functionType.padArguments(),
bare,
_functionType.takesArbitraryParameters()
);
// CALL arguments: outSize, outOff, inSize, (already present up to here) // CALL arguments: outSize, outOff, inSize, (already present up to here)
// inOff, value, addr, gas (stack top) // inOff, value, addr, gas (stack top)
@ -1075,7 +1092,13 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
m_context << eth::Instruction::POP; // pop contract address m_context << eth::Instruction::POP; // pop contract address
if (firstType) if (_functionType.getLocation() == FunctionType::Location::RIPEMD160)
{
// fix: built-in contract returns right-aligned data
CompilerUtils(m_context).loadFromMemory(0, IntegerType(160), false, true);
appendTypeConversion(IntegerType(160), FixedBytesType(20));
}
else if (firstType)
CompilerUtils(m_context).loadFromMemory(0, *firstType, false, true); CompilerUtils(m_context).loadFromMemory(0, *firstType, false, true);
} }
@ -1083,20 +1106,72 @@ void ExpressionCompiler::appendArgumentsCopyToMemory(
vector<ASTPointer<Expression const>> const& _arguments, vector<ASTPointer<Expression const>> const& _arguments,
TypePointers const& _types, TypePointers const& _types,
bool _padToWordBoundaries, bool _padToWordBoundaries,
bool _padExceptionIfFourBytes bool _padExceptionIfFourBytes,
bool _copyDynamicDataInPlace
) )
{ {
solAssert(_types.empty() || _types.size() == _arguments.size(), ""); solAssert(_types.empty() || _types.size() == _arguments.size(), "");
TypePointers types = _types;
if (_types.empty())
for (ASTPointer<Expression const> const& argument: _arguments)
types.push_back(argument->getType()->getRealType());
vector<size_t> dynamicArguments;
unsigned stackSizeOfDynamicTypes = 0;
for (size_t i = 0; i < _arguments.size(); ++i) for (size_t i = 0; i < _arguments.size(); ++i)
{ {
_arguments[i]->accept(*this); _arguments[i]->accept(*this);
TypePointer const& expectedType = _types.empty() ? _arguments[i]->getType()->getRealType() : _types[i]; TypePointer argType = types[i]->externalType();
appendTypeConversion(*_arguments[i]->getType(), *expectedType, true); solAssert(!!argType, "Externalable type expected.");
if (argType->isValueType())
appendTypeConversion(*_arguments[i]->getType(), *argType, true);
else
argType = _arguments[i]->getType()->getRealType()->externalType();
solAssert(!!argType, "Externalable type expected.");
bool pad = _padToWordBoundaries; bool pad = _padToWordBoundaries;
// Do not pad if the first argument has exactly four bytes // Do not pad if the first argument has exactly four bytes
if (i == 0 && pad && _padExceptionIfFourBytes && expectedType->getCalldataEncodedSize(false) == 4) if (i == 0 && pad && _padExceptionIfFourBytes && argType->getCalldataEncodedSize(false) == 4)
pad = false; pad = false;
appendTypeMoveToMemory(*expectedType, pad); if (!_copyDynamicDataInPlace && argType->isDynamicallySized())
{
solAssert(argType->getCategory() == Type::Category::Array, "Unknown dynamic type.");
auto const& arrayType = dynamic_cast<ArrayType const&>(*_arguments[i]->getType());
// move memory reference to top of stack
CompilerUtils(m_context).moveToStackTop(arrayType.getSizeOnStack());
if (arrayType.getLocation() == ArrayType::Location::CallData)
m_context << eth::Instruction::DUP2; // length is on stack
else if (arrayType.getLocation() == ArrayType::Location::Storage)
m_context << eth::Instruction::DUP3 << eth::Instruction::SLOAD;
else
{
solAssert(arrayType.getLocation() == ArrayType::Location::Memory, "");
m_context << eth::Instruction::DUP2 << eth::Instruction::MLOAD;
}
appendTypeMoveToMemory(IntegerType(256), true);
stackSizeOfDynamicTypes += arrayType.getSizeOnStack();
dynamicArguments.push_back(i);
}
else
appendTypeMoveToMemory(*argType, pad);
}
// copy dynamic values to memory
unsigned dynStackPointer = stackSizeOfDynamicTypes;
// stack layout: <dyn arg 1> ... <dyn arg m> <memory pointer>
for (size_t i: dynamicArguments)
{
auto const& arrayType = dynamic_cast<ArrayType const&>(*_arguments[i]->getType());
CompilerUtils(m_context).copyToStackTop(1 + dynStackPointer, arrayType.getSizeOnStack());
dynStackPointer -= arrayType.getSizeOnStack();
appendTypeMoveToMemory(arrayType, true);
}
solAssert(dynStackPointer == 0, "");
// remove dynamic values (and retain memory pointer)
if (stackSizeOfDynamicTypes > 0)
{
m_context << eth::swapInstruction(stackSizeOfDynamicTypes);
CompilerUtils(m_context).popStackSlots(stackSizeOfDynamicTypes);
} }
} }
@ -1108,8 +1183,13 @@ void ExpressionCompiler::appendTypeMoveToMemory(Type const& _type, bool _padToWo
void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression) void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression)
{ {
_expression.accept(*this); _expression.accept(*this);
appendTypeConversion(*_expression.getType(), _expectedType, true); if (_expectedType.isValueType())
appendTypeMoveToMemory(_expectedType); {
appendTypeConversion(*_expression.getType(), _expectedType, true);
appendTypeMoveToMemory(_expectedType);
}
else
appendTypeMoveToMemory(*_expression.getType()->getRealType());
} }
void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression) void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression)

18
libsolidity/ExpressionCompiler.h

@ -100,12 +100,18 @@ private:
/// Appends code to call a function of the given type with the given arguments. /// Appends code to call a function of the given type with the given arguments.
void appendExternalFunctionCall(FunctionType const& _functionType, std::vector<ASTPointer<Expression const>> const& _arguments, void appendExternalFunctionCall(FunctionType const& _functionType, std::vector<ASTPointer<Expression const>> const& _arguments,
bool bare = false); bool bare = false);
/// Appends code that evaluates the given arguments and moves the result to memory. The memory offset is /// Appends code that evaluates the given arguments and moves the result to memory encoded as
/// expected to be on the stack and is updated by this call. /// specified by the ABI. The memory offset is expected to be on the stack and is updated by
void appendArgumentsCopyToMemory(std::vector<ASTPointer<Expression const>> const& _arguments, /// this call. If @a _padToWordBoundaries is set to false, all values are concatenated without
TypePointers const& _types = {}, /// padding. If @a _copyDynamicDataInPlace is set, dynamic types is stored (without length)
bool _padToWordBoundaries = true, /// together with fixed-length data.
bool _padExceptionIfFourBytes = false); void appendArgumentsCopyToMemory(
std::vector<ASTPointer<Expression const>> const& _arguments,
TypePointers const& _types = {},
bool _padToWordBoundaries = true,
bool _padExceptionIfFourBytes = false,
bool _copyDynamicDataInPlace = false
);
/// Appends code that moves a stack element of the given type to memory. The memory offset is /// Appends code that moves a stack element of the given type to memory. The memory offset is
/// expected below the stack element and is updated by this call. /// expected below the stack element and is updated by this call.
void appendTypeMoveToMemory(Type const& _type, bool _padToWordBoundaries = true); void appendTypeMoveToMemory(Type const& _type, bool _padToWordBoundaries = true);

12
libsolidity/Types.cpp

@ -745,8 +745,6 @@ string ArrayType::toString() const
TypePointer ArrayType::externalType() const TypePointer ArrayType::externalType() const
{ {
if (m_location != Location::CallData)
return TypePointer();
if (m_isByteArray) if (m_isByteArray)
return shared_from_this(); return shared_from_this();
if (!m_baseType->externalType()) if (!m_baseType->externalType())
@ -1128,7 +1126,7 @@ unsigned FunctionType::getSizeOnStack() const
return size; return size;
} }
TypePointer FunctionType::externalType() const FunctionTypePointer FunctionType::externalFunctionType() const
{ {
TypePointers paramTypes; TypePointers paramTypes;
TypePointers retParamTypes; TypePointers retParamTypes;
@ -1136,13 +1134,13 @@ TypePointer FunctionType::externalType() const
for (auto type: m_parameterTypes) for (auto type: m_parameterTypes)
{ {
if (!type->externalType()) if (!type->externalType())
return TypePointer(); return FunctionTypePointer();
paramTypes.push_back(type->externalType()); paramTypes.push_back(type->externalType());
} }
for (auto type: m_returnParameterTypes) for (auto type: m_returnParameterTypes)
{ {
if (!type->externalType()) if (!type->externalType())
return TypePointer(); return FunctionTypePointer();
retParamTypes.push_back(type->externalType()); retParamTypes.push_back(type->externalType());
} }
return make_shared<FunctionType>(paramTypes, retParamTypes, m_location, m_arbitraryParameters); return make_shared<FunctionType>(paramTypes, retParamTypes, m_location, m_arbitraryParameters);
@ -1218,7 +1216,9 @@ string FunctionType::externalSignature(std::string const& _name) const
} }
string ret = funcName + "("; string ret = funcName + "(";
TypePointers externalParameterTypes = dynamic_cast<FunctionType const&>(*externalType()).getParameterTypes(); FunctionTypePointer external = externalFunctionType();
solAssert(!!external, "External function type requested.");
TypePointers externalParameterTypes = external->getParameterTypes();
for (auto it = externalParameterTypes.cbegin(); it != externalParameterTypes.cend(); ++it) for (auto it = externalParameterTypes.cbegin(); it != externalParameterTypes.cend(); ++it)
{ {
solAssert(!!(*it), "Parameter should have external type"); solAssert(!!(*it), "Parameter should have external type");

29
libsolidity/Types.h

@ -430,12 +430,20 @@ public:
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual unsigned getCalldataEncodedSize(bool _padded ) const override
{
return externalType()->getCalldataEncodedSize(_padded);
}
virtual unsigned getStorageBytes() const override { return 20; } virtual unsigned getStorageBytes() const override { return 20; }
virtual bool canLiveOutsideStorage() const override { return true; }
virtual bool isValueType() const override { return true; } virtual bool isValueType() const override { return true; }
virtual std::string toString() const override; virtual std::string toString() const override;
virtual MemberList const& getMembers() const override; virtual MemberList const& getMembers() const override;
virtual TypePointer externalType() const override { return std::make_shared<IntegerType>(160, IntegerType::Modifier::Address); } virtual TypePointer externalType() const override
{
return std::make_shared<IntegerType>(160, IntegerType::Modifier::Address);
}
bool isSuper() const { return m_super; } bool isSuper() const { return m_super; }
ContractDefinition const& getContractDefinition() const { return m_contract; } ContractDefinition const& getContractDefinition() const { return m_contract; }
@ -498,13 +506,21 @@ public:
explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {} explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {}
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual unsigned getCalldataEncodedSize(bool _padded) const override
{
return externalType()->getCalldataEncodedSize(_padded);
}
virtual unsigned getSizeOnStack() const override { return 1; } virtual unsigned getSizeOnStack() const override { return 1; }
virtual unsigned getStorageBytes() const override; virtual unsigned getStorageBytes() const override;
virtual bool canLiveOutsideStorage() const override { return true; }
virtual std::string toString() const override; virtual std::string toString() const override;
virtual bool isValueType() const override { return true; } virtual bool isValueType() const override { return true; }
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer externalType() const override { return std::make_shared<IntegerType>(8 * int(getStorageBytes())); } virtual TypePointer externalType() const override
{
return std::make_shared<IntegerType>(8 * int(getStorageBytes()));
}
EnumDefinition const& getEnumDefinition() const { return m_enum; } EnumDefinition const& getEnumDefinition() const { return m_enum; }
/// @returns the value that the string has in the Enum /// @returns the value that the string has in the Enum
@ -538,9 +554,12 @@ public:
virtual Category getCategory() const override { return Category::Function; } virtual Category getCategory() const override { return Category::Function; }
/// @returns TypePointer of a new FunctionType object. All input/return parameters are an appropriate external types of input/return parameters of current function. /// @returns TypePointer of a new FunctionType object. All input/return parameters are an
/// Returns an empty shared pointer if one of the input/return parameters does not have an externaltype. /// appropriate external types of input/return parameters of current function.
virtual TypePointer externalType() const override; /// Returns an empty shared pointer if one of the input/return parameters does not have an
/// external type.
FunctionTypePointer externalFunctionType() const;
virtual TypePointer externalType() const override { return externalFunctionType(); }
explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true); explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true);
explicit FunctionType(VariableDeclaration const& _varDecl); explicit FunctionType(VariableDeclaration const& _varDecl);

8
mix/ClientModel.cpp

@ -237,6 +237,7 @@ void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence,
{ {
try try
{ {
vector<Address> deployedContracts;
onStateReset(); onStateReset();
for (TransactionSettings const& transaction: _sequence) for (TransactionSettings const& transaction: _sequence)
{ {
@ -248,6 +249,7 @@ void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence,
TransactionSettings stdTransaction = transaction; TransactionSettings stdTransaction = transaction;
stdTransaction.gasAuto = true; stdTransaction.gasAuto = true;
Address address = deployContract(stdContractCode, stdTransaction); Address address = deployContract(stdContractCode, stdTransaction);
deployedContracts.push_back(address);
m_stdContractAddresses[stdTransaction.contractId] = address; m_stdContractAddresses[stdTransaction.contractId] = address;
m_stdContractNames[address] = stdTransaction.contractId; m_stdContractNames[address] = stdTransaction.contractId;
} }
@ -280,6 +282,11 @@ void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence,
{ {
QSolidityType const* type = p->type(); QSolidityType const* type = p->type();
QVariant value = transaction.parameterValues.value(p->name()); QVariant value = transaction.parameterValues.value(p->name());
if (type->type().type == SolidityType::Type::Address && value.toString().startsWith("<") && value.toString().endsWith(">"))
{
QStringList nb = value.toString().remove("<").remove(">").split(" - ");
value = QVariant(QString::fromStdString("0x" + toHex(deployedContracts.at(nb.back().toInt()).ref())));
}
encoder.encode(value, type->type()); encoder.encode(value, type->type());
} }
@ -288,6 +295,7 @@ void ClientModel::executeSequence(vector<TransactionSettings> const& _sequence,
bytes param = encoder.encodedData(); bytes param = encoder.encodedData();
contractCode.insert(contractCode.end(), param.begin(), param.end()); contractCode.insert(contractCode.end(), param.begin(), param.end());
Address newAddress = deployContract(contractCode, transaction); Address newAddress = deployContract(contractCode, transaction);
deployedContracts.push_back(newAddress);
auto contractAddressIter = m_contractAddresses.find(transaction.contractId); auto contractAddressIter = m_contractAddresses.find(transaction.contractId);
if (contractAddressIter == m_contractAddresses.end() || newAddress != contractAddressIter->second) if (contractAddressIter == m_contractAddresses.end() || newAddress != contractAddressIter->second)
{ {

7
mix/qml/Debugger.qml

@ -211,8 +211,8 @@ Rectangle {
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 15 anchors.topMargin: 15
anchors.left: parent.left; anchors.left: parent.left;
anchors.leftMargin: machineStates.sideMargin anchors.leftMargin: machineStates.sideMargin
width: debugScrollArea.width - machineStates.sideMargin * 2 - 20 ; width: debugScrollArea.width - machineStates.sideMargin * 2 - 20
spacing: machineStates.sideMargin spacing: machineStates.sideMargin
Rectangle { Rectangle {
@ -641,9 +641,6 @@ Rectangle {
} }
} }
Rectangle Rectangle
{ {
id: storageRect id: storageRect

96
mix/qml/QAddressView.qml

@ -0,0 +1,96 @@
import QtQuick 2.0
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3
Item
{
property alias value: textinput.text
property alias contractCreationTr: ctrModel
id: editRoot
height: 20
width: 200
SourceSansProBold
{
id: boldFont
}
function init()
{
trCombobox.visible = ctrModel.count > 1; //index 0 is a blank value.
if (value.indexOf("<") === 0)
{
for (var k = 0; k < ctrModel.count; k++)
{
if ("<" + ctrModel.get(k).functionId + ">" === value)
{
trCombobox.currentIndex = k;
return;
}
}
trCombobox.currentIndex = 0;
value = "";
}
}
Rectangle {
anchors.fill: parent
radius: 4
anchors.verticalCenter: parent.verticalCenter
height: 20
TextInput {
id: textinput
text: value
width: parent.width
height: parent.width
wrapMode: Text.WrapAnywhere
clip: true
font.family: boldFont.name
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: textinput.forceActiveFocus()
}
onTextChanged:
{
if (trCombobox.selected)
{
trCombobox.currentIndex = 0;
trCombobox.selected = false;
}
}
}
}
ListModel
{
id: ctrModel
}
ComboBox
{
property bool selected: false
id: trCombobox
model: ctrModel
textRole: "functionId"
height: 20
anchors.verticalCenter: parent.verticalCenter
anchors.left: textinput.parent.right
anchors.leftMargin: 3
onCurrentIndexChanged: {
trCombobox.selected = false;
if (currentText === "")
return;
else if (currentText !== " - ")
{
textinput.text = "<" + currentText + ">";
trCombobox.selected = true;
}
else if (textinput.text.indexOf("<") === 0)
{
textinput.text = "";
}
}
}
}

9
mix/qml/StateDialog.qml

@ -366,7 +366,12 @@ Dialog {
DefaultLabel { DefaultLabel {
Layout.preferredWidth: 150 Layout.preferredWidth: 150
text: styleData.row >= 0 ? transactionsModel.get(styleData.row).functionId : "" text: {
if (styleData.row >= 0)
return transactionsModel.get(styleData.row).functionId;
else
return "";
}
} }
} }
} }
@ -378,7 +383,6 @@ Dialog {
} }
} }
} }
} }
RowLayout RowLayout
@ -456,7 +460,6 @@ Dialog {
onAccepted: onAccepted:
{ {
var item = transactionDialog.getItem(); var item = transactionDialog.getItem();
if (transactionDialog.transactionIndex < transactionsModel.count) { if (transactionDialog.transactionIndex < transactionsModel.count) {
transactionsModel.set(transactionDialog.transactionIndex, item); transactionsModel.set(transactionDialog.transactionIndex, item);
stateTransactions[transactionDialog.transactionIndex] = item; stateTransactions[transactionDialog.transactionIndex] = item;

31
mix/qml/StructView.qml

@ -8,17 +8,19 @@ Column
id: root id: root
property alias members: repeater.model //js array property alias members: repeater.model //js array
property var value: ({}) property var value: ({})
property int transactionIndex
Layout.fillWidth: true Layout.fillWidth: true
spacing: 10
Repeater Repeater
{ {
id: repeater id: repeater
visible: model.length > 0 visible: model.length > 0
Layout.fillWidth: true Layout.fillWidth: true
RowLayout RowLayout
{ {
id: row id: row
height: 20 + (members[index].type.category === QSolidityType.Struct ? (20 * members[index].type.members.length) : 0) height: 30 + (members[index].type.category === QSolidityType.Struct ? (20 * members[index].type.members.length) : 0)
Layout.fillWidth: true Layout.fillWidth: true
DefaultLabel { DefaultLabel {
height: 20 height: 20
@ -51,10 +53,12 @@ Column
return Qt.createComponent("qrc:/qml/QBoolTypeView.qml"); return Qt.createComponent("qrc:/qml/QBoolTypeView.qml");
else if (t === QSolidityType.Bytes) else if (t === QSolidityType.Bytes)
return Qt.createComponent("qrc:/qml/QStringTypeView.qml"); return Qt.createComponent("qrc:/qml/QStringTypeView.qml");
else if (t === QSolidityType.Hash || t === QSolidityType.Address) else if (t === QSolidityType.Hash)
return Qt.createComponent("qrc:/qml/QHashTypeView.qml"); return Qt.createComponent("qrc:/qml/QHashTypeView.qml");
else if (t === QSolidityType.Struct) else if (t === QSolidityType.Struct)
return Qt.createComponent("qrc:/qml/StructView.qml"); return Qt.createComponent("qrc:/qml/StructView.qml");
else if (t === QSolidityType.Address)
return Qt.createComponent("qrc:/qml/QAddressView.qml");
else else
return undefined; return undefined;
} }
@ -63,7 +67,26 @@ Column
var ptype = members[index].type; var ptype = members[index].type;
var pname = members[index].name; var pname = members[index].name;
var vals = value; var vals = value;
if (ptype.category === QSolidityType.Struct && !item.members) if (ptype.category === QSolidityType.Address)
{
item.contractCreationTr.append({"functionId": " - "});
var trCr = -1;
for (var k = 0; k < transactionsModel.count; k++)
{
if (k >= transactionIndex)
break;
var tr = transactionsModel.get(k);
if (tr.functionId === tr.contractId)
{
trCr++;
if (modelData.type.name === qsTr("contract") + " " + tr.contractId)
item.contractCreationTr.append({ "functionId": tr.contractId + " - " + trCr });
}
}
item.value = getValue();
item.init();
}
else if (ptype.category === QSolidityType.Struct && !item.members)
{ {
item.value = getValue(); item.value = getValue();
item.members = ptype.members; item.members = ptype.members;

14
mix/qml/TransactionDialog.qml

@ -39,6 +39,8 @@ Dialog {
rowGasPrice.visible = !useTransactionDefaultValue; rowGasPrice.visible = !useTransactionDefaultValue;
transactionIndex = index; transactionIndex = index;
typeLoader.transactionIndex = index;
gasValueEdit.gasValue = item.gas; gasValueEdit.gasValue = item.gas;
gasAutoCheck.checked = item.gasAuto ? true : false; gasAutoCheck.checked = item.gasAuto ? true : false;
gasPriceField.value = item.gasPrice; gasPriceField.value = item.gasPrice;
@ -99,6 +101,18 @@ Dialog {
} }
function selectContract(contractName)
{
for (var k = 0; k < contractsModel.count; k++)
{
if (contractsModel.get(k).cid === contractName)
{
contractComboBox.currentIndex = k;
break;
}
}
}
function selectFunction(functionId) function selectFunction(functionId)
{ {
var functionIndex = -1; var functionIndex = -1;

1
mix/res.qrc

@ -67,5 +67,6 @@
<file>qml/img/stop_button2x.png</file> <file>qml/img/stop_button2x.png</file>
<file>qml/img/warningicon.png</file> <file>qml/img/warningicon.png</file>
<file>qml/img/warningicon@2x.png</file> <file>qml/img/warningicon@2x.png</file>
<file>qml/QAddressView.qml</file>
</qresource> </qresource>
</RCC> </RCC>

1
mix/test/qml/TestMain.qml

@ -96,6 +96,7 @@ TestCase
function test_dbg_arrayParametersAndStorage() { TestDebugger.test_arrayParametersAndStorage(); } function test_dbg_arrayParametersAndStorage() { TestDebugger.test_arrayParametersAndStorage(); }
function test_dbg_solidity() { TestDebugger.test_solidityDebugging(); } function test_dbg_solidity() { TestDebugger.test_solidityDebugging(); }
function test_dbg_vm() { TestDebugger.test_vmDebugging(); } function test_dbg_vm() { TestDebugger.test_vmDebugging(); }
function test_dbg_ctrTypeAsParam() { TestDebugger.test_ctrTypeAsParam(); }
function test_miner_getDefaultiner() { TestMiner.test_getDefaultMiner(); } function test_miner_getDefaultiner() { TestMiner.test_getDefaultMiner(); }
function test_miner_selectMiner() { TestMiner.test_selectMiner(); } function test_miner_selectMiner() { TestMiner.test_selectMiner(); }
function test_miner_mine() { TestMiner.test_mine(); } function test_miner_mine() { TestMiner.test_mine(); }

44
mix/test/qml/js/TestDebugger.js

@ -203,3 +203,47 @@ function test_vmDebugging()
tryCompare(mainApplication.mainContent.rightPane.vmMemory.listModel, "length", 0); tryCompare(mainApplication.mainContent.rightPane.vmMemory.listModel, "length", 0);
} }
function test_ctrTypeAsParam()
{
newProject();
editContract(
"contract C1 {\r " +
" function get() returns (uint256)\r " +
" {\r " +
" return 159;\r " +
" }\r " +
"}\r" +
"contract C2 {\r " +
" C1 c1;\r " +
" function getFromC1() returns (uint256)\r " +
" {\r " +
" return c1.get();\r " +
" }\r " +
" function C2(C1 _c1)\r" +
" {\r " +
" c1 = _c1;\r" +
" }\r " +
"}");
mainApplication.projectModel.stateListModel.editState(0); //C1 ctor already added
mainApplication.projectModel.stateDialog.model.addTransaction();
var transactionDialog = mainApplication.projectModel.stateDialog.transactionDialog;
ts.waitForRendering(transactionDialog, 3000);
transactionDialog.selectContract("C2");
transactionDialog.selectFunction("C2");
transactionDialog.acceptAndClose();
mainApplication.projectModel.stateDialog.model.addTransaction();
transactionDialog = mainApplication.projectModel.stateDialog.transactionDialog;
ts.waitForRendering(transactionDialog, 3000);
transactionDialog.selectContract("C2");
transactionDialog.selectFunction("getFromC1");
clickElement(transactionDialog, 406, 340);
clickElement(transactionDialog, 406, 366);
transactionDialog.acceptAndClose();
mainApplication.projectModel.stateDialog.acceptAndClose();
mainApplication.mainContent.startQuickDebugging();
if (!ts.waitForSignal(mainApplication.clientModel, "debugDataReady(QObject*)", 5000))
fail("Error running transaction");
tryCompare(mainApplication.mainContent.rightPane.transactionLog.transactionModel.get(4), "returned", "(159)");
}

2
mix/test/qml/js/TestTutorial.js

@ -52,7 +52,7 @@ function test_tutorial()
transactionDialog.selectFunction("setRating"); transactionDialog.selectFunction("setRating");
clickElement(transactionDialog, 200, 310); clickElement(transactionDialog, 200, 310);
ts.typeString("Titanic", transactionDialog); ts.typeString("Titanic", transactionDialog);
clickElement(transactionDialog, 200, 330); clickElement(transactionDialog, 200, 350);
ts.typeString("2", transactionDialog); ts.typeString("2", transactionDialog);
transactionDialog.acceptAndClose(); transactionDialog.acceptAndClose();
mainApplication.projectModel.stateDialog.acceptAndClose(); mainApplication.projectModel.stateDialog.acceptAndClose();

7
solc/CMakeLists.txt

@ -2,6 +2,7 @@ cmake_policy(SET CMP0015 NEW)
set(CMAKE_AUTOMOC OFF) set(CMAKE_AUTOMOC OFF)
aux_source_directory(. SRC_LIST) aux_source_directory(. SRC_LIST)
list(REMOVE_ITEM SRC_LIST "./jsonCompiler.cpp")
include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS})
include_directories(BEFORE ..) include_directories(BEFORE ..)
@ -18,3 +19,9 @@ target_link_libraries(${EXECUTABLE} solidity)
install( TARGETS ${EXECUTABLE} DESTINATION bin ) install( TARGETS ${EXECUTABLE} DESTINATION bin )
if (ETH_STATIC)
add_library(soljson STATIC jsonCompiler.cpp ${HEADERS})
else()
add_library(soljson SHARED jsonCompiler.cpp ${HEADERS})
endif()
target_link_libraries(soljson solidity)

100
solc/CommandLineInterface.cpp

@ -27,6 +27,7 @@
#include <fstream> #include <fstream>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include "BuildInfo.h" #include "BuildInfo.h"
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
@ -64,6 +65,18 @@ static string const g_argNatspecDevStr = "natspec-dev";
static string const g_argNatspecUserStr = "natspec-user"; static string const g_argNatspecUserStr = "natspec-user";
static string const g_argAddStandard = "add-std"; static string const g_argAddStandard = "add-std";
/// Possible arguments to for --combined-json
static set<string> const g_combinedJsonArgs{
"binary",
"opcodes",
"json-abi",
"sol-abi",
"asm",
"ast",
"natspec-user",
"natspec-dev"
};
static void version() static void version()
{ {
cout << "solc, the solidity compiler commandline interface " << dev::Version << endl cout << "solc, the solidity compiler commandline interface " << dev::Version << endl
@ -72,24 +85,24 @@ static void version()
exit(0); exit(0);
} }
static inline bool argToStdout(po::variables_map const& _args, string const& _name) static inline bool humanTargetedStdout(po::variables_map const& _args, string const& _name)
{ {
return _args.count(_name) && _args[_name].as<OutputType>() != OutputType::FILE; return _args.count(_name) && _args[_name].as<OutputType>() != OutputType::FILE;
} }
static bool needStdout(po::variables_map const& _args) static bool needsHumanTargetedStdout(po::variables_map const& _args)
{ {
return return
argToStdout(_args, g_argAbiStr) || humanTargetedStdout(_args, g_argAbiStr) ||
argToStdout(_args, g_argSolAbiStr) || humanTargetedStdout(_args, g_argSolAbiStr) ||
argToStdout(_args, g_argNatspecUserStr) || humanTargetedStdout(_args, g_argNatspecUserStr) ||
argToStdout(_args, g_argAstJson) || humanTargetedStdout(_args, g_argAstJson) ||
argToStdout(_args, g_argNatspecDevStr) || humanTargetedStdout(_args, g_argNatspecDevStr) ||
argToStdout(_args, g_argAsmStr) || humanTargetedStdout(_args, g_argAsmStr) ||
argToStdout(_args, g_argAsmJsonStr) || humanTargetedStdout(_args, g_argAsmJsonStr) ||
argToStdout(_args, g_argOpcodesStr) || humanTargetedStdout(_args, g_argOpcodesStr) ||
argToStdout(_args, g_argBinaryStr); humanTargetedStdout(_args, g_argBinaryStr);
} }
static inline bool outputToFile(OutputType type) static inline bool outputToFile(OutputType type)
@ -220,6 +233,11 @@ bool CommandLineInterface::parseArguments(int argc, char** argv)
("optimize", po::value<bool>()->default_value(false), "Optimize bytecode for size") ("optimize", po::value<bool>()->default_value(false), "Optimize bytecode for size")
("add-std", po::value<bool>()->default_value(false), "Add standard contracts") ("add-std", po::value<bool>()->default_value(false), "Add standard contracts")
("input-file", po::value<vector<string>>(), "input file") ("input-file", po::value<vector<string>>(), "input file")
(
"combined-json",
po::value<string>()->value_name(boost::join(g_combinedJsonArgs, ",")),
"Output a single json document containing the specified information, can be combined."
)
(g_argAstStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"), (g_argAstStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the AST of the contract.") "Request to output the AST of the contract.")
(g_argAstJson.c_str(), po::value<OutputType>()->value_name("stdout|file|both"), (g_argAstJson.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
@ -255,6 +273,16 @@ bool CommandLineInterface::parseArguments(int argc, char** argv)
cout << _exception.what() << endl; cout << _exception.what() << endl;
return false; return false;
} }
if (m_args.count("combined-json"))
{
vector<string> requests;
for (string const& item: boost::split(requests, m_args["combined-json"].as<string>(), boost::is_any_of(",")))
if (!g_combinedJsonArgs.count(item))
{
cout << "Invalid option to --combined-json: " << item << endl;
return false;
}
}
po::notify(m_args); po::notify(m_args);
if (m_args.count("help")) if (m_args.count("help"))
@ -350,6 +378,52 @@ bool CommandLineInterface::processInput()
return true; return true;
} }
void CommandLineInterface::handleCombinedJSON()
{
Json::Value output(Json::objectValue);
set<string> requests;
boost::split(requests, m_args["combined-json"].as<string>(), boost::is_any_of(","));
vector<string> contracts = m_compiler->getContractNames();
if (!contracts.empty())
output["contracts"] = Json::Value(Json::objectValue);
for (string const& contractName: contracts)
{
Json::Value contractData(Json::objectValue);
if (requests.count("sol-abi"))
contractData["sol-abi"] = m_compiler->getSolidityInterface(contractName);
if (requests.count("json-abi"))
contractData["json-abi"] = m_compiler->getInterface(contractName);
if (requests.count("binary"))
contractData["binary"] = toHex(m_compiler->getBytecode(contractName));
if (requests.count("opcodes"))
contractData["opcodes"] = eth::disassemble(m_compiler->getBytecode(contractName));
if (requests.count("asm"))
{
ostringstream unused;
contractData["asm"] = m_compiler->streamAssembly(unused, contractName, m_sourceCodes, true);
}
if (requests.count("natspec-dev"))
contractData["natspec-dev"] = m_compiler->getMetadata(contractName, DocumentationType::NatspecDev);
if (requests.count("natspec-user"))
contractData["natspec-user"] = m_compiler->getMetadata(contractName, DocumentationType::NatspecUser);
output["contracts"][contractName] = contractData;
}
if (requests.count("ast"))
{
output["sources"] = Json::Value(Json::objectValue);
for (auto const& sourceCode: m_sourceCodes)
{
ASTJsonConverter converter(m_compiler->getAST(sourceCode.first));
output["sources"][sourceCode.first] = Json::Value(Json::objectValue);
output["sources"][sourceCode.first]["AST"] = converter.json();
}
}
cout << Json::FastWriter().write(output) << endl;
}
void CommandLineInterface::handleAst(string const& _argStr) void CommandLineInterface::handleAst(string const& _argStr)
{ {
string title; string title;
@ -408,6 +482,8 @@ void CommandLineInterface::handleAst(string const& _argStr)
void CommandLineInterface::actOnInput() void CommandLineInterface::actOnInput()
{ {
handleCombinedJSON();
// do we need AST output? // do we need AST output?
handleAst(g_argAstStr); handleAst(g_argAstStr);
handleAst(g_argAstJson); handleAst(g_argAstJson);
@ -415,7 +491,7 @@ void CommandLineInterface::actOnInput()
vector<string> contracts = m_compiler->getContractNames(); vector<string> contracts = m_compiler->getContractNames();
for (string const& contract: contracts) for (string const& contract: contracts)
{ {
if (needStdout(m_args)) if (needsHumanTargetedStdout(m_args))
cout << endl << "======= " << contract << " =======" << endl; cout << endl << "======= " << contract << " =======" << endl;
// do we need EVM assembly? // do we need EVM assembly?

1
solc/CommandLineInterface.h

@ -53,6 +53,7 @@ public:
void actOnInput(); void actOnInput();
private: private:
void handleCombinedJSON();
void handleAst(std::string const& _argStr); void handleAst(std::string const& _argStr);
void handleBinary(std::string const& _contract); void handleBinary(std::string const& _contract);
void handleOpcode(std::string const& _contract); void handleOpcode(std::string const& _contract);

124
solc/jsonCompiler.cpp

@ -0,0 +1,124 @@
/*
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 2014
* JSON interface for the solidity compiler to be used from Javascript.
*/
#include <string>
#include <iostream>
#include <json/json.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/CommonIO.h>
#include <libevmcore/Instruction.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/ASTPrinter.h>
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Exceptions.h>
#include <libsolidity/CompilerStack.h>
#include <libsolidity/SourceReferenceFormatter.h>
#include <libsolidity/ASTJsonConverter.h>
using namespace std;
using namespace dev;
using namespace solidity;
string formatError(Exception const& _exception, string const& _name, CompilerStack const& _compiler)
{
ostringstream errorOutput;
SourceReferenceFormatter::printExceptionInformation(errorOutput, _exception, _name, _compiler);
Json::Value output(Json::objectValue);
output["error"] = errorOutput.str();
return Json::FastWriter().write(output);
}
string compile(string _input, bool _optimize)
{
StringMap sources;
sources[""] = _input;
Json::Value output(Json::objectValue);
CompilerStack compiler;
try
{
compiler.compile(_input, _optimize);
}
catch (ParserError const& exception)
{
return formatError(exception, "Parser error", compiler);
}
catch (DeclarationError const& exception)
{
return formatError(exception, "Declaration error", compiler);
}
catch (TypeError const& exception)
{
return formatError(exception, "Type error", compiler);
}
catch (CompilerError const& exception)
{
return formatError(exception, "Compiler error", compiler);
}
catch (InternalCompilerError const& exception)
{
return formatError(exception, "Internal compiler error", compiler);
}
catch (Exception const& exception)
{
output["error"] = "Exception during compilation: " + boost::diagnostic_information(exception);
return Json::FastWriter().write(output);
}
catch (...)
{
output["error"] = "Unknown exception during compilation.";
return Json::FastWriter().write(output);
}
output["contracts"] = Json::Value(Json::objectValue);
for (string const& contractName: compiler.getContractNames())
{
Json::Value contractData(Json::objectValue);
contractData["solidity_interface"] = compiler.getSolidityInterface(contractName);
contractData["interface"] = compiler.getInterface(contractName);
contractData["bytecode"] = toHex(compiler.getBytecode(contractName));
contractData["opcodes"] = eth::disassemble(compiler.getBytecode(contractName));
ostringstream unused;
contractData["assembly"] = compiler.streamAssembly(unused, contractName, sources, true);
output["contracts"][contractName] = contractData;
}
output["sources"] = Json::Value(Json::objectValue);
output["sources"][""] = Json::Value(Json::objectValue);
output["sources"][""]["AST"] = ASTJsonConverter(compiler.getAST("")).json();
return Json::FastWriter().write(output);
}
static string outputBuffer;
extern "C"
{
extern char const* compileJSON(char const* _input, bool _optimize)
{
outputBuffer = compile(_input, _optimize);
return outputBuffer.c_str();
}
}

2
test/TestHelper.cpp

@ -539,6 +539,8 @@ void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _e
void userDefinedTest(string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests) void userDefinedTest(string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests)
{ {
Options::get(); // parse command line options, e.g. to enable JIT
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
{ {
string arg = boost::unit_test::framework::master_test_suite().argv[i]; string arg = boost::unit_test::framework::master_test_suite().argv[i];

8
test/fuzzTesting/CMakeLists.txt

@ -8,10 +8,10 @@ include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
add_executable(createRandomVMTest createRandomVMTest.cpp ../libevm/vm.cpp ../TestHelper.cpp ../Stats.cpp) add_executable(createRandomVMTest "./createRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp")
add_executable(createRandomStateTest createRandomStateTest.cpp ../TestHelper.cpp ../Stats.cpp) add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp")
add_executable(checkRandomVMTest checkRandomVMTest.cpp ../libevm/vm.cpp ../TestHelper.cpp ../Stats.cpp) add_executable(checkRandomVMTest "./checkRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp")
add_executable(checkRandomStateTest checkRandomStateTest.cpp ../TestHelper.cpp ../Stats.cpp) add_executable(checkRandomStateTest "./checkRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp")
target_link_libraries(createRandomVMTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) target_link_libraries(createRandomVMTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
target_link_libraries(createRandomVMTest ethereum) target_link_libraries(createRandomVMTest ethereum)

84
test/libsolidity/SolidityEndToEndTest.cpp

@ -1476,7 +1476,7 @@ BOOST_AUTO_TEST_CASE(ripemd)
{ {
h256 ret; h256 ret;
dev::ripemd160(dev::ref(toBigEndian(_input)), bytesRef(&ret[0], 32)); dev::ripemd160(dev::ref(toBigEndian(_input)), bytesRef(&ret[0], 32));
return u256(ret) >> (256 - 160); return u256(ret);
}; };
testSolidityAgainstCpp("a(bytes32)", f, u256(4)); testSolidityAgainstCpp("a(bytes32)", f, u256(4));
testSolidityAgainstCpp("a(bytes32)", f, u256(5)); testSolidityAgainstCpp("a(bytes32)", f, u256(5));
@ -1791,7 +1791,7 @@ BOOST_AUTO_TEST_CASE(gas_for_builtin)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test(uint256)", 500) == bytes()); BOOST_CHECK(callContractFunction("test(uint256)", 500) == bytes());
BOOST_CHECK(callContractFunction("test(uint256)", 800) == encodeArgs(u256("0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"), true)); BOOST_CHECK(callContractFunction("test(uint256)", 800) == encodeArgs(u256("0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc000000000000000000000000"), true));
} }
BOOST_AUTO_TEST_CASE(value_complex) BOOST_AUTO_TEST_CASE(value_complex)
@ -2340,6 +2340,49 @@ BOOST_AUTO_TEST_CASE(event_lots_of_data)
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(address,bytes32,uint256,bool)"))); BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(address,bytes32,uint256,bool)")));
} }
BOOST_AUTO_TEST_CASE(event_really_lots_of_data)
{
char const* sourceCode = R"(
contract ClientReceipt {
event Deposit(uint fixeda, bytes dynx, uint fixedb);
function deposit() {
Deposit(10, msg.data, 15);
}
}
)";
compileAndRun(sourceCode);
callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(10, 4, 15) + FixedHash<4>(dev::sha3("deposit()")).asBytes());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(uint256,bytes,uint256)")));
}
BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage)
{
char const* sourceCode = R"(
contract ClientReceipt {
bytes x;
event Deposit(uint fixeda, bytes dynx, uint fixedb);
function deposit() {
x.length = 3;
x[0] = "A";
x[1] = "B";
x[2] = "C";
Deposit(10, x, 15);
}
}
)";
compileAndRun(sourceCode);
callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(10, 3, 15) + asBytes("ABC"));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(uint256,bytes,uint256)")));
}
BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(
@ -2428,6 +2471,24 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_string_literals)
bytes{0x66, 0x6f, 0x6f}))); bytes{0x66, 0x6f, 0x6f})));
} }
BOOST_AUTO_TEST_CASE(sha3_with_bytes)
{
char const* sourceCode = R"(
contract c {
bytes data;
function foo() returns (bool)
{
data.length = 3;
data[0] = "f";
data[1] = "o";
data[2] = "o";
return sha3(data) == sha3("foo");
}
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("foo()") == encodeArgs(true));
}
BOOST_AUTO_TEST_CASE(generic_call) BOOST_AUTO_TEST_CASE(generic_call)
{ {
char const* sourceCode = R"**( char const* sourceCode = R"**(
@ -3764,6 +3825,25 @@ BOOST_AUTO_TEST_CASE(packed_storage_signed)
BOOST_CHECK( callContractFunction("test()") == encodeArgs(u256(-2), u256(4), u256(-112), u256(0))); BOOST_CHECK( callContractFunction("test()") == encodeArgs(u256(-2), u256(4), u256(-112), u256(0)));
} }
BOOST_AUTO_TEST_CASE(external_types_in_calls)
{
char const* sourceCode = R"(
contract C1 { C1 public bla; function C1(C1 x) { bla = x; } }
contract C {
function test() returns (C1 x, C1 y) {
C1 c = new C1(C1(9));
x = c.bla();
y = this.t1(C1(7));
}
function t1(C1 a) returns (C1) { return a; }
function() returns (C1) { return C1(9); }
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(9), u256(7)));
BOOST_CHECK(callContractFunction("nonexisting") == encodeArgs(u256(9)));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

Loading…
Cancel
Save