Browse Source

Merge branch 'develop' into webthreestubclient

cl-refactor
Marek Kotewicz 10 years ago
parent
commit
864de82b7b
  1. 1
      eth/main.cpp
  2. 4
      libdevcrypto/Common.cpp
  3. 31
      libethash-cl/ethash_cl_miner.cpp
  4. 2
      libethcore/Ethash.cpp
  5. 11
      libsolidity/AST.cpp
  6. 17
      libsolidity/ASTJsonConverter.cpp
  7. 5
      libsolidity/ASTJsonConverter.h
  8. 4
      libsolidity/Compiler.h
  9. 4
      libsolidity/CompilerContext.h
  10. 9
      libsolidity/CompilerStack.cpp
  11. 5
      libsolidity/CompilerStack.h
  12. 7
      libsolidity/CompilerUtils.cpp
  13. 2
      libsolidity/CompilerUtils.h
  14. 14
      libsolidity/DeclarationContainer.cpp
  15. 104
      libsolidity/ExpressionCompiler.cpp
  16. 18
      libsolidity/ExpressionCompiler.h
  17. 6
      libsolidity/Types.cpp
  18. 6
      libsolidity/Types.h
  19. 8
      mix/ClientModel.cpp
  20. 5
      mix/qml/Debugger.qml
  21. 96
      mix/qml/QAddressView.qml
  22. 9
      mix/qml/StateDialog.qml
  23. 31
      mix/qml/StructView.qml
  24. 14
      mix/qml/TransactionDialog.qml
  25. 1
      mix/res.qrc
  26. 1
      mix/test/qml/TestMain.qml
  27. 44
      mix/test/qml/js/TestDebugger.js
  28. 2
      mix/test/qml/js/TestTutorial.js
  29. 7
      solc/CMakeLists.txt
  30. 124
      solc/jsonCompiler.cpp
  31. 61
      test/libsolidity/SolidityEndToEndTest.cpp

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

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

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

104
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)
@ -1089,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);
} }
} }
@ -1114,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);

6
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())
@ -1218,7 +1216,9 @@ string FunctionType::externalSignature(std::string const& _name) const
} }
string ret = funcName + "("; string ret = funcName + "(";
TypePointers externalParameterTypes = externalFunctionType()->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");

6
libsolidity/Types.h

@ -430,7 +430,7 @@ 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 = true) const override virtual unsigned getCalldataEncodedSize(bool _padded ) const override
{ {
return externalType()->getCalldataEncodedSize(_padded); return externalType()->getCalldataEncodedSize(_padded);
} }
@ -506,7 +506,7 @@ 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 = true) const override virtual unsigned getCalldataEncodedSize(bool _padded) const override
{ {
return externalType()->getCalldataEncodedSize(_padded); return externalType()->getCalldataEncodedSize(_padded);
} }
@ -558,7 +558,7 @@ public:
/// appropriate external types of input/return parameters of current function. /// appropriate external types of input/return parameters of current function.
/// Returns an empty shared pointer if one of the input/return parameters does not have an /// Returns an empty shared pointer if one of the input/return parameters does not have an
/// external type. /// external type.
virtual FunctionTypePointer externalFunctionType() const; FunctionTypePointer externalFunctionType() const;
virtual TypePointer externalType() const override { return externalFunctionType(); } virtual TypePointer externalType() const override { return externalFunctionType(); }
explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true); explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true);

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

5
mix/qml/Debugger.qml

@ -212,7 +212,7 @@ Rectangle {
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)

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

61
test/libsolidity/SolidityEndToEndTest.cpp

@ -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"**(

Loading…
Cancel
Save