From 43f269ce9a9114496a7e9a57876aa8a976ff042c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 27 Nov 2014 15:21:22 +0100 Subject: [PATCH 01/22] Solidity function AST nodes get documentation attribute --- libsolidity/AST.h | 20 +++++++++++++------- libsolidity/Parser.cpp | 5 +++-- test/solidityParser.cpp | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 3fb251d95..dc34e3695 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -174,13 +174,17 @@ class FunctionDefinition: public Declaration { public: FunctionDefinition(Location const& _location, ASTPointer const& _name, bool _isPublic, - ASTPointer const& _parameters, - bool _isDeclaredConst, - ASTPointer const& _returnParameters, - ASTPointer const& _body): - Declaration(_location, _name), m_isPublic(_isPublic), m_parameters(_parameters), - m_isDeclaredConst(_isDeclaredConst), m_returnParameters(_returnParameters), - m_body(_body) {} + std::string const& _documentation, + ASTPointer const& _parameters, + bool _isDeclaredConst, + ASTPointer const& _returnParameters, + ASTPointer const& _body): + Declaration(_location, _name), m_isPublic(_isPublic), + m_parameters(_parameters), + m_isDeclaredConst(_isDeclaredConst), + m_returnParameters(_returnParameters), + m_body(_body), + m_documentation(_documentation) {} virtual void accept(ASTVisitor& _visitor) override; bool isPublic() const { return m_isPublic; } @@ -190,6 +194,7 @@ public: std::vector> const& getReturnParameters() const { return m_returnParameters->getParameters(); } ASTPointer const& getReturnParameterList() const { return m_returnParameters; } Block& getBody() { return *m_body; } + std::string& getDocumentation() { return m_documentation; } void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); } std::vector const& getLocalVariables() const { return m_localVariables; } @@ -203,6 +208,7 @@ private: bool m_isDeclaredConst; ASTPointer m_returnParameters; ASTPointer m_body; + std::string m_documentation; std::vector m_localVariables; }; diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 276da0728..3cf44014f 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -142,8 +142,9 @@ ASTPointer Parser::parseFunctionDefinition(bool _isPublic) } ASTPointer block = parseBlock(); nodeFactory.setEndPositionFromNode(block); - return nodeFactory.createNode(name, _isPublic, parameters, - isDeclaredConst, returnParameters, block); + return nodeFactory.createNode(name, _isPublic, m_scanner->getCurrentCommentLiteral(), + parameters, + isDeclaredConst, returnParameters, block); } ASTPointer Parser::parseStructDefinition() diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index 9319a02c5..88a1fd5f0 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -37,13 +37,14 @@ namespace test namespace { -ASTPointer parseText(std::string const& _source) +ASTPointer parseText(std::string const& _source) { Parser parser; return parser.parse(std::make_shared(CharStream(_source))); } } + BOOST_AUTO_TEST_SUITE(SolidityParser) BOOST_AUTO_TEST_CASE(smoke_test) @@ -91,6 +92,36 @@ BOOST_AUTO_TEST_CASE(single_function_param) BOOST_CHECK_NO_THROW(parseText(text)); } +BOOST_AUTO_TEST_CASE(function_natspec_documentation) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " /// This is a test function\n" + " function functionName(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_CHECK_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + BOOST_CHECK_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(function->getDocumentation(), " This is a test function"); +} + +BOOST_AUTO_TEST_CASE(function_normal_comments) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " // We won't see this comment\n" + " function functionName(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_CHECK_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + BOOST_CHECK_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(function->getDocumentation(), ""); +} + BOOST_AUTO_TEST_CASE(struct_definition) { char const* text = "contract test {\n" From 390e2e8634f350b3515aeebb33116c0e4172332b Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 27 Nov 2014 18:24:59 +0100 Subject: [PATCH 02/22] Minor changes to magic variables. gas moves to "msg", ripemd160 returns hash160. --- libsolidity/GlobalContext.cpp | 2 +- libsolidity/Types.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libsolidity/GlobalContext.cpp b/libsolidity/GlobalContext.cpp index e958352fd..d8b637076 100644 --- a/libsolidity/GlobalContext.cpp +++ b/libsolidity/GlobalContext.cpp @@ -58,7 +58,7 @@ GlobalContext::GlobalContext(): FunctionType::Location::ECRECOVER)), make_shared("ripemd160", make_shared(TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), - TypePointers({std::make_shared(256, IntegerType::Modifier::HASH)}), + TypePointers({std::make_shared(160, IntegerType::Modifier::HASH)}), FunctionType::Location::RIPEMD160))} { } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 4ab53bf86..b81fbbe31 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -397,11 +397,11 @@ MagicType::MagicType(MagicType::Kind _kind): break; case Kind::MSG: m_members = MemberList({{"sender", make_shared(0, IntegerType::Modifier::ADDRESS)}, + {"gas", make_shared(256)}, {"value", make_shared(256)}}); break; case Kind::TX: m_members = MemberList({{"origin", make_shared(0, IntegerType::Modifier::ADDRESS)}, - {"gas", make_shared(256)}, {"gasprice", make_shared(256)}}); break; default: From e5da1ba6c6e8eaa6eb46eb0507ff0b348b297128 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 27 Nov 2014 18:57:50 +0100 Subject: [PATCH 03/22] Solidity work for documentation strings - Still a work in progress - Parser now properly gets each function's doc comment - Small changes in the scanner - Multiline comments are considered --- libsolidity/Parser.cpp | 4 +++- libsolidity/Scanner.cpp | 34 +++++++++++++++++++++++---- libsolidity/Scanner.h | 41 ++++++++++++++++++++++++++++---- test/solidityParser.cpp | 52 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 10 deletions(-) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 3cf44014f..17fd2d78c 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -118,6 +118,8 @@ ASTPointer Parser::parseFunctionDefinition(bool _isPublic) { ASTNodeFactory nodeFactory(*this); expectToken(Token::FUNCTION); + std::string docstring = m_scanner->getCurrentCommentLiteral(); + m_scanner->clearCurrentCommentLiteral(); ASTPointer name(expectIdentifierToken()); ASTPointer parameters(parseParameterList()); bool isDeclaredConst = false; @@ -142,7 +144,7 @@ ASTPointer Parser::parseFunctionDefinition(bool _isPublic) } ASTPointer block = parseBlock(); nodeFactory.setEndPositionFromNode(block); - return nodeFactory.createNode(name, _isPublic, m_scanner->getCurrentCommentLiteral(), + return nodeFactory.createNode(name, _isPublic, docstring, parameters, isDeclaredConst, returnParameters, block); } diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index dd18a320f..c40d98af5 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -180,10 +180,26 @@ Token::Value Scanner::skipSingleLineComment() /// For the moment this function simply consumes a single line triple slash doc comment Token::Value Scanner::scanDocumentationComment() { - LiteralScope literal(this); + LiteralScope literal(this, LITERAL_TYPE_COMMENT); advance(); //consume the last '/' - while (!isSourcePastEndOfInput() && !isLineTerminator(m_char)) + while (!isSourcePastEndOfInput()) { + if (isLineTerminator(m_char)) + { + // check if next line is also a documentation comment + skipWhitespace(); + if (m_source.get(0) == '/' && + m_source.get(1) == '/' && + m_source.get(2) == '/' && + !m_source.isPastEndOfInput(3)) + { + m_source.advanceBy(3); + addCommentLiteralChar('\n'); + } + else + break; // next line is not a documentation comment, we are done + + } addCommentLiteralChar(m_char); advance(); } @@ -474,7 +490,7 @@ Token::Value Scanner::scanString() { char const quote = m_char; advance(); // consume quote - LiteralScope literal(this); + LiteralScope literal(this, LITERAL_TYPE_STRING); while (m_char != quote && !isSourcePastEndOfInput() && !isLineTerminator(m_char)) { char c = m_char; @@ -505,7 +521,7 @@ void Scanner::scanDecimalDigits() Token::Value Scanner::scanNumber(char _charSeen) { enum { DECIMAL, HEX, BINARY } kind = DECIMAL; - LiteralScope literal(this); + LiteralScope literal(this, LITERAL_TYPE_NUMBER); if (_charSeen == '.') { // we have already seen a decimal point of the float @@ -758,7 +774,7 @@ Token::Value Scanner::scanIdentifierOrKeyword() { if (asserts(isIdentifierStart(m_char))) BOOST_THROW_EXCEPTION(InternalCompilerError()); - LiteralScope literal(this); + LiteralScope literal(this, LITERAL_TYPE_STRING); addLiteralCharAndAdvance(); // Scan the rest of the identifier characters. while (isIdentifierPart(m_char)) @@ -777,6 +793,14 @@ char CharStream::advanceAndGet() return get(); } +void CharStream::advanceBy(size_t _chars) +{ + if (asserts(!isPastEndOfInput(_chars))) + BOOST_THROW_EXCEPTION(InternalCompilerError()); + + m_pos += _chars; +} + char CharStream::rollback(size_t _amount) { if (asserts(m_pos >= _amount)) diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 957f02b1f..5123ccccc 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -74,9 +74,10 @@ public: CharStream(): m_pos(0) {} explicit CharStream(std::string const& _source): m_source(_source), m_pos(0) {} int getPos() const { return m_pos; } - bool isPastEndOfInput() const { return m_pos >= m_source.size(); } - char get() const { return m_source[m_pos]; } + bool isPastEndOfInput(size_t _charsForward = 0) const { return (m_pos + _charsForward) >= m_source.size(); } + char get(size_t _charsForward = 0) const { return m_source[m_pos + _charsForward]; } char advanceAndGet(); + void advanceBy(size_t _chars); char rollback(size_t _amount); ///@{ @@ -93,19 +94,45 @@ private: }; + class Scanner { public: + + enum LiteralType { + LITERAL_TYPE_STRING, + LITERAL_TYPE_NUMBER, // not really different from string type in behaviour + LITERAL_TYPE_COMMENT + }; /// Scoped helper for literal recording. Automatically drops the literal /// if aborting the scanning before it's complete. class LiteralScope { public: - explicit LiteralScope(Scanner* self): m_scanner(self), m_complete(false) { m_scanner->startNewLiteral(); } - ~LiteralScope() { if (!m_complete) m_scanner->dropLiteral(); } + explicit LiteralScope(Scanner* _self, enum LiteralType _type) + : m_type(_type) + , m_scanner(_self) + , m_complete(false) + { + if (_type == LITERAL_TYPE_COMMENT) + m_scanner->startNewCommentLiteral(); + else + m_scanner->startNewLiteral(); + } + ~LiteralScope() + { + if (!m_complete) + { + if (m_type == LITERAL_TYPE_COMMENT) + m_scanner->dropCommentLiteral(); + else + m_scanner->dropLiteral(); + } + } void complete() { m_complete = true; } private: + enum LiteralType m_type; Scanner* m_scanner; bool m_complete; }; @@ -133,8 +160,12 @@ public: ///@{ ///@name Information about the current comment token + Location getCurrentCommentLocation() const { return m_skippedComment.location; } std::string const& getCurrentCommentLiteral() const { return m_skippedComment.literal; } + /// Called by the parser during FunctionDefinition parsing to clear the current comment + void clearCurrentCommentLiteral() { m_skippedComment.literal.clear(); } + ///@} ///@{ @@ -166,9 +197,11 @@ private: ///@{ ///@name Literal buffer support inline void startNewLiteral() { m_nextToken.literal.clear(); } + inline void startNewCommentLiteral() { m_nextSkippedComment.literal.clear(); } inline void addLiteralChar(char c) { m_nextToken.literal.push_back(c); } inline void addCommentLiteralChar(char c) { m_nextSkippedComment.literal.push_back(c); } inline void dropLiteral() { m_nextToken.literal.clear(); } + inline void dropCommentLiteral() { m_nextSkippedComment.literal.clear(); } inline void addLiteralCharAndAdvance() { addLiteralChar(m_char); advance(); } ///@} diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index 88a1fd5f0..bda820b98 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -122,6 +122,58 @@ BOOST_AUTO_TEST_CASE(function_normal_comments) BOOST_CHECK_EQUAL(function->getDocumentation(), ""); } +BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " /// This is test function 1\n" + " function functionName1(hash hashin) returns (hash hashout) {}\n" + " /// This is test function 2\n" + " function functionName2(hash hashin) returns (hash hashout) {}\n" + " // nothing to see here\n" + " function functionName3(hash hashin) returns (hash hashout) {}\n" + " /// This is test function 4\n" + " function functionName4(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_CHECK_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_CHECK_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 1"); + + BOOST_CHECK_NO_THROW(function = functions.at(1)); + BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 2"); + + BOOST_CHECK_NO_THROW(function = functions.at(2)); + BOOST_CHECK_EQUAL(function->getDocumentation(), ""); + + BOOST_CHECK_NO_THROW(function = functions.at(3)); + BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 4"); +} + +#if 0 /* Work in progress - currently fails*/ +BOOST_AUTO_TEST_CASE(multiline_function_documentation) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " /// This is a test function\n" + " /// and it has 2 lines\n" + " function functionName1(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_CHECK_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_CHECK_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(function->getDocumentation(), + " This is a test function\n" + " and it has 2 lines"); +} +#endif + BOOST_AUTO_TEST_CASE(struct_definition) { char const* text = "contract test {\n" From 170ff1a07f8f4926afc53ad862b5ba8e6ab356d4 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 28 Nov 2014 00:06:38 +0100 Subject: [PATCH 04/22] Fixing multiline comment parsing in solidity --- libsolidity/Scanner.cpp | 6 ++++-- libsolidity/Scanner.h | 2 +- test/solidityParser.cpp | 2 -- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index c40d98af5..4da9874a2 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -193,8 +193,8 @@ Token::Value Scanner::scanDocumentationComment() m_source.get(2) == '/' && !m_source.isPastEndOfInput(3)) { - m_source.advanceBy(3); addCommentLiteralChar('\n'); + m_char = m_source.advanceBy(3); } else break; // next line is not a documentation comment, we are done @@ -793,12 +793,14 @@ char CharStream::advanceAndGet() return get(); } -void CharStream::advanceBy(size_t _chars) +char CharStream::advanceBy(size_t _chars) { if (asserts(!isPastEndOfInput(_chars))) BOOST_THROW_EXCEPTION(InternalCompilerError()); m_pos += _chars; + + return m_source[m_pos]; } char CharStream::rollback(size_t _amount) diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 5123ccccc..edec344ac 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -77,7 +77,7 @@ public: bool isPastEndOfInput(size_t _charsForward = 0) const { return (m_pos + _charsForward) >= m_source.size(); } char get(size_t _charsForward = 0) const { return m_source[m_pos + _charsForward]; } char advanceAndGet(); - void advanceBy(size_t _chars); + char advanceBy(size_t _chars); char rollback(size_t _amount); ///@{ diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index bda820b98..e05b88580 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -153,7 +153,6 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 4"); } -#if 0 /* Work in progress - currently fails*/ BOOST_AUTO_TEST_CASE(multiline_function_documentation) { ASTPointer contract; @@ -172,7 +171,6 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation) " This is a test function\n" " and it has 2 lines"); } -#endif BOOST_AUTO_TEST_CASE(struct_definition) { From 3e42b5ff0d5d61348472f6fb076b6960d1c0ea83 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 28 Nov 2014 00:40:00 +0100 Subject: [PATCH 05/22] Adding solidity natspec comment inside function body --- test/solidityParser.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index e05b88580..3a95ec065 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -172,6 +172,36 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation) " and it has 2 lines"); } +BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " /// fun1 description\n" + " function fun1(uint256 a) {\n" + " var b;\n" + " /// I should not interfere with actual natspec comments\n" + " uint256 c;\n" + " mapping(address=>hash) d;\n" + " string name = \"Solidity\";" + " }\n" + " uint256 stateVar;\n" + " /// This is a test function\n" + " /// and it has 2 lines\n" + " function fun(hash hashin) returns (hash hashout) {}\n" + "}\n"; + BOOST_CHECK_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_CHECK_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(function->getDocumentation(), " fun1 description"); + + BOOST_CHECK_NO_THROW(function = functions.at(1)); + BOOST_CHECK_EQUAL(function->getDocumentation(), + " This is a test function\n" + " and it has 2 lines"); +} + BOOST_AUTO_TEST_CASE(struct_definition) { char const* text = "contract test {\n" From 4bb7cc9f676fe3a3876c667630f27cd25a97362c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 28 Nov 2014 01:26:37 +0100 Subject: [PATCH 06/22] Solidity FunctionDefinition used ASTString shared ptr for docstrings --- libsolidity/AST.h | 15 ++++++++++----- libsolidity/Parser.cpp | 8 ++++++-- test/solidityParser.cpp | 20 +++++++++++--------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index dc34e3695..81a12ad1a 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -173,8 +173,9 @@ private: class FunctionDefinition: public Declaration { public: - FunctionDefinition(Location const& _location, ASTPointer const& _name, bool _isPublic, - std::string const& _documentation, + FunctionDefinition(Location const& _location, ASTPointer const& _name, + bool _isPublic, + ASTPointer const& _documentation, ASTPointer const& _parameters, bool _isDeclaredConst, ASTPointer const& _returnParameters, @@ -184,7 +185,9 @@ public: m_isDeclaredConst(_isDeclaredConst), m_returnParameters(_returnParameters), m_body(_body), - m_documentation(_documentation) {} + m_documentation(_documentation) + {} + virtual void accept(ASTVisitor& _visitor) override; bool isPublic() const { return m_isPublic; } @@ -194,7 +197,9 @@ public: std::vector> const& getReturnParameters() const { return m_returnParameters->getParameters(); } ASTPointer const& getReturnParameterList() const { return m_returnParameters; } Block& getBody() { return *m_body; } - std::string& getDocumentation() { return m_documentation; } + /// @return A shared pointer of an ASTString. + /// Can contain a nullptr in which case indicates absence of documentation + ASTPointer const& getDocumentation() { return m_documentation; } void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); } std::vector const& getLocalVariables() const { return m_localVariables; } @@ -208,7 +213,7 @@ private: bool m_isDeclaredConst; ASTPointer m_returnParameters; ASTPointer m_body; - std::string m_documentation; + ASTPointer m_documentation; std::vector m_localVariables; }; diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 17fd2d78c..72921623a 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -117,9 +117,13 @@ ASTPointer Parser::parseContractDefinition() ASTPointer Parser::parseFunctionDefinition(bool _isPublic) { ASTNodeFactory nodeFactory(*this); + ASTPointer docstring; expectToken(Token::FUNCTION); - std::string docstring = m_scanner->getCurrentCommentLiteral(); - m_scanner->clearCurrentCommentLiteral(); + if (m_scanner->getCurrentCommentLiteral() != "") + { + docstring = std::make_shared(m_scanner->getCurrentCommentLiteral()); + m_scanner->clearCurrentCommentLiteral(); + } ASTPointer name(expectIdentifierToken()); ASTPointer parameters(parseParameterList()); bool isDeclaredConst = false; diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index 3a95ec065..89ef0ac0f 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation) BOOST_CHECK_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(function->getDocumentation(), " This is a test function"); + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is a test function"); } BOOST_AUTO_TEST_CASE(function_normal_comments) @@ -119,7 +119,8 @@ BOOST_AUTO_TEST_CASE(function_normal_comments) BOOST_CHECK_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(function->getDocumentation(), ""); + BOOST_CHECK_MESSAGE(function->getDocumentation().get() == nullptr, + "Should not have gotten a Natspect comment for this function"); } BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) @@ -141,16 +142,17 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) auto functions = contract->getDefinedFunctions(); BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 1"); + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is test function 1"); BOOST_CHECK_NO_THROW(function = functions.at(1)); - BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 2"); + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is test function 2"); BOOST_CHECK_NO_THROW(function = functions.at(2)); - BOOST_CHECK_EQUAL(function->getDocumentation(), ""); + BOOST_CHECK_MESSAGE(function->getDocumentation().get() == nullptr, + "Should not have gotten natspec comment for functionName3()"); BOOST_CHECK_NO_THROW(function = functions.at(3)); - BOOST_CHECK_EQUAL(function->getDocumentation(), " This is test function 4"); + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is test function 4"); } BOOST_AUTO_TEST_CASE(multiline_function_documentation) @@ -167,7 +169,7 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation) auto functions = contract->getDefinedFunctions(); BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(function->getDocumentation(), + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is a test function\n" " and it has 2 lines"); } @@ -194,10 +196,10 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) auto functions = contract->getDefinedFunctions(); BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(function->getDocumentation(), " fun1 description"); + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " fun1 description"); BOOST_CHECK_NO_THROW(function = functions.at(1)); - BOOST_CHECK_EQUAL(function->getDocumentation(), + BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is a test function\n" " and it has 2 lines"); } From 7ac651726f41bef005f163d21a862474a6518ca5 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 28 Nov 2014 11:17:18 +0100 Subject: [PATCH 07/22] Solidity natspec docstring test improvements - Adding a test for docstring being between function signature and function body - Properly checking for exceptions in parsing - Small parser fix --- libsolidity/Parser.cpp | 2 +- libsolidity/Scanner.h | 3 +- test/solidityParser.cpp | 70 +++++++++++++++++++++++++++-------------- 3 files changed, 49 insertions(+), 26 deletions(-) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 72921623a..9ed081cce 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -118,12 +118,12 @@ ASTPointer Parser::parseFunctionDefinition(bool _isPublic) { ASTNodeFactory nodeFactory(*this); ASTPointer docstring; - expectToken(Token::FUNCTION); if (m_scanner->getCurrentCommentLiteral() != "") { docstring = std::make_shared(m_scanner->getCurrentCommentLiteral()); m_scanner->clearCurrentCommentLiteral(); } + expectToken(Token::FUNCTION); ASTPointer name(expectIdentifierToken()); ASTPointer parameters(parseParameterList()); bool isDeclaredConst = false; diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index edec344ac..702310102 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -109,8 +109,7 @@ public: class LiteralScope { public: - explicit LiteralScope(Scanner* _self, enum LiteralType _type) - : m_type(_type) + explicit LiteralScope(Scanner* _self, enum LiteralType _type): m_type(_type) , m_scanner(_self) , m_complete(false) { diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index 89ef0ac0f..e4db2ece7 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -101,10 +101,10 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation) " /// This is a test function\n" " function functionName(hash hashin) returns (hash hashout) {}\n" "}\n"; - BOOST_CHECK_NO_THROW(contract = parseText(text)); + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); - BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is a test function"); + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is a test function"); } BOOST_AUTO_TEST_CASE(function_normal_comments) @@ -116,10 +116,10 @@ BOOST_AUTO_TEST_CASE(function_normal_comments) " // We won't see this comment\n" " function functionName(hash hashin) returns (hash hashout) {}\n" "}\n"; - BOOST_CHECK_NO_THROW(contract = parseText(text)); + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); - BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_MESSAGE(function->getDocumentation().get() == nullptr, + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr, "Should not have gotten a Natspect comment for this function"); } @@ -138,21 +138,21 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation) " /// This is test function 4\n" " function functionName4(hash hashin) returns (hash hashout) {}\n" "}\n"; - BOOST_CHECK_NO_THROW(contract = parseText(text)); + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); - BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is test function 1"); + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 1"); - BOOST_CHECK_NO_THROW(function = functions.at(1)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is test function 2"); + BOOST_REQUIRE_NO_THROW(function = functions.at(1)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 2"); - BOOST_CHECK_NO_THROW(function = functions.at(2)); - BOOST_CHECK_MESSAGE(function->getDocumentation().get() == nullptr, + BOOST_REQUIRE_NO_THROW(function = functions.at(2)); + BOOST_CHECK_MESSAGE(function->getDocumentation() == nullptr, "Should not have gotten natspec comment for functionName3()"); - BOOST_CHECK_NO_THROW(function = functions.at(3)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " This is test function 4"); + BOOST_REQUIRE_NO_THROW(function = functions.at(3)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is test function 4"); } BOOST_AUTO_TEST_CASE(multiline_function_documentation) @@ -165,11 +165,11 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation) " /// and it has 2 lines\n" " function functionName1(hash hashin) returns (hash hashout) {}\n" "}\n"; - BOOST_CHECK_NO_THROW(contract = parseText(text)); + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); - BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is a test function\n" " and it has 2 lines"); } @@ -192,18 +192,42 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) " /// and it has 2 lines\n" " function fun(hash hashin) returns (hash hashout) {}\n" "}\n"; - BOOST_CHECK_NO_THROW(contract = parseText(text)); + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); auto functions = contract->getDefinedFunctions(); - BOOST_CHECK_NO_THROW(function = functions.at(0)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), " fun1 description"); + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " fun1 description"); - BOOST_CHECK_NO_THROW(function = functions.at(1)); - BOOST_CHECK_EQUAL(*function->getDocumentation().get(), + BOOST_REQUIRE_NO_THROW(function = functions.at(1)); + BOOST_CHECK_EQUAL(*function->getDocumentation(), " This is a test function\n" " and it has 2 lines"); } +BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " function fun1(uint256 a) {\n" + " /// I should have been above the function signature" + " {\n" + " var b;\n" + " /// I should not interfere with actual natspec comments\n" + " uint256 c;\n" + " mapping(address=>hash) d;\n" + " string name = \"Solidity\";" + " }\n" + "}\n"; + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_MESSAGE(!function->getDocumentation(), + "Shouldn't get natspec docstring for this function"); +} + BOOST_AUTO_TEST_CASE(struct_definition) { char const* text = "contract test {\n" From 0238863bfcd13ad98caf87e9fd2aabcdcabeda9d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Nov 2014 12:44:57 +0100 Subject: [PATCH 08/22] Avoid 20ms sleep time in Whisper. --- libwhisper/WhisperHost.cpp | 6 ++++++ libwhisper/WhisperHost.h | 9 ++++++++- libwhisper/WhisperPeer.cpp | 14 +++++++++----- libwhisper/WhisperPeer.h | 2 ++ 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 0fb7a206c..9b26e3260 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -156,6 +156,12 @@ void WhisperHost::uninstallWatch(unsigned _i) m_filters.erase(fit); } +void WhisperHost::doWork() +{ + for (auto& i: peers()) + i->cap()->sendMessages(); +} + void WhisperHost::cleanup() { // remove old messages. diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 91934dd98..b38964f8e 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include "Common.h" @@ -38,7 +39,7 @@ namespace dev namespace shh { -class WhisperHost: public HostCapability, public Interface +class WhisperHost: public HostCapability, public Interface, public Worker { friend class WhisperPeer; @@ -64,7 +65,13 @@ public: void cleanup(); +protected: + void doWork(); + private: + virtual void onStarting() { startWorking(); } + virtual void onStopping() { stopWorking(); } + void streamMessage(h256 _m, RLPStream& _s) const; void noteChanged(h256 _messageHash, h256 _filter); diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index 56f4e456e..c3a28e3c3 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -72,7 +72,6 @@ bool WhisperPeer::interpret(unsigned _id, RLP const& _r) for (auto i: _r) if (n++) host()->inject(Envelope(i), this); - sendMessages(); break; } default: @@ -97,10 +96,15 @@ void WhisperPeer::sendMessages() } } - if (!n) - // pause for a bit if no messages to send - this is horrible and broken. - // the message subsystem should really just keep pumping out messages while m_unseen.size() and there's bandwidth for them. - this_thread::sleep_for(chrono::milliseconds(20)); + // the message subsystem should really just keep pumping out messages while m_unseen.size() and there's bandwidth for them. + auto diff = chrono::duration_cast(chrono::system_clock::now() - m_timer); + if (n || diff.count() > 0) + { + RLPStream s; + prep(s, MessagesPacket, n).appendRaw(amalg.out(), n); + sealAndSend(s); + m_timer = chrono::system_clock::now(); + } { RLPStream s; diff --git a/libwhisper/WhisperPeer.h b/libwhisper/WhisperPeer.h index f60de8f01..faac2d870 100644 --- a/libwhisper/WhisperPeer.h +++ b/libwhisper/WhisperPeer.h @@ -68,6 +68,8 @@ private: mutable dev::Mutex x_unseen; std::map m_unseen; ///< Rated according to what they want. + + std::chrono::system_clock::time_point m_timer = std::chrono::system_clock::now(); }; } From fa78d8bb9acba0f1fa0559a36191a0a80c0deb6b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Nov 2014 13:14:56 +0100 Subject: [PATCH 09/22] Remove minGasPrice --- alethzero/MainWin.cpp | 1 - eth/main.cpp | 6 +----- libethcore/BlockInfo.cpp | 18 +++++++----------- libethcore/BlockInfo.h | 4 +--- libethcore/CommonEth.cpp | 2 +- libethereum/BlockChain.cpp | 4 ++-- libethereum/Executive.cpp | 7 ------- libethereum/State.cpp | 1 - libweb3jsonrpc/WebThreeStubServer.cpp | 1 - neth/main.cpp | 12 ++++-------- 10 files changed, 16 insertions(+), 40 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e5506a660..d4a122732 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1259,7 +1259,6 @@ void Main::on_blocks_currentItemChanged() s << "
D/TD: 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << ""; s << "   Children: " << details.children.size() << ""; s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << ""; - s << "   Minimum gas price: " << formatBalance(info.minGasPrice) << ""; s << "
Coinbase: " << pretty(info.coinbaseAddress).toHtmlEscaped().toStdString() << " " << info.coinbaseAddress; s << "
Nonce: " << info.nonce << ""; s << "
Parent: " << info.parentHash << ""; diff --git a/eth/main.cpp b/eth/main.cpp index 408654018..be1a4ae65 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -498,8 +498,6 @@ int main(int argc, char** argv) if (size > 0) cwarn << "Invalid address length:" << size; } - else if (gasPrice < info.minGasPrice) - cwarn << "Minimum gas price is" << info.minGasPrice; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else if (ssize < 40) @@ -561,7 +559,7 @@ int main(int argc, char** argv) BlockInfo info(blockData); u256 minGas = (u256)Client::txGas(0, 0); Address dest = h160(fromHex(hexAddr)); - c->transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice); + c->transact(us.secret(), amount, dest, bytes(), minGas); } } else @@ -601,8 +599,6 @@ int main(int argc, char** argv) u256 minGas = (u256)Client::txGas(init.size(), 0); if (endowment < 0) cwarn << "Invalid endowment"; - else if (gasPrice < info.minGasPrice) - cwarn << "Minimum gas price is" << info.minGasPrice; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 44da9603c..015f8dad6 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -58,9 +58,9 @@ h256 BlockInfo::headerHashWithoutNonce() const void BlockInfo::streamRLP(RLPStream& _s, bool _nonce) const { - _s.appendList(_nonce ? 15 : 14) + _s.appendList(_nonce ? 14 : 13) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom - << difficulty << number << minGasPrice << gasLimit << gasUsed << timestamp << extraData; + << difficulty << number << gasLimit << gasUsed << timestamp << extraData; if (_nonce) _s << nonce; } @@ -86,12 +86,11 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) logBloom = _header[field = 6].toHash(); difficulty = _header[field = 7].toInt(); number = _header[field = 8].toInt(); - minGasPrice = _header[field = 9].toInt(); - gasLimit = _header[field = 10].toInt(); - gasUsed = _header[field = 11].toInt(); - timestamp = _header[field = 12].toInt(); - extraData = _header[field = 13].toBytes(); - nonce = _header[field = 14].toHash(); + gasLimit = _header[field = 9].toInt(); + gasUsed = _header[field = 10].toInt(); + timestamp = _header[field = 11].toInt(); + extraData = _header[field = 12].toBytes(); + nonce = _header[field = 13].toHash(); } catch (Exception const& _e) @@ -147,9 +146,6 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const if (transactionsRoot != t.root()) BOOST_THROW_EXCEPTION(InvalidTransactionsHash(t.root(), transactionsRoot)); - if (minGasPrice > mgp) - BOOST_THROW_EXCEPTION(InvalidMinGasPrice(minGasPrice, mgp)); - if (sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index d91ff244d..aa7456f72 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -66,7 +66,6 @@ public: h512 logBloom; // TODO LogBloom - get include u256 difficulty; u256 number; - u256 minGasPrice; u256 gasLimit; u256 gasUsed; u256 timestamp; @@ -95,7 +94,6 @@ public: logBloom == _cmp.logBloom && difficulty == _cmp.difficulty && number == _cmp.number && - minGasPrice == _cmp.minGasPrice && gasLimit == _cmp.gasLimit && gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && @@ -122,7 +120,7 @@ public: inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { _out << _bi.hash << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << - _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.minGasPrice << " " << _bi.gasLimit << " " << + _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp << " " << _bi.nonce; return _out; } diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index c12c71774..610d141ed 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -33,7 +33,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 44; +const unsigned c_protocolVersion = 45; const unsigned c_databaseVersion = 4; static const vector> g_units = diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 765b54627..264cdbd57 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -101,9 +101,9 @@ bytes BlockChain::createGenesisBlock() stateRoot = state.root(); } - block.appendList(15) + block.appendList(14) // TODO: maybe make logbloom correct? - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 0 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index c3a8b2a80..ac557e198 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -58,13 +58,6 @@ bool Executive::setup(bytesConstRef _rlp) BOOST_THROW_EXCEPTION(InvalidNonce(nonceReq, m_t.nonce())); } - // Don't like transactions whose gas price is too low. NOTE: this won't stay here forever - it's just until we get a proper gas price discovery protocol going. - if (m_t.gasPrice() < m_s.m_currentBlock.minGasPrice) - { - clog(StateDetail) << "Offered gas-price is too low: Require >" << m_s.m_currentBlock.minGasPrice << " Got" << m_t.gasPrice(); - BOOST_THROW_EXCEPTION(GasPriceTooLow()); - } - // Check gas cost is enough. u256 gasCost = m_t.data().size() * c_txDataGas + c_txGas; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 40327b108..8cd53e912 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -501,7 +501,6 @@ void State::resetCurrent() m_currentBlock.timestamp = time(0); m_currentBlock.transactionsRoot = h256(); m_currentBlock.sha3Uncles = h256(); - m_currentBlock.minGasPrice = 10 * szabo; m_currentBlock.populateFromParent(m_previousBlock); // Update timestamp according to clock. diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 8ee9ee722..7607b7a95 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -51,7 +51,6 @@ static Json::Value toJson(dev::eth::BlockInfo const& _bi) res["transactionsRoot"] = toJS(_bi.transactionsRoot); res["difficulty"] = toJS(_bi.difficulty); res["number"] = (int)_bi.number; - res["minGasPrice"] = toJS(_bi.minGasPrice); res["gasLimit"] = (int)_bi.gasLimit; res["timestamp"] = (int)_bi.timestamp; res["extraData"] = jsFromBinary(_bi.extraData); diff --git a/neth/main.cpp b/neth/main.cpp index 6be555fbb..e3a27c1d8 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -603,7 +603,7 @@ int main(int argc, char** argv) vector l; l.push_back("Amount"); stringstream label; - label << "Gas price (" << info.minGasPrice << ")"; + label << "Gas price"; l.push_back(label.str()); l.push_back("Gas"); vector b; @@ -652,8 +652,6 @@ int main(int argc, char** argv) if (size > 0) cwarn << "Invalid address length:" << size; } - else if (gasPrice < info.minGasPrice) - cwarn << "Minimum gas price is" << info.minGasPrice; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else if (ssize < 40) @@ -704,7 +702,7 @@ int main(int argc, char** argv) BlockInfo info(blockData); u256 minGas = (u256)Client::txGas(0, 0); Address dest = h160(fromHex(fields[0])); - c.transact(us.secret(), amount, dest, bytes(), minGas, info.minGasPrice); + c.transact(us.secret(), amount, dest, bytes(), minGas, 10 * dev::eth::szabo); } } } @@ -718,7 +716,7 @@ int main(int argc, char** argv) vector l; l.push_back("Endowment"); stringstream label; - label << "Gas price (" << info.minGasPrice << ")"; + label << "Gas price"; l.push_back(label.str()); l.push_back("Gas"); vector b; @@ -766,13 +764,11 @@ int main(int argc, char** argv) u256 minGas = (u256)Client::txGas(init.size(), 0); if (endowment < 0) cwarn << "Invalid endowment"; - else if (gasPrice < info.minGasPrice) - cwarn << "Minimum gas price is" << info.minGasPrice; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else { - c.transact(us.secret(), endowment, init, gas, gasPrice); + c.transact(us.secret(), endowment, init, gas, 10 * dev::eth::szabo); } } } From d9bdfe5b4dd7a81d0a37c138cf80ae1b38f6a87e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Nov 2014 14:22:50 +0100 Subject: [PATCH 10/22] Latest PoC-7 changes. --- alethzero/MainWin.cpp | 6 +++--- eth/main.cpp | 6 +++--- libethereum/Executive.cpp | 7 ++++--- libethereum/Interface.h | 2 +- libevm/FeeStructure.cpp | 4 +++- libevm/FeeStructure.h | 4 +++- libevm/VM.h | 5 +++++ neth/main.cpp | 10 +++++----- 8 files changed, 27 insertions(+), 17 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index d4a122732..fc27d6e30 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1664,7 +1664,7 @@ void Main::on_data_textChanged() errs.append("
" + QString::fromStdString(i).toHtmlEscaped() + "
"); } ui->code->setHtml(errs + lll + solidity + "

Code

" + QString::fromStdString(disassemble(m_data)).toHtmlEscaped()); - ui->gas->setMinimum((qint64)Client::txGas(m_data.size(), 0)); + ui->gas->setMinimum((qint64)Client::txGas(m_data, 0)); if (!ui->gas->isEnabled()) ui->gas->setValue(m_backupGas); ui->gas->setEnabled(true); @@ -1675,7 +1675,7 @@ void Main::on_data_textChanged() ui->code->setHtml(QString::fromStdString(dev::memDump(m_data, 8, true))); if (ethereum()->codeAt(fromString(ui->destination->currentText()), 0).size()) { - ui->gas->setMinimum((qint64)Client::txGas(m_data.size(), 1)); + ui->gas->setMinimum((qint64)Client::txGas(m_data, 1)); if (!ui->gas->isEnabled()) ui->gas->setValue(m_backupGas); ui->gas->setEnabled(true); @@ -1684,7 +1684,7 @@ void Main::on_data_textChanged() { if (ui->gas->isEnabled()) m_backupGas = ui->gas->value(); - ui->gas->setValue((qint64)Client::txGas(m_data.size())); + ui->gas->setValue((qint64)Client::txGas(m_data)); ui->gas->setEnabled(false); } } diff --git a/eth/main.cpp b/eth/main.cpp index be1a4ae65..9b63e0643 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -492,7 +492,7 @@ int main(int argc, char** argv) cnote << ssbd.str(); int ssize = sechex.length(); int size = hexAddr.length(); - u256 minGas = (u256)Client::txGas(data.size(), 0); + u256 minGas = (u256)Client::txGas(data, 0); if (size < 40) { if (size > 0) @@ -557,7 +557,7 @@ int main(int argc, char** argv) auto h = bc.currentHash(); auto blockData = bc.block(h); BlockInfo info(blockData); - u256 minGas = (u256)Client::txGas(0, 0); + u256 minGas = (u256)Client::txGas(bytes(), 0); Address dest = h160(fromHex(hexAddr)); c->transact(us.secret(), amount, dest, bytes(), minGas); } @@ -596,7 +596,7 @@ int main(int argc, char** argv) cnote << "Init:"; cnote << ssc.str(); } - u256 minGas = (u256)Client::txGas(init.size(), 0); + u256 minGas = (u256)Client::txGas(init, 0); if (endowment < 0) cwarn << "Invalid endowment"; else if (gas < minGas) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index ac557e198..6a123875c 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -22,6 +22,7 @@ #include #include #include +#include "Interface.h" #include "Executive.h" #include "State.h" #include "ExtVM.h" @@ -59,7 +60,7 @@ bool Executive::setup(bytesConstRef _rlp) } // Check gas cost is enough. - u256 gasCost = m_t.data().size() * c_txDataGas + c_txGas; + auto gasCost = Interface::txGas(m_t.data()); if (m_t.gas() < gasCost) { @@ -99,9 +100,9 @@ bool Executive::setup(bytesConstRef _rlp) } if (m_t.isCreation()) - return create(m_sender, m_t.value(), m_t.gasPrice(), m_t.gas() - gasCost, &m_t.data(), m_sender); + return create(m_sender, m_t.value(), m_t.gasPrice(), m_t.gas() - (u256)gasCost, &m_t.data(), m_sender); else - return call(m_t.receiveAddress(), m_sender, m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - gasCost, m_sender); + return call(m_t.receiveAddress(), m_sender, m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - (u256)gasCost, m_sender); } bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress) diff --git a/libethereum/Interface.h b/libethereum/Interface.h index add9a1bda..d598e1f9b 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -128,7 +128,7 @@ public: virtual Addresses addresses(int _block) const = 0; /// Get the fee associated for a transaction with the given data. - static u256 txGas(unsigned _dataCount, u256 _gas = 0) { return c_txDataGas * _dataCount + c_txGas + _gas; } + template static bigint txGas(T const& _data, u256 _gas = 0) { bigint ret = c_txGas + _gas; for (auto i: _data) ret += i ? c_txDataNonZeroGas : c_txDataZeroGas; return ret; } /// Get the remaining gas limit in this block. virtual u256 gasLimitRemaining() const = 0; diff --git a/libevm/FeeStructure.cpp b/libevm/FeeStructure.cpp index 6d868cac5..59a5329bc 100644 --- a/libevm/FeeStructure.cpp +++ b/libevm/FeeStructure.cpp @@ -35,8 +35,10 @@ u256 const dev::eth::c_sstoreRefundGas = 100; u256 const dev::eth::c_createGas = 100; u256 const dev::eth::c_callGas = 20; u256 const dev::eth::c_memoryGas = 1; -u256 const dev::eth::c_txDataGas = 5; +u256 const dev::eth::c_txDataZeroGas = 1; +u256 const dev::eth::c_txDataNonZeroGas = 5; u256 const dev::eth::c_txGas = 500; u256 const dev::eth::c_logGas = 32; u256 const dev::eth::c_logDataGas = 1; u256 const dev::eth::c_logTopicGas = 32; +u256 const dev::eth::c_copyGas = 1; diff --git a/libevm/FeeStructure.h b/libevm/FeeStructure.h index e57f7ccf8..4f415da5d 100644 --- a/libevm/FeeStructure.h +++ b/libevm/FeeStructure.h @@ -38,11 +38,13 @@ extern u256 const c_sstoreRefundGas; ///< Refunded gas, once per SSTORE operatio extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction. extern u256 const c_callGas; ///< Once per CALL operation & message call transaction. extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. -extern u256 const c_txDataGas; ///< Per byte of data attached to a transaction. NOTE: Not payable on data of calls between transactions. +extern u256 const c_txDataZeroGas; ///< Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions. +extern u256 const c_txDataNonZeroGas; ///< Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. extern u256 const c_txGas; ///< Per transaction. NOTE: Not payable on data of calls between transactions. extern u256 const c_logGas; ///< Per LOG* operation. extern u256 const c_logDataGas; ///< Per byte in a LOG* operation's data. extern u256 const c_logTopicGas; ///< Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas. +extern u256 const c_copyGas; ///< Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added. } } diff --git a/libevm/VM.h b/libevm/VM.h index 425eab8c8..9d43d7177 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -131,6 +131,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con // FEES... bigint runGas = c_stepGas; bigint newTempSize = m_temp.size(); + bigint copySize = 0; auto onOperation = [&]() { @@ -193,14 +194,17 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con break; case Instruction::CALLDATACOPY: require(3); + copySize = m_stack[m_stack.size() - 3]; newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]); break; case Instruction::CODECOPY: require(3); + copySize = m_stack[m_stack.size() - 3]; newTempSize = memNeed(m_stack.back(), m_stack[m_stack.size() - 3]); break; case Instruction::EXTCODECOPY: require(4); + copySize = m_stack[m_stack.size() - 4]; newTempSize = memNeed(m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 4]); break; @@ -365,6 +369,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con newTempSize = (newTempSize + 31) / 32 * 32; if (newTempSize > m_temp.size()) runGas += c_memoryGas * (newTempSize - m_temp.size()) / 32; + runGas += c_copyGas * (copySize + 31) / 32; onOperation(); // if (_onOp) diff --git a/neth/main.cpp b/neth/main.cpp index e3a27c1d8..cb6d35593 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -646,7 +646,7 @@ int main(int argc, char** argv) ssbd << bbd; cnote << ssbd.str(); int ssize = fields[4].length(); - u256 minGas = (u256)Client::txGas(data.size(), 0); + u256 minGas = (u256)Client::txGas(data, 0); if (size < 40) { if (size > 0) @@ -700,9 +700,9 @@ int main(int argc, char** argv) auto h = bc.currentHash(); auto blockData = bc.block(h); BlockInfo info(blockData); - u256 minGas = (u256)Client::txGas(0, 0); + u256 minGas = (u256)Client::txGas(bytes(), 0); Address dest = h160(fromHex(fields[0])); - c.transact(us.secret(), amount, dest, bytes(), minGas, 10 * dev::eth::szabo); + c.transact(us.secret(), amount, dest, bytes(), minGas); } } } @@ -761,14 +761,14 @@ int main(int argc, char** argv) cnote << "Init:"; cnote << ssc.str(); } - u256 minGas = (u256)Client::txGas(init.size(), 0); + u256 minGas = (u256)Client::txGas(init, 0); if (endowment < 0) cwarn << "Invalid endowment"; else if (gas < minGas) cwarn << "Minimum gas amount is" << minGas; else { - c.transact(us.secret(), endowment, init, gas, 10 * dev::eth::szabo); + c.transact(us.secret(), endowment, init, gas); } } } From 362e5d81450825b019e0f95c3a8f418f1545de5f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Nov 2014 14:28:02 +0100 Subject: [PATCH 11/22] Warning fix. ECDSA recover fix. --- libethereum/State.cpp | 2 +- libsolidity/ExpressionCompiler.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 8cd53e912..9a0426e18 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -54,7 +54,7 @@ void ecrecoverCode(bytesConstRef _in, bytesRef _out) memcpy(&in, _in.data(), min(_in.size(), sizeof(in))); memset(_out.data(), 0, _out.size()); - if (in.v > 28) + if ((u256)in.v > 28) return; SignatureStruct sig{in.r, in.s, (byte)((int)(u256)in.v - 27)}; if (!sig.isValid()) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 4dc377791..c3c7116e4 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -363,7 +363,7 @@ void ExpressionCompiler::endVisit(Identifier& _identifier) m_context << m_context.getFunctionEntryLabel(*functionDef).pushTag(); return; } - if (VariableDeclaration* varDef = dynamic_cast(declaration)) + if (/*VariableDeclaration* varDef = */dynamic_cast(declaration)) { m_currentLValue.fromIdentifier(_identifier, *_identifier.getReferencedDeclaration()); m_currentLValue.retrieveValueIfLValueNotRequested(_identifier); From 6ee69c2141ecdc513612e7194587fa684047f134 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 28 Nov 2014 15:40:01 +0100 Subject: [PATCH 12/22] Version bump. --- libdevcore/Common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index ae073b9b1..280268d8b 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.7.10"; +char const* Version = "0.7.11"; } From c0896891748b4bdb21287947de5ed87d77d2bbf8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 29 Nov 2014 18:31:02 +0100 Subject: [PATCH 13/22] Remove old bloom stuff. Fix genesis. --- libethcore/CommonEth.cpp | 2 +- libethereum/BlockChain.cpp | 19 +------------------ libethereum/BlockChain.h | 12 ------------ libethereum/BlockDetails.h | 22 ---------------------- 4 files changed, 2 insertions(+), 53 deletions(-) diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 610d141ed..010b7e408 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -34,7 +34,7 @@ namespace eth { const unsigned c_protocolVersion = 45; -const unsigned c_databaseVersion = 4; +const unsigned c_databaseVersion = 5; static const vector> g_units = { diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 264cdbd57..531005fb2 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -102,8 +102,7 @@ bytes BlockChain::createGenesisBlock() } block.appendList(14) - // TODO: maybe make logbloom correct? - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 0 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); @@ -169,8 +168,6 @@ void BlockChain::close() delete m_db; m_lastBlockHash = m_genesisHash; m_details.clear(); - m_blooms.clear(); - m_traces.clear(); m_cache.clear(); } @@ -307,14 +304,10 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) State s(bi.coinbaseAddress, _db); auto tdIncrease = s.enactOn(&_block, bi, *this); auto b = s.oldBloom(); - BlockBlooms bb; - BlockTraces bt; BlockLogBlooms blb; BlockReceipts br; for (unsigned i = 0; i < s.pending().size(); ++i) { - bb.blooms.push_back(s.changesFromPending(i).bloom()); - bt.traces.push_back(s.changesFromPending(i)); blb.blooms.push_back(s.receipt(i).bloom()); br.receipts.push_back(s.receipt(i)); } @@ -330,14 +323,6 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) m_details[newHash] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}, b); m_details[bi.parentHash].children.push_back(newHash); } - { - WriteGuard l(x_blooms); - m_blooms[newHash] = bb; - } - { - WriteGuard l(x_traces); - m_traces[newHash] = bt; - } { WriteGuard l(x_logBlooms); m_logBlooms[newHash] = blb; @@ -349,8 +334,6 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) m_extrasDB->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)dev::ref(m_details[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp())); - m_extrasDB->Put(m_writeOptions, toSlice(newHash, 1), (ldb::Slice)dev::ref(m_blooms[newHash].rlp())); - m_extrasDB->Put(m_writeOptions, toSlice(newHash, 2), (ldb::Slice)dev::ref(m_traces[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(newHash, 3), (ldb::Slice)dev::ref(m_logBlooms[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(newHash, 4), (ldb::Slice)dev::ref(m_receipts[newHash].rlp())); m_db->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)ref(_block)); diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 74d94e164..d03818bd3 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -101,14 +101,6 @@ public: BlockDetails details(h256 _hash) const { return queryExtras(_hash, m_details, x_details, NullBlockDetails); } BlockDetails details() const { return details(currentHash()); } - /// Get the transactions' bloom filters of a block (or the most recent mined if none given). Thread-safe. - BlockBlooms blooms(h256 _hash) const { return queryExtras(_hash, m_blooms, x_blooms, NullBlockBlooms); } - BlockBlooms blooms() const { return blooms(currentHash()); } - - /// Get the transactions' trace manifests of a block (or the most recent mined if none given). Thread-safe. - BlockTraces traces(h256 _hash) const { return queryExtras(_hash, m_traces, x_traces, NullBlockTraces); } - BlockTraces traces() const { return traces(currentHash()); } - /// Get the transactions' log blooms of a block (or the most recent mined if none given). Thread-safe. BlockLogBlooms logBlooms(h256 _hash) const { return queryExtras(_hash, m_logBlooms, x_logBlooms, NullBlockLogBlooms); } BlockLogBlooms logBlooms() const { return logBlooms(currentHash()); } @@ -193,10 +185,6 @@ private: /// The caches of the disk DB and their locks. mutable boost::shared_mutex x_details; mutable BlockDetailsHash m_details; - mutable boost::shared_mutex x_blooms; - mutable BlockBloomsHash m_blooms; - mutable boost::shared_mutex x_traces; - mutable BlockTracesHash m_traces; mutable boost::shared_mutex x_logBlooms; mutable BlockLogBloomsHash m_logBlooms; mutable boost::shared_mutex x_receipts; diff --git a/libethereum/BlockDetails.h b/libethereum/BlockDetails.h index 973e93070..0c3af5b33 100644 --- a/libethereum/BlockDetails.h +++ b/libethereum/BlockDetails.h @@ -54,24 +54,6 @@ struct BlockDetails h256 bloom; }; -struct BlockBlooms -{ - BlockBlooms() {} - BlockBlooms(RLP const& _r) { blooms = _r.toVector(); } - bytes rlp() const { RLPStream s; s << blooms; return s.out(); } - - h256s blooms; -}; - -struct BlockTraces -{ - BlockTraces() {} - BlockTraces(RLP const& _r) { for (auto const& i: _r) traces.emplace_back(i.data()); } - bytes rlp() const { RLPStream s(traces.size()); for (auto const& i: traces) i.streamRLP(s); return s.out(); } - - Manifests traces; -}; - struct BlockLogBlooms { BlockLogBlooms() {} @@ -91,14 +73,10 @@ struct BlockReceipts }; typedef std::map BlockDetailsHash; -typedef std::map BlockBloomsHash; -typedef std::map BlockTracesHash; typedef std::map BlockLogBloomsHash; typedef std::map BlockReceiptsHash; static const BlockDetails NullBlockDetails; -static const BlockBlooms NullBlockBlooms; -static const BlockTraces NullBlockTraces; static const BlockLogBlooms NullBlockLogBlooms; static const BlockReceipts NullBlockReceipts; From eccdf006ea8646986f982aec0e4ba658592726db Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 29 Nov 2014 20:31:44 +0100 Subject: [PATCH 14/22] Variable EXP gas cost. --- libevm/FeeStructure.cpp | 2 ++ libevm/FeeStructure.h | 2 ++ libevm/VM.h | 8 +++++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libevm/FeeStructure.cpp b/libevm/FeeStructure.cpp index 59a5329bc..3e957118e 100644 --- a/libevm/FeeStructure.cpp +++ b/libevm/FeeStructure.cpp @@ -34,6 +34,8 @@ u256 const dev::eth::c_sstoreResetGas = 100; u256 const dev::eth::c_sstoreRefundGas = 100; u256 const dev::eth::c_createGas = 100; u256 const dev::eth::c_callGas = 20; +u256 const dev::eth::c_expGas = 1; +u256 const dev::eth::c_expByteGas = 1; u256 const dev::eth::c_memoryGas = 1; u256 const dev::eth::c_txDataZeroGas = 1; u256 const dev::eth::c_txDataNonZeroGas = 5; diff --git a/libevm/FeeStructure.h b/libevm/FeeStructure.h index 4f415da5d..3fb8175e6 100644 --- a/libevm/FeeStructure.h +++ b/libevm/FeeStructure.h @@ -37,6 +37,8 @@ extern u256 const c_sstoreResetGas; ///< Once per SSTORE operation if the zeron extern u256 const c_sstoreRefundGas; ///< Refunded gas, once per SSTORE operation if the zeroness changes to zero. extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction. extern u256 const c_callGas; ///< Once per CALL operation & message call transaction. +extern u256 const c_expGas; ///< Once per EXP instuction. +extern u256 const c_expByteGas; ///< Times ceil(log256(exponent)) for the EXP instruction. extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. extern u256 const c_txDataZeroGas; ///< Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions. extern u256 const c_txDataNonZeroGas; ///< Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. diff --git a/libevm/VM.h b/libevm/VM.h index 9d43d7177..b0267c051 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -242,6 +242,13 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con runGas = c_createGas; break; } + case Instruction::EXP: + { + require(2); + auto expon = m_stack[m_stack.size() - 2]; + runGas = c_expGas + c_extByteGas * (32 - (h256(expon).firstBitSet() / 8)); + break; + } case Instruction::PC: case Instruction::MSIZE: @@ -308,7 +315,6 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::SDIV: case Instruction::MOD: case Instruction::SMOD: - case Instruction::EXP: case Instruction::LT: case Instruction::GT: case Instruction::SLT: From 278dc7981b1a496a49bc4eef5c495da61149e441 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 29 Nov 2014 20:42:01 +0100 Subject: [PATCH 15/22] Compile fix. --- libevm/VM.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevm/VM.h b/libevm/VM.h index b0267c051..8fdd3de92 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -246,7 +246,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con { require(2); auto expon = m_stack[m_stack.size() - 2]; - runGas = c_expGas + c_extByteGas * (32 - (h256(expon).firstBitSet() / 8)); + runGas = c_expGas + c_expByteGas * (32 - (h256(expon).firstBitSet() / 8)); break; } From eb5369d6f213fbedb3fae40c8668a30726b19645 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sun, 30 Nov 2014 22:43:40 +0100 Subject: [PATCH 16/22] Simplifying scanning for natspec documentation - Scanner no longer remembers the last natspect comment until a new one is encountered. It remembers it only until the next scan() --- libsolidity/Parser.cpp | 4 +--- libsolidity/Scanner.cpp | 42 ++++++++++++++--------------------------- libsolidity/Scanner.h | 8 +++----- 3 files changed, 18 insertions(+), 36 deletions(-) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 9ed081cce..0506bc3e3 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -119,10 +119,8 @@ ASTPointer Parser::parseFunctionDefinition(bool _isPublic) ASTNodeFactory nodeFactory(*this); ASTPointer docstring; if (m_scanner->getCurrentCommentLiteral() != "") - { docstring = std::make_shared(m_scanner->getCurrentCommentLiteral()); - m_scanner->clearCurrentCommentLiteral(); - } + expectToken(Token::FUNCTION); ASTPointer name(expectIdentifierToken()); ASTPointer parameters(parseParameterList()); diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 4da9874a2..3335e9df4 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -104,16 +104,14 @@ int hexValue(char c) void Scanner::reset(CharStream const& _source) { - bool foundDocComment; m_source = _source; m_char = m_source.get(); skipWhitespace(); - foundDocComment = scanToken(); + scanToken(); - // special version of Scanner:next() taking the previous scanToken() result into account m_currentToken = m_nextToken; - if (scanToken() || foundDocComment) - m_skippedComment = m_nextSkippedComment; + m_skippedComment = m_nextSkippedComment; + scanToken(); } @@ -142,8 +140,9 @@ BOOST_STATIC_ASSERT(Token::NUM_TOKENS <= 0x100); Token::Value Scanner::next() { m_currentToken = m_nextToken; - if (scanToken()) - m_skippedComment = m_nextSkippedComment; + m_skippedComment = m_nextSkippedComment; + scanToken(); + return m_currentToken.token; } @@ -188,13 +187,13 @@ Token::Value Scanner::scanDocumentationComment() { // check if next line is also a documentation comment skipWhitespace(); - if (m_source.get(0) == '/' && + if (!m_source.isPastEndOfInput(3) && + m_source.get(0) == '/' && m_source.get(1) == '/' && - m_source.get(2) == '/' && - !m_source.isPastEndOfInput(3)) + m_source.get(2) == '/') { addCommentLiteralChar('\n'); - m_char = m_source.advanceBy(3); + m_char = m_source.advanceAndGet(3); } else break; // next line is not a documentation comment, we are done @@ -230,10 +229,10 @@ Token::Value Scanner::skipMultiLineComment() return Token::ILLEGAL; } -bool Scanner::scanToken() +void Scanner::scanToken() { - bool foundDocComment = false; m_nextToken.literal.clear(); + m_nextSkippedComment.literal.clear(); Token::Value token; do { @@ -345,7 +344,6 @@ bool Scanner::scanToken() m_nextSkippedComment.location.end = getSourcePos(); m_nextSkippedComment.token = comment; token = Token::WHITESPACE; - foundDocComment = true; } else token = skipSingleLineComment(); @@ -441,8 +439,6 @@ bool Scanner::scanToken() while (token == Token::WHITESPACE); m_nextToken.location.end = getSourcePos(); m_nextToken.token = token; - - return foundDocComment; } bool Scanner::scanEscape() @@ -783,23 +779,13 @@ Token::Value Scanner::scanIdentifierOrKeyword() return KeywordOrIdentifierToken(m_nextToken.literal); } -char CharStream::advanceAndGet() +char CharStream::advanceAndGet(size_t _chars) { if (isPastEndOfInput()) return 0; - ++m_pos; + m_pos += _chars; if (isPastEndOfInput()) return 0; - return get(); -} - -char CharStream::advanceBy(size_t _chars) -{ - if (asserts(!isPastEndOfInput(_chars))) - BOOST_THROW_EXCEPTION(InternalCompilerError()); - - m_pos += _chars; - return m_source[m_pos]; } diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 702310102..e9262ba39 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -76,8 +76,7 @@ public: int getPos() const { return m_pos; } bool isPastEndOfInput(size_t _charsForward = 0) const { return (m_pos + _charsForward) >= m_source.size(); } char get(size_t _charsForward = 0) const { return m_source[m_pos + _charsForward]; } - char advanceAndGet(); - char advanceBy(size_t _chars); + char advanceAndGet(size_t _chars=1); char rollback(size_t _amount); ///@{ @@ -213,9 +212,8 @@ private: bool scanHexByte(char& o_scannedByte); - /// Scans a single Solidity token. Returns true if the scanned token was - /// a skipped documentation comment. False in all other cases. - bool scanToken(); + /// Scans a single Solidity token. + void scanToken(); /// Skips all whitespace and @returns true if something was skipped. bool skipWhitespace(); From 87c58e48666c7b79ae58aa2fffeb6a9234711c33 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sun, 30 Nov 2014 23:25:42 +0100 Subject: [PATCH 17/22] Moving LiteralScope to Scanner.cpp --- libsolidity/Scanner.cpp | 41 ++++++++++++++++++++++++++++++++++++++++ libsolidity/Scanner.h | 42 +---------------------------------------- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 3335e9df4..6ef8a6c79 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -102,6 +102,47 @@ int hexValue(char c) } } // end anonymous namespace + + +/// Scoped helper for literal recording. Automatically drops the literal +/// if aborting the scanning before it's complete. +enum LiteralType { + LITERAL_TYPE_STRING, + LITERAL_TYPE_NUMBER, // not really different from string type in behaviour + LITERAL_TYPE_COMMENT +}; + +class LiteralScope +{ +public: + explicit LiteralScope(Scanner* _self, enum LiteralType _type): m_type(_type) + , m_scanner(_self) + , m_complete(false) + { + if (_type == LITERAL_TYPE_COMMENT) + m_scanner->m_nextSkippedComment.literal.clear(); + else + m_scanner->m_nextToken.literal.clear(); + } + ~LiteralScope() + { + if (!m_complete) + { + if (m_type == LITERAL_TYPE_COMMENT) + m_scanner->m_nextSkippedComment.literal.clear(); + else + m_scanner->m_nextToken.literal.clear(); + } + } + void complete() { m_complete = true; } + +private: + enum LiteralType m_type; + Scanner* m_scanner; + bool m_complete; +}; // end of LiteralScope class + + void Scanner::reset(CharStream const& _source) { m_source = _source; diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index e9262ba39..49ac3651c 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -96,45 +96,9 @@ private: class Scanner { + friend class LiteralScope; public: - enum LiteralType { - LITERAL_TYPE_STRING, - LITERAL_TYPE_NUMBER, // not really different from string type in behaviour - LITERAL_TYPE_COMMENT - }; - /// Scoped helper for literal recording. Automatically drops the literal - /// if aborting the scanning before it's complete. - class LiteralScope - { - public: - explicit LiteralScope(Scanner* _self, enum LiteralType _type): m_type(_type) - , m_scanner(_self) - , m_complete(false) - { - if (_type == LITERAL_TYPE_COMMENT) - m_scanner->startNewCommentLiteral(); - else - m_scanner->startNewLiteral(); - } - ~LiteralScope() - { - if (!m_complete) - { - if (m_type == LITERAL_TYPE_COMMENT) - m_scanner->dropCommentLiteral(); - else - m_scanner->dropLiteral(); - } - } - void complete() { m_complete = true; } - - private: - enum LiteralType m_type; - Scanner* m_scanner; - bool m_complete; - }; - Scanner() { reset(CharStream()); } explicit Scanner(CharStream const& _source) { reset(_source); } @@ -194,12 +158,8 @@ private: ///@{ ///@name Literal buffer support - inline void startNewLiteral() { m_nextToken.literal.clear(); } - inline void startNewCommentLiteral() { m_nextSkippedComment.literal.clear(); } inline void addLiteralChar(char c) { m_nextToken.literal.push_back(c); } inline void addCommentLiteralChar(char c) { m_nextSkippedComment.literal.push_back(c); } - inline void dropLiteral() { m_nextToken.literal.clear(); } - inline void dropCommentLiteral() { m_nextSkippedComment.literal.clear(); } inline void addLiteralCharAndAdvance() { addLiteralChar(m_char); advance(); } ///@} From 70dd83f88748c0737fac034f450432f67e81d3b0 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sun, 30 Nov 2014 23:33:04 +0100 Subject: [PATCH 18/22] Adding natspec comment test being between keyword and signature --- test/solidityParser.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/test/solidityParser.cpp b/test/solidityParser.cpp index e4db2ece7..6a97a5d99 100644 --- a/test/solidityParser.cpp +++ b/test/solidityParser.cpp @@ -204,6 +204,29 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body) " and it has 2 lines"); } +BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature) +{ + ASTPointer contract; + ASTPointer function; + char const* text = "contract test {\n" + " uint256 stateVar;\n" + " function ///I am in the wrong place \n" + " fun1(uint256 a) {\n" + " var b;\n" + " /// I should not interfere with actual natspec comments\n" + " uint256 c;\n" + " mapping(address=>hash) d;\n" + " string name = \"Solidity\";" + " }\n" + "}\n"; + BOOST_REQUIRE_NO_THROW(contract = parseText(text)); + auto functions = contract->getDefinedFunctions(); + + BOOST_REQUIRE_NO_THROW(function = functions.at(0)); + BOOST_CHECK_MESSAGE(!function->getDocumentation(), + "Shouldn't get natspec docstring for this function"); +} + BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature) { ASTPointer contract; @@ -211,8 +234,7 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature) char const* text = "contract test {\n" " uint256 stateVar;\n" " function fun1(uint256 a) {\n" - " /// I should have been above the function signature" - " {\n" + " /// I should have been above the function signature\n" " var b;\n" " /// I should not interfere with actual natspec comments\n" " uint256 c;\n" From 6e0839efe38ef7573f220777f077c2ba782f8eae Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 1 Dec 2014 01:05:55 +0100 Subject: [PATCH 19/22] simplifying Scanner::reset() --- libsolidity/Scanner.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index 6ef8a6c79..4ffc2223f 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -150,9 +150,7 @@ void Scanner::reset(CharStream const& _source) skipWhitespace(); scanToken(); - m_currentToken = m_nextToken; - m_skippedComment = m_nextSkippedComment; - scanToken(); + next(); } From 9baae5fbf4d88ab4b27d5c6a726d08c29acdfa29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 1 Dec 2014 14:49:40 +0100 Subject: [PATCH 20/22] Windows fix --- libp2p/Host.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 6e151d34d..b233fe552 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -78,7 +78,7 @@ std::vector Host::getInterfaceAddresses() char *addrStr = inet_ntoa(addr); bi::address address(bi::address::from_string(addrStr)); if (!isLocalHostAddress(address)) - addresses.push_back(ad.to_v4()); + addresses.push_back(address.to_v4()); } WSACleanup(); @@ -153,7 +153,7 @@ int Host::listen4(bi::tcp::acceptor* _acceptor, unsigned short _listenPort) bi::tcp::endpoint Host::traverseNAT(std::vector const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr) { - asserts(_listenPort); + asserts(_listenPort != 0); UPnP* upnp; try From 965af120d6fd51a09b007c92921855a0d715014b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 1 Dec 2014 15:58:49 +0100 Subject: [PATCH 21/22] C Interface draft 1 --- libevmjit/interface.c | 30 ++++++++++++++++++++++++++++++ windows/LibEvmJit.vcxproj | 1 + windows/LibEvmJit.vcxproj.filters | 3 +++ 3 files changed, 34 insertions(+) create mode 100644 libevmjit/interface.c diff --git a/libevmjit/interface.c b/libevmjit/interface.c new file mode 100644 index 000000000..47589578b --- /dev/null +++ b/libevmjit/interface.c @@ -0,0 +1,30 @@ +#include + +// JIT object opaque type +typedef struct evm_jit evm_jit; + +// Contract execution return code +typedef int evm_jit_return_code; + +// Host-endian 256-bit integer type +typedef struct i256 i256; + +// Big-endian right aligned 256-bit hash +typedef struct h256 h256; + +// Runtime data struct - must be provided by external language (Go, C++, Python) +typedef struct evm_jit_rt evm_jit_rt; + +// Runtime callback functions - implementations must be provided by external language (Go, C++, Python) +void evm_jit_rt_sload(evm_jit_rt* _rt, i256* _index, i256* _ret); +void evm_jit_rt_sstore(evm_jit_rt* _rt, i256* _index, i256* _value); +void evm_jit_rt_balance(evm_jit_rt* _rt, h256* _address, i256* _ret); +// And so on... + +evm_jit* evm_jit_create(evm_jit_rt* _runtime_data); + +evm_jit_return_code evm_jit_execute(evm_jit* _jit); + +void evm_jit_get_return_data(evm_jit* _jit, char* _return_data_offset, size_t* _return_data_size); + +void evm_jit_destroy(evm_jit* _jit); diff --git a/windows/LibEvmJit.vcxproj b/windows/LibEvmJit.vcxproj index a9288a212..50824fb2d 100644 --- a/windows/LibEvmJit.vcxproj +++ b/windows/LibEvmJit.vcxproj @@ -131,6 +131,7 @@ + diff --git a/windows/LibEvmJit.vcxproj.filters b/windows/LibEvmJit.vcxproj.filters index ae89fe550..1a0d86e56 100644 --- a/windows/LibEvmJit.vcxproj.filters +++ b/windows/LibEvmJit.vcxproj.filters @@ -48,6 +48,9 @@ libevmjit + + libevmjit + From 428468e2d221f5ab86acc06180b09ab905a456f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 1 Dec 2014 18:17:44 +0100 Subject: [PATCH 22/22] MSVS update --- windows/LibEthereum.vcxproj | 4 +++- windows/LibEthereum.vcxproj.filters | 16 +++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 4ae5d5bf8..66efe7dc2 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -125,6 +125,7 @@ + @@ -342,6 +343,7 @@ + @@ -574,4 +576,4 @@ - + \ No newline at end of file diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index fd03dd451..85f1fdedc 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -190,12 +190,6 @@ libdevcrypto - - libdevcrypto - - - libdevcrypto - libethereum @@ -205,6 +199,11 @@ libevm + + + + libethereum + @@ -444,6 +443,9 @@ libevm + + libethereum + @@ -480,4 +482,4 @@ {d838fece-fc20-42f6-bff5-97c236159b80} - + \ No newline at end of file