From 307e42a6c30148dde6d3be474b1960282f4e48b2 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 17 Feb 2015 16:19:11 +0100 Subject: [PATCH 1/6] getMemberTypes() respects source order --- libsolidity/Types.cpp | 32 ++++++++++++++++---------------- libsolidity/Types.h | 8 +++++--- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index d2f0e9bfd..a9c480176 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -573,19 +573,19 @@ MemberList const& ContractType::getMembers() const if (!m_members) { // All address members and all interface functions - map members(IntegerType::AddressMemberList.begin(), - IntegerType::AddressMemberList.end()); + vector> members(IntegerType::AddressMemberList.begin(), + IntegerType::AddressMemberList.end()); if (m_super) { for (ContractDefinition const* base: m_contract.getLinearizedBaseContracts()) for (ASTPointer const& function: base->getDefinedFunctions()) - if (!function->isConstructor() && !function->getName().empty() && + if (!function->isConstructor() && !function->getName().empty()&& function->isVisibleInDerivedContracts()) - members.insert(make_pair(function->getName(), make_shared(*function, true))); + members.push_back(make_pair(function->getName(), make_shared(*function, true))); } else for (auto const& it: m_contract.getInterfaceFunctions()) - members[it.second->getDeclaration().getName()] = it.second; + members.push_back(make_pair(it.second->getDeclaration().getName(), it.second)); m_members.reset(new MemberList(members)); } return *m_members; @@ -653,9 +653,9 @@ MemberList const& StructType::getMembers() const // We need to lazy-initialize it because of recursive references. if (!m_members) { - map members; + vector> members; for (ASTPointer const& variable: m_struct.getMembers()) - members[variable->getName()] = variable->getType(); + members.push_back(make_pair(variable->getName(), variable->getType())); m_members.reset(new MemberList(members)); } return *m_members; @@ -857,15 +857,15 @@ MemberList const& FunctionType::getMembers() const case Location::Bare: if (!m_members) { - map members{ - {"gas", make_shared(parseElementaryTypeVector({"uint"}), - TypePointers{copyAndSetGasOrValue(true, false)}, - Location::SetGas, false, m_gasSet, m_valueSet)}, + vector> members{ {"value", make_shared(parseElementaryTypeVector({"uint"}), TypePointers{copyAndSetGasOrValue(false, true)}, Location::SetValue, false, m_gasSet, m_valueSet)}}; - if (m_location == Location::Creation) - members.erase("gas"); + if (m_location != Location::Creation) + members.push_back(make_pair("gas", make_shared( + parseElementaryTypeVector({"uint"}), + TypePointers{copyAndSetGasOrValue(true, false)}, + Location::SetGas, false, m_gasSet, m_valueSet))); m_members.reset(new MemberList(members)); } return *m_members; @@ -959,7 +959,7 @@ MemberList const& TypeType::getMembers() const // We need to lazy-initialize it because of recursive references. if (!m_members) { - map members; + vector> members; if (m_actualType->getCategory() == Category::Contract && m_currentContract != nullptr) { ContractDefinition const& contract = dynamic_cast(*m_actualType).getContractDefinition(); @@ -969,14 +969,14 @@ MemberList const& TypeType::getMembers() const // functions. Note that this does not add inherited functions on purpose. for (ASTPointer const& f: contract.getDefinedFunctions()) if (!f->isConstructor() && !f->getName().empty() && f->isVisibleInDerivedContracts()) - members[f->getName()] = make_shared(*f); + members.push_back(make_pair(f->getName(), make_shared(*f))); } else if (m_actualType->getCategory() == Category::Enum) { EnumDefinition const& enumDef = dynamic_cast(*m_actualType).getEnumDefinition(); auto enumType = make_shared(enumDef); for (ASTPointer const& enumValue: enumDef.getMembers()) - members.insert(make_pair(enumValue->getName(), enumType)); + members.push_back(make_pair(enumValue->getName(), enumType)); } m_members.reset(new MemberList(members)); } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index b66857f0c..d529d8d08 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -50,14 +50,16 @@ using TypePointers = std::vector; class MemberList { public: - using MemberMap = std::map; + using MemberMap = std::vector>; MemberList() {} explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {} TypePointer getMemberType(std::string const& _name) const { - auto it = m_memberTypes.find(_name); - return it != m_memberTypes.end() ? it->second : TypePointer(); + for (auto const& it: m_memberTypes) + if (it.first == _name) + return it.second; + return TypePointer(); } MemberMap::const_iterator begin() const { return m_memberTypes.begin(); } From 05938330e6b5295ae5fe11bc7fabac257a718da2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 17 Feb 2015 23:01:46 +0100 Subject: [PATCH 2/6] Style fix. --- alethzero/Transact.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index 3031232c2..bfeb41d9a 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -169,9 +169,7 @@ void Transact::rejigData() QString lll; QString solidity; if (src.find_first_not_of("1234567890abcdefABCDEF") == string::npos && src.size() % 2 == 0) - { m_data = fromHex(src); - } else if (sourceIsSolidity(src)) { dev::solidity::CompilerStack compiler; From c1572ea90bff2d03122af2753260d2ee30b4824f Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 18 Feb 2015 00:15:08 +0100 Subject: [PATCH 3/6] Fixes for assigning and deleting structs containing byte arrays. --- libsolidity/CompilerContext.h | 1 + libsolidity/ExpressionCompiler.cpp | 25 ++++++++++++++++++++- libsolidity/ExpressionCompiler.h | 2 +- test/SolidityEndToEndTest.cpp | 36 ++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 6d6a65b61..f202d7f4e 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -48,6 +48,7 @@ public: bytes const& getCompiledContract(ContractDefinition const& _contract) const; void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } + unsigned getStackHeight() { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); } bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration) != 0; } bool isLocalVariable(Declaration const* _declaration) const; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 3bf1c8c93..a8bc53e0f 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1119,9 +1119,13 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co { solAssert(_sourceType.getCategory() == m_dataType->getCategory(), ""); if (m_dataType->getCategory() == Type::Category::ByteArray) + { CompilerUtils(*m_context).copyByteArrayToStorage( dynamic_cast(*m_dataType), dynamic_cast(_sourceType)); + if (_move) + *m_context << eth::Instruction::POP; + } else if (m_dataType->getCategory() == Type::Category::Struct) { // stack layout: source_ref target_ref @@ -1136,12 +1140,14 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co *m_context << structType.getStorageOffsetOfMember(member.first) << eth::Instruction::DUP3 << eth::Instruction::DUP2 << eth::Instruction::ADD; + // stack: source_ref target_ref member_offset source_member_ref LValue rightHandSide(*m_context, LValueType::Storage, memberType); rightHandSide.retrieveValue(_location, true); - // stack: source_ref target_ref offset source_value... + // stack: source_ref target_ref member_offset source_value... *m_context << eth::dupInstruction(2 + memberType->getSizeOnStack()) << eth::dupInstruction(2 + memberType->getSizeOnStack()) << eth::Instruction::ADD; + // stack: source_ref target_ref member_offset source_value... target_member_ref LValue memberLValue(*m_context, LValueType::Storage, memberType); memberLValue.storeValue(*memberType, _location, true); *m_context << eth::Instruction::POP; @@ -1189,6 +1195,23 @@ void ExpressionCompiler::LValue::setToZero(Location const& _location) const case LValueType::Storage: if (m_dataType->getCategory() == Type::Category::ByteArray) CompilerUtils(*m_context).clearByteArray(dynamic_cast(*m_dataType)); + else if (m_dataType->getCategory() == Type::Category::Struct) + { + // stack layout: ref + auto const& structType = dynamic_cast(*m_dataType); + for (auto const& member: structType.getMembers()) + { + // zero each member that is not a mapping + TypePointer const& memberType = member.second; + if (memberType->getCategory() == Type::Category::Mapping) + continue; + *m_context << structType.getStorageOffsetOfMember(member.first) + << eth::Instruction::DUP2 << eth::Instruction::ADD; + LValue memberValue(*m_context, LValueType::Storage, memberType); + memberValue.setToZero(); + } + *m_context << eth::Instruction::POP; + } else { if (m_size == 0) diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 734da50de..471d81865 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -144,7 +144,7 @@ private: void retrieveValue(Location const& _location, bool _remove = false) const; /// Moves a value from the stack to the lvalue. Removes the value if @a _move is true. /// @a _location is the source location of the expression that caused this operation. - /// Stack pre: [lvalue_ref] value + /// Stack pre: value [lvalue_ref] /// Stack post if !_move: value_of(lvalue_ref) void storeValue(Type const& _sourceType, Location const& _location = Location(), bool _move = false) const; /// Stores zero in the lvalue. diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 103b11269..8c87db2d8 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2479,6 +2479,42 @@ BOOST_AUTO_TEST_CASE(struct_copy) BOOST_CHECK(callContractFunction("retrieve(uint256)", 8) == encodeArgs(0, 0, 0, 0)); } +BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete) +{ + char const* sourceCode = R"( + contract c { + struct Struct { uint a; bytes data; uint b; } + Struct data1; + Struct data2; + function set(uint _a, bytes _data, uint _b) external returns (bool) { + data1.a = _a; + data1.b = _b; + data1.data = _data; + return true; + } + function copy() returns (bool) { + data1 = data2; + return true; + } + function del() returns (bool) { + delete data1; + return true; + } + } + )"; + compileAndRun(sourceCode); + string data = "123456789012345678901234567890123"; + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", u256(data.length()), 12, data, 13) == encodeArgs(true)); + BOOST_CHECK(!m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("copy()") == encodeArgs(true)); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", u256(data.length()), 12, data, 13) == encodeArgs(true)); + BOOST_CHECK(!m_state.storage(m_contractAddress).empty()); + BOOST_CHECK(callContractFunction("del()") == encodeArgs(true)); + BOOST_CHECK(m_state.storage(m_contractAddress).empty()); +} + BOOST_AUTO_TEST_CASE(struct_copy_via_local) { char const* sourceCode = R"( From 27d436a04cd35a11de1345e4af045853d626b38b Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 18 Feb 2015 13:35:12 +0100 Subject: [PATCH 4/6] Rename "protected" to "inheritable". --- libsolidity/AST.h | 6 +++--- libsolidity/Parser.cpp | 4 ++-- libsolidity/Token.h | 4 ++-- libsolidity/grammar.txt | 4 ++-- test/SolidityNameAndTypeResolution.cpp | 12 ++++++------ test/SolidityParser.cpp | 6 +++--- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index af45934f7..62855bc7a 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -133,7 +133,7 @@ class Declaration: public ASTNode { public: /// Visibility ordered from restricted to unrestricted. - enum class Visibility { Default, Private, Protected, Public, External }; + enum class Visibility { Default, Private, Inheritable, Public, External }; Declaration(Location const& _location, ASTPointer const& _name, Visibility _visibility = Visibility::Default): @@ -144,7 +144,7 @@ public: Visibility getVisibility() const { return m_visibility == Visibility::Default ? getDefaultVisibility() : m_visibility; } bool isPublic() const { return getVisibility() >= Visibility::Public; } bool isVisibleInContract() const { return getVisibility() != Visibility::External; } - bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Protected; } + bool isVisibleInDerivedContracts() const { return isVisibleInContract() && getVisibility() >= Visibility::Inheritable; } /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope. /// Available only after name and type resolution step. @@ -453,7 +453,7 @@ public: bool isIndexed() const { return m_isIndexed; } protected: - Visibility getDefaultVisibility() const override { return Visibility::Protected; } + Visibility getDefaultVisibility() const override { return Visibility::Inheritable; } private: ASTPointer m_typeName; ///< can be empty ("var") diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index cf57ca50e..72334c6cc 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -186,8 +186,8 @@ Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token) Declaration::Visibility visibility(Declaration::Visibility::Default); if (_token == Token::Public) visibility = Declaration::Visibility::Public; - else if (_token == Token::Protected) - visibility = Declaration::Visibility::Protected; + else if (_token == Token::Inheritable) + visibility = Declaration::Visibility::Inheritable; else if (_token == Token::Private) visibility = Declaration::Visibility::Private; else if (_token == Token::External) diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 7bf8a7ef0..e9765e5eb 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -162,7 +162,7 @@ namespace solidity K(New, "new", 0) \ K(Public, "public", 0) \ K(Private, "private", 0) \ - K(Protected, "protected", 0) \ + K(Inheritable, "inheritable", 0) \ K(Return, "return", 0) \ K(Returns, "returns", 0) \ K(Struct, "struct", 0) \ @@ -380,7 +380,7 @@ public: static bool isCountOp(Value op) { return op == Inc || op == Dec; } static bool isShiftOp(Value op) { return (SHL <= op) && (op <= SHR); } static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; } - static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Protected; } + static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Inheritable; } static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == Token::SubEther; } // Returns a string corresponding to the JS token string diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt index 5e6e65f85..a3b246873 100644 --- a/libsolidity/grammar.txt +++ b/libsolidity/grammar.txt @@ -6,10 +6,10 @@ ContractPart = StateVariableDeclaration | StructDefinition | ModifierDefinition InheritanceSpecifier = Identifier ( '(' Expression ( ',' Expression )* ')' )? StructDefinition = 'struct' Identifier '{' ( VariableDeclaration (';' VariableDeclaration)* )? '} -StateVariableDeclaration = TypeName ( 'public' | 'protected' | 'private' )? Identifier ';' +StateVariableDeclaration = TypeName ( 'public' | 'inheritable' | 'private' )? Identifier ';' ModifierDefinition = 'modifier' Identifier ParameterList? Block FunctionDefinition = 'function' Identifier ParameterList - ( Identifier | 'constant' | 'public' | 'protected' | 'private' )* + ( Identifier | 'constant' | 'external' | 'public' | 'inheritable' | 'private' )* ( 'returns' ParameterList )? Block EnumValue = Identifier diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 6b337ac74..bfef873c4 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -470,7 +470,7 @@ BOOST_AUTO_TEST_CASE(illegal_override_indirect) BOOST_AUTO_TEST_CASE(illegal_override_visibility) { char const* text = R"( - contract B { function f() protected {} } + contract B { function f() inheritable {} } contract C is B { function f() public {} } )"; BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); @@ -706,7 +706,7 @@ BOOST_AUTO_TEST_CASE(private_state_variable) " uint64(2);\n" " }\n" "uint256 private foo;\n" - "uint256 protected bar;\n" + "uint256 inheritable bar;\n" "}\n"; ASTPointer source; @@ -717,7 +717,7 @@ BOOST_AUTO_TEST_CASE(private_state_variable) function = retrieveFunctionBySignature(contract, "foo()"); BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a private variable should not exist"); function = retrieveFunctionBySignature(contract, "bar()"); - BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of a protected variable should not exist"); + BOOST_CHECK_MESSAGE(function == nullptr, "Accessor function of an inheritable variable should not exist"); } BOOST_AUTO_TEST_CASE(fallback_function) @@ -832,11 +832,11 @@ BOOST_AUTO_TEST_CASE(access_to_default_function_visibility) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } -BOOST_AUTO_TEST_CASE(access_to_protected_function) +BOOST_AUTO_TEST_CASE(access_to_inheritable_function) { char const* text = R"( contract c { - function f() protected {} + function f() inheritable {} } contract d { function g() { c(0).f(); } @@ -856,7 +856,7 @@ BOOST_AUTO_TEST_CASE(access_to_default_state_variable_visibility) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } -BOOST_AUTO_TEST_CASE(access_to_protected_state_variable) +BOOST_AUTO_TEST_CASE(access_to_inheritable_state_variable) { char const* text = R"( contract c { diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index 5f9064e0c..ddb582447 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -651,13 +651,13 @@ BOOST_AUTO_TEST_CASE(visibility_specifiers) char const* text = R"( contract c { uint private a; - uint protected b; + uint inheritable b; uint public c; uint d; function f() {} function f_priv() private {} function f_public() public {} - function f_protected() protected {} + function f_inheritable() inheritable {} })"; BOOST_CHECK_NO_THROW(parseText(text)); } @@ -666,7 +666,7 @@ BOOST_AUTO_TEST_CASE(multiple_visibility_specifiers) { char const* text = R"( contract c { - uint private protected a; + uint private inheritable a; })"; BOOST_CHECK_THROW(parseText(text), ParserError); } From 551d7588e1db010cd43497a4575c9a2a5ea37dc8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 18 Feb 2015 14:09:26 +0100 Subject: [PATCH 5/6] Disable SECP256k1 windows warnings. --- secp256k1/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/secp256k1/CMakeLists.txt b/secp256k1/CMakeLists.txt index 8dbe175d5..deafa245a 100644 --- a/secp256k1/CMakeLists.txt +++ b/secp256k1/CMakeLists.txt @@ -31,7 +31,7 @@ else() add_library(${EXECUTABLE} SHARED ${EXECUTABLE}.c) endif() # /TP - compile project as cpp project - set_target_properties(${EXECUTABLE} PROPERTIES COMPILE_FLAGS "/TP") + set_target_properties(${EXECUTABLE} PROPERTIES COMPILE_FLAGS "/TP /wd4244") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_NUM_BOOST -DUSE_FIELD_10X26 -DUSE_FIELD_INV_BUILTIN") endif() From 9dffb5fe937f407776f7189e9907d045d8c85ae4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 18 Feb 2015 15:27:19 +0100 Subject: [PATCH 6/6] Fixes #1088. --- libweb3jsonrpc/WebThreeStubServerBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 7e15ada90..8e0b30366 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -542,7 +542,7 @@ std::string WebThreeStubServerBase::eth_solidity(std::string const& _code) int WebThreeStubServerBase::eth_number() { - return client()->number() + 1; + return client()->number(); } int WebThreeStubServerBase::eth_peerCount()