Browse Source

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

mix_srcdbg

Conflicts:
	mix/ClientModel.cpp
	mix/qml/Debugger.qml
	mix/qml/MainContent.qml
cl-refactor
arkpar 10 years ago
parent
commit
63065bde05
  1. 2
      cmake/EthCompilerSettings.cmake
  2. 13
      evmjit/libevmjit-cpp/JitVM.cpp
  3. 2
      libethcore/BlockInfo.cpp
  4. 5
      libethereum/BlockChain.cpp
  5. 12
      libethereum/Client.cpp
  6. 2
      libethereum/Executive.cpp
  7. 3
      libethereum/Transaction.cpp
  8. 3
      libevm/VM.cpp
  9. 58
      libsolidity/AST.cpp
  10. 16
      libsolidity/AST.h
  11. 304
      libsolidity/ArrayUtils.cpp
  12. 78
      libsolidity/ArrayUtils.h
  13. 108
      libsolidity/Compiler.cpp
  14. 7
      libsolidity/Compiler.h
  15. 33
      libsolidity/CompilerContext.cpp
  16. 8
      libsolidity/CompilerContext.h
  17. 170
      libsolidity/CompilerUtils.cpp
  18. 13
      libsolidity/CompilerUtils.h
  19. 8
      libsolidity/ExpressionCompiler.cpp
  20. 122
      libsolidity/LValue.cpp
  21. 44
      libsolidity/LValue.h
  22. 10
      libsolidity/SourceReferenceFormatter.cpp
  23. 29
      libsolidity/Types.cpp
  24. 1
      mix/AppContext.cpp
  25. 21
      mix/ClientModel.cpp
  26. 25
      mix/ClientModel.h
  27. 12
      mix/FileIo.cpp
  28. 2
      mix/FileIo.h
  29. 6
      mix/MixClient.cpp
  30. 2
      mix/MixClient.h
  31. 52
      mix/qml/Debugger.qml
  32. 308
      mix/qml/DeploymentDialog.qml
  33. 348
      mix/qml/FilesSection.qml
  34. 10
      mix/qml/MainContent.qml
  35. 2
      mix/qml/ProjectFilesStyle.qml
  36. 20
      mix/qml/ProjectList.qml
  37. 19
      mix/qml/ProjectModel.qml
  38. 128
      mix/qml/StatusPane.qml
  39. 49
      mix/qml/TransactionLog.qml
  40. 60
      mix/qml/WebPreview.qml
  41. BIN
      mix/qml/img/search_filled.png
  42. 382
      mix/qml/js/ProjectModel.js
  43. 25
      mix/qml/js/TransactionHelper.js
  44. 13
      mix/qml/main.qml
  45. 1
      mix/res.qrc
  46. 242
      test/SolidityEndToEndTest.cpp
  47. 109
      test/SolidityNameAndTypeResolution.cpp
  48. 34
      test/SolidityParser.cpp
  49. 50
      test/TestHelper.cpp
  50. 10
      test/block.cpp
  51. 69
      test/stMemoryStressTestFiller.json
  52. 1465
      test/stMemoryTestFiller.json
  53. 682
      test/stQuadraticComplexityTestFiller.json
  54. 158
      test/stRefundTestFiller.json
  55. 55
      test/stSolidityTestFiller.json
  56. 1015
      test/stSystemOperationsTestFiller.json
  57. 10
      test/stTransactionTestFiller.json
  58. 41
      test/state.cpp
  59. 19
      test/transaction.cpp
  60. 169
      test/ttTransactionTestFiller.json
  61. 6
      test/vm.cpp
  62. 366
      test/vmArithmeticTestFiller.json
  63. 168
      test/vmEnvironmentalInfoTestFiller.json
  64. 85
      test/vmIOandFlowOperationsTestFiller.json
  65. 238
      test/vmSha3TestFiller.json

2
cmake/EthCompilerSettings.cmake

@ -3,7 +3,7 @@
# C++11 check and activation # C++11 check and activation
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB -fPIC") set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -Werror -DSHAREDLIB -fPIC")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE")

13
evmjit/libevmjit-cpp/JitVM.cpp

@ -1,10 +1,14 @@
#pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wconversion"
#include "JitVM.h" #include "JitVM.h"
#include <libdevcore/Log.h>
#include <libdevcrypto/SHA3.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>
#include <libdevcrypto/SHA3.h>
#include <evmjit/libevmjit/ExecutionEngine.h> #include <evmjit/libevmjit/ExecutionEngine.h>
#include "Utils.h" #include "Utils.h"
namespace dev namespace dev
@ -27,12 +31,13 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step)
if (rejected) if (rejected)
{ {
UNTESTED; cwarn << "Execution rejected by EVM JIT (gas limit: " << m_gas << "), executing with interpreter";
std::cerr << "Rejected\n";
VMFactory::setKind(VMKind::Interpreter); VMFactory::setKind(VMKind::Interpreter);
m_fallbackVM = VMFactory::create(m_gas); m_fallbackVM = VMFactory::create(m_gas);
VMFactory::setKind(VMKind::JIT); VMFactory::setKind(VMKind::JIT);
return m_fallbackVM->go(_ext, _onOp, _step); auto&& output = m_fallbackVM->go(_ext, _onOp, _step);
m_gas = m_fallbackVM->gas(); // copy remaining gas, Executive expects it
return output;
} }
m_data.gas = static_cast<decltype(m_data.gas)>(m_gas); m_data.gas = static_cast<decltype(m_data.gas)>(m_gas);

2
libethcore/BlockInfo.cpp

@ -134,7 +134,7 @@ void BlockInfo::populate(bytesConstRef _block, bool _checkNonce)
RLP header = root[0]; RLP header = root[0];
if (!header.isList()) if (!header.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat(0,header.data()) << errinfo_comment("block header needs to be a list")); BOOST_THROW_EXCEPTION(InvalidBlockFormat(0, header.data()) << errinfo_comment("block header needs to be a list"));
populateFromHeader(header, _checkNonce); populateFromHeader(header, _checkNonce);
if (!root[1].isList()) if (!root[1].isList())

5
libethereum/BlockChain.cpp

@ -209,6 +209,11 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db)
try try
#endif #endif
{ {
RLP blockRLP(_block);
if (!blockRLP.isList())
BOOST_THROW_EXCEPTION(InvalidBlockFormat(0, blockRLP.data()) << errinfo_comment("block header needs to be a list"));
bi.populate(&_block); bi.populate(&_block);
bi.verifyInternals(&_block); bi.verifyInternals(&_block);
} }

12
libethereum/Client.cpp

@ -257,7 +257,13 @@ LocalisedLogEntries Client::peekWatch(unsigned _watchId) const
Guard l(m_filterLock); Guard l(m_filterLock);
try { try {
#if ETH_DEBUG
cdebug << "peekWatch" << _watchId;
#endif
auto& w = m_watches.at(_watchId); auto& w = m_watches.at(_watchId);
#if ETH_DEBUG
cdebug << "lastPoll updated to " << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();
#endif
w.lastPoll = chrono::system_clock::now(); w.lastPoll = chrono::system_clock::now();
return w.changes; return w.changes;
} catch (...) {} } catch (...) {}
@ -271,7 +277,13 @@ LocalisedLogEntries Client::checkWatch(unsigned _watchId)
LocalisedLogEntries ret; LocalisedLogEntries ret;
try { try {
#if ETH_DEBUG
cdebug << "checkWatch" << _watchId;
#endif
auto& w = m_watches.at(_watchId); auto& w = m_watches.at(_watchId);
#if ETH_DEBUG
cdebug << "lastPoll updated to " << chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();
#endif
std::swap(ret, w.changes); std::swap(ret, w.changes);
w.lastPoll = chrono::system_clock::now(); w.lastPoll = chrono::system_clock::now();
} catch (...) {} } catch (...) {}

2
libethereum/Executive.cpp

@ -176,7 +176,7 @@ OnOpFunc Executive::simpleTrace()
o << endl << " STACK" << endl; o << endl << " STACK" << endl;
for (auto i: vm.stack()) for (auto i: vm.stack())
o << (h256)i << endl; o << (h256)i << endl;
o << " MEMORY" << endl << memDump(vm.memory()); o << " MEMORY" << endl << (vm.memory().size() > 1000) ? " mem size greater than 1000 bytes " : memDump(vm.memory());
o << " STORAGE" << endl; o << " STORAGE" << endl;
for (auto const& i: ext.state().storage(ext.myAddress)) for (auto const& i: ext.state().storage(ext.myAddress))
o << showbase << hex << i.first << ": " << i.second << endl; o << showbase << hex << i.first << ": " << i.second << endl;

3
libethereum/Transaction.cpp

@ -36,6 +36,9 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckSignature _checkSig)
RLP rlp(_rlpData); RLP rlp(_rlpData);
try try
{ {
if (!rlp.isList())
BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("transaction RLP must be a list"));
m_nonce = rlp[field = 0].toInt<u256>(); m_nonce = rlp[field = 0].toInt<u256>();
m_gasPrice = rlp[field = 1].toInt<u256>(); m_gasPrice = rlp[field = 1].toInt<u256>();
m_gas = rlp[field = 2].toInt<u256>(); m_gas = rlp[field = 2].toInt<u256>();

3
libevm/VM.cpp

@ -38,8 +38,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps)
auto gasForMem = [](bigint _size) -> bigint auto gasForMem = [](bigint _size) -> bigint
{ {
bigint s = _size / 32; bigint s = _size / 32;
// return (bigint)c_memoryGas * (s + s * s / 1024); return (bigint)c_memoryGas * (s + s * s / 1024);
return (bigint)c_memoryGas * s;
}; };
if (m_jumpDests.empty()) if (m_jumpDests.empty())

58
libsolidity/AST.cpp

@ -209,6 +209,33 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::getIn
return *m_interfaceFunctionList; return *m_interfaceFunctionList;
} }
vector<Declaration const*> const& ContractDefinition::getInheritableMembers() const
{
if (!m_inheritableMembers)
{
set<string> memberSeen;
m_inheritableMembers.reset(new vector<Declaration const*>());
auto addInheritableMember = [&](Declaration const* _decl)
{
if (memberSeen.count(_decl->getName()) == 0 && _decl->isVisibleInDerivedContracts())
{
memberSeen.insert(_decl->getName());
m_inheritableMembers->push_back(_decl);
}
};
for (ASTPointer<FunctionDefinition> const& f: getDefinedFunctions())
addInheritableMember(f.get());
for (ASTPointer<VariableDeclaration> const& v: getStateVariables())
addInheritableMember(v.get());
for (ASTPointer<StructDefinition> const& s: getDefinedStructs())
addInheritableMember(s.get());
}
return *m_inheritableMembers;
}
TypePointer EnumValue::getType(ContractDefinition const*) const TypePointer EnumValue::getType(ContractDefinition const*) const
{ {
EnumDefinition const* parentDef = dynamic_cast<EnumDefinition const*>(getScope()); EnumDefinition const* parentDef = dynamic_cast<EnumDefinition const*>(getScope());
@ -281,7 +308,9 @@ 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."));
for (ASTPointer<ModifierInvocation> const& modifier: m_functionModifiers) for (ASTPointer<ModifierInvocation> const& modifier: m_functionModifiers)
modifier->checkTypeRequirements(); modifier->checkTypeRequirements(isConstructor() ?
dynamic_cast<ContractDefinition const&>(*getScope()).getBaseContracts() :
vector<ASTPointer<InheritanceSpecifier>>());
m_body->checkTypeRequirements(); m_body->checkTypeRequirements();
} }
@ -324,19 +353,34 @@ void ModifierDefinition::checkTypeRequirements()
m_body->checkTypeRequirements(); m_body->checkTypeRequirements();
} }
void ModifierInvocation::checkTypeRequirements() void ModifierInvocation::checkTypeRequirements(vector<ASTPointer<InheritanceSpecifier>> const& _bases)
{ {
m_modifierName->checkTypeRequirements(); m_modifierName->checkTypeRequirements();
for (ASTPointer<Expression> const& argument: m_arguments) for (ASTPointer<Expression> const& argument: m_arguments)
argument->checkTypeRequirements(); argument->checkTypeRequirements();
ModifierDefinition const* modifier = dynamic_cast<ModifierDefinition const*>(m_modifierName->getReferencedDeclaration()); auto declaration = m_modifierName->getReferencedDeclaration();
solAssert(modifier, "Function modifier not found."); vector<ASTPointer<VariableDeclaration>> emptyParameterList;
vector<ASTPointer<VariableDeclaration>> const& parameters = modifier->getParameters(); vector<ASTPointer<VariableDeclaration>> const* parameters = nullptr;
if (parameters.size() != m_arguments.size()) if (auto modifier = dynamic_cast<ModifierDefinition const*>(declaration))
parameters = &modifier->getParameters();
else
// check parameters for Base constructors
for (auto const& base: _bases)
if (declaration == base->getName()->getReferencedDeclaration())
{
if (auto referencedConstructor = dynamic_cast<ContractDefinition const&>(*declaration).getConstructor())
parameters = &referencedConstructor->getParameters();
else
parameters = &emptyParameterList;
break;
}
if (!parameters)
BOOST_THROW_EXCEPTION(createTypeError("Referenced declaration is neither modifier nor base class."));
if (parameters->size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for modifier invocation.")); BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for modifier invocation."));
for (size_t i = 0; i < m_arguments.size(); ++i) for (size_t i = 0; i < m_arguments.size(); ++i)
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType())) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*(*parameters)[i]->getType()))
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in modifier invocation.")); BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in modifier invocation."));
} }

16
libsolidity/AST.h

@ -144,7 +144,7 @@ public:
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; } bool isVisibleInContract() const { return getVisibility() != Visibility::External; }
bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Internal; } virtual 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.
@ -247,6 +247,9 @@ public:
/// as intended for use by the ABI. /// as intended for use by the ABI.
std::map<FixedHash<4>, FunctionTypePointer> getInterfaceFunctions() const; std::map<FixedHash<4>, FunctionTypePointer> getInterfaceFunctions() const;
/// @returns a list of the inheritable members of this contract
std::vector<Declaration const*> const& getInheritableMembers() const;
/// List of all (direct and indirect) base contracts in order from derived to base, including /// List of all (direct and indirect) base contracts in order from derived to base, including
/// the contract itself. Available after name resolution /// the contract itself. Available after name resolution
std::vector<ContractDefinition const*> const& getLinearizedBaseContracts() const { return m_linearizedBaseContracts; } std::vector<ContractDefinition const*> const& getLinearizedBaseContracts() const { return m_linearizedBaseContracts; }
@ -273,6 +276,7 @@ private:
std::vector<ContractDefinition const*> m_linearizedBaseContracts; std::vector<ContractDefinition const*> m_linearizedBaseContracts;
mutable std::unique_ptr<std::vector<std::pair<FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList; mutable std::unique_ptr<std::vector<std::pair<FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList;
mutable std::unique_ptr<std::vector<ASTPointer<EventDefinition>>> m_interfaceEvents; mutable std::unique_ptr<std::vector<ASTPointer<EventDefinition>>> m_interfaceEvents;
mutable std::unique_ptr<std::vector<Declaration const*>> m_inheritableMembers;
}; };
class InheritanceSpecifier: public ASTNode class InheritanceSpecifier: public ASTNode
@ -405,6 +409,11 @@ 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
{
return !isConstructor() && !getName().empty() && isVisibleInContract() &&
getVisibility() >= Visibility::Internal;
}
virtual TypePointer getType(ContractDefinition const*) const override; virtual TypePointer getType(ContractDefinition const*) const override;
/// Checks that all parameters have allowed types and calls checkTypeRequirements on the body. /// Checks that all parameters have allowed types and calls checkTypeRequirements on the body.
@ -501,7 +510,7 @@ private:
}; };
/** /**
* Invocation/usage of a modifier in a function header. * Invocation/usage of a modifier in a function header or a base constructor call.
*/ */
class ModifierInvocation: public ASTNode class ModifierInvocation: public ASTNode
{ {
@ -516,7 +525,8 @@ public:
ASTPointer<Identifier> const& getName() const { return m_modifierName; } ASTPointer<Identifier> const& getName() const { return m_modifierName; }
std::vector<ASTPointer<Expression>> const& getArguments() const { return m_arguments; } std::vector<ASTPointer<Expression>> const& getArguments() const { return m_arguments; }
void checkTypeRequirements(); /// @param _bases is the list of base contracts for base constructor calls. For modifiers an empty vector should be passed.
void checkTypeRequirements(std::vector<ASTPointer<InheritanceSpecifier>> const& _bases);
private: private:
ASTPointer<Identifier> m_modifierName; ASTPointer<Identifier> m_modifierName;

304
libsolidity/ArrayUtils.cpp

@ -0,0 +1,304 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2015
* Code generation utils that handle arrays.
*/
#include <libsolidity/ArrayUtils.h>
#include <libevmcore/Instruction.h>
#include <libsolidity/CompilerContext.h>
#include <libsolidity/CompilerUtils.h>
#include <libsolidity/Types.h>
#include <libsolidity/Utils.h>
#include <libsolidity/LValue.h>
using namespace std;
using namespace dev;
using namespace solidity;
void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const
{
// stack layout: [source_ref] target_ref (top)
// need to leave target_ref on the stack at the end
solAssert(_targetType.getLocation() == ArrayType::Location::Storage, "");
IntegerType uint256(256);
Type const* targetBaseType = _targetType.isByteArray() ? &uint256 : &(*_targetType.getBaseType());
Type const* sourceBaseType = _sourceType.isByteArray() ? &uint256 : &(*_sourceType.getBaseType());
switch (_sourceType.getLocation())
{
case ArrayType::Location::CallData:
{
solAssert(_targetType.isByteArray(), "Non byte arrays not yet implemented here.");
solAssert(_sourceType.isByteArray(), "Non byte arrays not yet implemented here.");
// This also assumes that after "length" we only have zeros, i.e. it cannot be used to
// slice a byte array from calldata.
// stack: source_offset source_len target_ref
// fetch old length and convert to words
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
convertLengthToSize(_targetType);
// stack here: source_offset source_len target_ref target_length_words
// actual array data is stored at SHA3(storage_offset)
m_context << eth::Instruction::DUP2;
CompilerUtils(m_context).computeHashStatic();
// compute target_data_end
m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2 << eth::Instruction::ADD
<< eth::Instruction::SWAP1;
// stack here: source_offset source_len target_ref target_data_end target_data_ref
// store length (in bytes)
m_context << eth::Instruction::DUP4 << eth::Instruction::DUP1 << eth::Instruction::DUP5
<< eth::Instruction::SSTORE;
// jump to end if length is zero
m_context << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
// store start offset
m_context << eth::Instruction::DUP5;
// stack now: source_offset source_len target_ref target_data_end target_data_ref calldata_offset
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart
// copy from calldata and store
<< eth::Instruction::DUP1 << eth::Instruction::CALLDATALOAD
<< eth::Instruction::DUP3 << eth::Instruction::SSTORE
// increment target_data_ref by 1
<< eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD
// increment calldata_offset by 32
<< eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD
// check for loop condition
<< eth::Instruction::DUP1 << eth::Instruction::DUP6 << eth::Instruction::GT;
m_context.appendConditionalJumpTo(copyLoopStart);
m_context << eth::Instruction::POP;
m_context << copyLoopEnd;
// now clear leftover bytes of the old value
// stack now: source_offset source_len target_ref target_data_end target_data_ref
clearStorageLoop(IntegerType(256));
// stack now: source_offset source_len target_ref target_data_end
m_context << eth::Instruction::POP << eth::Instruction::SWAP2
<< eth::Instruction::POP << eth::Instruction::POP;
break;
}
case ArrayType::Location::Storage:
{
// this copies source to target and also clears target if it was larger
solAssert(sourceBaseType->getStorageSize() == targetBaseType->getStorageSize(),
"Copying with different storage sizes not yet implemented.");
// stack: source_ref target_ref
// store target_ref
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;
// stack: target_ref source_ref target_ref
// fetch lengthes
retrieveLength(_targetType);
m_context << eth::Instruction::SWAP2;
// stack: target_ref target_len target_ref source_ref
retrieveLength(_sourceType);
// stack: target_ref target_len target_ref source_ref source_len
if (_targetType.isDynamicallySized())
// store new target length
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::SSTORE;
// compute hashes (data positions)
m_context << eth::Instruction::SWAP2;
if (_targetType.isDynamicallySized())
CompilerUtils(m_context).computeHashStatic();
m_context << eth::Instruction::SWAP1;
if (_sourceType.isDynamicallySized())
CompilerUtils(m_context).computeHashStatic();
// stack: target_ref target_len source_len target_data_pos source_data_pos
m_context << eth::Instruction::DUP4;
convertLengthToSize(_sourceType);
m_context << eth::Instruction::DUP4;
convertLengthToSize(_sourceType);
// stack: target_ref target_len source_len target_data_pos source_data_pos target_size source_size
// @todo we might be able to go without a third counter
m_context << u256(0);
// stack: target_ref target_len source_len target_data_pos source_data_pos target_size source_size counter
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart;
// check for loop condition
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3
<< eth::Instruction::GT << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
// copy
m_context << eth::Instruction::DUP4 << eth::Instruction::DUP2 << eth::Instruction::ADD;
StorageItem(m_context, *sourceBaseType).retrieveValue(SourceLocation(), true);
m_context << eth::dupInstruction(5 + sourceBaseType->getSizeOnStack())
<< eth::dupInstruction(2 + sourceBaseType->getSizeOnStack()) << eth::Instruction::ADD;
StorageItem(m_context, *targetBaseType).storeValue(*sourceBaseType, SourceLocation(), true);
// increment
m_context << targetBaseType->getStorageSize() << eth::Instruction::ADD;
m_context.appendJumpTo(copyLoopStart);
m_context << copyLoopEnd;
// zero-out leftovers in target
// stack: target_ref target_len source_len target_data_pos source_data_pos target_size source_size counter
// add counter to target_data_pos
m_context << eth::Instruction::DUP5 << eth::Instruction::ADD
<< eth::Instruction::SWAP5 << eth::Instruction::POP;
// stack: target_ref target_len target_data_pos_updated target_data_pos source_data_pos target_size source_size
// add size to target_data_pos to get target_data_end
m_context << eth::Instruction::POP << eth::Instruction::DUP3 << eth::Instruction::ADD
<< eth::Instruction::SWAP4
<< eth::Instruction::POP << eth::Instruction::POP << eth::Instruction::POP;
// stack: target_ref target_data_end target_data_pos_updated
clearStorageLoop(*targetBaseType);
m_context << eth::Instruction::POP;
break;
}
default:
solAssert(false, "Given byte array location not implemented.");
}
}
void ArrayUtils::clearArray(ArrayType const& _type) const
{
solAssert(_type.getLocation() == ArrayType::Location::Storage, "");
if (_type.isDynamicallySized())
clearDynamicArray(_type);
else if (_type.getLength() == 0)
m_context << eth::Instruction::POP;
else if (_type.getLength() < 5) // unroll loop for small arrays @todo choose a good value
{
for (unsigned i = 1; i < _type.getLength(); ++i)
{
StorageItem(m_context, *_type.getBaseType()).setToZero(SourceLocation(), false);
m_context << u256(_type.getBaseType()->getStorageSize()) << eth::Instruction::ADD;
}
StorageItem(m_context, *_type.getBaseType()).setToZero(SourceLocation(), true);
}
else
{
m_context
<< eth::Instruction::DUP1 << u256(_type.getLength())
<< u256(_type.getBaseType()->getStorageSize())
<< eth::Instruction::MUL << eth::Instruction::ADD << eth::Instruction::SWAP1;
clearStorageLoop(*_type.getBaseType());
m_context << eth::Instruction::POP;
}
}
void ArrayUtils::clearDynamicArray(ArrayType const& _type) const
{
solAssert(_type.getLocation() == ArrayType::Location::Storage, "");
solAssert(_type.isDynamicallySized(), "");
// fetch length
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
// set length to zero
m_context << u256(0) << eth::Instruction::DUP3 << eth::Instruction::SSTORE;
// stack: ref old_length
convertLengthToSize(_type);
// compute data positions
m_context << eth::Instruction::SWAP1;
CompilerUtils(m_context).computeHashStatic();
// stack: len data_pos (len is in slots for byte array and in items for other arrays)
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD
<< eth::Instruction::SWAP1;
// stack: data_pos_end data_pos
if (_type.isByteArray())
clearStorageLoop(IntegerType(256));
else
clearStorageLoop(*_type.getBaseType());
// cleanup
m_context << eth::Instruction::POP;
}
void ArrayUtils::resizeDynamicArray(const ArrayType& _type) const
{
solAssert(_type.getLocation() == ArrayType::Location::Storage, "");
solAssert(_type.isDynamicallySized(), "");
eth::AssemblyItem resizeEnd = m_context.newTag();
// stack: ref new_length
// fetch old length
m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD;
// stack: ref new_length old_length
// store new length
m_context << eth::Instruction::DUP2 << eth::Instruction::DUP4 << eth::Instruction::SSTORE;
// skip if size is not reduced
m_context << eth::Instruction::DUP2 << eth::Instruction::DUP2
<< eth::Instruction::ISZERO << eth::Instruction::GT;
m_context.appendConditionalJumpTo(resizeEnd);
// size reduced, clear the end of the array
// stack: ref new_length old_length
convertLengthToSize(_type);
m_context << eth::Instruction::DUP2;
convertLengthToSize(_type);
// stack: ref new_length old_size new_size
// compute data positions
m_context << eth::Instruction::DUP4;
CompilerUtils(m_context).computeHashStatic();
// stack: ref new_length old_size new_size data_pos
m_context << eth::Instruction::SWAP2 << eth::Instruction::DUP3 << eth::Instruction::ADD;
// stack: ref new_length data_pos new_size delete_end
m_context << eth::Instruction::SWAP2 << eth::Instruction::ADD;
// stack: ref new_length delete_end delete_start
if (_type.isByteArray())
clearStorageLoop(IntegerType(256));
else
clearStorageLoop(*_type.getBaseType());
m_context << resizeEnd;
// cleanup
m_context << eth::Instruction::POP << eth::Instruction::POP << eth::Instruction::POP;
}
void ArrayUtils::clearStorageLoop(Type const& _type) const
{
// stack: end_pos pos
eth::AssemblyItem loopStart = m_context.newTag();
m_context << loopStart;
// check for loop condition
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3
<< eth::Instruction::GT << eth::Instruction::ISZERO;
eth::AssemblyItem zeroLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(zeroLoopEnd);
// delete
StorageItem(m_context, _type).setToZero(SourceLocation(), false);
// increment
m_context << u256(1) << eth::Instruction::ADD;
m_context.appendJumpTo(loopStart);
// cleanup
m_context << zeroLoopEnd;
m_context << eth::Instruction::POP;
}
void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType) const
{
if (_arrayType.isByteArray())
m_context << u256(31) << eth::Instruction::ADD
<< u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
else if (_arrayType.getBaseType()->getStorageSize() > 1)
m_context << _arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL;
}
void ArrayUtils::retrieveLength(ArrayType const& _arrayType) const
{
if (_arrayType.isDynamicallySized())
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
else
m_context << _arrayType.getLength();
}

78
libsolidity/ArrayUtils.h

@ -0,0 +1,78 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2015
* Code generation utils that handle arrays.
*/
#pragma once
namespace dev
{
namespace solidity
{
class CompilerContext;
class Type;
class ArrayType;
/**
* Class that provides code generation for handling arrays.
*/
class ArrayUtils
{
public:
ArrayUtils(CompilerContext& _context): m_context(_context) {}
/// Copies an array to an array in storage. The arrays can be of different types only if
/// their storage representation is the same.
/// Stack pre: [source_reference] target_reference
/// Stack post: target_reference
void copyArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const;
/// Clears the given dynamic or static array.
/// Stack pre: reference
/// Stack post:
void clearArray(ArrayType const& _type) const;
/// Clears the length and data elements of the array referenced on the stack.
/// Stack pre: reference
/// Stack post:
void clearDynamicArray(ArrayType const& _type) const;
/// Changes the size of a dynamic array and clears the tail if it is shortened.
/// Stack pre: reference new_length
/// Stack post:
void resizeDynamicArray(ArrayType const& _type) const;
/// Appends a loop that clears a sequence of storage slots of the given type (excluding end).
/// Stack pre: end_ref start_ref
/// Stack post: end_ref
void clearStorageLoop(Type const& _type) const;
/// Converts length to size (multiplies by size on stack), rounds up for byte arrays.
/// Stack pre: length
/// Stack post: size
void convertLengthToSize(ArrayType const& _arrayType) const;
/// Retrieves the length (number of elements) of the array ref on the stack. This also
/// works for statically-sized arrays.
/// Stack pre: reference
/// Stack post: reference length
void retrieveLength(ArrayType const& _arrayType) const;
private:
CompilerContext& m_context;
};
}
}

108
libsolidity/Compiler.cpp

@ -58,7 +58,10 @@ void Compiler::compileContract(ContractDefinition const& _contract,
while (!functions.empty()) while (!functions.empty())
{ {
for (Declaration const* function: functions) for (Declaration const* function: functions)
{
m_context.setStackOffset(0);
function->accept(*this); function->accept(*this);
}
functions = m_context.getFunctionsWithoutCode(); functions = m_context.getFunctionsWithoutCode();
} }
@ -79,37 +82,38 @@ void Compiler::initializeContext(ContractDefinition const& _contract,
void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext) void Compiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext)
{ {
// arguments for base constructors, filled in derived-to-base order
map<ContractDefinition const*, vector<ASTPointer<Expression>> const*> baseArguments;
// Determine the arguments that are used for the base constructors. // Determine the arguments that are used for the base constructors.
std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts(); std::vector<ContractDefinition const*> const& bases = _contract.getLinearizedBaseContracts();
for (ContractDefinition const* contract: bases) for (ContractDefinition const* contract: bases)
{
if (FunctionDefinition const* constructor = contract->getConstructor())
for (auto const& modifier: constructor->getModifiers())
{
auto baseContract = dynamic_cast<ContractDefinition const*>(
modifier->getName()->getReferencedDeclaration());
if (baseContract)
if (m_baseArguments.count(baseContract->getConstructor()) == 0)
m_baseArguments[baseContract->getConstructor()] = &modifier->getArguments();
}
for (ASTPointer<InheritanceSpecifier> const& base: contract->getBaseContracts()) for (ASTPointer<InheritanceSpecifier> const& base: contract->getBaseContracts())
{ {
ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>( ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>(
base->getName()->getReferencedDeclaration()); base->getName()->getReferencedDeclaration());
solAssert(baseContract, ""); solAssert(baseContract, "");
if (baseArguments.count(baseContract) == 0)
baseArguments[baseContract] = &base->getArguments();
}
// Call constructors in base-to-derived order. if (m_baseArguments.count(baseContract->getConstructor()) == 0)
// The Constructor for the most derived contract is called later. m_baseArguments[baseContract->getConstructor()] = &base->getArguments();
for (unsigned i = 1; i < bases.size(); i++) }
{
ContractDefinition const* base = bases[bases.size() - i];
solAssert(base, "");
initializeStateVariables(*base);
FunctionDefinition const* baseConstructor = base->getConstructor();
if (!baseConstructor)
continue;
solAssert(baseArguments[base], "");
appendBaseConstructorCall(*baseConstructor, *baseArguments[base]);
} }
initializeStateVariables(_contract); // Initialization of state variables in base-to-derived order.
if (_contract.getConstructor()) for (ContractDefinition const* contract: boost::adaptors::reverse(bases))
appendConstructorCall(*_contract.getConstructor()); initializeStateVariables(*contract);
if (FunctionDefinition const* constructor = _contract.getConstructor())
appendConstructor(*constructor);
else if (auto c = m_context.getNextConstructor(_contract))
appendBaseConstructor(*c);
eth::AssemblyItem sub = m_context.addSubroutine(_runtimeContext.getAssembly()); eth::AssemblyItem sub = m_context.addSubroutine(_runtimeContext.getAssembly());
// stack contains sub size // stack contains sub size
@ -126,22 +130,23 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
} }
} }
void Compiler::appendBaseConstructorCall(FunctionDefinition const& _constructor, void Compiler::appendBaseConstructor(FunctionDefinition const& _constructor)
vector<ASTPointer<Expression>> const& _arguments)
{ {
CompilerContext::LocationSetter locationSetter(m_context, &_constructor); CompilerContext::LocationSetter locationSetter(m_context, &_constructor);
FunctionType constructorType(_constructor); FunctionType constructorType(_constructor);
eth::AssemblyItem returnLabel = m_context.pushNewTag(); if (!constructorType.getParameterTypes().empty())
for (unsigned i = 0; i < _arguments.size(); ++i) {
compileExpression(*_arguments[i], constructorType.getParameterTypes()[i]); std::vector<ASTPointer<Expression>> const* arguments = m_baseArguments[&_constructor];
m_context.appendJumpTo(m_context.getFunctionEntryLabel(_constructor)); solAssert(arguments, "");
m_context << returnLabel; for (unsigned i = 0; i < arguments->size(); ++i)
compileExpression(*(arguments->at(i)), constructorType.getParameterTypes()[i]);
}
_constructor.accept(*this);
} }
void Compiler::appendConstructorCall(FunctionDefinition const& _constructor) void Compiler::appendConstructor(FunctionDefinition const& _constructor)
{ {
CompilerContext::LocationSetter locationSetter(m_context, &_constructor); CompilerContext::LocationSetter locationSetter(m_context, &_constructor);
eth::AssemblyItem returnTag = m_context.pushNewTag();
// copy constructor arguments from code to memory and then to stack, they are supplied after the actual program // copy constructor arguments from code to memory and then to stack, they are supplied after the actual program
unsigned argumentSize = 0; unsigned argumentSize = 0;
for (ASTPointer<VariableDeclaration> const& var: _constructor.getParameters()) for (ASTPointer<VariableDeclaration> const& var: _constructor.getParameters())
@ -155,8 +160,7 @@ void Compiler::appendConstructorCall(FunctionDefinition const& _constructor)
m_context << eth::Instruction::CODECOPY; m_context << eth::Instruction::CODECOPY;
appendCalldataUnpacker(FunctionType(_constructor).getParameterTypes(), true); appendCalldataUnpacker(FunctionType(_constructor).getParameterTypes(), true);
} }
m_context.appendJumpTo(m_context.getFunctionEntryLabel(_constructor)); _constructor.accept(*this);
m_context << returnTag;
} }
void Compiler::appendFunctionSelector(ContractDefinition const& _contract) void Compiler::appendFunctionSelector(ContractDefinition const& _contract)
@ -296,28 +300,36 @@ bool Compiler::visit(FunctionDefinition const& _function)
// although note that this reduces the size of the visible stack // although note that this reduces the size of the visible stack
m_context.startFunction(_function); m_context.startFunction(_function);
m_returnTag = m_context.newTag();
m_breakTags.clear();
m_continueTags.clear();
m_stackCleanupForReturn = 0;
m_currentFunction = &_function;
m_modifierDepth = 0;
// stack upon entry: [return address] [arg0] [arg1] ... [argn] // stack upon entry: [return address] [arg0] [arg1] ... [argn]
// reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp] // reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp]
unsigned parametersSize = CompilerUtils::getSizeOnStack(_function.getParameters()); unsigned parametersSize = CompilerUtils::getSizeOnStack(_function.getParameters());
m_context.adjustStackOffset(parametersSize); if (!_function.isConstructor())
// adding 1 for return address.
m_context.adjustStackOffset(parametersSize + 1);
for (ASTPointer<VariableDeclaration const> const& variable: _function.getParameters()) for (ASTPointer<VariableDeclaration const> const& variable: _function.getParameters())
{ {
m_context.addVariable(*variable, parametersSize); m_context.addVariable(*variable, parametersSize);
parametersSize -= variable->getType()->getSizeOnStack(); parametersSize -= variable->getType()->getSizeOnStack();
} }
for (ASTPointer<VariableDeclaration const> const& variable: _function.getReturnParameters()) for (ASTPointer<VariableDeclaration const> const& variable: _function.getReturnParameters())
m_context.addAndInitializeVariable(*variable); m_context.addAndInitializeVariable(*variable);
for (VariableDeclaration const* localVariable: _function.getLocalVariables()) for (VariableDeclaration const* localVariable: _function.getLocalVariables())
m_context.addAndInitializeVariable(*localVariable); m_context.addAndInitializeVariable(*localVariable);
if (_function.isConstructor())
if (auto c = m_context.getNextConstructor(dynamic_cast<ContractDefinition const&>(*_function.getScope())))
appendBaseConstructor(*c);
m_returnTag = m_context.newTag();
m_breakTags.clear();
m_continueTags.clear();
m_stackCleanupForReturn = 0;
m_currentFunction = &_function;
m_modifierDepth = 0;
appendModifierOrFunctionCode(); appendModifierOrFunctionCode();
m_context << m_returnTag; m_context << m_returnTag;
@ -352,8 +364,14 @@ bool Compiler::visit(FunctionDefinition const& _function)
} }
//@todo assert that everything is in place now //@todo assert that everything is in place now
m_context << eth::Instruction::JUMP; for (ASTPointer<VariableDeclaration const> const& variable: _function.getParameters() + _function.getReturnParameters())
m_context.removeVariable(*variable);
for (VariableDeclaration const* localVariable: _function.getLocalVariables())
m_context.removeVariable(*localVariable);
m_context.adjustStackOffset(-c_returnValuesSize);
if (!_function.isConstructor())
m_context << eth::Instruction::JUMP;
return false; return false;
} }
@ -515,6 +533,16 @@ void Compiler::appendModifierOrFunctionCode()
else else
{ {
ASTPointer<ModifierInvocation> const& modifierInvocation = m_currentFunction->getModifiers()[m_modifierDepth]; ASTPointer<ModifierInvocation> const& modifierInvocation = m_currentFunction->getModifiers()[m_modifierDepth];
// constructor call should be excluded
if (dynamic_cast<ContractDefinition const*>(modifierInvocation->getName()->getReferencedDeclaration()))
{
++m_modifierDepth;
appendModifierOrFunctionCode();
--m_modifierDepth;
return;
}
ModifierDefinition const& modifier = m_context.getFunctionModifier(modifierInvocation->getName()->getName()); ModifierDefinition const& modifier = m_context.getFunctionModifier(modifierInvocation->getName()->getName());
CompilerContext::LocationSetter locationSetter(m_context, &modifier); CompilerContext::LocationSetter locationSetter(m_context, &modifier);
solAssert(modifier.getParameters().size() == modifierInvocation->getArguments().size(), ""); solAssert(modifier.getParameters().size() == modifierInvocation->getArguments().size(), "");

7
libsolidity/Compiler.h

@ -55,9 +55,8 @@ private:
/// Adds the code that is run at creation time. Should be run after exchanging the run-time context /// Adds the code that is run at creation time. Should be run after exchanging the run-time context
/// with a new and initialized context. Adds the constructor code. /// with a new and initialized context. Adds the constructor code.
void packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext); void packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext);
void appendBaseConstructorCall(FunctionDefinition const& _constructor, void appendBaseConstructor(FunctionDefinition const& _constructor);
std::vector<ASTPointer<Expression>> const& _arguments); void appendConstructor(FunctionDefinition const& _constructor);
void appendConstructorCall(FunctionDefinition const& _constructor);
void appendFunctionSelector(ContractDefinition const& _contract); void appendFunctionSelector(ContractDefinition const& _contract);
/// Creates code that unpacks the arguments for the given function represented by a vector of TypePointers. /// Creates code that unpacks the arguments for the given function represented by a vector of TypePointers.
/// From memory if @a _fromMemory is true, otherwise from call data. /// From memory if @a _fromMemory is true, otherwise from call data.
@ -94,6 +93,8 @@ private:
unsigned m_modifierDepth = 0; unsigned m_modifierDepth = 0;
FunctionDefinition const* m_currentFunction; FunctionDefinition const* m_currentFunction;
unsigned m_stackCleanupForReturn; ///< this number of stack elements need to be removed before jump to m_returnTag unsigned m_stackCleanupForReturn; ///< this number of stack elements need to be removed before jump to m_returnTag
// arguments for base constructors, filled in derived-to-base order
std::map<FunctionDefinition const*, std::vector<ASTPointer<Expression>> const*> m_baseArguments;
}; };
} }

33
libsolidity/CompilerContext.cpp

@ -51,8 +51,6 @@ void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
void CompilerContext::startFunction(Declaration const& _function) void CompilerContext::startFunction(Declaration const& _function)
{ {
m_functionsWithCode.insert(&_function); m_functionsWithCode.insert(&_function);
m_localVariables.clear();
m_asm.setDeposit(0);
*this << getFunctionEntryLabel(_function); *this << getFunctionEntryLabel(_function);
} }
@ -63,6 +61,12 @@ void CompilerContext::addVariable(VariableDeclaration const& _declaration,
m_localVariables[&_declaration] = unsigned(m_asm.deposit()) - _offsetToCurrent; m_localVariables[&_declaration] = unsigned(m_asm.deposit()) - _offsetToCurrent;
} }
void CompilerContext::removeVariable(VariableDeclaration const& _declaration)
{
solAssert(m_localVariables.count(&_declaration), "");
m_localVariables.erase(&_declaration);
}
void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration) void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration)
{ {
LocationSetter locationSetter(*this, &_declaration); LocationSetter locationSetter(*this, &_declaration);
@ -110,11 +114,8 @@ eth::AssemblyItem CompilerContext::getVirtualFunctionEntryLabel(FunctionDefiniti
eth::AssemblyItem CompilerContext::getSuperFunctionEntryLabel(string const& _name, ContractDefinition const& _base) eth::AssemblyItem CompilerContext::getSuperFunctionEntryLabel(string const& _name, ContractDefinition const& _base)
{ {
// search for first contract after _base auto it = getSuperContract(_base);
solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); for (; it != m_inheritanceHierarchy.end(); ++it)
auto it = find(m_inheritanceHierarchy.begin(), m_inheritanceHierarchy.end(), &_base);
solAssert(it != m_inheritanceHierarchy.end(), "Base not found in inheritance hierarchy.");
for (++it; it != m_inheritanceHierarchy.end(); ++it)
for (ASTPointer<FunctionDefinition> const& function: (*it)->getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: (*it)->getDefinedFunctions())
if (!function->isConstructor() && function->getName() == _name) if (!function->isConstructor() && function->getName() == _name)
return getFunctionEntryLabel(*function); return getFunctionEntryLabel(*function);
@ -122,6 +123,16 @@ eth::AssemblyItem CompilerContext::getSuperFunctionEntryLabel(string const& _nam
return m_asm.newTag(); // not reached return m_asm.newTag(); // not reached
} }
FunctionDefinition const* CompilerContext::getNextConstructor(ContractDefinition const& _contract) const
{
vector<ContractDefinition const*>::const_iterator it = getSuperContract(_contract);
for (; it != m_inheritanceHierarchy.end(); ++it)
if ((*it)->getConstructor())
return (*it)->getConstructor();
return nullptr;
}
set<Declaration const*> CompilerContext::getFunctionsWithoutCode() set<Declaration const*> CompilerContext::getFunctionsWithoutCode()
{ {
set<Declaration const*> functions; set<Declaration const*> functions;
@ -201,5 +212,13 @@ CompilerContext& CompilerContext::operator<<(bytes const& _data)
return *this; return *this;
} }
vector<ContractDefinition const*>::const_iterator CompilerContext::getSuperContract(ContractDefinition const& _contract) const
{
solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set.");
auto it = find(m_inheritanceHierarchy.begin(), m_inheritanceHierarchy.end(), &_contract);
solAssert(it != m_inheritanceHierarchy.end(), "Base not found in inheritance hierarchy.");
return ++it;
}
} }
} }

8
libsolidity/CompilerContext.h

@ -43,11 +43,13 @@ public:
void addMagicGlobal(MagicVariableDeclaration const& _declaration); void addMagicGlobal(MagicVariableDeclaration const& _declaration);
void addStateVariable(VariableDeclaration const& _declaration); void addStateVariable(VariableDeclaration const& _declaration);
void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0); void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0);
void removeVariable(VariableDeclaration const& _declaration);
void addAndInitializeVariable(VariableDeclaration const& _declaration); void addAndInitializeVariable(VariableDeclaration const& _declaration);
void setCompiledContracts(std::map<ContractDefinition const*, bytes const*> const& _contracts) { m_compiledContracts = _contracts; } void setCompiledContracts(std::map<ContractDefinition const*, bytes const*> const& _contracts) { m_compiledContracts = _contracts; }
bytes const& getCompiledContract(ContractDefinition const& _contract) const; bytes const& getCompiledContract(ContractDefinition const& _contract) const;
void setStackOffset(int _offset) { m_asm.setDeposit(_offset); }
void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); }
unsigned getStackHeight() const { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); } unsigned getStackHeight() const { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); }
@ -62,6 +64,8 @@ public:
/// @returns the entry label of function with the given name from the most derived class just /// @returns the entry label of function with the given name from the most derived class just
/// above _base in the current inheritance hierarchy. /// above _base in the current inheritance hierarchy.
eth::AssemblyItem getSuperFunctionEntryLabel(std::string const& _name, ContractDefinition const& _base); eth::AssemblyItem getSuperFunctionEntryLabel(std::string const& _name, ContractDefinition const& _base);
FunctionDefinition const* getNextConstructor(ContractDefinition const& _contract) const;
/// @returns the set of functions for which we still need to generate code /// @returns the set of functions for which we still need to generate code
std::set<Declaration const*> getFunctionsWithoutCode(); std::set<Declaration const*> getFunctionsWithoutCode();
/// Resets function specific members, inserts the function entry label and marks the function /// Resets function specific members, inserts the function entry label and marks the function
@ -126,9 +130,11 @@ public:
LocationSetter(CompilerContext& _compilerContext, ASTNode const* _node): LocationSetter(CompilerContext& _compilerContext, ASTNode const* _node):
ScopeGuard(std::bind(&CompilerContext::popVisitedNodes, _compilerContext)) { _compilerContext.pushVisitedNodes(_node); } ScopeGuard(std::bind(&CompilerContext::popVisitedNodes, _compilerContext)) { _compilerContext.pushVisitedNodes(_node); }
}; };
eth::Assembly m_asm;
private: private:
std::vector<ContractDefinition const*>::const_iterator getSuperContract(const ContractDefinition &_contract) const;
eth::Assembly m_asm;
/// Magic global variables like msg, tx or this, distinguished by type. /// Magic global variables like msg, tx or this, distinguished by type.
std::set<Declaration const*> m_magicGlobals; std::set<Declaration const*> m_magicGlobals;
/// Other already compiled contracts to be used in contract creation calls. /// Other already compiled contracts to be used in contract creation calls.

170
libsolidity/CompilerUtils.cpp

@ -164,134 +164,6 @@ void CompilerUtils::computeHashStatic(Type const& _type, bool _padToWordBoundari
m_context << u256(length) << u256(0) << eth::Instruction::SHA3; m_context << u256(length) << u256(0) << eth::Instruction::SHA3;
} }
void CompilerUtils::copyByteArrayToStorage(
ArrayType const& _targetType, ArrayType const& _sourceType) const
{
// stack layout: [source_ref] target_ref (top)
// need to leave target_ref on the stack at the end
solAssert(_targetType.getLocation() == ArrayType::Location::Storage, "");
solAssert(_targetType.isByteArray(), "Non byte arrays not yet implemented here.");
solAssert(_sourceType.isByteArray(), "Non byte arrays not yet implemented here.");
switch (_sourceType.getLocation())
{
case ArrayType::Location::CallData:
{
// This also assumes that after "length" we only have zeros, i.e. it cannot be used to
// slice a byte array from calldata.
// stack: source_offset source_len target_ref
// fetch old length and convert to words
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
m_context << u256(31) << eth::Instruction::ADD
<< u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
// stack here: source_offset source_len target_ref target_length_words
// actual array data is stored at SHA3(storage_offset)
m_context << eth::Instruction::DUP2;
CompilerUtils(m_context).computeHashStatic();
// compute target_data_end
m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2 << eth::Instruction::ADD
<< eth::Instruction::SWAP1;
// stack here: source_offset source_len target_ref target_data_end target_data_ref
// store length (in bytes)
m_context << eth::Instruction::DUP4 << eth::Instruction::DUP1 << eth::Instruction::DUP5
<< eth::Instruction::SSTORE;
// jump to end if length is zero
m_context << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
// store start offset
m_context << eth::Instruction::DUP5;
// stack now: source_offset source_len target_ref target_data_end target_data_ref calldata_offset
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart
// copy from calldata and store
<< eth::Instruction::DUP1 << eth::Instruction::CALLDATALOAD
<< eth::Instruction::DUP3 << eth::Instruction::SSTORE
// increment target_data_ref by 1
<< eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD
// increment calldata_offset by 32
<< eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD
// check for loop condition
<< eth::Instruction::DUP1 << eth::Instruction::DUP6 << eth::Instruction::GT;
m_context.appendConditionalJumpTo(copyLoopStart);
m_context << eth::Instruction::POP;
m_context << copyLoopEnd;
// now clear leftover bytes of the old value
// stack now: source_offset source_len target_ref target_data_end target_data_ref
clearStorageLoop();
// stack now: source_offset source_len target_ref target_data_end
m_context << eth::Instruction::POP << eth::Instruction::SWAP2
<< eth::Instruction::POP << eth::Instruction::POP;
break;
}
case ArrayType::Location::Storage:
{
// this copies source to target and also clears target if it was larger
// stack: source_ref target_ref
// store target_ref
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;
// fetch lengthes
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP2
<< eth::Instruction::DUP1 << eth::Instruction::SLOAD;
// stack: target_ref target_len_bytes target_ref source_ref source_len_bytes
// store new target length
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::SSTORE;
// compute hashes (data positions)
m_context << eth::Instruction::SWAP2;
CompilerUtils(m_context).computeHashStatic();
m_context << eth::Instruction::SWAP1;
CompilerUtils(m_context).computeHashStatic();
// stack: target_ref target_len_bytes source_len_bytes target_data_pos source_data_pos
// convert lengthes from bytes to storage slots
m_context << u256(31) << u256(32) << eth::Instruction::DUP1 << eth::Instruction::DUP3
<< eth::Instruction::DUP8 << eth::Instruction::ADD << eth::Instruction::DIV
<< eth::Instruction::SWAP2
<< eth::Instruction::DUP6 << eth::Instruction::ADD << eth::Instruction::DIV;
// stack: target_ref target_len_bytes source_len_bytes target_data_pos source_data_pos target_len source_len
// @todo we might be able to go without a third counter
m_context << u256(0);
// stack: target_ref target_len_bytes source_len_bytes target_data_pos source_data_pos target_len source_len counter
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart;
// check for loop condition
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3
<< eth::Instruction::GT << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
// copy
m_context << eth::Instruction::DUP4 << eth::Instruction::DUP2 << eth::Instruction::ADD
<< eth::Instruction::SLOAD
<< eth::Instruction::DUP6 << eth::Instruction::DUP3 << eth::Instruction::ADD
<< eth::Instruction::SSTORE;
// increment
m_context << u256(1) << eth::Instruction::ADD;
m_context.appendJumpTo(copyLoopStart);
m_context << copyLoopEnd;
// zero-out leftovers in target
// stack: target_ref target_len_bytes source_len_bytes target_data_pos source_data_pos target_len source_len counter
// add counter to target_data_pos
m_context << eth::Instruction::DUP5 << eth::Instruction::ADD
<< eth::Instruction::SWAP5 << eth::Instruction::POP;
// stack: target_ref target_len_bytes target_data_pos_updated target_data_pos source_data_pos target_len source_len
// add length to target_data_pos to get target_data_end
m_context << eth::Instruction::POP << eth::Instruction::DUP3 << eth::Instruction::ADD
<< eth::Instruction::SWAP4
<< eth::Instruction::POP << eth::Instruction::POP << eth::Instruction::POP;
// stack: target_ref target_data_end target_data_pos_updated
clearStorageLoop();
m_context << eth::Instruction::POP;
break;
}
default:
solAssert(false, "Given byte array location not implemented.");
}
}
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries) unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
{ {
unsigned _encodedSize = _type.getCalldataEncodedSize(); unsigned _encodedSize = _type.getCalldataEncodedSize();
@ -316,28 +188,6 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
return numBytes; return numBytes;
} }
void CompilerUtils::clearByteArray(ArrayType const& _type) const
{
solAssert(_type.getLocation() == ArrayType::Location::Storage, "");
solAssert(_type.isByteArray(), "Non byte arrays not yet implemented here.");
// fetch length
m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD;
// set length to zero
m_context << u256(0) << eth::Instruction::DUP3 << eth::Instruction::SSTORE;
// convert length from bytes to storage slots
m_context << u256(31) << eth::Instruction::ADD
<< u256(32) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
// compute data positions
m_context << eth::Instruction::SWAP1;
CompilerUtils(m_context).computeHashStatic();
// stack: len data_pos
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD
<< eth::Instruction::SWAP1;
clearStorageLoop();
// cleanup
m_context << eth::Instruction::POP;
}
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const
{ {
@ -356,25 +206,5 @@ unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBou
return numBytes; return numBytes;
} }
void CompilerUtils::clearStorageLoop() const
{
// stack: end_pos pos
eth::AssemblyItem loopStart = m_context.newTag();
m_context << loopStart;
// check for loop condition
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3
<< eth::Instruction::GT << eth::Instruction::ISZERO;
eth::AssemblyItem zeroLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(zeroLoopEnd);
// zero out
m_context << u256(0) << eth::Instruction::DUP2 << eth::Instruction::SSTORE;
// increment
m_context << u256(1) << eth::Instruction::ADD;
m_context.appendJumpTo(loopStart);
// cleanup
m_context << zeroLoopEnd;
m_context << eth::Instruction::POP;
}
} }
} }

13
libsolidity/CompilerUtils.h

@ -79,15 +79,6 @@ public:
/// @note Only works for types of fixed size. /// @note Only works for types of fixed size.
void computeHashStatic(Type const& _type = IntegerType(256), bool _padToWordBoundaries = false); void computeHashStatic(Type const& _type = IntegerType(256), bool _padToWordBoundaries = false);
/// Copies a byte array to a byte array in storage.
/// Stack pre: [source_reference] target_reference
/// Stack post: target_reference
void copyByteArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const;
/// Clears the length and data elements of the byte array referenced on the stack.
/// Stack pre: reference
/// Stack post:
void clearByteArray(ArrayType const& _type) const;
/// Bytes we need to the start of call data. /// Bytes we need to the start of call data.
/// - The size in bytes of the function (hash) identifier. /// - The size in bytes of the function (hash) identifier.
static const unsigned int dataStartOffset; static const unsigned int dataStartOffset;
@ -97,10 +88,6 @@ private:
unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const; unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const;
/// Loads type from memory assuming memory offset is on stack top. /// Loads type from memory assuming memory offset is on stack top.
unsigned loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries); unsigned loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries);
/// Appends a loop that clears a sequence of storage slots (excluding end).
/// Stack pre: end_ref start_ref
/// Stack post: end_ref
void clearStorageLoop() const;
CompilerContext& m_context; CompilerContext& m_context;
}; };

8
libsolidity/ExpressionCompiler.cpp

@ -93,7 +93,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
m_context << eth::Instruction::DUP1 m_context << eth::Instruction::DUP1
<< structType->getStorageOffsetOfMember(names[i]) << structType->getStorageOffsetOfMember(names[i])
<< eth::Instruction::ADD; << eth::Instruction::ADD;
StorageItem(m_context, types[i]).retrieveValue(SourceLocation(), true); StorageItem(m_context, *types[i]).retrieveValue(SourceLocation(), true);
solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented."); solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented.");
m_context << eth::Instruction::SWAP1; m_context << eth::Instruction::SWAP1;
retSizeOnStack += types[i]->getSizeOnStack(); retSizeOnStack += types[i]->getSizeOnStack();
@ -104,7 +104,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
{ {
// simple value // simple value
solAssert(accessorType.getReturnParameterTypes().size() == 1, ""); solAssert(accessorType.getReturnParameterTypes().size() == 1, "");
StorageItem(m_context, returnType).retrieveValue(SourceLocation(), true); StorageItem(m_context, *returnType).retrieveValue(SourceLocation(), true);
retSizeOnStack = returnType->getSizeOnStack(); retSizeOnStack = returnType->getSizeOnStack();
} }
solAssert(retSizeOnStack <= 15, "Stack too deep."); solAssert(retSizeOnStack <= 15, "Stack too deep.");
@ -680,7 +680,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
break; break;
case ArrayType::Location::Storage: case ArrayType::Location::Storage:
setLValueToStorageItem(_memberAccess); setLValue<StorageArrayLength>(_memberAccess, type);
break; break;
default: default:
solAssert(false, "Unsupported array location."); solAssert(false, "Unsupported array location.");
@ -1044,7 +1044,7 @@ void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaratio
void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression) void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression)
{ {
setLValue<StorageItem>(_expression, _expression.getType()); setLValue<StorageItem>(_expression, *_expression.getType());
} }
} }

122
libsolidity/LValue.cpp

@ -32,15 +32,14 @@ using namespace solidity;
StackVariable::StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration): StackVariable::StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration):
LValue(_compilerContext, _declaration.getType()), LValue(_compilerContext, *_declaration.getType()),
m_baseStackOffset(m_context.getBaseStackOffsetOfVariable(_declaration)), m_baseStackOffset(m_context.getBaseStackOffsetOfVariable(_declaration)),
m_size(m_dataType->getSizeOnStack()) m_size(m_dataType.getSizeOnStack())
{ {
} }
void StackVariable::retrieveValue(SourceLocation const& _location, bool _remove) const void StackVariable::retrieveValue(SourceLocation const& _location, bool) const
{ {
(void)_remove;
unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset); unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset);
if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory
BOOST_THROW_EXCEPTION(CompilerError() BOOST_THROW_EXCEPTION(CompilerError()
@ -49,9 +48,8 @@ void StackVariable::retrieveValue(SourceLocation const& _location, bool _remove)
m_context << eth::dupInstruction(stackPos + 1); m_context << eth::dupInstruction(stackPos + 1);
} }
void StackVariable::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const void StackVariable::storeValue(Type const&, SourceLocation const& _location, bool _move) const
{ {
(void)_sourceType;
unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1; unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1;
if (stackDiff > 16) if (stackDiff > 16)
BOOST_THROW_EXCEPTION(CompilerError() BOOST_THROW_EXCEPTION(CompilerError()
@ -63,7 +61,7 @@ void StackVariable::storeValue(Type const& _sourceType, SourceLocation const& _l
retrieveValue(_location); retrieveValue(_location);
} }
void StackVariable::setToZero(SourceLocation const& _location) const void StackVariable::setToZero(SourceLocation const& _location, bool) const
{ {
unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset); unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset);
if (stackDiff > 16) if (stackDiff > 16)
@ -77,20 +75,20 @@ void StackVariable::setToZero(SourceLocation const& _location) const
StorageItem::StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration): StorageItem::StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration):
StorageItem(_compilerContext, _declaration.getType()) StorageItem(_compilerContext, *_declaration.getType())
{ {
m_context << m_context.getStorageLocationOfVariable(_declaration); m_context << m_context.getStorageLocationOfVariable(_declaration);
} }
StorageItem::StorageItem(CompilerContext& _compilerContext, TypePointer const& _type): StorageItem::StorageItem(CompilerContext& _compilerContext, Type const& _type):
LValue(_compilerContext, _type) LValue(_compilerContext, _type)
{ {
if (m_dataType->isValueType()) if (m_dataType.isValueType())
{ {
solAssert(m_dataType->getStorageSize() == m_dataType->getSizeOnStack(), ""); solAssert(m_dataType.getStorageSize() == m_dataType.getSizeOnStack(), "");
solAssert(m_dataType->getStorageSize() <= numeric_limits<unsigned>::max(), solAssert(m_dataType.getStorageSize() <= numeric_limits<unsigned>::max(),
"The storage size of " + m_dataType->toString() + " should fit in an unsigned"); "The storage size of " + m_dataType.toString() + " should fit in an unsigned");
m_size = unsigned(m_dataType->getStorageSize()); m_size = unsigned(m_dataType.getStorageSize());
} }
else else
m_size = 0; // unused m_size = 0; // unused
@ -98,7 +96,7 @@ StorageItem::StorageItem(CompilerContext& _compilerContext, TypePointer const& _
void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
{ {
if (!m_dataType->isValueType()) if (!m_dataType.isValueType())
return; // no distinction between value and reference for non-value types return; // no distinction between value and reference for non-value types
if (!_remove) if (!_remove)
m_context << eth::Instruction::DUP1; m_context << eth::Instruction::DUP1;
@ -118,7 +116,7 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const
{ {
// stack layout: value value ... value target_ref // stack layout: value value ... value target_ref
if (m_dataType->isValueType()) if (m_dataType.isValueType())
{ {
if (!_move) // copy values if (!_move) // copy values
{ {
@ -143,20 +141,20 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
} }
else else
{ {
solAssert(_sourceType.getCategory() == m_dataType->getCategory(), solAssert(_sourceType.getCategory() == m_dataType.getCategory(),
"Wrong type conversation for assignment."); "Wrong type conversation for assignment.");
if (m_dataType->getCategory() == Type::Category::Array) if (m_dataType.getCategory() == Type::Category::Array)
{ {
CompilerUtils(m_context).copyByteArrayToStorage( ArrayUtils(m_context).copyArrayToStorage(
dynamic_cast<ArrayType const&>(*m_dataType), dynamic_cast<ArrayType const&>(m_dataType),
dynamic_cast<ArrayType const&>(_sourceType)); dynamic_cast<ArrayType const&>(_sourceType));
if (_move) if (_move)
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
} }
else if (m_dataType->getCategory() == Type::Category::Struct) else if (m_dataType.getCategory() == Type::Category::Struct)
{ {
// stack layout: source_ref target_ref // stack layout: source_ref target_ref
auto const& structType = dynamic_cast<StructType const&>(*m_dataType); auto const& structType = dynamic_cast<StructType const&>(m_dataType);
solAssert(structType == _sourceType, "Struct assignment with conversion."); solAssert(structType == _sourceType, "Struct assignment with conversion.");
for (auto const& member: structType.getMembers()) for (auto const& member: structType.getMembers())
{ {
@ -167,12 +165,12 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
m_context << structType.getStorageOffsetOfMember(member.first) m_context << structType.getStorageOffsetOfMember(member.first)
<< eth::Instruction::DUP3 << eth::Instruction::DUP2 << eth::Instruction::ADD; << eth::Instruction::DUP3 << eth::Instruction::DUP2 << eth::Instruction::ADD;
// stack: source_ref target_ref member_offset source_member_ref // stack: source_ref target_ref member_offset source_member_ref
StorageItem(m_context, memberType).retrieveValue(_location, true); StorageItem(m_context, *memberType).retrieveValue(_location, true);
// stack: source_ref target_ref member_offset source_value... // stack: source_ref target_ref member_offset source_value...
m_context << eth::dupInstruction(2 + memberType->getSizeOnStack()) m_context << eth::dupInstruction(2 + memberType->getSizeOnStack())
<< eth::dupInstruction(2 + memberType->getSizeOnStack()) << eth::Instruction::ADD; << eth::dupInstruction(2 + memberType->getSizeOnStack()) << eth::Instruction::ADD;
// stack: source_ref target_ref member_offset source_value... target_member_ref // stack: source_ref target_ref member_offset source_value... target_member_ref
StorageItem(m_context, memberType).storeValue(*memberType, _location, true); StorageItem(m_context, *memberType).storeValue(*memberType, _location, true);
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
} }
if (_move) if (_move)
@ -187,16 +185,18 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
} }
} }
void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
void StorageItem::setToZero(SourceLocation const& _location) const
{ {
(void)_location; if (m_dataType.getCategory() == Type::Category::Array)
if (m_dataType->getCategory() == Type::Category::Array) {
CompilerUtils(m_context).clearByteArray(dynamic_cast<ArrayType const&>(*m_dataType)); if (!_removeReference)
else if (m_dataType->getCategory() == Type::Category::Struct) m_context << eth::Instruction::DUP1;
ArrayUtils(m_context).clearArray(dynamic_cast<ArrayType const&>(m_dataType));
}
else if (m_dataType.getCategory() == Type::Category::Struct)
{ {
// stack layout: ref // stack layout: ref
auto const& structType = dynamic_cast<StructType const&>(*m_dataType); auto const& structType = dynamic_cast<StructType const&>(m_dataType);
for (auto const& member: structType.getMembers()) for (auto const& member: structType.getMembers())
{ {
// zero each member that is not a mapping // zero each member that is not a mapping
@ -205,19 +205,61 @@ void StorageItem::setToZero(SourceLocation const& _location) const
continue; continue;
m_context << structType.getStorageOffsetOfMember(member.first) m_context << structType.getStorageOffsetOfMember(member.first)
<< eth::Instruction::DUP2 << eth::Instruction::ADD; << eth::Instruction::DUP2 << eth::Instruction::ADD;
StorageItem(m_context, memberType).setToZero(); StorageItem(m_context, *memberType).setToZero();
} }
m_context << eth::Instruction::POP; if (_removeReference)
m_context << eth::Instruction::POP;
} }
else else
{ {
if (m_size == 0) if (m_size == 0 && _removeReference)
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
for (unsigned i = 0; i < m_size; ++i) else if (m_size == 1)
if (i + 1 >= m_size) m_context
m_context << u256(0) << eth::Instruction::SWAP1 << eth::Instruction::SSTORE; << u256(0) << (_removeReference ? eth::Instruction::SWAP1 : eth::Instruction::DUP2)
else << eth::Instruction::SSTORE;
m_context << u256(0) << eth::Instruction::DUP2 << eth::Instruction::SSTORE else
<< u256(1) << eth::Instruction::ADD; {
if (!_removeReference)
m_context << eth::Instruction::DUP1;
for (unsigned i = 0; i < m_size; ++i)
if (i + 1 >= m_size)
m_context << u256(0) << eth::Instruction::SWAP1 << eth::Instruction::SSTORE;
else
m_context << u256(0) << eth::Instruction::DUP2 << eth::Instruction::SSTORE
<< u256(1) << eth::Instruction::ADD;
}
} }
} }
StorageArrayLength::StorageArrayLength(CompilerContext& _compilerContext, const ArrayType& _arrayType):
LValue(_compilerContext, *_arrayType.getMemberType("length")),
m_arrayType(_arrayType)
{
solAssert(m_arrayType.isDynamicallySized(), "");
}
void StorageArrayLength::retrieveValue(SourceLocation const& _location, bool _remove) const
{
if (!_remove)
m_context << eth::Instruction::DUP1;
m_context << eth::Instruction::SLOAD;
}
void StorageArrayLength::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const
{
if (_move)
m_context << eth::Instruction::SWAP1;
else
m_context << eth::Instruction::DUP2;
ArrayUtils(m_context).resizeDynamicArray(m_arrayType);
}
void StorageArrayLength::setToZero(SourceLocation const& _location, bool _removeReference) const
{
if (!_removeReference)
m_context << eth::Instruction::DUP1;
ArrayUtils(m_context).clearDynamicArray(m_arrayType);
}

44
libsolidity/LValue.h

@ -24,6 +24,7 @@
#include <memory> #include <memory>
#include <libevmcore/SourceLocation.h> #include <libevmcore/SourceLocation.h>
#include <libsolidity/ArrayUtils.h>
namespace dev namespace dev
{ {
@ -32,6 +33,7 @@ namespace solidity
class Declaration; class Declaration;
class Type; class Type;
class ArrayType;
class CompilerContext; class CompilerContext;
/** /**
@ -40,7 +42,7 @@ class CompilerContext;
class LValue class LValue
{ {
protected: protected:
LValue(CompilerContext& _compilerContext, std::shared_ptr<Type const> const& _dataType): LValue(CompilerContext& _compilerContext, Type const& _dataType):
m_context(_compilerContext), m_dataType(_dataType) {} m_context(_compilerContext), m_dataType(_dataType) {}
public: public:
@ -56,13 +58,14 @@ public:
/// Stack post: if !_move: value_of(lvalue_ref) /// Stack post: if !_move: value_of(lvalue_ref)
virtual void storeValue(Type const& _sourceType, virtual void storeValue(Type const& _sourceType,
SourceLocation const& _location = SourceLocation(), bool _move = false) const = 0; SourceLocation const& _location = SourceLocation(), bool _move = false) const = 0;
/// Stores zero in the lvalue. /// Stores zero in the lvalue. Removes the reference from the stack if @a _removeReference is true.
/// @a _location is the source location of the requested operation /// @a _location is the source location of the requested operation
virtual void setToZero(SourceLocation const& _location = SourceLocation()) const = 0; virtual void setToZero(
SourceLocation const& _location = SourceLocation(), bool _removeReference = true) const = 0;
protected: protected:
CompilerContext& m_context; CompilerContext& m_context;
std::shared_ptr<Type const> m_dataType; Type const& m_dataType;
}; };
/** /**
@ -71,13 +74,14 @@ protected:
class StackVariable: public LValue class StackVariable: public LValue
{ {
public: public:
explicit StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration); StackVariable(CompilerContext& _compilerContext, Declaration const& _declaration);
virtual bool storesReferenceOnStack() const { return false; } virtual bool storesReferenceOnStack() const { return false; }
virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override; virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
virtual void storeValue(Type const& _sourceType, virtual void storeValue(Type const& _sourceType,
SourceLocation const& _location = SourceLocation(), bool _move = false) const override; SourceLocation const& _location = SourceLocation(), bool _move = false) const override;
virtual void setToZero(SourceLocation const& _location = SourceLocation()) const override; virtual void setToZero(
SourceLocation const& _location = SourceLocation(), bool _removeReference = true) const override;
private: private:
/// Base stack offset (@see CompilerContext::getBaseStackOffsetOfVariable) of the local variable. /// Base stack offset (@see CompilerContext::getBaseStackOffsetOfVariable) of the local variable.
@ -93,14 +97,15 @@ class StorageItem: public LValue
{ {
public: public:
/// Constructs the LValue and pushes the location of @a _declaration onto the stack. /// Constructs the LValue and pushes the location of @a _declaration onto the stack.
explicit StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration); StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration);
/// Constructs the LValue and assumes that the storage reference is already on the stack. /// Constructs the LValue and assumes that the storage reference is already on the stack.
explicit StorageItem(CompilerContext& _compilerContext, std::shared_ptr<Type const> const& _type); StorageItem(CompilerContext& _compilerContext, Type const& _type);
virtual bool storesReferenceOnStack() const { return true; } virtual bool storesReferenceOnStack() const { return true; }
virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override; virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
virtual void storeValue(Type const& _sourceType, virtual void storeValue(Type const& _sourceType,
SourceLocation const& _location = SourceLocation(), bool _move = false) const override; SourceLocation const& _location = SourceLocation(), bool _move = false) const override;
virtual void setToZero(SourceLocation const& _location = SourceLocation()) const override; virtual void setToZero(
SourceLocation const& _location = SourceLocation(), bool _removeReference = true) const override;
private: private:
/// Number of stack elements occupied by the value (not the reference). /// Number of stack elements occupied by the value (not the reference).
@ -108,5 +113,26 @@ private:
unsigned m_size; unsigned m_size;
}; };
/**
* Reference to the "length" member of a dynamically-sized array. This is an LValue with special
* semantics since assignments to it might reduce its length and thus arrays members have to be
* deleted.
*/
class StorageArrayLength: public LValue
{
public:
/// Constructs the LValue, assumes that the reference to the array head is already on the stack.
StorageArrayLength(CompilerContext& _compilerContext, ArrayType const& _arrayType);
virtual bool storesReferenceOnStack() const { return true; }
virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
virtual void storeValue(Type const& _sourceType,
SourceLocation const& _location = SourceLocation(), bool _move = false) const override;
virtual void setToZero(
SourceLocation const& _location = SourceLocation(), bool _removeReference = true) const override;
private:
ArrayType const& m_arrayType;
};
} }
} }

10
libsolidity/SourceReferenceFormatter.cpp

@ -44,8 +44,14 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream,
tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end);
if (startLine == endLine) if (startLine == endLine)
{ {
_stream << _scanner.getLineAtPosition(_location.start) << endl string line = _scanner.getLineAtPosition(_location.start);
<< string(startColumn, ' ') << "^"; _stream << line << endl;
std::for_each(line.cbegin(), line.cbegin() + startColumn,
[&_stream](char const& ch)
{
_stream << (ch == '\t' ? '\t' : ' ');
});
_stream << "^";
if (endColumn > startColumn + 2) if (endColumn > startColumn + 2)
_stream << string(endColumn - startColumn - 2, '-'); _stream << string(endColumn - startColumn - 2, '-');
if (endColumn > startColumn + 1) if (endColumn > startColumn + 1)

29
libsolidity/Types.cpp

@ -537,7 +537,19 @@ TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const
bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const
{ {
return _convertTo.getCategory() == getCategory(); if (_convertTo.getCategory() != getCategory())
return false;
auto& convertTo = dynamic_cast<ArrayType const&>(_convertTo);
// let us not allow assignment to memory arrays for now
if (convertTo.getLocation() != Location::Storage)
return false;
if (convertTo.isByteArray() != isByteArray())
return false;
if (!getBaseType()->isImplicitlyConvertibleTo(*convertTo.getBaseType()))
return false;
if (convertTo.isDynamicallySized())
return true;
return !isDynamicallySized() && convertTo.getLength() >= getLength();
} }
TypePointer ArrayType::unaryOperatorResult(Token::Value _operator) const TypePointer ArrayType::unaryOperatorResult(Token::Value _operator) const
@ -552,7 +564,10 @@ bool ArrayType::operator==(Type const& _other) const
if (_other.getCategory() != getCategory()) if (_other.getCategory() != getCategory())
return false; return false;
ArrayType const& other = dynamic_cast<ArrayType const&>(_other); ArrayType const& other = dynamic_cast<ArrayType const&>(_other);
return other.m_location == m_location; if (other.m_location != m_location || other.isByteArray() != isByteArray() ||
other.isDynamicallySized() != isDynamicallySized())
return false;
return isDynamicallySized() || getLength() == other.getLength();
} }
u256 ArrayType::getStorageSize() const u256 ArrayType::getStorageSize() const
@ -628,8 +643,7 @@ MemberList const& ContractType::getMembers() const
{ {
for (ContractDefinition const* base: m_contract.getLinearizedBaseContracts()) for (ContractDefinition const* base: m_contract.getLinearizedBaseContracts())
for (ASTPointer<FunctionDefinition> const& function: base->getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: base->getDefinedFunctions())
if (!function->isConstructor() && !function->getName().empty()&& if (function->isVisibleInDerivedContracts())
function->isVisibleInDerivedContracts())
members.push_back(make_pair(function->getName(), make_shared<FunctionType>(*function, true))); members.push_back(make_pair(function->getName(), make_shared<FunctionType>(*function, true)));
} }
else else
@ -1024,10 +1038,9 @@ MemberList const& TypeType::getMembers() const
vector<ContractDefinition const*> currentBases = m_currentContract->getLinearizedBaseContracts(); vector<ContractDefinition const*> currentBases = m_currentContract->getLinearizedBaseContracts();
if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end()) if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end())
// We are accessing the type of a base contract, so add all public and protected // We are accessing the type of a base contract, so add all public and protected
// functions. Note that this does not add inherited functions on purpose. // members. Note that this does not add inherited functions on purpose.
for (ASTPointer<FunctionDefinition> const& f: contract.getDefinedFunctions()) for (Declaration const* decl: contract.getInheritableMembers())
if (!f->isConstructor() && !f->getName().empty() && f->isVisibleInDerivedContracts()) members.push_back(make_pair(decl->getName(), decl->getType()));
members.push_back(make_pair(f->getName(), make_shared<FunctionType>(*f)));
} }
else if (m_actualType->getCategory() == Category::Enum) else if (m_actualType->getCategory() == Category::Enum)
{ {

1
mix/AppContext.cpp

@ -73,6 +73,7 @@ void AppContext::load()
qmlRegisterType<QHashType>("org.ethereum.qml.QHashType", 1, 0, "QHashType"); qmlRegisterType<QHashType>("org.ethereum.qml.QHashType", 1, 0, "QHashType");
qmlRegisterType<QBoolType>("org.ethereum.qml.QBoolType", 1, 0, "QBoolType"); qmlRegisterType<QBoolType>("org.ethereum.qml.QBoolType", 1, 0, "QBoolType");
qmlRegisterType<QVariableDeclaration>("org.ethereum.qml.QVariableDeclaration", 1, 0, "QVariableDeclaration"); qmlRegisterType<QVariableDeclaration>("org.ethereum.qml.QVariableDeclaration", 1, 0, "QVariableDeclaration");
qmlRegisterType<RecordLogEntry>("org.ethereum.qml.RecordLogEntry", 1, 0, "RecordLogEntry");
QQmlComponent projectModelComponent(m_applicationEngine, QUrl("qrc:/qml/ProjectModel.qml")); QQmlComponent projectModelComponent(m_applicationEngine, QUrl("qrc:/qml/ProjectModel.qml"));
QObject* projectModel = projectModelComponent.create(); QObject* projectModel = projectModelComponent.create();
if (projectModelComponent.isError()) if (projectModelComponent.isError())

21
mix/ClientModel.cpp

@ -82,7 +82,7 @@ ClientModel::ClientModel(AppContext* _context):
qRegisterMetaType<QInstruction*>("QInstruction"); qRegisterMetaType<QInstruction*>("QInstruction");
qRegisterMetaType<QCode*>("QCode"); qRegisterMetaType<QCode*>("QCode");
qRegisterMetaType<QCallData*>("QCallData"); qRegisterMetaType<QCallData*>("QCallData");
qRegisterMetaType<RecordLogEntry*>("RecordLogEntry"); qRegisterMetaType<RecordLogEntry*>("RecordLogEntry*");
connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection); connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection);
m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString()));
@ -340,6 +340,11 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
debugDataReady(debugData); debugDataReady(debugData);
} }
void ClientModel::emptyRecord()
{
debugDataReady(new QDebugData());
}
void ClientModel::debugRecord(unsigned _index) void ClientModel::debugRecord(unsigned _index)
{ {
ExecutionResult const& e = m_client->executions().at(_index); ExecutionResult const& e = m_client->executions().at(_index);
@ -363,6 +368,18 @@ void ClientModel::callContract(Address const& _contract, bytes const& _data, Tra
m_client->transact(m_client->userAccount().secret(), _tr.value, _contract, _data, _tr.gas, _tr.gasPrice); m_client->transact(m_client->userAccount().secret(), _tr.value, _contract, _data, _tr.gas, _tr.gasPrice);
} }
RecordLogEntry* ClientModel::lastBlock() const
{
eth::BlockInfo blockInfo = m_client->blockInfo();
std::stringstream strGas;
strGas << blockInfo.gasUsed;
std::stringstream strNumber;
strNumber << blockInfo.number;
RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(toHex(blockInfo.hash.ref()))), tr("Gas Used: ") + QString::fromStdString(strGas.str()), QString(), QString(), false, RecordLogEntry::RecordType::Block);
QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership);
return record;
}
void ClientModel::onStateReset() void ClientModel::onStateReset()
{ {
m_contractAddresses.clear(); m_contractAddresses.clear();
@ -438,7 +455,7 @@ void ClientModel::onNewTransaction()
} }
} }
RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall()); RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction);
QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership); QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership);
emit newRecord(log); emit newRecord(log);
} }

25
mix/ClientModel.h

@ -72,6 +72,7 @@ struct TransactionSettings
class RecordLogEntry: public QObject class RecordLogEntry: public QObject
{ {
Q_OBJECT Q_OBJECT
Q_ENUMS(RecordType)
/// Recording index /// Recording index
Q_PROPERTY(unsigned recordIndex MEMBER m_recordIndex CONSTANT) Q_PROPERTY(unsigned recordIndex MEMBER m_recordIndex CONSTANT)
/// Human readable transaction bloack and transaction index /// Human readable transaction bloack and transaction index
@ -88,13 +89,20 @@ class RecordLogEntry: public QObject
Q_PROPERTY(QString returned MEMBER m_returned CONSTANT) Q_PROPERTY(QString returned MEMBER m_returned CONSTANT)
/// true if call, false if transaction /// true if call, false if transaction
Q_PROPERTY(bool call MEMBER m_call CONSTANT) Q_PROPERTY(bool call MEMBER m_call CONSTANT)
/// @returns record type
Q_PROPERTY(RecordType type MEMBER m_type CONSTANT)
public: public:
enum RecordType
{
Transaction,
Block
};
RecordLogEntry(): RecordLogEntry():
m_recordIndex(0), m_call(false) {} m_recordIndex(0), m_call(false), m_type(RecordType::Transaction) {}
RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call): RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type):
m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call) {} m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type) {}
private: private:
unsigned m_recordIndex; unsigned m_recordIndex;
@ -105,6 +113,7 @@ private:
QString m_address; QString m_address;
QString m_returned; QString m_returned;
bool m_call; bool m_call;
RecordType m_type;
}; };
/** /**
@ -123,11 +132,12 @@ public:
Q_PROPERTY(bool mining MEMBER m_mining NOTIFY miningStateChanged) Q_PROPERTY(bool mining MEMBER m_mining NOTIFY miningStateChanged)
/// @returns deployed contracts addresses /// @returns deployed contracts addresses
Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged) Q_PROPERTY(QVariantMap contractAddresses READ contractAddresses NOTIFY contractAddressesChanged)
// @returns the last block
Q_PROPERTY(RecordLogEntry* lastBlock READ lastBlock CONSTANT)
/// ethereum.js RPC request entry point /// ethereum.js RPC request entry point
/// @param _message RPC request in Json format /// @param _message RPC request in Json format
/// @returns RPC response in Json format /// @returns RPC response in Json format
Q_INVOKABLE QString apiCall(QString const& _message); Q_INVOKABLE QString apiCall(QString const& _message);
/// Simulate mining. Creates a new block /// Simulate mining. Creates a new block
Q_INVOKABLE void mine(); Q_INVOKABLE void mine();
@ -139,6 +149,8 @@ public slots:
void setupState(QVariantMap _state); void setupState(QVariantMap _state);
/// Show the debugger for a specified record /// Show the debugger for a specified record
Q_INVOKABLE void debugRecord(unsigned _index); Q_INVOKABLE void debugRecord(unsigned _index);
/// Show the debugger for an empty record
Q_INVOKABLE void emptyRecord();
private slots: private slots:
/// Update UI with machine states result. Display a modal dialog. /// Update UI with machine states result. Display a modal dialog.
@ -177,6 +189,7 @@ signals:
void stateCleared(); void stateCleared();
private: private:
RecordLogEntry* lastBlock() const;
QVariantMap contractAddresses() const; QVariantMap contractAddresses() const;
void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance); void executeSequence(std::vector<TransactionSettings> const& _sequence, u256 _balance);
dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings());
@ -199,3 +212,5 @@ private:
} }
} }
Q_DECLARE_METATYPE(dev::mix::RecordLogEntry*)

12
mix/FileIo.cpp

@ -20,6 +20,9 @@
* Ethereum IDE client. * Ethereum IDE client.
*/ */
#include <QDebug>
#include <QDesktopServices>
#include <QMimeDatabase>
#include <QDirIterator> #include <QDirIterator>
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
@ -37,6 +40,12 @@ using namespace dev;
using namespace dev::crypto; using namespace dev::crypto;
using namespace dev::mix; using namespace dev::mix;
void FileIo::openFileBrowser(QString const& _dir)
{
QDesktopServices::openUrl(QUrl(_dir));
}
QString FileIo::pathFromUrl(QString const& _url) QString FileIo::pathFromUrl(QString const& _url)
{ {
QUrl url(_url); QUrl url(_url);
@ -126,6 +135,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder)
dev::RLPStream rlpStr; dev::RLPStream rlpStr;
int k = 1; int k = 1;
std::vector<bytes> files; std::vector<bytes> files;
QMimeDatabase mimeDb;
for (auto item: deployDir.entryInfoList(QDir::Files)) for (auto item: deployDir.entryInfoList(QDir::Files))
{ {
QFile qFile(item.filePath()); QFile qFile(item.filePath());
@ -137,7 +147,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder)
std::string path = fileInfo.fileName() == "index.html" ? "/" : fileInfo.fileName().toStdString(); std::string path = fileInfo.fileName() == "index.html" ? "/" : fileInfo.fileName().toStdString();
jsonValue["path"] = path; //TODO: Manage relative sub folder jsonValue["path"] = path; //TODO: Manage relative sub folder
jsonValue["file"] = "/" + fileInfo.fileName().toStdString(); jsonValue["file"] = "/" + fileInfo.fileName().toStdString();
jsonValue["contentType"] = "text/html"; //TODO: manage multiple content type jsonValue["contentType"] = mimeDb.mimeTypeForFile(qFile.fileName()).name().toStdString();
QByteArray a = qFile.readAll(); QByteArray a = qFile.readAll();
bytes data = bytes(a.begin(), a.end()); bytes data = bytes(a.begin(), a.end());
files.push_back(data); files.push_back(data);

2
mix/FileIo.h

@ -55,6 +55,8 @@ public:
Q_INVOKABLE bool fileExists(QString const& _url); Q_INVOKABLE bool fileExists(QString const& _url);
/// Compress a folder, @returns sha3 of the compressed file. /// Compress a folder, @returns sha3 of the compressed file.
Q_INVOKABLE QStringList makePackage(QString const& _deploymentFolder); Q_INVOKABLE QStringList makePackage(QString const& _deploymentFolder);
/// Open a file browser
Q_INVOKABLE void openFileBrowser(QString const& _dir);
private: private:
QString getHomePath() const; QString getHomePath() const;

6
mix/MixClient.cpp

@ -436,6 +436,12 @@ h256 MixClient::hashFromNumber(unsigned _number) const
eth::BlockInfo MixClient::blockInfo(h256 _hash) const eth::BlockInfo MixClient::blockInfo(h256 _hash) const
{ {
return BlockInfo(bc().block(_hash)); return BlockInfo(bc().block(_hash));
}
eth::BlockInfo MixClient::blockInfo() const
{
return BlockInfo(bc().block());
} }
eth::BlockDetails MixClient::blockDetails(h256 _hash) const eth::BlockDetails MixClient::blockDetails(h256 _hash) const

2
mix/MixClient.h

@ -89,6 +89,8 @@ public:
eth::MineProgress miningProgress() const override; eth::MineProgress miningProgress() const override;
std::pair<h256, u256> getWork() override { return std::pair<h256, u256>(); } std::pair<h256, u256> getWork() override { return std::pair<h256, u256>(); }
bool submitNonce(h256 const&) override { return false; } bool submitNonce(h256 const&) override { return false; }
/// @returns the last mined block information
eth::BlockInfo blockInfo() const;
private: private:
void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call); void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call);

52
mix/qml/Debugger.qml

@ -13,6 +13,7 @@ Rectangle {
property alias transactionLog: transactionLog property alias transactionLog: transactionLog
signal debugExecuteLocation(string documentId, var location) signal debugExecuteLocation(string documentId, var location)
property string compilationErrorMessage
property bool assemblyMode: false property bool assemblyMode: false
objectName: "debugPanel" objectName: "debugPanel"
@ -30,26 +31,30 @@ Rectangle {
Debugger.updateMode(); Debugger.updateMode();
} }
function displayCompilationErrorIfAny()
{
debugScrollArea.visible = false;
compilationErrorArea.visible = true;
machineStates.visible = false;
var errorInfo = ErrorLocationFormater.extractErrorInfo(compilationErrorMessage, false);
errorLocation.text = errorInfo.errorLocation;
errorDetail.text = errorInfo.errorDetail;
errorLine.text = errorInfo.errorLine;
}
function update(data, giveFocus) function update(data, giveFocus)
{ {
if (statusPane && codeModel.hasContract) if (data === null)
Debugger.init(null);
else if (data.states.length === 0)
Debugger.init(null);
else if (codeModel.hasContract)
{ {
Debugger.init(data); Debugger.init(data);
debugScrollArea.visible = true; debugScrollArea.visible = true;
compilationErrorArea.visible = false; compilationErrorArea.visible = false;
machineStates.visible = true; machineStates.visible = true;
} }
else
{
debugScrollArea.visible = false;
compilationErrorArea.visible = true;
machineStates.visible = false;
var errorInfo = ErrorLocationFormater.extractErrorInfo(statusPane.result.compilerMessage, false);
errorLocation.text = errorInfo.errorLocation;
errorDetail.text = errorInfo.errorDetail;
errorLine.text = errorInfo.errorLine;
}
if (giveFocus) if (giveFocus)
forceActiveFocus(); forceActiveFocus();
} }
@ -68,7 +73,13 @@ Rectangle {
Connections { Connections {
target: codeModel target: codeModel
//onCompilationComplete: update(null, false); onCompilationComplete: {
debugPanel.compilationErrorMessage = "";
}
onCompilationError: {
debugPanel.compilationErrorMessage = _error;
}
} }
Settings { Settings {
@ -86,7 +97,7 @@ Rectangle {
visible: false; visible: false;
id: compilationErrorArea id: compilationErrorArea
width: parent.width - 20 width: parent.width - 20
height: 500 height: 600
color: "#ededed" color: "#ededed"
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
@ -95,7 +106,20 @@ Rectangle {
{ {
width: parent.width width: parent.width
anchors.top: parent.top anchors.top: parent.top
spacing: 25 spacing: 15
Rectangle
{
height: 15
Button {
text: qsTr("Back to Debugger")
onClicked: {
debugScrollArea.visible = true;
compilationErrorArea.visible = false;
machineStates.visible = true;
}
}
}
RowLayout RowLayout
{ {
height: 100 height: 100

308
mix/qml/DeploymentDialog.qml

@ -12,18 +12,20 @@ import "."
Window { Window {
id: modalDeploymentDialog id: modalDeploymentDialog
modality: Qt.ApplicationModal modality: Qt.ApplicationModal
width: 600 width: 930
height: 350 height: 350
visible: false visible: false
property alias applicationUrlEth: applicationUrlEth.text property alias applicationUrlEth: applicationUrlEth.text
property alias applicationUrlHttp: applicationUrlHttp.text property alias applicationUrlHttp: applicationUrlHttp.text
property string urlHintContract: "c83d3e22645fb015d02043a744921cc2f828c64d" property string urlHintContract: "c83d3e22645fb015d02043a744921cc2f828c64d" /* TODO: replace with the good address */
property string packageHash property string packageHash
property alias packageBase64: base64Value.text property alias packageBase64: base64Value.text
property string eth: "afb7cdbd076674fd2c67f8a66518e3145b184ae4"; property string eth: "4c3f7330690ed3657d3fa20fe5717b84010528ae"; /* TODO: replace with the good address */
property string wallet: "c83d3e22645fb015d02043a744921cc2f828c64d"; property string currentAccount
property alias gasToUse: gasToUseInput.text
color: Style.generic.layout.backgroundColor color: Style.generic.layout.backgroundColor
@ -37,6 +39,59 @@ Window {
modalDeploymentDialog.setX((Screen.width - width) / 2); modalDeploymentDialog.setX((Screen.width - width) / 2);
modalDeploymentDialog.setY((Screen.height - height) / 2); modalDeploymentDialog.setY((Screen.height - height) / 2);
visible = true; visible = true;
var requests = [{
//accounts
jsonrpc: "2.0",
method: "eth_accounts",
params: null,
id: 0
}];
TransactionHelper.rpcCall(requests, function(arg1, arg2)
{
modelAccounts.clear();
var ids = JSON.parse(arg2)[0].result;
requests = [];
for (var k in ids)
{
modelAccounts.append({ "id": ids[k] })
requests.push({
//accounts
jsonrpc: "2.0",
method: "eth_balanceAt",
params: [ids[k]],
id: k
});
}
if (ids.length > 0)
currentAccount = modelAccounts.get(0).id;
TransactionHelper.rpcCall(requests, function (request, response){
var balanceRet = JSON.parse(response);
for (var k in balanceRet)
{
var ether = QEtherHelper.createEther(balanceRet[k].result, QEther.Wei);
comboAccounts.balances.push(ether.format());
}
balance.text = comboAccounts.balances[0];
});
});
}
function stopForInputError(inError)
{
errorDialog.text = "";
if (inError.length > 0)
{
errorDialog.text = qsTr("The length of a string cannot exceed 32 characters.\nPlease verify the following value(s):\n\n")
for (var k in inError)
errorDialog.text += inError[k] + "\n";
errorDialog.open();
return true;
}
return false;
} }
function pad(h) function pad(h)
@ -49,6 +104,52 @@ Window {
return h; return h;
} }
function waitForTrCountToIncrement(callBack)
{
poolLog.callBack = callBack;
poolLog.k = -1;
poolLog.elapsed = 0;
poolLog.start();
}
Timer
{
id: poolLog
property var callBack
property int k: -1
property int elapsed
interval: 500
running: false
repeat: true
onTriggered: {
elapsed += interval;
var requests = [];
var jsonRpcRequestId = 0;
requests.push({
jsonrpc: "2.0",
method: "eth_countAt",
params: [ currentAccount ],
id: jsonRpcRequestId++
});
TransactionHelper.rpcCall(requests, function (httpRequest, response){
response = response.replace(/,0+/, ''); // ==> result:27,00000000
var count = JSON.parse(response)[0].result
if (k < parseInt(count) && k > 0)
{
stop();
callBack(1);
}
else if (elapsed > 25000)
{
stop();
callBack(-1);
}
else
k = parseInt(JSON.parse(response)[0].result);
})
}
}
Rectangle Rectangle
{ {
anchors.fill : parent anchors.fill : parent
@ -60,15 +161,63 @@ Window {
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
width: parent.width width: parent.width
DefaultLabel
{
text: qsTr("Account used to deploy:")
}
Rectangle
{
width: 300
height: 25
color: "transparent"
ComboBox {
id: comboAccounts
property var balances: []
onCurrentIndexChanged : {
if (modelAccounts.count > 0)
{
currentAccount = modelAccounts.get(currentIndex).id;
balance.text = balances[currentIndex];
}
}
model: ListModel {
id: modelAccounts
}
}
DefaultLabel
{
anchors.verticalCenter: parent.verticalCenter
anchors.left: comboAccounts.right
anchors.leftMargin: 20
id: balance;
}
}
DefaultLabel DefaultLabel
{ {
text: qsTr("Ethereum Application URL: ") text: qsTr("Ethereum Application URL: ")
} }
DefaultTextField Rectangle
{ {
Layout.fillWidth: true Layout.fillWidth: true
id: applicationUrlEth height: 25
color: "transparent"
DefaultTextField
{
width: 350
id: applicationUrlEth
}
DefaultLabel
{
anchors.verticalCenter: parent.verticalCenter;
anchors.left: applicationUrlEth.right
text: "/" + projectModel.projectTitle
}
} }
DefaultLabel DefaultLabel
@ -82,6 +231,18 @@ Window {
id: applicationUrlHttp id: applicationUrlHttp
} }
DefaultLabel
{
text: qsTr("Amount of gas to use for each contract deployment: ")
}
DefaultTextField
{
text: "20000"
Layout.fillWidth: true
id: gasToUseInput
}
DefaultLabel DefaultLabel
{ {
text: qsTr("Package (Base64): ") text: qsTr("Package (Base64): ")
@ -103,16 +264,47 @@ Window {
icon: StandardIcon.Warning icon: StandardIcon.Warning
} }
MessageDialog {
id: errorDialog
standardButtons: StandardButton.Ok
icon: StandardIcon.Error
}
RowLayout RowLayout
{ {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right; anchors.right: parent.right;
anchors.bottomMargin: 10 anchors.bottomMargin: 10
Button { Button {
text: qsTr("Deploy to Ethereum"); text: qsTr("Deploy contract / Package resources");
tooltip: qsTr("Deploy contract and package resources files.") tooltip: qsTr("Deploy contract and package resources files.")
onClicked: { onClicked: {
deployWarningDialog.open(); var inError = [];
var ethUrl = ProjectModelCode.formatAppUrl(applicationUrlEth.text);
for (var k in ethUrl)
{
if (ethUrl[k].length > 32)
inError.push(qsTr("Member too long: " + ethUrl[k]) + "\n");
}
if (!stopForInputError(inError))
deployWarningDialog.open();
}
}
Button {
text: qsTr("Package resources only");
tooltip: qsTr("Package resources files.")
enabled: Object.keys(projectModel.deploymentAddresses).length > 0
onClicked: {
ProjectModelCode.startDeployProject(false);
}
}
Button {
text: qsTr("Open Package Directory");
enabled: projectModel.deploymentDir !== ""
onClicked: {
fileIo.openFileBrowser(projectModel.deploymentDir);
} }
} }
@ -123,10 +315,14 @@ Window {
if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "") if (applicationUrlHttp.text === "" || deploymentDialog.packageHash === "")
{ {
deployDialog.title = text; deployDialog.title = text;
deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step. ") deployDialog.text = qsTr("Please provide the link where the resources are stored and ensure the package is aleary built using the deployment step.")
deployDialog.open(); deployDialog.open();
return;
} }
else var inError = [];
if (applicationUrlHttp.text.length > 32)
inError.push(qsTr(applicationUrlHttp.text));
if (!stopForInputError(inError))
ProjectModelCode.registerToUrlHint(); ProjectModelCode.registerToUrlHint();
} }
} }
@ -135,98 +331,6 @@ Window {
text: qsTr("Close"); text: qsTr("Close");
onClicked: close(); onClicked: close();
} }
Button {
text: qsTr("Check Ownership");
visible : false
onClicked: {
var requests = [];
var ethStr = QEtherHelper.createString("wallet");
var ethHash = QEtherHelper.createHash(eth);
requests.push({ //owner
jsonrpc: "2.0",
method: "eth_call",
params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0xec7b9200" + ethStr.encodeValueAsString() } ],
id: 3
});
requests.push({ //register
jsonrpc: "2.0",
method: "eth_call",
params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x6be16bed" + ethStr.encodeValueAsString() } ],
id: 4
});
var jsonRpcUrl = "http://localhost:8080";
var rpcRequest = JSON.stringify(requests);
var httpRequest = new XMLHttpRequest();
httpRequest.open("POST", jsonRpcUrl, true);
httpRequest.setRequestHeader("Content-type", "application/json");
httpRequest.setRequestHeader("Content-length", rpcRequest.length);
httpRequest.setRequestHeader("Connection", "close");
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
console.log(httpRequest.responseText);
} else {
var errorText = qsTr("path registration failed ") + httpRequest.status;
console.log(errorText);
}
}
}
httpRequest.send(rpcRequest);
}
}
Button {
text: qsTr("Generate registrar init");
visible: false
onClicked: {
console.log("registering eth/wallet")
var jsonRpcRequestId = 0;
var requests = [];
var walletStr = QEtherHelper.createString("wallet");
requests.push({ //reserve
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x1c83171b" + walletStr.encodeValueAsString() } ],
id: jsonRpcRequestId++
});
requests.push({ //setRegister
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "to": '0x' + modalDeploymentDialog.eth, "data": "0x96077307" + walletStr.encodeValueAsString() + pad(wallet) } ],
id: jsonRpcRequestId++
});
var jsonRpcUrl = "http://localhost:8080";
var rpcRequest = JSON.stringify(requests);
var httpRequest = new XMLHttpRequest();
httpRequest.open("POST", jsonRpcUrl, true);
httpRequest.setRequestHeader("Content-type", "application/json");
httpRequest.setRequestHeader("Content-length", rpcRequest.length);
httpRequest.setRequestHeader("Connection", "close");
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
console.log(httpRequest.responseText);
} else {
var errorText = qsTr("path registration failed ") + httpRequest.status;
console.log(errorText);
}
}
}
httpRequest.send(rpcRequest);
}
}
} }
} }
} }

348
mix/qml/FilesSection.qml

@ -6,17 +6,19 @@ import QtQuick.Controls.Styles 1.3
import "." import "."
ColumnLayout { Rectangle
{
Layout.fillWidth: true
Layout.minimumHeight: hiddenHeightTopLevel()
height: hiddenHeightTopLevel()
Layout.maximumHeight: hiddenHeightTopLevel()
id: wrapperItem id: wrapperItem
signal documentSelected(string doc, string groupName) signal documentSelected(string doc, string groupName)
property alias model: filesList.model property alias model: filesList.model
property string sectionName; property string sectionName;
property variant selManager; property variant selManager;
Layout.fillWidth: true property int index;
Layout.minimumHeight: hiddenHeightTopLevel() color: index % 2 === 0 ? "transparent" : ProjectFilesStyle.title.background
height: hiddenHeightTopLevel()
Layout.maximumHeight: hiddenHeightTopLevel()
spacing: 0
function hiddenHeightTopLevel() function hiddenHeightTopLevel()
{ {
@ -48,196 +50,203 @@ ColumnLayout {
model.remove(i); model.remove(i);
} }
SourceSansProRegular ColumnLayout {
{ anchors.fill: parent
id: fileNameFont spacing: 0
}
SourceSansProBold
{
id: boldFont
}
RowLayout SourceSansProRegular
{ {
anchors.top: parent.top id: fileNameFont
id: rowCol
width: parent.width
height: ProjectFilesStyle.documentsList.height
Image {
source: "qrc:/qml/img/opentriangleindicator_filesproject.png"
width: 15
sourceSize.width: 12
id: imgArrow
anchors.right: section.left
anchors.rightMargin: 8
anchors.top: parent.top
anchors.topMargin: 6
} }
Text SourceSansProBold
{ {
id: section id: boldFont
text: sectionName
anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin
color: ProjectFilesStyle.documentsList.sectionColor
font.family: boldFont.name
font.pointSize: ProjectFilesStyle.documentsList.sectionFontSize
states: [
State {
name: "hidden"
PropertyChanges { target: filesList; visible: false; }
PropertyChanges { target: rowCol; Layout.minimumHeight: ProjectFilesStyle.documentsList.height; Layout.maximumHeight: ProjectFilesStyle.documentsList.height; height: ProjectFilesStyle.documentsList.height; }
PropertyChanges { target: imgArrow; source: "qrc:/qml/img/closedtriangleindicator_filesproject.png" }
}
]
} }
MouseArea { RowLayout
id: titleMouseArea {
anchors.fill: parent anchors.top: parent.top
hoverEnabled: true id: rowCol
z: 2 height: ProjectFilesStyle.documentsList.height
onClicked: { Layout.fillWidth: true
if (section.state === "hidden")
section.state = "";
else Image {
section.state = "hidden"; source: "qrc:/qml/img/opentriangleindicator_filesproject.png"
width: 15
sourceSize.width: 12
id: imgArrow
anchors.right: section.left
anchors.rightMargin: 8
anchors.top: parent.top
anchors.topMargin: 10
}
Text
{
id: section
text: sectionName
anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin
color: ProjectFilesStyle.documentsList.sectionColor
font.family: boldFont.name
font.pointSize: ProjectFilesStyle.documentsList.sectionFontSize
states: [
State {
name: "hidden"
PropertyChanges { target: filesList; visible: false; }
PropertyChanges { target: rowCol; Layout.minimumHeight: ProjectFilesStyle.documentsList.height; Layout.maximumHeight: ProjectFilesStyle.documentsList.height; height: ProjectFilesStyle.documentsList.height; }
PropertyChanges { target: imgArrow; source: "qrc:/qml/img/closedtriangleindicator_filesproject.png" }
}
]
}
MouseArea {
id: titleMouseArea
anchors.fill: parent
hoverEnabled: true
z: 2
onClicked: {
if (section.state === "hidden")
section.state = "";
else
section.state = "hidden";
}
} }
} }
}
ColumnLayout { ColumnLayout {
height: wrapperItem.hiddenHeightRepeater() height: wrapperItem.hiddenHeightRepeater()
Layout.minimumHeight: wrapperItem.hiddenHeightRepeater() Layout.minimumHeight: wrapperItem.hiddenHeightRepeater()
Layout.preferredHeight: wrapperItem.hiddenHeightRepeater() Layout.preferredHeight: wrapperItem.hiddenHeightRepeater()
Layout.maximumHeight: wrapperItem.hiddenHeightRepeater() Layout.maximumHeight: wrapperItem.hiddenHeightRepeater()
width: parent.width width: parent.width
visible: section.state !== "hidden"
spacing: 0
Repeater
{
id: filesList
visible: section.state !== "hidden" visible: section.state !== "hidden"
Rectangle spacing: 0
Repeater
{ {
id: filesList
visible: section.state !== "hidden" visible: section.state !== "hidden"
id: rootItem Rectangle
Layout.fillWidth: true {
Layout.minimumHeight: wrapperItem.hiddenHeightElement() visible: section.state !== "hidden"
Layout.preferredHeight: wrapperItem.hiddenHeightElement() id: rootItem
Layout.maximumHeight: wrapperItem.hiddenHeightElement() Layout.fillWidth: true
height: wrapperItem.hiddenHeightElement() Layout.minimumHeight: wrapperItem.hiddenHeightElement()
color: isSelected ? ProjectFilesStyle.documentsList.highlightColor : ProjectFilesStyle.documentsList.background Layout.preferredHeight: wrapperItem.hiddenHeightElement()
property bool isSelected Layout.maximumHeight: wrapperItem.hiddenHeightElement()
property bool renameMode height: wrapperItem.hiddenHeightElement()
Text { color: isSelected ? ProjectFilesStyle.documentsList.highlightColor : "transparent"
id: nameText property bool isSelected
height: parent.height property bool renameMode
visible: !renameMode Text {
color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color id: nameText
text: name; height: parent.height
font.family: fileNameFont.name visible: !renameMode
font.pointSize: ProjectFilesStyle.documentsList.fontSize color: rootItem.isSelected ? ProjectFilesStyle.documentsList.selectedColor : ProjectFilesStyle.documentsList.color
anchors.verticalCenter: parent.verticalCenter text: name;
verticalAlignment: Text.AlignVCenter font.family: fileNameFont.name
anchors.left: parent.left font.pointSize: ProjectFilesStyle.documentsList.fontSize
anchors.leftMargin: ProjectFilesStyle.general.leftMargin + 2 anchors.verticalCenter: parent.verticalCenter
width: parent.width verticalAlignment: Text.AlignVCenter
Connections anchors.left: parent.left
{ anchors.leftMargin: ProjectFilesStyle.general.leftMargin + 2
target: selManager width: parent.width
onSelected: { Connections
if (groupName != sectionName) {
rootItem.isSelected = false; target: selManager
else if (doc === documentId) onSelected: {
rootItem.isSelected = true; if (groupName != sectionName)
else rootItem.isSelected = false;
rootItem.isSelected = false; else if (doc === documentId)
rootItem.isSelected = true;
else
rootItem.isSelected = false;
if (rootItem.isSelected && section.state === "hidden") if (rootItem.isSelected && section.state === "hidden")
section.state = ""; section.state = "";
}
} }
} }
}
TextInput { TextInput {
id: textInput id: textInput
text: nameText.text text: nameText.text
visible: renameMode visible: renameMode
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: ProjectFilesStyle.general.leftMargin anchors.leftMargin: ProjectFilesStyle.general.leftMargin
MouseArea { MouseArea {
id: textMouseArea id: textMouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
z: 2 z: 2
onClicked: { onClicked: {
textInput.forceActiveFocus(); textInput.forceActiveFocus();
}
} }
}
onVisibleChanged: { onVisibleChanged: {
if (visible) { if (visible) {
selectAll(); selectAll();
forceActiveFocus(); forceActiveFocus();
}
} }
}
onAccepted: close(true); onAccepted: close(true);
onCursorVisibleChanged: { onCursorVisibleChanged: {
if (!cursorVisible) if (!cursorVisible)
close(false); close(false);
} }
onFocusChanged: { onFocusChanged: {
if (!focus) if (!focus)
close(false); close(false);
} }
function close(accept) { function close(accept) {
rootItem.renameMode = false; rootItem.renameMode = false;
if (accept) if (accept)
{ {
var i = getDocumentIndex(documentId); var i = getDocumentIndex(documentId);
projectModel.renameDocument(documentId, textInput.text); projectModel.renameDocument(documentId, textInput.text);
wrapperItem.model.set(i, projectModel.getDocument(documentId)); wrapperItem.model.set(i, projectModel.getDocument(documentId));
}
} }
} }
}
MouseArea { MouseArea {
id: mouseArea id: mouseArea
z: 1 z: 1
hoverEnabled: false hoverEnabled: false
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked:{ onClicked:{
if (mouse.button === Qt.RightButton && !isContract) if (mouse.button === Qt.RightButton && !isContract)
contextMenu.popup(); contextMenu.popup();
else if (mouse.button === Qt.LeftButton) else if (mouse.button === Qt.LeftButton)
{ {
rootItem.isSelected = true; rootItem.isSelected = true;
projectModel.openDocument(documentId); projectModel.openDocument(documentId);
documentSelected(documentId, groupName); documentSelected(documentId, groupName);
}
} }
} }
}
Menu { Menu {
id: contextMenu id: contextMenu
MenuItem { MenuItem {
text: qsTr("Rename") text: qsTr("Rename")
onTriggered: { onTriggered: {
rootItem.renameMode = true; rootItem.renameMode = true;
}
} }
} MenuItem {
MenuItem { text: qsTr("Delete")
text: qsTr("Delete") onTriggered: {
onTriggered: { projectModel.removeDocument(documentId);
projectModel.removeDocument(documentId); wrapperItem.removeDocument(documentId);
wrapperItem.removeDocument(documentId); }
} }
} }
} }
@ -245,4 +254,3 @@ ColumnLayout {
} }
} }
} }

10
mix/qml/MainContent.qml

@ -95,6 +95,12 @@ Rectangle {
codeEditor.toggleBreakpoint(); codeEditor.toggleBreakpoint();
} }
function displayCompilationErrorIfAny()
{
rightView.visible = true;
rightView.displayCompilationErrorIfAny();
}
CodeEditorExtensionManager { CodeEditorExtensionManager {
headerView: headerPaneTabs; headerView: headerPaneTabs;
} }
@ -217,7 +223,3 @@ Rectangle {
} }
} }
} }

2
mix/qml/ProjectFilesStyle.qml

@ -25,7 +25,7 @@ QtObject {
property string sectionColor: "#808080" property string sectionColor: "#808080"
property string selectedColor: "white" property string selectedColor: "white"
property string highlightColor: "#4a90e2" property string highlightColor: "#4a90e2"
property int height: 25 property int height: 35
property int fileNameHeight: 30 property int fileNameHeight: 30
property int fontSize: absoluteSize(2)// 13 property int fontSize: absoluteSize(2)// 13
property int sectionFontSize: absoluteSize(2)// 13 property int sectionFontSize: absoluteSize(2)// 13

20
mix/qml/ProjectList.qml

@ -26,11 +26,9 @@ Item {
Image { Image {
id: projectIcon id: projectIcon
source: "qrc:/qml/img/dappProjectIcon.png" source: "qrc:/qml/img/dappProjectIcon.png"
//sourceSize.height: 32
anchors.right: projectTitle.left anchors.right: projectTitle.left
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: 6 anchors.rightMargin: 6
//anchors.centerIn: parent
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
width: 32 width: 32
height: 32 height: 32
@ -65,7 +63,7 @@ Item {
Rectangle Rectangle
{ {
Layout.fillWidth: true Layout.fillWidth: true
height: 10 height: 3
color: ProjectFilesStyle.documentsList.background color: ProjectFilesStyle.documentsList.background
} }
@ -82,14 +80,24 @@ Item {
anchors.top: parent.top anchors.top: parent.top
width: parent.width width: parent.width
spacing: 0 spacing: 0
Repeater { Repeater {
model: [qsTr("Contracts"), qsTr("Javascript"), qsTr("Web Pages"), qsTr("Styles"), qsTr("Images"), qsTr("Misc")]; model: [qsTr("Contracts"), qsTr("Javascript"), qsTr("Web Pages"), qsTr("Styles"), qsTr("Images"), qsTr("Misc")];
signal selected(string doc, string groupName) signal selected(string doc, string groupName)
property int incr: -1;
id: sectionRepeater id: sectionRepeater
FilesSection FilesSection
{ {
id: section;
sectionName: modelData sectionName: modelData
index:
{
for (var k in sectionRepeater.model)
{
if (sectionRepeater.model[k] === modelData)
return k;
}
}
model: sectionModel model: sectionModel
selManager: sectionRepeater selManager: sectionRepeater
@ -119,7 +127,7 @@ Item {
ci++; ci++;
} }
} }
} }
} }
} }
@ -170,10 +178,10 @@ Item {
projectModel.openDocument(newDoc.documentId); projectModel.openDocument(newDoc.documentId);
sectionRepeater.selected(newDoc.documentId, modelData); sectionRepeater.selected(newDoc.documentId, modelData);
} }
} }
} }
} }
} }
} }
} }

19
mix/qml/ProjectModel.qml

@ -7,6 +7,7 @@ import Qt.labs.settings 1.0
import "js/ProjectModel.js" as ProjectModelCode import "js/ProjectModel.js" as ProjectModelCode
Item { Item {
id: projectModel id: projectModel
signal projectClosed signal projectClosed
@ -33,6 +34,7 @@ Item {
property string projectTitle: "" property string projectTitle: ""
property string currentDocumentId: "" property string currentDocumentId: ""
property var deploymentAddresses: [] property var deploymentAddresses: []
property string deploymentDir
property var listModel: projectListModel property var listModel: projectListModel
property var stateListModel: projectStateListModel.model property var stateListModel: projectStateListModel.model
property CodeEditorView codeEditor: null property CodeEditorView codeEditor: null
@ -57,6 +59,7 @@ Item {
function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); } function addExistingFiles(paths) { ProjectModelCode.doAddExistingFiles(paths); }
function deployProject() { ProjectModelCode.deployProject(false); } function deployProject() { ProjectModelCode.deployProject(false); }
function registerToUrlHint() { ProjectModelCode.registerToUrlHint(); } function registerToUrlHint() { ProjectModelCode.registerToUrlHint(); }
function formatAppUrl() { ProjectModelCode.formatAppUrl(url); }
Connections { Connections {
target: appContext target: appContext
@ -93,28 +96,17 @@ Item {
MessageDialog { MessageDialog {
id: deployWarningDialog id: deployWarningDialog
property bool redeploy
title: qsTr("Project") title: qsTr("Project")
text: text:
{ {
if (Object.keys(projectModel.deploymentAddresses).length > 0) if (Object.keys(projectModel.deploymentAddresses).length > 0)
{ return qsTr("This project has been already deployed to the network. Do you want to redeploy it? (Contract state will be reset)")
redeploy = true
standardButtons = StandardButton.Ok | StandardButton.Reset | StandardButton.Abort;
return qsTr("This project has been already deployed to the network. Do you want to repackage the resources only, or also reset the deployed contract to its initial state?")
}
else else
{
redeploy = false;
standardButtons = StandardButton.Ok | StandardButton.Abort;
return qsTr("This action will deploy to the network. Do you want to deploy it?") return qsTr("This action will deploy to the network. Do you want to deploy it?")
}
} }
icon: StandardIcon.Question icon: StandardIcon.Question
standardButtons: StandardButton.Ok | StandardButton.Abort
onAccepted: { onAccepted: {
ProjectModelCode.startDeployProject(!redeploy);
}
onReset: {
ProjectModelCode.startDeployProject(true); ProjectModelCode.startDeployProject(true);
} }
} }
@ -123,7 +115,6 @@ Item {
id: deployRessourcesDialog id: deployRessourcesDialog
title: qsTr("Project") title: qsTr("Project")
standardButtons: StandardButton.Ok standardButtons: StandardButton.Ok
icon: StandardIcon.Info
} }
DeploymentDialog DeploymentDialog

128
mix/qml/StatusPane.qml

@ -1,6 +1,7 @@
import QtQuick 2.2 import QtQuick 2.2
import QtQuick.Controls 1.1 import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.3
import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "js/ErrorLocationFormater.js" as ErrorLocationFormater
import "." import "."
@ -13,7 +14,7 @@ Rectangle {
if (!message) if (!message)
{ {
status.state = ""; status.state = "";
status.text = qsTr("Compile without errors."); status.text = qsTr("Compile successfully.");
logslink.visible = false; logslink.visible = false;
debugImg.state = "active"; debugImg.state = "active";
} }
@ -35,17 +36,24 @@ Rectangle {
logslink.visible = false; logslink.visible = false;
} }
function errorMessage(text)
{
status.state = "error";
status.text = text
logslink.visible = false;
}
Connections { Connections {
target:clientModel target:clientModel
onRunStarted: infoMessage(qsTr("Running transactions...")); onRunStarted: infoMessage(qsTr("Running transactions..."));
onRunFailed: infoMessage(qsTr("Error running transactions")); onRunFailed: errorMessage(qsTr("Error running transactions"));
onRunComplete: infoMessage(qsTr("Run complete")); onRunComplete: infoMessage(qsTr("Run complete"));
onNewBlock: infoMessage(qsTr("New block created")); onNewBlock: infoMessage(qsTr("New block created"));
} }
Connections { Connections {
target:projectModel target:projectModel
onDeploymentStarted: infoMessage(qsTr("Running deployment...")); onDeploymentStarted: infoMessage(qsTr("Running deployment..."));
onDeploymentError: infoMessage(error); onDeploymentError: errorMessage(error);
onDeploymentComplete: infoMessage(qsTr("Deployment complete")); onDeploymentComplete: infoMessage(qsTr("Deployment complete"));
onDeploymentStepChanged: infoMessage(message); onDeploymentStepChanged: infoMessage(message);
} }
@ -57,6 +65,7 @@ Rectangle {
color: "transparent" color: "transparent"
anchors.fill: parent anchors.fill: parent
Rectangle { Rectangle {
id: statusContainer id: statusContainer
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@ -65,49 +74,84 @@ Rectangle {
width: 500 width: 500
height: 30 height: 30
color: "#fcfbfc" color: "#fcfbfc"
RowLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
spacing: 5
Text { Text {
font.pointSize: StatusPaneStyle.general.statusFontSize anchors.verticalCenter: parent.verticalCenter
height: 9 anchors.horizontalCenter: parent.horizontalCenter
font.family: "sans serif" font.pointSize: StatusPaneStyle.general.statusFontSize
objectName: "status" height: 15
id: status font.family: "sans serif"
states:[ objectName: "status"
State { wrapMode: Text.WrapAnywhere
name: "error" elide: Text.ElideRight
PropertyChanges { maximumLineCount: 1
target: status clip: true
color: "red" id: status
} states: [
PropertyChanges { State {
target: statusContainer name: "error"
color: "#fffcd5" PropertyChanges {
} target: status
color: "red"
} }
] PropertyChanges {
target: statusContainer
color: "#fffcd5"
}
}
]
onTextChanged:
{
updateWidth()
toolTipInfo.tooltip = text;
} }
Text { function updateWidth()
visible: false {
font.pointSize: StatusPaneStyle.general.logLinkFontSize if (text.length > 80)
height: 9 width = parent.width - 10
text: qsTr("See Log.") else
font.family: "Monospace" width = undefined
objectName: "status" }
id: logslink }
color: "#8c8a74"
MouseArea { Button
anchors.fill: parent {
onClicked: { anchors.fill: parent
mainContent.ensureRightView(); id: toolTip
} action: toolTipInfo
text: ""
style:
ButtonStyle {
background:Rectangle {
color: "transparent"
} }
} }
} }
Action {
id: toolTipInfo
tooltip: ""
}
}
Button
{
id: logslink
anchors.left: statusContainer.right
anchors.leftMargin: 9
visible: false
anchors.verticalCenter: parent.verticalCenter
action: displayLogAction
iconSource: "qrc:/qml/img/search_filled.png"
}
Action {
id: displayLogAction
tooltip: qsTr("Display Log")
onTriggered: {
mainContent.displayCompilationErrorIfAny();
}
} }
Rectangle Rectangle
@ -120,9 +164,13 @@ Rectangle {
RowLayout RowLayout
{ {
anchors.fill: parent anchors.fill: parent
Rectangle { anchors.top: statusHeader.top
anchors.right: statusHeader.right
Rectangle
{
color: "transparent" color: "transparent"
anchors.fill: parent anchors.fill: parent
Button Button
{ {
anchors.right: parent.right anchors.right: parent.right

49
mix/qml/TransactionLog.qml

@ -3,15 +3,13 @@ import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1 import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.1 import QtQuick.Dialogs 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import org.ethereum.qml.RecordLogEntry 1.0
Item { Item {
property bool showLogs: true
property ListModel fullModel: ListModel{} property ListModel fullModel: ListModel{}
property ListModel transactionModel: ListModel{} property ListModel transactionModel: ListModel{}
onShowLogsChanged: { property ListModel callModel: ListModel{}
logTable.model = showLogs ? fullModel : transactionModel
}
Action { Action {
id: addStateAction id: addStateAction
@ -78,13 +76,24 @@ Item {
action: mineAction action: mineAction
} }
CheckBox { ComboBox {
id: recording id: itemFilter
text: qsTr("Record transactions");
checked: true function getCurrentModel()
Layout.fillWidth: true {
return currentIndex === 0 ? fullModel : currentIndex === 1 ? transactionModel : currentIndex === 2 ? callModel : fullModel;
}
model: ListModel {
ListElement { text: qsTr("Calls and Transactions"); value: 0; }
ListElement { text: qsTr("Only Transactions"); value: 1; }
ListElement { text: qsTr("Only Calls"); value: 2; }
}
onCurrentIndexChanged:
{
logTable.model = itemFilter.getCurrentModel();
}
} }
} }
TableView { TableView {
@ -125,7 +134,10 @@ Item {
} }
onActivated: { onActivated: {
var item = logTable.model.get(row); var item = logTable.model.get(row);
clientModel.debugRecord(item.recordIndex); if (item.type === RecordLogEntry.Transaction)
clientModel.debugRecord(item.recordIndex);
else
clientModel.emptyRecord();
} }
Keys.onPressed: { Keys.onPressed: {
if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < logTable.model.count) { if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_C && currentRow >=0 && currentRow < logTable.model.count) {
@ -141,15 +153,18 @@ Item {
onStateCleared: { onStateCleared: {
fullModel.clear(); fullModel.clear();
transactionModel.clear(); transactionModel.clear();
callModel.clear();
} }
onNewRecord: { onNewRecord: {
if (recording.checked) fullModel.append(_r);
{ if (!_r.call)
fullModel.append(_r); transactionModel.append(_r);
if (!_r.call) else
transactionModel.append(_r); callModel.append(_r);
} }
onMiningComplete: {
fullModel.append(clientModel.lastBlock);
transactionModel.append(clientModel.lastBlock);
} }
} }
} }

60
mix/qml/WebPreview.qml

@ -26,7 +26,8 @@ Item {
function reload() { function reload() {
if (initialized) { if (initialized) {
updateContract(); updateContract();
webView.runJavaScript("reloadPage()"); //webView.runJavaScript("reloadPage()");
setPreviewUrl(urlInput.text);
} }
} }
@ -55,11 +56,13 @@ Item {
} }
function changePage() { function changePage() {
if (pageCombo.currentIndex >= 0 && pageCombo.currentIndex < pageListModel.count) { setPreviewUrl(urlInput.text);
/*if (pageCombo.currentIndex >= 0 && pageCombo.currentIndex < pageListModel.count) {
urlInput.text = httpServer.url + "/" + pageListModel.get(pageCombo.currentIndex).documentId;
setPreviewUrl(httpServer.url + "/" + pageListModel.get(pageCombo.currentIndex).documentId); setPreviewUrl(httpServer.url + "/" + pageListModel.get(pageCombo.currentIndex).documentId);
} else { } else {
setPreviewUrl(""); setPreviewUrl("");
} }*/
} }
Connections { Connections {
target: appContext target: appContext
@ -98,24 +101,16 @@ Item {
updateDocument(documentId, function(i) { pageListModel.set(i, projectModel.getDocument(documentId)) } ) updateDocument(documentId, function(i) { pageListModel.set(i, projectModel.getDocument(documentId)) } )
} }
onDocumentOpened: {
if (!document.isHtml)
return;
for (var i = 0; i < pageListModel.count; i++) {
var doc = pageListModel.get(i);
if (doc.documentId === document.documentId) {
pageCombo.currentIndex = i;
}
}
}
onProjectLoading: { onProjectLoading: {
for (var i = 0; i < target.listModel.count; i++) { for (var i = 0; i < target.listModel.count; i++) {
var document = target.listModel.get(i); var document = target.listModel.get(i);
if (document.isHtml) { if (document.isHtml) {
pageListModel.append(document); pageListModel.append(document);
if (pageListModel.count === 1) //first page added if (pageListModel.count === 1) //first page added
changePage(); {
urlInput.text = httpServer.url + "/" + document.documentId;
setPreviewUrl(httpServer.url + "/" + document.documentId);
}
} }
} }
} }
@ -151,13 +146,20 @@ Item {
else else
{ {
//document request //document request
if (urlPath === "/")
urlPath = "/index.html";
var documentId = urlPath.substr(urlPath.lastIndexOf("/") + 1); var documentId = urlPath.substr(urlPath.lastIndexOf("/") + 1);
var content = ""; var content = "";
if (projectModel.codeEditor.isDocumentOpen(documentId)) if (projectModel.codeEditor.isDocumentOpen(documentId))
content = projectModel.codeEditor.getDocumentText(documentId); content = projectModel.codeEditor.getDocumentText(documentId);
else else
content = fileIo.readFile(projectModel.getDocument(documentId).path); {
if (documentId === pageListModel.get(pageCombo.currentIndex).documentId) { var doc = projectModel.getDocument(documentId);
if (doc !== undefined)
content = fileIo.readFile(doc.path);
}
if (documentId === urlInput.text.replace(httpServer.url + "/", "")) {
//root page, inject deployment script //root page, inject deployment script
content = "<script>web3=parent.web3;contracts=parent.contracts;</script>\n" + content; content = "<script>web3=parent.web3;contracts=parent.contracts;</script>\n" + content;
_request.setResponseContentType("text/html"); _request.setResponseContentType("text/html");
@ -181,19 +183,23 @@ Item {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 3 anchors.leftMargin: 3
spacing: 3 spacing: 3
DefaultLabel {
text: qsTr("Preview of")
anchors.verticalCenter: parent.verticalCenter
}
ComboBox { DefaultTextField
id: pageCombo {
model: pageListModel id: urlInput
textRole: "name"
currentIndex: -1
onCurrentIndexChanged: changePage()
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
height: 21 height: 21
width: 300
Keys.onEnterPressed:
{
setPreviewUrl(text);
}
Keys.onReturnPressed:
{
setPreviewUrl(text);
}
focus: true
} }
Action { Action {

BIN
mix/qml/img/search_filled.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

382
mix/qml/js/ProjectModel.js

@ -20,6 +20,7 @@
* Ethereum IDE client. * Ethereum IDE client.
*/ */
Qt.include("QEtherHelper.js") Qt.include("QEtherHelper.js")
Qt.include("TransactionHelper.js")
var htmlTemplate = "<html>\n<head>\n<script>\n</script>\n</head>\n<body>\n<script>\n</script>\n</body>\n</html>"; var htmlTemplate = "<html>\n<head>\n<script>\n</script>\n</head>\n<body>\n<script>\n</script>\n</body>\n</html>";
var contractTemplate = "contract Contract {\n}\n"; var contractTemplate = "contract Contract {\n}\n";
@ -50,7 +51,8 @@ function saveProject() {
applicationUrlEth: deploymentDialog.applicationUrlEth, applicationUrlEth: deploymentDialog.applicationUrlEth,
applicationUrlHttp: deploymentDialog.applicationUrlHttp, applicationUrlHttp: deploymentDialog.applicationUrlHttp,
packageHash: deploymentDialog.packageHash, packageHash: deploymentDialog.packageHash,
packageBase64: deploymentDialog.packageBase64 packageBase64: deploymentDialog.packageBase64,
deploymentDir: projectModel.deploymentDir
}; };
for (var i = 0; i < projectListModel.count; i++) for (var i = 0; i < projectListModel.count; i++)
projectData.files.push(projectListModel.get(i).fileName) projectData.files.push(projectListModel.get(i).fileName)
@ -68,6 +70,8 @@ function loadProject(path) {
var projectFile = path + projectFileName; var projectFile = path + projectFileName;
var json = fileIo.readFile(projectFile); var json = fileIo.readFile(projectFile);
var projectData = JSON.parse(json); var projectData = JSON.parse(json);
if (projectData.deploymentDir)
projectModel.deploymentDir = projectData.deploymentDir
if (projectData.packageHash) if (projectData.packageHash)
deploymentDialog.packageHash = projectData.packageHash deploymentDialog.packageHash = projectData.packageHash
if (projectData.packageBase64) if (projectData.packageBase64)
@ -303,49 +307,61 @@ function startDeployProject(erasePrevious)
console.log("Deploying " + deploymentId + " to " + jsonRpcUrl); console.log("Deploying " + deploymentId + " to " + jsonRpcUrl);
deploymentStarted(); deploymentStarted();
var requests = []; var ctrNames = Object.keys(codeModel.contracts);
var requestNames = []; var ctrAddresses = {};
setDefaultBlock(0, function() {
for (var c in codeModel.contracts) { //TODO: order based on dependencies deployContracts(0, ctrAddresses, ctrNames, function (){
var code = codeModel.contracts[c].codeHex; finalizeDeployment(deploymentId, ctrAddresses);
requests.push({
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "code": code } ],
id: jsonRpcRequestId++
}); });
requestNames.push(c); });
} }
var rpcRequest = JSON.stringify(requests); function setDefaultBlock(val, callBack)
var httpRequest = new XMLHttpRequest(); {
httpRequest.open("POST", jsonRpcUrl, true); var requests = [{
httpRequest.setRequestHeader("Content-type", "application/json"); jsonrpc: "2.0",
httpRequest.setRequestHeader("Content-length", rpcRequest.length); method: "eth_setDefaultBlock",
httpRequest.setRequestHeader("Connection", "close"); params: [val],
httpRequest.onreadystatechange = function() { id: 0
if (httpRequest.readyState === XMLHttpRequest.DONE) { }];
if (httpRequest.status === 200) { rpcCall(requests, function (httpCall, response){
var rpcResponse = JSON.parse(httpRequest.responseText); callBack();
if (rpcResponse.length === requestNames.length) { });
var contractAddresses = {}; }
for (var r = 0; r < rpcResponse.length; r++)
contractAddresses[requestNames[r]] = rpcResponse[r].result; function deployContracts(ctrIndex, ctrAddresses, ctrNames, callBack)
finalizeDeployment(deploymentId, contractAddresses); {
} var code = codeModel.contracts[ctrNames[ctrIndex]].codeHex;
} else { var requests = [{
var errorText = qsTr("Deployment error: RPC server HTTP status ") + httpRequest.status; jsonrpc: "2.0",
console.log(errorText); method: "eth_transact",
deploymentError(errorText); params: [ { "from": deploymentDialog.currentAccount, "gas": deploymentDialog.gasToUse, "code": code } ],
id: 0
}];
rpcCall(requests, function (httpCall, response){
var txt = qsTr("Please wait while " + ctrNames[ctrIndex] + " is published ...")
deploymentStepChanged(txt);
console.log(txt);
ctrAddresses[ctrNames[ctrIndex]] = JSON.parse(response)[0].result
deploymentDialog.waitForTrCountToIncrement(function(status) {
if (status === -1)
{
trCountIncrementTimeOut();
return;
} }
} ctrIndex++;
} if (ctrIndex < ctrNames.length)
httpRequest.send(rpcRequest); deployContracts(ctrIndex, ctrAddresses, ctrNames, callBack);
else
callBack();
});
});
} }
function finalizeDeployment(deploymentId, addresses) { function finalizeDeployment(deploymentId, addresses) {
deploymentStepChanged(qsTr("Packaging application ...")); deploymentStepChanged(qsTr("Packaging application ..."));
var deploymentDir = projectPath + deploymentId + "/"; var deploymentDir = projectPath + deploymentId + "/";
projectModel.deploymentDir = deploymentDir;
fileIo.makeDir(deploymentDir); fileIo.makeDir(deploymentDir);
for (var i = 0; i < projectListModel.count; i++) { for (var i = 0; i < projectListModel.count; i++) {
var doc = projectListModel.get(i); var doc = projectListModel.get(i);
@ -372,16 +388,16 @@ function finalizeDeployment(deploymentId, addresses) {
} }
//write deployment js //write deployment js
var deploymentJs = var deploymentJs =
"// Autogenerated by Mix\n" + "// Autogenerated by Mix\n" +
"web3 = require(\"web3\");\n" + "web3 = require(\"web3\");\n" +
"contracts = {};\n"; "contracts = {};\n";
for (var c in codeModel.contracts) { for (var c in codeModel.contracts) {
var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]"; var contractAccessor = "contracts[\"" + codeModel.contracts[c].contract.name + "\"]";
deploymentJs += contractAccessor + " = {\n" + deploymentJs += contractAccessor + " = {\n" +
"\tinterface: " + codeModel.contracts[c].contractInterface + ",\n" + "\tinterface: " + codeModel.contracts[c].contractInterface + ",\n" +
"\taddress: \"" + addresses[c] + "\"\n" + "\taddress: \"" + addresses[c] + "\"\n" +
"};\n" + "};\n" +
contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n"; contractAccessor + ".contract = web3.eth.contract(" + contractAccessor + ".address, " + contractAccessor + ".interface);\n";
} }
fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs); fileIo.writeFile(deploymentDir + "deployment.js", deploymentJs);
//copy scripts //copy scripts
@ -395,152 +411,185 @@ function finalizeDeployment(deploymentId, addresses) {
deploymentDialog.packageBase64 = packageRet[1]; deploymentDialog.packageBase64 = packageRet[1];
var applicationUrlEth = deploymentDialog.applicationUrlEth; var applicationUrlEth = deploymentDialog.applicationUrlEth;
applicationUrlEth = formatAppUrl(applicationUrlEth);
applicationUrlEth = formatAppUrl(applicationUrlEth);
deploymentStepChanged(qsTr("Registering application on the Ethereum network ...")); deploymentStepChanged(qsTr("Registering application on the Ethereum network ..."));
checkRegistration(applicationUrlEth, deploymentDialog.eth, function () { checkEthPath(applicationUrlEth, function () {
deploymentComplete(); deploymentComplete();
deployRessourcesDialog.text = qsTr("Register Web Application to finalize deployment."); deployRessourcesDialog.text = qsTr("Register Web Application to finalize deployment.");
deployRessourcesDialog.open(); deployRessourcesDialog.open();
setDefaultBlock(-1, function() {});
}); });
} }
function rpcCall(requests, callBack) function checkEthPath(dappUrl, callBack)
{ {
var jsonRpcUrl = "http://localhost:8080"; if (dappUrl.length === 1)
var rpcRequest = JSON.stringify(requests); registerContentHash(deploymentDialog.eth, callBack); // we directly create a dapp under the root registrar.
var httpRequest = new XMLHttpRequest(); else
httpRequest.open("POST", jsonRpcUrl, true);
httpRequest.setRequestHeader("Content-type", "application/json");
httpRequest.setRequestHeader("Content-length", rpcRequest.length);
httpRequest.setRequestHeader("Connection", "close");
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status !== 200)
{
var errorText = qsTr("Deployment error: Error while registering Dapp ") + httpRequest.status;
console.log(errorText);
deploymentError(errorText);
return;
}
callBack(httpRequest.status, httpRequest.responseText)
}
}
httpRequest.send(rpcRequest);
}
function checkRegistration(dappUrl, addr, callBack)
{
var requests = [];
var data = "";
if (dappUrl.length > 0)
{ {
//checking path (register). // the first owned reigstrar must have been created to follow the path.
var str = createString(dappUrl[0]); var str = createString(dappUrl[0]);
data = "0x6be16bed" + str.encodeValueAsString(); var requests = [];
console.log("checking if path exists (register) => " + JSON.stringify(dappUrl));
requests.push({ requests.push({
jsonrpc: "2.0", //register()
method: "eth_call", jsonrpc: "2.0",
params: [ { "to": '0x' + addr, "data": data } ], method: "eth_call",
id: jsonRpcRequestId++ params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + deploymentDialog.eth, "data": "0x6be16bed" + str.encodeValueAsString() } ],
}); id: jsonRpcRequestId++
});
rpcCall(requests, function (httpRequest, response) { rpcCall(requests, function (httpRequest, response) {
var address = JSON.parse(response)[0].result.replace('0x', ''); var res = JSON.parse(response);
if (address === "") var addr = normalizeAddress(res[0].result);
if (addr.replace(/0+/g, "") === "")
{ {
var errorTxt = qsTr("Path does not exists " + JSON.stringify(dappUrl) + " cannot continue"); var errorTxt = qsTr("Path does not exists " + JSON.stringify(dappUrl) + ". Please register using Registration Dapp. Aborting.");
deploymentError(errorTxt); deploymentError(errorTxt);
console.log(errorTxt); console.log(errorTxt);
return;
} }
else
dappUrl.splice(0, 1); {
checkRegistration(dappUrl, address, callBack); dappUrl.splice(0, 1);
checkRegistration(dappUrl, addr, callBack);
}
}); });
} }
}
function checkRegistration(dappUrl, addr, callBack)
{
if (dappUrl.length === 1)
registerContentHash(addr, callBack); // We do not create the register for the last part, just registering the content hash.
else else
{ {
var paramTitle = createString(projectModel.projectTitle); var txt = qsTr("Checking " + JSON.stringify(dappUrl) + " ... in registrar " + addr);
deploymentStepChanged(txt);
console.log(txt);
var requests = [];
var registrar = {}
var str = createString(dappUrl[0]);
requests.push({ requests.push({
//owner() //getOwner()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_call", method: "eth_call",
params: [ { "to": '0x' + addr, "data": "0xec7b9200" + paramTitle.encodeValueAsString() } ], params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x893d20e8" } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
requests.push({ requests.push({
//accounts //register()
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_accounts", method: "eth_call",
params: null, params: [ { "from": deploymentDialog.currentAccount, "to": '0x' + addr, "data": "0x6be16bed" + str.encodeValueAsString() } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
rpcCall(requests, function (httpRequest, response) { rpcCall(requests, function (httpRequest, response) {
requests = [];
var res = JSON.parse(response); var res = JSON.parse(response);
var currentOwner = res[0].result; var nextAddr = normalizeAddress(res[1].result);
var noOwner = currentOwner.replace('0x', '').replace(/0/g, '') === ''; var errorTxt;
if (res[1].result === "0x")
if (noOwner)
{ {
requests.push({ errorTxt = qsTr("Error when creating new owned regsitrar. Please use the regsitration Dapp. Aborting");
//reserve() deploymentError(errorTxt);
jsonrpc: "2.0", console.log(errorTxt);
method: "eth_transact", }
params: [ { "to": '0x' + addr, "data": "0x1c83171b" + paramTitle.encodeValueAsString() } ], else if (normalizeAddress(deploymentDialog.currentAccount) !== normalizeAddress(res[0].result))
id: jsonRpcRequestId++ {
}); errorTxt = qsTr("You are not the owner of " + dappUrl[0] + ". Aborting");
deploymentError(errorTxt);
console.log(errorTxt);
}
else if (nextAddr.replace(/0+/g, "") !== "")
{
dappUrl.splice(0, 1);
checkRegistration(dappUrl, nextAddr, callBack);
} }
else else
{ {
var bOwner = false; var txt = qsTr("Registering sub domain " + dappUrl[0] + " ...");
currentOwner = normalizeAddress(currentOwner); console.log(txt);
for (var u in res[1].result) deploymentStepChanged(txt);
{ //current registrar is owned => ownedregistrar creation and continue.
if (normalizeAddress(res[1].result[u]) === currentOwner) requests = [];
bOwner = true;
} requests.push({
jsonrpc: "2.0",
if (!bOwner) method: "eth_transact",
{ params: [ { "from": deploymentDialog.currentAccount, "gas": 20000, "code": "0x60056013565b61059e8061001d6000396000f35b33600081905550560060003560e060020a90048063019848921461009a578063449c2090146100af5780635d574e32146100cd5780635fd4b08a146100e1578063618242da146100f65780636be16bed1461010b5780636c4489b414610129578063893d20e8146101585780639607730714610173578063c284bc2a14610187578063e50f599a14610198578063e5811b35146101af578063ec7b9200146101cd57005b6100a560043561031b565b8060005260206000f35b6100ba6004356103a0565b80600160a060020a031660005260206000f35b6100db600435602435610537565b60006000f35b6100ec600435610529565b8060005260206000f35b6101016004356103dd565b8060005260206000f35b6101166004356103bd565b80600160a060020a031660005260206000f35b61013460043561034b565b82600160a060020a031660005281600160a060020a03166020528060405260606000f35b610160610341565b80600160a060020a031660005260206000f35b6101816004356024356102b4565b60006000f35b6101926004356103fd565b60006000f35b6101a96004356024356044356101f2565b60006000f35b6101ba6004356101eb565b80600160a060020a031660005260206000f35b6101d8600435610530565b80600160a060020a031660005260206000f35b6000919050565b600054600160a060020a031633600160a060020a031614610212576102af565b8160026000858152602001908152602001600020819055508061023457610287565b81600160a060020a0316837f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a3826001600084600160a060020a03168152602001908152602001600020819055505b827f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505050565b600054600160a060020a031633600160a060020a0316146102d457610317565b806002600084815260200190815260200160002060010181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b5050565b60006001600083600160a060020a03168152602001908152602001600020549050919050565b6000600054905090565b6000600060006002600085815260200190815260200160002054925060026000858152602001908152602001600020600101549150600260008581526020019081526020016000206002015490509193909250565b600060026000838152602001908152602001600020549050919050565b600060026000838152602001908152602001600020600101549050919050565b600060026000838152602001908152602001600020600201549050919050565b600054600160a060020a031633600160a060020a03161461041d57610526565b80600160006002600085815260200190815260200160002054600160a060020a031681526020019081526020016000205414610458576104d2565b6002600082815260200190815260200160002054600160a060020a0316817f680ad70765443c2967675ab0fb91a46350c01c6df59bf9a41ff8a8dd097464ec60006000a36000600160006002600085815260200190815260200160002054600160a060020a03168152602001908152602001600020819055505b6002600082815260200190815260200160002060008101600090556001810160009055600281016000905550807f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b50565b6000919050565b6000919050565b600054600160a060020a031633600160a060020a0316146105575761059a565b806002600084815260200190815260200160002060020181905550817f18d67da0cd86808336a3aa8912f6ea70c5250f1a98b586d1017ef56fe199d4fc60006000a25b505056" } ],
var errorTxt = qsTr("Current user is not the owner of this path. Cannot continue") id: jsonRpcRequestId++
deploymentError(errorTxt); });
console.log(errorTxt);
return; rpcCall(requests, function(httpRequest, response) {
} var newCtrAddress = normalizeAddress(JSON.parse(response)[0].result);
requests = [];
var txt = qsTr("Please wait " + dappUrl[0] + " is registering ...");
deploymentStepChanged(txt);
console.log(txt);
deploymentDialog.waitForTrCountToIncrement(function(status) {
if (status === -1)
{
trCountIncrementTimeOut();
return;
}
var crLevel = createString(dappUrl[0]).encodeValueAsString();
requests.push({
//setRegister()
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "from": deploymentDialog.currentAccount, "gas": 2000, "to": '0x' + addr, "data": "0x96077307" + crLevel + deploymentDialog.pad(newCtrAddress) } ],
id: jsonRpcRequestId++
});
rpcCall(requests, function(request, response){
dappUrl.splice(0, 1);
checkRegistration(dappUrl, newCtrAddress, callBack);
});
});
});
} }
console.log("setContentHash");
requests.push({
//setContent()
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "to": '0x' + addr, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + deploymentDialog.packageHash } ],
id: jsonRpcRequestId++
});
rpcCall(requests, function (httpRequest, response) {
callBack();
});
}); });
} }
} }
function trCountIncrementTimeOut()
{
var error = qsTr("Something went wrong during the deployment. Please verify the amount of gas for this transaction and check your balance.")
console.log(error);
deploymentError(error);
}
function registerContentHash(registrar, callBack)
{
var txt = qsTr("Finalizing Dapp registration ...");
deploymentStepChanged(txt);
console.log(txt);
var requests = [];
var paramTitle = createString(projectModel.projectTitle);
requests.push({
//setContent()
jsonrpc: "2.0",
method: "eth_transact",
params: [ { "from": deploymentDialog.currentAccount, "gas": 2000, "gasPrice": "10", "to": '0x' + registrar, "data": "0x5d574e32" + paramTitle.encodeValueAsString() + deploymentDialog.packageHash } ],
id: jsonRpcRequestId++
});
rpcCall(requests, function (httpRequest, response) {
callBack();
});
}
function registerToUrlHint() function registerToUrlHint()
{ {
deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.applicationUrlHttp) + ") ..."); deploymentStepChanged(qsTr("Registering application Resources (" + deploymentDialog.applicationUrlHttp) + ") ...");
var requests = []; var requests = [];
var paramUrlHttp = createString(deploymentDialog.applicationUrlHttp); var paramUrlHttp = createString(deploymentDialog.applicationUrlHttp);
requests.push({ requests.push({
//urlHint => suggestUrl //urlHint => suggestUrl
jsonrpc: "2.0", jsonrpc: "2.0",
method: "eth_transact", method: "eth_transact",
params: [ { "to": '0x' + deploymentDialog.urlHintContract, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ], params: [ { "to": '0x' + deploymentDialog.urlHintContract, "gas": 2000, "data": "0x4983e19c" + deploymentDialog.packageHash + paramUrlHttp.encodeValueAsString() } ],
id: jsonRpcRequestId++ id: jsonRpcRequestId++
}); });
rpcCall(requests, function (httpRequest, response) { rpcCall(requests, function (httpRequest, response) {
deploymentComplete(); deploymentComplete();
@ -550,40 +599,35 @@ function registerToUrlHint()
function normalizeAddress(addr) function normalizeAddress(addr)
{ {
addr = addr.replace('0x', ''); addr = addr.replace('0x', '');
var i = 0; if (addr.length <= 40)
for (var k in addr) return addr;
{ var left = addr.length - 40;
if (addr[k] !== "0") return addr.substring(left);
break;
else
i++;
}
return addr.substring(i);
} }
function formatAppUrl(url) function formatAppUrl(url)
{ {
var slash = url.indexOf("/"); if (url.toLowerCase().indexOf("eth://") === 0)
var dot = url.indexOf("."); url = url.substring(6);
if (slash === -1 && dot === -1) if (url === "")
return url; return [projectModel.projectTitle];
if ((slash !== -1 && slash < dot) || dot === -1)
return url.split("/"); var ret;
if (url.indexOf("/") === -1)
ret = url.split('.').reverse();
else else
{ {
var dotted; var slash = url.indexOf("/");
var ret = []; var left = url.substring(0, slash);
if (slash !== -1) var leftA = left.split(".");
{ leftA.reverse();
ret.push(url.split("/"));
dotted = ret[0].split("."); var right = url.substring(slash + 1);
} var rightA = right.split('/');
else ret = leftA.concat(rightA);
dotted = url.split(".");
for (var k in dotted)
ret.unshift(dotted[k]);
return ret;
} }
if (ret[0].toLowerCase() === "eth")
ret.splice(0, 1);
ret.push(projectModel.projectTitle);
return ret;
} }

25
mix/qml/js/TransactionHelper.js

@ -10,3 +10,28 @@ function defaultTransaction()
parameters: {} parameters: {}
}; };
} }
function rpcCall(requests, callBack)
{
var jsonRpcUrl = "http://localhost:8080";
var rpcRequest = JSON.stringify(requests);
var httpRequest = new XMLHttpRequest();
httpRequest.open("POST", jsonRpcUrl, true);
httpRequest.setRequestHeader("Content-type", "application/json");
httpRequest.setRequestHeader("Content-length", rpcRequest.length);
httpRequest.setRequestHeader("Connection", "close");
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status !== 200 || httpRequest.responseText === "")
{
var errorText = qsTr("Deployment error: Error while registering Dapp ") + httpRequest.status;
console.log(errorText);
deploymentError(errorText);
}
else
callBack(httpRequest.status, httpRequest.responseText)
}
}
httpRequest.send(rpcRequest);
}

13
mix/qml/main.qml

@ -61,7 +61,7 @@ ApplicationWindow {
MenuItem { action: toggleTransactionLogAction } MenuItem { action: toggleTransactionLogAction }
MenuItem { action: toggleWebPreviewAction } MenuItem { action: toggleWebPreviewAction }
MenuItem { action: toggleWebPreviewOrientationAction } MenuItem { action: toggleWebPreviewOrientationAction }
MenuItem { action: toggleCallsInLog } //MenuItem { action: toggleCallsInLog }
} }
} }
@ -97,7 +97,7 @@ ApplicationWindow {
Action { Action {
id: mineAction id: mineAction
text: qsTr("Mine") text: qsTr("New Block")
shortcut: "Ctrl+M" shortcut: "Ctrl+M"
onTriggered: clientModel.mine(); onTriggered: clientModel.mine();
enabled: codeModel.hasContract && !clientModel.running && !clientModel.mining enabled: codeModel.hasContract && !clientModel.running && !clientModel.mining
@ -179,15 +179,6 @@ ApplicationWindow {
onTriggered: mainContent.toggleWebPreviewOrientation(); onTriggered: mainContent.toggleWebPreviewOrientation();
} }
Action {
id: toggleCallsInLog
text: qsTr("Show Calls in Transaction Log")
shortcut: ""
checkable: true
checked: mainContent.rightPane.transactionLog.showLogs
onTriggered: mainContent.rightPane.transactionLog.showLogs = !mainContent.rightPane.transactionLog.showLogs
}
Action { Action {
id: toggleRunOnLoadAction id: toggleRunOnLoadAction
text: qsTr("Load State on Startup") text: qsTr("Load State on Startup")

1
mix/res.qrc

@ -102,5 +102,6 @@
<file>qml/WebPreviewStyle.qml</file> <file>qml/WebPreviewStyle.qml</file>
<file>qml/img/available_updates.png</file> <file>qml/img/available_updates.png</file>
<file>qml/DeploymentDialog.qml</file> <file>qml/DeploymentDialog.qml</file>
<file>qml/img/search_filled.png</file>
</qresource> </qresource>
</RCC> </RCC>

242
test/SolidityEndToEndTest.cpp

@ -2768,6 +2768,248 @@ BOOST_AUTO_TEST_CASE(dynamic_out_of_bounds_array_access)
BOOST_CHECK(callContractFunction("length()") == encodeArgs(4)); BOOST_CHECK(callContractFunction("length()") == encodeArgs(4));
} }
BOOST_AUTO_TEST_CASE(fixed_array_cleanup)
{
char const* sourceCode = R"(
contract c {
uint spacer1;
uint spacer2;
uint[20] data;
function fill() {
for (uint i = 0; i < data.length; ++i) data[i] = i+1;
}
function clear() { delete data; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("fill()") == bytes());
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("clear()") == bytes());
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(short_fixed_array_cleanup)
{
char const* sourceCode = R"(
contract c {
uint spacer1;
uint spacer2;
uint[3] data;
function fill() {
for (uint i = 0; i < data.length; ++i) data[i] = i+1;
}
function clear() { delete data; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("fill()") == bytes());
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("clear()") == bytes());
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(dynamic_array_cleanup)
{
char const* sourceCode = R"(
contract c {
uint[20] spacer;
uint[] dynamic;
function fill() {
dynamic.length = 21;
for (uint i = 0; i < dynamic.length; ++i) dynamic[i] = i+1;
}
function halfClear() { dynamic.length = 5; }
function fullClear() { delete dynamic; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("fill()") == bytes());
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("halfClear()") == bytes());
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("fullClear()") == bytes());
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(dynamic_multi_array_cleanup)
{
char const* sourceCode = R"(
contract c {
struct s { uint[][] d; }
s[] data;
function fill() returns (uint) {
data.length = 3;
data[2].d.length = 4;
data[2].d[3].length = 5;
data[2].d[3][4] = 8;
return data[2].d[3][4];
}
function clear() { delete data; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("fill()") == encodeArgs(8));
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("clear()") == bytes());
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(array_copy_storage_storage_dyn_dyn)
{
char const* sourceCode = R"(
contract c {
uint[] data1;
uint[] data2;
function setData1(uint length, uint index, uint value) {
data1.length = length; if (index < length) data1[index] = value;
}
function copyStorageStorage() { data2 = data1; }
function getData2(uint index) returns (uint len, uint val) {
len = data2.length; if (index < len) val = data2[index];
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("setData1(uint256,uint256,uint256)", 10, 5, 4) == bytes());
BOOST_CHECK(callContractFunction("copyStorageStorage()") == bytes());
BOOST_CHECK(callContractFunction("getData2(uint256)", 5) == encodeArgs(10, 4));
BOOST_CHECK(callContractFunction("setData1(uint256,uint256,uint256)", 0, 0, 0) == bytes());
BOOST_CHECK(callContractFunction("copyStorageStorage()") == bytes());
BOOST_CHECK(callContractFunction("getData2(uint256)", 0) == encodeArgs(0, 0));
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(array_copy_storage_storage_static_static)
{
char const* sourceCode = R"(
contract c {
uint[40] data1;
uint[20] data2;
function test() returns (uint x, uint y){
data1[30] = 4;
data1[2] = 7;
data1[3] = 9;
data2[3] = 8;
data1 = data2;
x = data1[3];
y = data1[30]; // should be cleared
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(8, 0));
}
BOOST_AUTO_TEST_CASE(array_copy_storage_storage_static_dynamic)
{
char const* sourceCode = R"(
contract c {
uint[9] data1;
uint[] data2;
function test() returns (uint x, uint y){
data1[8] = 4;
data2 = data1;
x = data2.length;
y = data2[8];
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(9, 4));
}
BOOST_AUTO_TEST_CASE(array_copy_storage_storage_struct)
{
char const* sourceCode = R"(
contract c {
struct Data { uint x; uint y; }
Data[] data1;
Data[] data2;
function test() returns (uint x, uint y) {
data1.length = 9;
data1[8].x = 4;
data1[8].y = 5;
data2 = data1;
x = data2[8].x;
y = data2[8].y;
data1.length = 0;
data2 = data1;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(4, 5));
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base)
{
char const* sourceCode = R"(
contract Base {
function Base(uint i)
{
m_i = i;
}
uint public m_i;
}
contract Derived is Base(2) {
function Derived(uint i) Base(i)
{}
}
contract Final is Derived(4) {
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("m_i()") == encodeArgs(4));
}
BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base_base)
{
char const* sourceCode = R"(
contract Base {
function Base(uint j)
{
m_i = j;
}
uint public m_i;
}
contract Base1 is Base(3) {
function Base1(uint k) Base(k*k) {}
}
contract Derived is Base(3), Base1(2) {
function Derived(uint i) Base(i) Base1(i)
{}
}
contract Final is Derived(4) {
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("m_i()") == encodeArgs(4));
}
BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base_base_with_gap)
{
char const* sourceCode = R"(
contract Base {
function Base(uint i)
{
m_i = i;
}
uint public m_i;
}
contract Base1 is Base(3) {}
contract Derived is Base(2), Base1 {
function Derived(uint i) Base(i) {}
}
contract Final is Derived(4) {
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("m_i()") == encodeArgs(4));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

109
test/SolidityNameAndTypeResolution.cpp

@ -436,7 +436,7 @@ BOOST_AUTO_TEST_CASE(inheritance_diamond_basic)
function g() { f(); rootFunction(); } function g() { f(); rootFunction(); }
} }
)"; )";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
} }
BOOST_AUTO_TEST_CASE(cyclic_inheritance) BOOST_AUTO_TEST_CASE(cyclic_inheritance)
@ -720,6 +720,58 @@ BOOST_AUTO_TEST_CASE(private_state_variable)
BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an internal variable should not exist"); BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an internal variable should not exist");
} }
BOOST_AUTO_TEST_CASE(base_class_state_variable_accessor)
{
// test for issue #1126 https://github.com/ethereum/cpp-ethereum/issues/1126
char const* text = "contract Parent {\n"
" uint256 public m_aMember;\n"
"}\n"
"contract Child is Parent{\n"
" function foo() returns (uint256) { return Parent.m_aMember; }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
}
BOOST_AUTO_TEST_CASE(base_class_state_variable_internal_member)
{
char const* text = "contract Parent {\n"
" uint256 internal m_aMember;\n"
"}\n"
"contract Child is Parent{\n"
" function foo() returns (uint256) { return Parent.m_aMember; }\n"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text));
}
BOOST_AUTO_TEST_CASE(state_variable_member_of_wrong_class1)
{
char const* text = "contract Parent1 {\n"
" uint256 internal m_aMember1;\n"
"}\n"
"contract Parent2 is Parent1{\n"
" uint256 internal m_aMember2;\n"
"}\n"
"contract Child is Parent2{\n"
" function foo() returns (uint256) { return Parent2.m_aMember1; }\n"
"}\n";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(state_variable_member_of_wrong_class2)
{
char const* text = "contract Parent1 {\n"
" uint256 internal m_aMember1;\n"
"}\n"
"contract Parent2 is Parent1{\n"
" uint256 internal m_aMember2;\n"
"}\n"
"contract Child is Parent2{\n"
" function foo() returns (uint256) { return Child.m_aMember2; }\n"
" uint256 public m_aMember3;\n"
"}\n";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(fallback_function) BOOST_AUTO_TEST_CASE(fallback_function)
{ {
char const* text = R"( char const* text = R"(
@ -1185,6 +1237,61 @@ BOOST_AUTO_TEST_CASE(array_with_nonconstant_length)
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
} }
BOOST_AUTO_TEST_CASE(array_copy_with_different_types1)
{
char const* text = R"(
contract c {
bytes a;
uint[] b;
function f() { b = a; }
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types2)
{
char const* text = R"(
contract c {
uint32[] a;
uint8[] b;
function f() { b = a; }
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types_conversion_possible)
{
char const* text = R"(
contract c {
uint32[] a;
uint8[] b;
function f() { a = b; }
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types_static_dynamic)
{
char const* text = R"(
contract c {
uint32[] a;
uint8[80] b;
function f() { a = b; }
})";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(array_copy_with_different_types_dynamic_static)
{
char const* text = R"(
contract c {
uint[] a;
uint[80] b;
function f() { b = a; }
})";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

34
test/SolidityParser.cpp

@ -367,6 +367,40 @@ BOOST_AUTO_TEST_CASE(variable_definition_with_initialization)
BOOST_CHECK_NO_THROW(parseText(text)); BOOST_CHECK_NO_THROW(parseText(text));
} }
BOOST_AUTO_TEST_CASE(variable_definition_in_function_parameter)
{
char const* text = R"(
contract test {
function fun(var a) {}
}
)";
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_CASE(variable_definition_in_mapping)
{
char const* text = R"(
contract test {
function fun() {
mapping(var=>hash) d;
}
}
)";
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_CASE(variable_definition_in_function_return)
{
char const* text = R"(
contract test {
function fun() returns(var d) {
return 1;
}
}
)";
BOOST_CHECK_THROW(parseText(text), ParserError);
}
BOOST_AUTO_TEST_CASE(operator_expression) BOOST_AUTO_TEST_CASE(operator_expression)
{ {
char const* text = "contract test {\n" char const* text = "contract test {\n"

50
test/TestHelper.cpp

@ -139,27 +139,35 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state)
} }
void ImportTest::importTransaction(json_spirit::mObject& _o) void ImportTest::importTransaction(json_spirit::mObject& _o)
{ {
BOOST_REQUIRE(_o.count("nonce")> 0); if (_o.count("secretKey") > 0)
BOOST_REQUIRE(_o.count("gasPrice") > 0); {
BOOST_REQUIRE(_o.count("gasLimit") > 0); BOOST_REQUIRE(_o.count("nonce") > 0);
BOOST_REQUIRE(_o.count("to") > 0); BOOST_REQUIRE(_o.count("gasPrice") > 0);
BOOST_REQUIRE(_o.count("value") > 0); BOOST_REQUIRE(_o.count("gasLimit") > 0);
BOOST_REQUIRE(_o.count("secretKey") > 0); BOOST_REQUIRE(_o.count("to") > 0);
BOOST_REQUIRE(_o.count("data") > 0); BOOST_REQUIRE(_o.count("value") > 0);
BOOST_REQUIRE(_o.count("data") > 0);
if (bigint(_o["nonce"].get_str()) >= c_max256plus1)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'nonce' is equal or greater than 2**256") ); if (bigint(_o["nonce"].get_str()) >= c_max256plus1)
if (bigint(_o["gasPrice"].get_str()) >= c_max256plus1) BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'nonce' is equal or greater than 2**256") );
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasPrice' is equal or greater than 2**256") ); if (bigint(_o["gasPrice"].get_str()) >= c_max256plus1)
if (bigint(_o["gasLimit"].get_str()) >= c_max256plus1) BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasPrice' is equal or greater than 2**256") );
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasLimit' is equal or greater than 2**256") ); if (bigint(_o["gasLimit"].get_str()) >= c_max256plus1)
if (bigint(_o["value"].get_str()) >= c_max256plus1) BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasLimit' is equal or greater than 2**256") );
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'value' is equal or greater than 2**256") ); if (bigint(_o["value"].get_str()) >= c_max256plus1)
BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'value' is equal or greater than 2**256") );
m_transaction = _o["to"].get_str().empty() ?
Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())) : m_transaction = _o["to"].get_str().empty() ?
Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), Address(_o["to"].get_str()), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())); Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())) :
Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), Address(_o["to"].get_str()), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str()));
}
else
{
RLPStream transactionRLPStream = createRLPStreamFromTransactionFields(_o);
RLP transactionRLP(transactionRLPStream.out());
m_transaction = Transaction(transactionRLP.data(), CheckSignature::Sender);
}
} }
void ImportTest::exportTest(bytes _output, State& _statePost) void ImportTest::exportTest(bytes _output, State& _statePost)

10
test/block.cpp

@ -496,11 +496,21 @@ BOOST_AUTO_TEST_CASE(blValidBlockTest)
dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests); dev::test::executeTests("blValidBlockTest", "/BlockTests", dev::test::doBlockTests);
} }
BOOST_AUTO_TEST_CASE(blInvalidTransactionRLP)
{
dev::test::executeTests("blInvalidTransactionRLP", "/BlockTests", dev::test::doBlockTests);
}
BOOST_AUTO_TEST_CASE(blInvalidHeaderTest) BOOST_AUTO_TEST_CASE(blInvalidHeaderTest)
{ {
dev::test::executeTests("blInvalidHeaderTest", "/BlockTests", dev::test::doBlockTests); dev::test::executeTests("blInvalidHeaderTest", "/BlockTests", dev::test::doBlockTests);
} }
BOOST_AUTO_TEST_CASE(blForkBlocks)
{
dev::test::executeTests("blForkBlocks", "/BlockTests", dev::test::doBlockTests);
}
BOOST_AUTO_TEST_CASE(userDefinedFileBl) BOOST_AUTO_TEST_CASE(userDefinedFileBl)
{ {
dev::test::userDefinedTest("--bltest", dev::test::doBlockTests); dev::test::userDefinedTest("--bltest", dev::test::doBlockTests);

69
test/stMemoryStressTestFiller.json

@ -0,0 +1,69 @@
{
"mload32bitBound": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "17592320524892",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 1 ]] (MLOAD 4294967296) } ",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "175923205248920",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "17592320524892",
"to" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"value" : "10",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"mload32bitBound2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "37791080412587",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 1 ]] (MLOAD 6294967296) } ",
"storage": {}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "377910804219850",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "37791080412587",
"to" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"value" : "10",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
}
}

1465
test/stMemoryTestFiller.json

File diff suppressed because it is too large

682
test/stQuadraticComplexityTestFiller.json

File diff suppressed because one or more lines are too long

158
test/stRefundTestFiller.json

@ -304,33 +304,135 @@
"data" : "" "data" : ""
} }
}, },
"RefundOverflow" : { "refund_CallA" : {
"env" : { "env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentDifficulty" : "45678256", "currentNumber" : "0",
"currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", "currentGasLimit" : "1000000",
"currentNumber" : "0", "currentDifficulty" : "256",
"currentTimestamp" : 1, "currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
}, },
"pre" : { "pre" : {
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "400", "balance" : "1000000000000000000",
"code" : "0x", "nonce" : "0",
"nonce" : "0", "code" : "{ [[ 0 ]] (CALL 500 0xaaae7baea6a6c7c4c2dfeb977efac326af552aaa 0 0 0 0 0 )}",
"storage" : { "storage" : {
} "0x01" : "0x01"
} }
}, },
"transaction" : { "aaae7baea6a6c7c4c2dfeb977efac326af552aaa" : {
"data" : "", "balance" : "1000000000000000000",
"gasLimit" : "5789604461865809771178549250434395392663499233282028201972879200395656482016", "nonce" : "0",
"gasPrice" : "20", "code" : "{ [[ 1 ]] 0 }",
"nonce" : "0", "storage" : {
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "0x01" : "0x01"
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", }
"value" : "" },
} "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
} "balance" : "2000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "1500",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"refund_CallA2" : {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (CALL 50 0xaaae7baea6a6c7c4c2dfeb977efac326af552aaa 0 0 0 0 0 )}",
"storage" : {
"0x01" : "0x01"
}
},
"aaae7baea6a6c7c4c2dfeb977efac326af552aaa" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 1 ]] 0 }",
"storage" : {
"0x01" : "0x01"
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "850",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
},
"refund_CallA_OOG" : {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : 1,
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"095e7baea6a6c7c4c2dfeb977efac326af552d87" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (CALL 1 0xaaae7baea6a6c7c4c2dfeb977efac326af552aaa 0 0 0 0 0 )}",
"storage" : {
"0x01" : "0x01"
}
},
"aaae7baea6a6c7c4c2dfeb977efac326af552aaa" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 1 ]] 0 }",
"storage" : {
"0x01" : "0x01"
}
},
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "1000",
"nonce" : "0",
"code" : "",
"storage": {}
}
},
"transaction" : {
"nonce" : "0",
"gasPrice" : "1",
"gasLimit" : "850",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "10",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"data" : ""
}
}
} }

55
test/stSolidityTestFiller.json

@ -525,60 +525,5 @@
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "1" "value" : "1"
} }
},
"QuadraticComplexity" : {
"env" : {
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentDifficulty" : "45678256",
"currentGasLimit" : "100000000",
"currentNumber" : "0",
"currentTimestamp" : 1,
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
},
"pre" :
{
"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "10000000",
"//" : "contract caller ",
"//" : "{ ",
"//" : " int value; ",
"//" : " function run(int count) ",
"//" : " { ",
"//" : " value = count; ",
"//" : " address a = 0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b; ",
"//" : " while(count > 0) ",
"//" : " { ",
"//" : " a.call('just', 'call'); ",
"//" : " count = count - 1; ",
"//" : " } ",
"//" : " } ",
"//" : "} ",
"code" : "0x60003560e060020a9004806361a4770614601557005b601e6004356024565b60006000f35b60008160008190555073b94f5374fce5edbc8e2a8697c15331677e6ebf0b90505b600082131560bf5780600160a060020a03166000600060007f6a7573740000000000000000000000000000000000000000000000000000000081526004017f63616c6c000000000000000000000000000000000000000000000000000000008152602001600060008560155a03f150506001820391506045565b505056",
"nonce" : "0",
"storage" : {
}
},
"b94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "100000",
"code" : "{ (CALLDATACOPY 0 0 32) }",
"nonce" : "0",
"storage" : {
}
}
},
"transaction" :
{
"//" : "run(int256)",
"data" : "0x61a47706000000000000000000000000000000000000000000000000000000000000c350",
"gasLimit" : "904+68*x+e",
"gasLimit" : "3500000",
"gasPrice" : "1",
"nonce" : "0",
"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
"to" : "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "1"
}
} }
} }

1015
test/stSystemOperationsTestFiller.json

File diff suppressed because it is too large

10
test/stTransactionTestFiller.json

@ -547,7 +547,7 @@
"code" : "{(CALL 0 0 1 0 0 0 0) (SUICIDE 0)}", "code" : "{(CALL 0 0 1 0 0 0 0) (SUICIDE 0)}",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"0000000000000000000000000000000000000000" : { "0000000000000000000000000000000000000000" : {
@ -596,7 +596,7 @@
"code" : "{(CALL 20 0 1 0 0 0 0) (SUICIDE 0)}", "code" : "{(CALL 20 0 1 0 0 0 0) (SUICIDE 0)}",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"0000000000000000000000000000000000000000" : { "0000000000000000000000000000000000000000" : {
@ -645,7 +645,7 @@
"code" : "{(SUICIDE 0) (CALL 0 2000 0 0 0 0 0) }", "code" : "{(SUICIDE 0) (CALL 0 2000 0 0 0 0 0) }",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
}, },
"0000000000000000000000000000000000000000" : { "0000000000000000000000000000000000000000" : {
@ -693,7 +693,7 @@
"code" : "{(SUICIDE 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b)}", "code" : "{(SUICIDE 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b)}",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },
@ -733,7 +733,7 @@
"code" : "{(SUICIDE 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b)}", "code" : "{(SUICIDE 0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b)}",
"nonce" : "0", "nonce" : "0",
"storage" : { "storage" : {
} }
} }
}, },

41
test/state.cpp

@ -159,11 +159,52 @@ BOOST_AUTO_TEST_CASE(stBlockHashTest)
dev::test::executeTests("stBlockHashTest", "/StateTests", dev::test::doStateTests); dev::test::executeTests("stBlockHashTest", "/StateTests", dev::test::doStateTests);
} }
BOOST_AUTO_TEST_CASE(stQuadraticComplexityTest)
{
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];
if (arg == "--quadratic" || arg == "--all")
{
auto start = chrono::steady_clock::now();
dev::test::executeTests("stQuadraticComplexityTest", "/StateTests", dev::test::doStateTests);
auto end = chrono::steady_clock::now();
auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
cnote << "test duration: " << duration.count() << " milliseconds.\n";
}
}
}
BOOST_AUTO_TEST_CASE(stMemoryStressTest)
{
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];
if (arg == "--memory" || arg == "--all")
{
auto start = chrono::steady_clock::now();
dev::test::executeTests("stMemoryStressTest", "/StateTests", dev::test::doStateTests);
auto end = chrono::steady_clock::now();
auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
cnote << "test duration: " << duration.count() << " milliseconds.\n";
}
}
}
BOOST_AUTO_TEST_CASE(stSolidityTest) BOOST_AUTO_TEST_CASE(stSolidityTest)
{ {
dev::test::executeTests("stSolidityTest", "/StateTests", dev::test::doStateTests); dev::test::executeTests("stSolidityTest", "/StateTests", dev::test::doStateTests);
} }
BOOST_AUTO_TEST_CASE(stMemoryTest)
{
dev::test::executeTests("stMemoryTest", "/StateTests", dev::test::doStateTests);
}
BOOST_AUTO_TEST_CASE(stCreateTest) BOOST_AUTO_TEST_CASE(stCreateTest)
{ {
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)

19
test/transaction.cpp

@ -90,8 +90,9 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
o["sender"] = toString(txFromFields.sender()); o["sender"] = toString(txFromFields.sender());
} }
catch(...) catch(Exception const& _e)
{ {
cnote << "Transaction Exception: " << diagnostic_information(_e);
o.erase(o.find("transaction")); o.erase(o.find("transaction"));
} }
} }
@ -115,7 +116,21 @@ BOOST_AUTO_TEST_CASE(ttWrongRLPTransaction)
BOOST_AUTO_TEST_CASE(tt10mbDataField) BOOST_AUTO_TEST_CASE(tt10mbDataField)
{ {
dev::test::executeTests("tt10mbDataField", "/TransactionTests", dev::test::doTransactionTests); 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];
if (arg == "--bigdata" || arg == "--all")
{
auto start = chrono::steady_clock::now();
dev::test::executeTests("tt10mbDataField", "/TransactionTests", dev::test::doTransactionTests);
auto end = chrono::steady_clock::now();
auto duration(chrono::duration_cast<chrono::milliseconds>(end - start));
cnote << "test duration: " << duration.count() << " milliseconds.\n";
}
}
} }
BOOST_AUTO_TEST_CASE(ttCreateTest) BOOST_AUTO_TEST_CASE(ttCreateTest)

169
test/ttTransactionTestFiller.json

@ -14,7 +14,7 @@
} }
}, },
"WrongVRSTestVl27" : { "WrongVRSTestVl26" : {
"transaction" : "transaction" :
{ {
"data" : "", "data" : "",
@ -29,6 +29,21 @@
} }
}, },
"WrongVRSTestVl29" : {
"transaction" :
{
"data" : "",
"gasLimit" : "2000",
"gasPrice" : "1",
"nonce" : "0",
"to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"value" : "10",
"v" : "29",
"r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a",
"s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"
}
},
"WrongVRSTestVge31" : { "WrongVRSTestVge31" : {
"transaction" : "transaction" :
{ {
@ -136,7 +151,22 @@
} }
}, },
"TransactionWithSvalueOverflow" : { "TransactionWithSvalueHigh" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "11",
"v" : "27",
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
"s" : "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e"
}
},
"TransactionWithSvalueTooHigh" : {
"transaction" : "transaction" :
{ {
"data" : "", "data" : "",
@ -151,7 +181,52 @@
} }
}, },
"TransactionWithSvalueOverflow" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "11",
"v" : "27",
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
"s" : "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0000"
}
},
"TransactionWithRvalueOverflow" : { "TransactionWithRvalueOverflow" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "11",
"v" : "27",
"r" : "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410000",
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithRvalueHigh" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "11",
"v" : "27",
"r" : "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
"s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"
}
},
"TransactionWithRvalueTooHigh" : {
"transaction" : "transaction" :
{ {
"data" : "", "data" : "",
@ -166,6 +241,51 @@
} }
}, },
"TransactionWithRvalueWrongSize" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "11",
"v" : "27",
"r" : "0xebaaedce6af48a03bbfd25e8cd0364141",
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithSvalueWrongSize" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "11",
"v" : "27",
"r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a",
"s" : "0xef0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithHihghNonce" : {
"transaction" :
{
"data" : "",
"gasLimit" : "850",
"gasPrice" : "1",
"nonce" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0",
"v" : "27",
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithNonceOverflow" : { "TransactionWithNonceOverflow" : {
"transaction" : "transaction" :
{ {
@ -181,6 +301,51 @@
} }
}, },
"TransactionWithHihghGas" : {
"transaction" :
{
"data" : "",
"gasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"gasPrice" : "1",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0",
"v" : "27",
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithHihghGasPrice" : {
"transaction" :
{
"data" : "",
"gasLimit" : "1000",
"gasPrice" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0",
"v" : "27",
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithGasLimitxPriceOverflow" : {
"transaction" :
{
"data" : "",
"gasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"gasPrice" : "100000000000000000",
"nonce" : "0",
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87",
"value" : "0",
"v" : "27",
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353",
"s" : "0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804"
}
},
"TransactionWithGasPriceOverflow" : { "TransactionWithGasPriceOverflow" : {
"transaction" : "transaction" :
{ {

6
test/vm.cpp

@ -518,7 +518,7 @@ BOOST_AUTO_TEST_CASE(vmPerformanceTest)
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];
if (arg == "--performance") if (arg == "--performance" || arg == "--all")
{ {
auto start = chrono::steady_clock::now(); auto start = chrono::steady_clock::now();
@ -536,7 +536,7 @@ BOOST_AUTO_TEST_CASE(vmInputLimitsTest1)
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];
if (arg == "--inputlimits") if (arg == "--inputlimits" || arg == "--all")
{ {
auto start = chrono::steady_clock::now(); auto start = chrono::steady_clock::now();
@ -554,7 +554,7 @@ BOOST_AUTO_TEST_CASE(vmInputLimitsTest2)
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];
if (arg == "--inputlimits") if (arg == "--inputlimits" || arg == "--all")
dev::test::executeTests("vmInputLimitsTest2", "/VMTests", dev::test::doVMTests); dev::test::executeTests("vmInputLimitsTest2", "/VMTests", dev::test::doVMTests);
} }
} }

366
test/vmArithmeticTestFiller.json

@ -897,7 +897,7 @@
} }
}, },
"sdiv5": { "sdiv_i256min": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0", "currentNumber" : "0",
@ -925,6 +925,62 @@
} }
}, },
"sdiv_i256min2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SDIV (- 0 57896044618658097711785492504343953926634992332820282019728792003956564819968) (- 0 1) ) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"sdiv_i256min3": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SDIV 115792089237316195423570985008687907853269984665640564039457584007913129639935 (- 0 57896044618658097711785492504343953926634992332820282019728792003956564819967) ) }",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"mod0": { "mod0": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
@ -1205,6 +1261,90 @@
} }
}, },
"smod5": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SMOD (- 0 57896044618658097711785492504343953926634992332820282019728792003956564819967) 57896044618658097711785492504343953926634992332820282019728792003956564819967)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"smod6": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SMOD (- 0 115792089237316195423570985008687907853269984665640564039457584007913129639935) 57896044618658097711785492504343953926634992332820282019728792003956564819967)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"smod7": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SMOD (- 0 57896044618658097711785492504343953926634992332820282019728792003956564819967) 115792089237316195423570985008687907853269984665640564039457584007913129639935)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"addmod0": { "addmod0": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
@ -1261,6 +1401,118 @@
} }
}, },
"addmod1_overflowDiff": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (ADDMOD (- 0 1) (- 0 2) 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"addmod1_overflow2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (ADDMOD (- 0 1) 0 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"addmod1_overflow3": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (ADDMOD (- 0 1) 1 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"addmod1_overflow3": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (ADDMOD (- 0 1) 2 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"addmod2": { "addmod2": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
@ -1542,6 +1794,118 @@
} }
}, },
"mulmod1_overflow": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (MULMOD (- 0 1) 2 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"mulmod1_overflow2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (MULMOD 57896044618658097711785492504343953926634992332820282019728792003956564819968 2 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"mulmod1_overflow3": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (MULMOD 57896044618658097711785492504343953926634992332820282019728792003956564819967 2 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"mulmod1_overflow4": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ [[ 0 ]] (MULMOD 57896044618658097711785492504343953926634992332820282019728792003956564819969 2 5) } ",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f2947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"mulmod2": { "mulmod2": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

168
test/vmEnvironmentalInfoTestFiller.json

@ -703,6 +703,174 @@
} }
}, },
"calldatacopy0_return": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (CALLDATACOPY 0 1 2 ) (RETURN 0 (MSIZE))}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "0x1234567890abcdef01234567890abcdef",
"gasPrice" : "1000000000",
"gas" : "100000000000"
}
},
"calldatacopyZeroMemExpansion_return": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (CALLDATACOPY 0 0 0 ) (RETURN 0 (MSIZE))}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "0x1234567890abcdef01234567890abcdef",
"gasPrice" : "1000000000",
"gas" : "100000000000"
}
},
"calldatacopy_DataIndexTooHigh_return": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (CALLDATACOPY 0 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa 0xff ) (RETURN 0 (MSIZE))}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "0x1234567890abcdef01234567890abcdef",
"gasPrice" : "1000000000",
"gas" : "100000000000"
}
},
"calldatacopy_DataIndexTooHigh2_return": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (CALLDATACOPY 0 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa 9 ) (RETURN 0 (MSIZE))}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "0x1234567890abcdef01234567890abcdef",
"gasPrice" : "1000000000",
"gas" : "100000000000"
}
},
"calldatacopy1_return": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (CALLDATACOPY 0 1 1 ) (RETURN 0 (MSIZE))}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "0x1234567890abcdef01234567890abcdef",
"gasPrice" : "1000000000",
"gas" : "100000000000"
}
},
"calldatacopy2_return": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "{ (CALLDATACOPY 0 1 0 ) (RETURN 0 (MSIZE))}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "0x1234567890abcdef01234567890abcdef",
"gasPrice" : "1000000000",
"gas" : "100000000000"
}
},
"codesize": { "codesize": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

85
test/vmIOandFlowOperationsTestFiller.json

@ -727,6 +727,91 @@
} }
}, },
"jumpTo1InstructionafterJump": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "0x6003565b6001600055",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"jumpTo1InstructionafterJump_noJumpDest": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "0x6003566001600055",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"jumpTo1InstructionafterJump_jumpdestFirstInstruction": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "1000000000000000000",
"nonce" : "0",
"code" : "0x5b6003565b6001600055",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "1000000000000000000",
"data" : "",
"gasPrice" : "100000000000000",
"gas" : "10000"
}
},
"jumpDynamicJumpSameDest": { "jumpDynamicJumpSameDest": {
"env" : { "env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",

238
test/vmSha3TestFiller.json

@ -201,13 +201,13 @@
"currentNumber" : "0", "currentNumber" : "0",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentDifficulty" : "256", "currentDifficulty" : "256",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
}, },
"pre" : { "pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : 0, "nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)}", "code" : "{ [[ 0 ]] (SHA3 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)}",
"storage": {} "storage": {}
} }
@ -229,13 +229,13 @@
"currentNumber" : "0", "currentNumber" : "0",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentDifficulty" : "256", "currentDifficulty" : "256",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
}, },
"pre" : { "pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : 0, "nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 2)}", "code" : "{ [[ 0 ]] (SHA3 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 2)}",
"storage": {} "storage": {}
} }
@ -257,13 +257,13 @@
"currentNumber" : "0", "currentNumber" : "0",
"currentGasLimit" : "1000000", "currentGasLimit" : "1000000",
"currentDifficulty" : "256", "currentDifficulty" : "256",
"currentTimestamp" : 1, "currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
}, },
"pre" : { "pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : 0, "nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 0x1000000 2)}", "code" : "{ [[ 0 ]] (SHA3 0x1000000 2)}",
"storage": {} "storage": {}
} }
@ -277,5 +277,229 @@
"gasPrice" : "1", "gasPrice" : "1",
"gas" : "0x100000000" "gas" : "0x100000000"
} }
} },
"sha3_memSizeNoQuadraticCost31": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 960 1)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost32": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 992 1)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost32_zeroSize": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 1024 0)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost33": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 1024 1)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost63": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 1984 1)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost64": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 2016 1)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost64_2": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 2016 32)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
"sha3_memSizeQuadraticCost65": {
"env" : {
"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6",
"currentNumber" : "0",
"currentGasLimit" : "1000000",
"currentDifficulty" : "256",
"currentTimestamp" : "1",
"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
},
"pre" : {
"0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
"balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"nonce" : "0",
"code" : "{ [[ 0 ]] (SHA3 2048 1)}",
"storage": {}
}
},
"exec" : {
"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
"origin" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"caller" : "cd1722f3947def4cf144679da39c4c32bdc35681",
"value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"data" : "",
"gasPrice" : "1",
"gas" : "0x100000000"
}
},
} }

Loading…
Cancel
Save