From bf3a76f5af38c5d62d52600e2b57e51247adb0b8 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 16 Oct 2014 17:56:10 +0200 Subject: [PATCH 01/21] Improved exceptions and reporting exceptions for command-line compiler. --- libdevcore/Exceptions.h | 3 + libethcore/Exceptions.cpp | 2 - libsolidity/AST.cpp | 37 ++++++------ libsolidity/Exceptions.cpp | 47 +++++++++++++++ libsolidity/Exceptions.h | 43 ++++++++++++- libsolidity/NameAndTypeResolver.cpp | 9 +-- libsolidity/Parser.cpp | 11 +--- libsolidity/Types.cpp | 2 +- solc/main.cpp | 93 +++++++++++++++++++++-------- 9 files changed, 183 insertions(+), 64 deletions(-) create mode 100644 libsolidity/Exceptions.cpp diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 1a54814c6..0be1cf30e 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -28,6 +28,9 @@ #include "CommonData.h" #include "FixedHash.h" +// for use in what() implementations +#define ETH_RETURN_STRING(S) static std::string s_what; s_what = S; return s_what.c_str(); + namespace dev { // base class for all exceptions diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp index c6f35763e..f9054ec5d 100644 --- a/libethcore/Exceptions.cpp +++ b/libethcore/Exceptions.cpp @@ -26,8 +26,6 @@ using namespace std; using namespace dev; using namespace dev::eth; -#define ETH_RETURN_STRING(S) static string s_what; s_what = S; return s_what.c_str(); - const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); } const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); } const char* InvalidTransactionsHash::what() const noexcept { ETH_RETURN_STRING("Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref())); } diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 15da9e0d8..0671ecd7a 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -252,8 +252,8 @@ void Statement::expectType(Expression& _expression, const Type& _expectedType) { _expression.checkTypeRequirements(); if (!_expression.getType()->isImplicitlyConvertibleTo(_expectedType)) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Type not implicitly convertible " - "to expected type.")); + BOOST_THROW_EXCEPTION(TypeError(_expression.getLocation(), + "Type not implicitly convertible to expected type.")); //@todo provide more information to the exception } @@ -289,9 +289,9 @@ void Return::checkTypeRequirements() { BOOST_ASSERT(m_returnParameters != nullptr); if (m_returnParameters->getParameters().size() != 1) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Different number of arguments in " - "return statement than in returns " - "declaration.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Different number of arguments in " + "return statement than in returns " + "declaration.")); // this could later be changed such that the paramaters type is an anonymous struct type, // but for now, we only allow one return parameter expectType(*m_expression, *m_returnParameters->getParameters().front()->getType()); @@ -327,7 +327,7 @@ void Assignment::checkTypeRequirements() { // complex assignment if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator))) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Operator not compatible with type.")); } } @@ -337,7 +337,7 @@ void UnaryOperation::checkTypeRequirements() m_subExpression->checkTypeRequirements(); m_type = m_subExpression->getType(); if (m_type->acceptsUnaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Unary operator not compatible with type.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Unary operator not compatible with type.")); } void BinaryOperation::checkTypeRequirements() @@ -349,7 +349,7 @@ void BinaryOperation::checkTypeRequirements() else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType())) m_commonType = m_right->getType(); else - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("No common type found in binary operation.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "No common type found in binary operation.")); if (Token::isCompareOp(m_operator)) m_type = std::make_shared(); else @@ -357,7 +357,7 @@ void BinaryOperation::checkTypeRequirements() BOOST_ASSERT(Token::isBinaryOp(m_operator)); m_type = m_commonType; if (!m_commonType->acceptsBinaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Operator not compatible with type.")); } } @@ -375,11 +375,10 @@ void FunctionCall::checkTypeRequirements() //@todo for structs, we have to check the number of arguments to be equal to the // number of non-mapping members if (m_arguments.size() != 1) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("More than one argument for " - "explicit type conersion.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "More than one argument for " + "explicit type conersion.")); if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type->getActualType())) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Explicit type conversion not " - "allowed.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Explicit type conversion not allowed.")); m_type = type->getActualType(); } else if (category == Type::Category::FUNCTION) @@ -392,12 +391,10 @@ void FunctionCall::checkTypeRequirements() FunctionDefinition const& fun = function->getFunction(); std::vector> const& parameters = fun.getParameters(); if (parameters.size() != m_arguments.size()) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Wrong argument count for " - "function call.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Wrong argument count for function call.")); for (size_t i = 0; i < m_arguments.size(); ++i) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType())) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Invalid type for argument in " - "function call.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Invalid type for argument in function call.")); // @todo actually the return type should be an anonymous struct, // but we change it to the type of the first return value until we have structs if (fun.getReturnParameterList()->getParameters().empty()) @@ -407,7 +404,7 @@ void FunctionCall::checkTypeRequirements() } else { - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Type does not support invocation.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Type does not support invocation.")); } } @@ -438,8 +435,8 @@ void Identifier::checkTypeRequirements() if (variable != nullptr) { if (!variable->getType()) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Variable referenced before type " - "could be determined.")); + BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Variable referenced before type " + "could be determined.")); m_type = variable->getType(); return; } diff --git a/libsolidity/Exceptions.cpp b/libsolidity/Exceptions.cpp new file mode 100644 index 000000000..53380d778 --- /dev/null +++ b/libsolidity/Exceptions.cpp @@ -0,0 +1,47 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @author Christian + * @date 2014 + * Solidity exception hierarchy. + */ + +#include + + +namespace dev +{ +namespace solidity +{ + +const char* ParserError::what() const noexcept +{ + ETH_RETURN_STRING("Parser error: " + m_description); +} + +const char* DeclarationError::what() const noexcept +{ + ETH_RETURN_STRING("Declaration error: " + m_description); +} + +const char* TypeError::what() const noexcept +{ + ETH_RETURN_STRING("Type error: " + m_description); +} + +} +} diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index c600ebf12..075af2b93 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -22,16 +22,53 @@ #pragma once +#include #include +#include namespace dev { namespace solidity { -struct ParserError: virtual Exception {}; -struct TypeError: virtual Exception {}; -struct DeclarationError: virtual Exception {}; +class ParserError: public virtual Exception +{ +public: + ParserError(int _position, std::string const& _description): + m_position(_position), m_description(_description) {} + virtual const char* what() const noexcept; + int getPosition() const { return m_position; } + +private: + int m_position; + std::string m_description; +}; + +class TypeError: public virtual Exception +{ +public: + TypeError(Location const& _location, std::string const& _description): + m_location(_location), m_description(_description) {} + virtual const char* what() const noexcept; + Location const& getLocation() const { return m_location; } + +private: + Location m_location; + std::string m_description; +}; + +class DeclarationError: public virtual Exception +{ +public: + DeclarationError(Location const& _location, std::string const& _description): + m_location(_location), m_description(_description) {} + virtual const char* what() const noexcept; + Location const& getLocation() const { return m_location; } + +private: + Location m_location; + std::string m_description; +}; } } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 707b6ce14..8fe452812 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -137,7 +137,8 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio { BOOST_ASSERT(m_currentScope != nullptr); if (!m_currentScope->registerDeclaration(_declaration)) - BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Identifier already declared.")); + BOOST_THROW_EXCEPTION(DeclarationError(_declaration.getLocation(), "Identifier already declared.")); + //@todo the exception should also contain the location of the first declaration if (_opensScope) enterNewSubScope(_declaration); } @@ -175,11 +176,11 @@ bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_typeName.getName()); if (declaration == nullptr) - BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Undeclared identifier.")); + BOOST_THROW_EXCEPTION(DeclarationError(_typeName.getLocation(), "Undeclared identifier.")); StructDefinition* referencedStruct = dynamic_cast(declaration); //@todo later, contracts are also valid types if (referencedStruct == nullptr) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Identifier does not name a type name.")); + BOOST_THROW_EXCEPTION(TypeError(_typeName.getLocation(), "Identifier does not name a type name.")); _typeName.setReferencedStruct(*referencedStruct); return false; } @@ -188,7 +189,7 @@ bool ReferencesResolver::visit(Identifier& _identifier) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName()); if (declaration == nullptr) - BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Undeclared identifier.")); + BOOST_THROW_EXCEPTION(DeclarationError(_identifier.getLocation(), "Undeclared identifier.")); _identifier.setReferencedDeclaration(*declaration); return false; } diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 408aa7bd6..3887ac8f2 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -536,16 +536,7 @@ ASTPointer Parser::getLiteralAndAdvance() void Parser::throwExpectationError(std::string const& _description) { - //@todo put some of this stuff into ParserError - int line, column; - std::tie(line, column) = m_scanner->translatePositionToLineColumn(getPosition()); - std::stringstream buf; - buf << "Solidity parser error: " << _description - << " at line " << (line + 1) - << ", column " << (column + 1) << "\n" - << m_scanner->getLineAtPosition(getPosition()) << "\n" - << std::string(column, ' ') << "^"; - BOOST_THROW_EXCEPTION(ParserError() << errinfo_comment(buf.str())); + BOOST_THROW_EXCEPTION(ParserError(getPosition(), _description)); } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 7634951a1..d5ae0c3e5 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -88,9 +88,9 @@ std::shared_ptr IntegerType::smallestTypeForLiteral(std::string con IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): m_bits(_bits), m_modifier(_modifier) { - BOOST_ASSERT(_bits > 0 && _bits <= 256 && _bits % 8 == 0); if (isAddress()) _bits = 160; + BOOST_ASSERT(_bits > 0 && _bits <= 256 && _bits % 8 == 0); } bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const diff --git a/solc/main.cpp b/solc/main.cpp index e155b0fe6..91cabfb33 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -9,21 +9,10 @@ #include #include #include +#include -namespace dev -{ -namespace solidity -{ - -ASTPointer parseAST(std::string const& _source) -{ - ASTPointer scanner = std::make_shared(CharStream(_source)); - Parser parser; - return parser.parse(scanner); -} - -} -} // end namespaces +using namespace dev; +using namespace solidity; void help() { @@ -44,6 +33,33 @@ void version() exit(0); } +void printSourcePart(std::ostream& _stream, Location const& _location, Scanner const& _scanner) +{ + int startLine; + int startColumn; + std::tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start); + _stream << " starting at line " << (startLine + 1) << ", column " << (startColumn + 1) << "\n"; + int endLine; + int endColumn; + std::tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); + if (startLine == endLine) + { + _stream << _scanner.getLineAtPosition(_location.start) << "\n" + << std::string(startColumn, ' ') << "^"; + if (endColumn > startColumn + 2) + _stream << std::string(endColumn - startColumn - 2, '-'); + if (endColumn > startColumn + 1) + _stream << "^"; + _stream << "\n"; + } + else + { + _stream << _scanner.getLineAtPosition(_location.start) << "\n" + << std::string(startColumn, ' ') << "^\n" + << "Spanning multiple lines.\n"; + } +} + int main(int argc, char** argv) { std::string infile; @@ -57,28 +73,57 @@ int main(int argc, char** argv) else infile = argv[i]; } - std::string src; + std::string sourceCode; if (infile.empty()) { std::string s; while (!std::cin.eof()) { getline(std::cin, s); - src.append(s); + sourceCode.append(s); } } else + sourceCode = asString(dev::contents(infile)); + + ASTPointer ast; + std::shared_ptr scanner = std::make_shared(CharStream(sourceCode)); + Parser parser; + try + { + ast = parser.parse(scanner); + } + catch (ParserError const& exc) { - src = dev::asString(dev::contents(infile)); + int line; + int column; + std::tie(line, column) = scanner->translatePositionToLineColumn(exc.getPosition()); + std::cerr << exc.what() << " at line " << (line + 1) << ", column " << (column + 1) << std::endl; + std::cerr << scanner->getLineAtPosition(exc.getPosition()) << std::endl; + std::cerr << std::string(column, ' ') << "^" << std::endl; + return -1; } - std::cout << "Parsing..." << std::endl; - // @todo catch exception - dev::solidity::ASTPointer ast = dev::solidity::parseAST(src); + + dev::solidity::NameAndTypeResolver resolver; + try + { + resolver.resolveNamesAndTypes(*ast.get()); + } + catch (DeclarationError const& exc) + { + std::cerr << exc.what() << std::endl; + printSourcePart(std::cerr, exc.getLocation(), *scanner); + return -1; + } + catch (TypeError const& exc) + { + std::cerr << exc.what() << std::endl; + printSourcePart(std::cerr, exc.getLocation(), *scanner); + return -1; + } + std::cout << "Syntax tree for the contract:" << std::endl; - dev::solidity::ASTPrinter printer(ast, src); + dev::solidity::ASTPrinter printer(ast, sourceCode); printer.print(std::cout); - std::cout << "Resolving identifiers..." << std::endl; - dev::solidity::NameAndTypeResolver resolver; - resolver.resolveNamesAndTypes(*ast.get()); return 0; } From 8bb71c4ebf3fcccd27ea52dac0ca7e4e5ada9dcf Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 23 Oct 2014 19:22:30 +0200 Subject: [PATCH 02/21] Use boost errinfo. --- libdevcore/Exceptions.h | 3 - libethcore/Exceptions.cpp | 2 + libsolidity/AST.cpp | 34 ++++--- libsolidity/AST.h | 9 +- libsolidity/Exceptions.h | 42 +------- libsolidity/NameAndTypeResolver.cpp | 12 ++- libsolidity/Parser.cpp | 20 ++-- libsolidity/Parser.h | 5 +- libsolidity/SourceReferenceFormatter.cpp | 96 +++++++++++++++++++ ...eptions.cpp => SourceReferenceFormatter.h} | 29 +++--- solc/main.cpp | 47 ++------- 11 files changed, 173 insertions(+), 126 deletions(-) create mode 100644 libsolidity/SourceReferenceFormatter.cpp rename libsolidity/{Exceptions.cpp => SourceReferenceFormatter.h} (55%) diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 0be1cf30e..1a54814c6 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -28,9 +28,6 @@ #include "CommonData.h" #include "FixedHash.h" -// for use in what() implementations -#define ETH_RETURN_STRING(S) static std::string s_what; s_what = S; return s_what.c_str(); - namespace dev { // base class for all exceptions diff --git a/libethcore/Exceptions.cpp b/libethcore/Exceptions.cpp index f9054ec5d..c6f35763e 100644 --- a/libethcore/Exceptions.cpp +++ b/libethcore/Exceptions.cpp @@ -26,6 +26,8 @@ using namespace std; using namespace dev; using namespace dev::eth; +#define ETH_RETURN_STRING(S) static string s_what; s_what = S; return s_what.c_str(); + const char* InvalidBlockFormat::what() const noexcept { ETH_RETURN_STRING("Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"); } const char* UncleInChain::what() const noexcept { ETH_RETURN_STRING("Uncle in block already mentioned: Uncles " + toString(m_uncles) + " (" + m_block.abridged() + ")"); } const char* InvalidTransactionsHash::what() const noexcept { ETH_RETURN_STRING("Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref())); } diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 0671ecd7a..50c53bf37 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -248,12 +248,17 @@ void Literal::accept(ASTVisitor& _visitor) _visitor.endVisit(*this); } +TypeError ASTNode::createTypeError(std::string const& _description) +{ + return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description); +} + void Statement::expectType(Expression& _expression, const Type& _expectedType) { _expression.checkTypeRequirements(); if (!_expression.getType()->isImplicitlyConvertibleTo(_expectedType)) - BOOST_THROW_EXCEPTION(TypeError(_expression.getLocation(), - "Type not implicitly convertible to expected type.")); + BOOST_THROW_EXCEPTION(TypeError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Type not implicitly convertible to expected type.")); //@todo provide more information to the exception } @@ -289,9 +294,8 @@ void Return::checkTypeRequirements() { BOOST_ASSERT(m_returnParameters != nullptr); if (m_returnParameters->getParameters().size() != 1) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Different number of arguments in " - "return statement than in returns " - "declaration.")); + BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement " + "than in returns declaration.")); // this could later be changed such that the paramaters type is an anonymous struct type, // but for now, we only allow one return parameter expectType(*m_expression, *m_returnParameters->getParameters().front()->getType()); @@ -327,7 +331,7 @@ void Assignment::checkTypeRequirements() { // complex assignment if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator))) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); } } @@ -337,7 +341,7 @@ void UnaryOperation::checkTypeRequirements() m_subExpression->checkTypeRequirements(); m_type = m_subExpression->getType(); if (m_type->acceptsUnaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Unary operator not compatible with type.")); + BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type.")); } void BinaryOperation::checkTypeRequirements() @@ -349,7 +353,7 @@ void BinaryOperation::checkTypeRequirements() else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType())) m_commonType = m_right->getType(); else - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "No common type found in binary operation.")); + BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation.")); if (Token::isCompareOp(m_operator)) m_type = std::make_shared(); else @@ -357,7 +361,7 @@ void BinaryOperation::checkTypeRequirements() BOOST_ASSERT(Token::isBinaryOp(m_operator)); m_type = m_commonType; if (!m_commonType->acceptsBinaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); } } @@ -375,10 +379,10 @@ void FunctionCall::checkTypeRequirements() //@todo for structs, we have to check the number of arguments to be equal to the // number of non-mapping members if (m_arguments.size() != 1) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "More than one argument for " + BOOST_THROW_EXCEPTION(createTypeError("More than one argument for " "explicit type conersion.")); if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type->getActualType())) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Explicit type conversion not allowed.")); + BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed.")); m_type = type->getActualType(); } else if (category == Type::Category::FUNCTION) @@ -391,10 +395,10 @@ void FunctionCall::checkTypeRequirements() FunctionDefinition const& fun = function->getFunction(); std::vector> const& parameters = fun.getParameters(); if (parameters.size() != m_arguments.size()) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Wrong argument count for function call.")); + BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); for (size_t i = 0; i < m_arguments.size(); ++i) if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType())) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Invalid type for argument in function call.")); + BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); // @todo actually the return type should be an anonymous struct, // but we change it to the type of the first return value until we have structs if (fun.getReturnParameterList()->getParameters().empty()) @@ -404,7 +408,7 @@ void FunctionCall::checkTypeRequirements() } else { - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Type does not support invocation.")); + BOOST_THROW_EXCEPTION(createTypeError("Type does not support invocation.")); } } @@ -435,7 +439,7 @@ void Identifier::checkTypeRequirements() if (variable != nullptr) { if (!variable->getType()) - BOOST_THROW_EXCEPTION(TypeError(getLocation(), "Variable referenced before type " + BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type " "could be determined.")); m_type = variable->getType(); return; diff --git a/libsolidity/AST.h b/libsolidity/AST.h index d5e1e0662..5679ed831 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -22,16 +22,16 @@ #pragma once -#include #include #include #include - +#include #include #include #include #include +#include namespace dev { @@ -57,6 +57,11 @@ public: Location const& getLocation() const { return m_location; } +protected: + /// Creates a @ref TypeError exception and decorates it with the current location and + /// the given description + TypeError createTypeError(std::string const& _description); + private: Location m_location; }; diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index 075af2b93..330c37788 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -31,44 +31,12 @@ namespace dev namespace solidity { -class ParserError: public virtual Exception -{ -public: - ParserError(int _position, std::string const& _description): - m_position(_position), m_description(_description) {} - virtual const char* what() const noexcept; - int getPosition() const { return m_position; } - -private: - int m_position; - std::string m_description; -}; - -class TypeError: public virtual Exception -{ -public: - TypeError(Location const& _location, std::string const& _description): - m_location(_location), m_description(_description) {} - virtual const char* what() const noexcept; - Location const& getLocation() const { return m_location; } - -private: - Location m_location; - std::string m_description; -}; - -class DeclarationError: public virtual Exception -{ -public: - DeclarationError(Location const& _location, std::string const& _description): - m_location(_location), m_description(_description) {} - virtual const char* what() const noexcept; - Location const& getLocation() const { return m_location; } +struct ParserError: public virtual Exception {}; +struct TypeError: public virtual Exception {}; +struct DeclarationError: public virtual Exception {}; -private: - Location m_location; - std::string m_description; -}; +typedef boost::error_info errinfo_sourcePosition; +typedef boost::error_info errinfo_sourceLocation; } } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 8fe452812..a56502727 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -137,7 +137,8 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio { BOOST_ASSERT(m_currentScope != nullptr); if (!m_currentScope->registerDeclaration(_declaration)) - BOOST_THROW_EXCEPTION(DeclarationError(_declaration.getLocation(), "Identifier already declared.")); + BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) + << errinfo_comment("Identifier already declared.")); //@todo the exception should also contain the location of the first declaration if (_opensScope) enterNewSubScope(_declaration); @@ -176,11 +177,13 @@ bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_typeName.getName()); if (declaration == nullptr) - BOOST_THROW_EXCEPTION(DeclarationError(_typeName.getLocation(), "Undeclared identifier.")); + BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_typeName.getLocation()) + << errinfo_comment("Undeclared identifier.")); StructDefinition* referencedStruct = dynamic_cast(declaration); //@todo later, contracts are also valid types if (referencedStruct == nullptr) - BOOST_THROW_EXCEPTION(TypeError(_typeName.getLocation(), "Identifier does not name a type name.")); + BOOST_THROW_EXCEPTION(TypeError() << errinfo_sourceLocation(_typeName.getLocation()) + << errinfo_comment("Identifier does not name a type name.")); _typeName.setReferencedStruct(*referencedStruct); return false; } @@ -189,7 +192,8 @@ bool ReferencesResolver::visit(Identifier& _identifier) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName()); if (declaration == nullptr) - BOOST_THROW_EXCEPTION(DeclarationError(_identifier.getLocation(), "Undeclared identifier.")); + BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_identifier.getLocation()) + << errinfo_comment("Undeclared identifier.")); _identifier.setReferencedDeclaration(*declaration); return false; } diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 3887ac8f2..1ea413ee9 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -106,7 +106,7 @@ ASTPointer Parser::parseContractDefinition() expectToken(Token::SEMICOLON); } else - throwExpectationError("Function, variable or struct declaration expected."); + BOOST_THROW_EXCEPTION(createParserError("Function, variable or struct declaration expected.")); } nodeFactory.markEndPosition(); expectToken(Token::RBRACE); @@ -184,7 +184,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) else if (token == Token::VAR) { if (!_allowVar) - throwExpectationError("Expected explicit type name."); + BOOST_THROW_EXCEPTION(createParserError("Expected explicit type name.")); m_scanner->next(); } else if (token == Token::MAPPING) @@ -198,7 +198,7 @@ ASTPointer Parser::parseTypeName(bool _allowVar) type = nodeFactory.createNode(expectIdentifierToken()); } else - throwExpectationError("Expected type name"); + BOOST_THROW_EXCEPTION(createParserError("Expected type name")); return type; } @@ -208,7 +208,7 @@ ASTPointer Parser::parseMapping() expectToken(Token::MAPPING); expectToken(Token::LPAREN); if (!Token::isElementaryTypeName(m_scanner->getCurrentToken())) - throwExpectationError("Expected elementary type name for mapping key type"); + BOOST_THROW_EXCEPTION(createParserError("Expected elementary type name for mapping key type")); ASTPointer keyType; keyType = ASTNodeFactory(*this).createNode(m_scanner->getCurrentToken()); m_scanner->next(); @@ -481,7 +481,7 @@ ASTPointer Parser::parsePrimaryExpression() } else { - throwExpectationError("Expected primary expression."); + BOOST_THROW_EXCEPTION(createParserError("Expected primary expression.")); return ASTPointer(); // this is not reached } break; @@ -507,7 +507,7 @@ std::vector> Parser::parseFunctionCallArguments() void Parser::expectToken(Token::Value _value) { if (m_scanner->getCurrentToken() != _value) - throwExpectationError(std::string("Expected token ") + std::string(Token::getName(_value))); + BOOST_THROW_EXCEPTION(createParserError(std::string("Expected token ") + std::string(Token::getName(_value)))); m_scanner->next(); } @@ -515,7 +515,7 @@ Token::Value Parser::expectAssignmentOperator() { Token::Value op = m_scanner->getCurrentToken(); if (!Token::isAssignmentOp(op)) - throwExpectationError(std::string("Expected assignment operator")); + BOOST_THROW_EXCEPTION(createParserError("Expected assignment operator")); m_scanner->next(); return op; } @@ -523,7 +523,7 @@ Token::Value Parser::expectAssignmentOperator() ASTPointer Parser::expectIdentifierToken() { if (m_scanner->getCurrentToken() != Token::IDENTIFIER) - throwExpectationError("Expected identifier"); + BOOST_THROW_EXCEPTION(createParserError("Expected identifier")); return getLiteralAndAdvance(); } @@ -534,9 +534,9 @@ ASTPointer Parser::getLiteralAndAdvance() return identifier; } -void Parser::throwExpectationError(std::string const& _description) +ParserError Parser::createParserError(std::string const& _description) const { - BOOST_THROW_EXCEPTION(ParserError(getPosition(), _description)); + return ParserError() << errinfo_sourcePosition(getPosition()) << errinfo_comment(_description); } diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 7cc415136..14338dc28 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -73,9 +73,12 @@ private: Token::Value expectAssignmentOperator(); ASTPointer expectIdentifierToken(); ASTPointer getLiteralAndAdvance(); - void throwExpectationError(std::string const& _description); /// @} + /// Creates a @ref ParserError exception and annotates it with the current position and the + /// given @a _description. + ParserError createParserError(std::string const& _description) const; + std::shared_ptr m_scanner; }; diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/SourceReferenceFormatter.cpp new file mode 100644 index 000000000..6d2911165 --- /dev/null +++ b/libsolidity/SourceReferenceFormatter.cpp @@ -0,0 +1,96 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @author Christian + * @date 2014 + * Formatting functions for errors referencing positions and locations in the source. + */ + +#include +#include +#include + +namespace dev +{ +namespace solidity +{ + +void SourceReferenceFormatter::printSourceLocation(std::ostream& _stream, + Location const& _location, + Scanner const& _scanner) +{ + int startLine; + int startColumn; + std::tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start); + _stream << "starting at line " << (startLine + 1) << ", column " << (startColumn + 1) << "\n"; + int endLine; + int endColumn; + std::tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); + if (startLine == endLine) + { + _stream << _scanner.getLineAtPosition(_location.start) << "\n" + << std::string(startColumn, ' ') << "^"; + if (endColumn > startColumn + 2) + _stream << std::string(endColumn - startColumn - 2, '-'); + if (endColumn > startColumn + 1) + _stream << "^"; + _stream << "\n"; + } + else + _stream << _scanner.getLineAtPosition(_location.start) << "\n" + << std::string(startColumn, ' ') << "^\n" + << "Spanning multiple lines.\n"; +} + +void SourceReferenceFormatter::printSourcePosition(std::ostream& _stream, + int _position, + const Scanner& _scanner) +{ + int line; + int column; + std::tie(line, column) = _scanner.translatePositionToLineColumn(_position); + _stream << "at line " << (line + 1) << ", column " << (column + 1) << "\n" + << _scanner.getLineAtPosition(_position) << "\n" + << std::string(column, ' ') << "^" << std::endl; +} + +void SourceReferenceFormatter::printExceptionInformation(std::ostream& _stream, + Exception const& _exception, + std::string const& _name, + Scanner const& _scanner) +{ + std::cerr << _name; + std::string const* description = boost::get_error_info(_exception); + if (description != nullptr) + std::cerr << ": " << *description; + + int const* position = boost::get_error_info(_exception); + if (position != nullptr) + { + std::cerr << " "; + printSourcePosition(std::cerr, *position, _scanner); + } + Location const* location = boost::get_error_info(_exception); + if (location != nullptr) + { + std::cerr << " "; + printSourceLocation(_stream, *location, _scanner); + } +} + +} +} diff --git a/libsolidity/Exceptions.cpp b/libsolidity/SourceReferenceFormatter.h similarity index 55% rename from libsolidity/Exceptions.cpp rename to libsolidity/SourceReferenceFormatter.h index 53380d778..4736066fd 100644 --- a/libsolidity/Exceptions.cpp +++ b/libsolidity/SourceReferenceFormatter.h @@ -17,31 +17,32 @@ /** * @author Christian * @date 2014 - * Solidity exception hierarchy. + * Formatting functions for errors referencing positions and locations in the source. */ -#include +#pragma once +#include +#include namespace dev { -namespace solidity -{ -const char* ParserError::what() const noexcept -{ - ETH_RETURN_STRING("Parser error: " + m_description); -} +class Exception; // forward -const char* DeclarationError::what() const noexcept +namespace solidity { - ETH_RETURN_STRING("Declaration error: " + m_description); -} -const char* TypeError::what() const noexcept +class Scanner; // forward + +struct SourceReferenceFormatter { - ETH_RETURN_STRING("Type error: " + m_description); -} +public: + static void printSourceLocation(std::ostream& _stream, Location const& _location, Scanner const& _scanner); + static void printSourcePosition(std::ostream& _stream, int _position, Scanner const& _scanner); + static void printExceptionInformation(std::ostream& _stream, Exception const& _exception, + std::string const& _name, Scanner const& _scanner); +}; } } diff --git a/solc/main.cpp b/solc/main.cpp index 91cabfb33..ba0b6ccf7 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include using namespace dev; using namespace solidity; @@ -33,33 +34,6 @@ void version() exit(0); } -void printSourcePart(std::ostream& _stream, Location const& _location, Scanner const& _scanner) -{ - int startLine; - int startColumn; - std::tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start); - _stream << " starting at line " << (startLine + 1) << ", column " << (startColumn + 1) << "\n"; - int endLine; - int endColumn; - std::tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); - if (startLine == endLine) - { - _stream << _scanner.getLineAtPosition(_location.start) << "\n" - << std::string(startColumn, ' ') << "^"; - if (endColumn > startColumn + 2) - _stream << std::string(endColumn - startColumn - 2, '-'); - if (endColumn > startColumn + 1) - _stream << "^"; - _stream << "\n"; - } - else - { - _stream << _scanner.getLineAtPosition(_location.start) << "\n" - << std::string(startColumn, ' ') << "^\n" - << "Spanning multiple lines.\n"; - } -} - int main(int argc, char** argv) { std::string infile; @@ -93,14 +67,9 @@ int main(int argc, char** argv) { ast = parser.parse(scanner); } - catch (ParserError const& exc) + catch (ParserError const& exception) { - int line; - int column; - std::tie(line, column) = scanner->translatePositionToLineColumn(exc.getPosition()); - std::cerr << exc.what() << " at line " << (line + 1) << ", column " << (column + 1) << std::endl; - std::cerr << scanner->getLineAtPosition(exc.getPosition()) << std::endl; - std::cerr << std::string(column, ' ') << "^" << std::endl; + SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Parser error", *scanner); return -1; } @@ -109,16 +78,14 @@ int main(int argc, char** argv) { resolver.resolveNamesAndTypes(*ast.get()); } - catch (DeclarationError const& exc) + catch (DeclarationError const& exception) { - std::cerr << exc.what() << std::endl; - printSourcePart(std::cerr, exc.getLocation(), *scanner); + SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Declaration error", *scanner); return -1; } - catch (TypeError const& exc) + catch (TypeError const& exception) { - std::cerr << exc.what() << std::endl; - printSourcePart(std::cerr, exc.getLocation(), *scanner); + SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Type error", *scanner); return -1; } From eda9393fd09e7e79b20aa37e805261d2b6f0cf54 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 23 Oct 2014 22:06:57 +0200 Subject: [PATCH 03/21] Watch API. --- libethereum/Client.h | 2 +- libp2p/Host.cpp | 3 +++ libwhisper/Interface.h | 25 +++++++++++++++---------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/libethereum/Client.h b/libethereum/Client.h index cabc9ac23..8ec65c199 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -285,7 +285,7 @@ private: State m_preMine; ///< The present state of the client. State m_postMine; ///< The state of the client which we're mining (i.e. it'll have all the rewards added). - std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. + std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. std::vector m_miners; mutable boost::shared_mutex x_miners; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index ff6bdf996..fafb7d48a 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -143,6 +143,9 @@ void Host::stop() void Host::quit() { + // called to force io_service to kill any remaining tasks it might have - + // such tasks may involve socket reads from Capabilities that maintain references + // to resources we're about to free. stop(); m_ioService.reset(); // m_acceptor & m_socket are DANGEROUS now. diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index e131a3ada..63cc44a9b 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -43,6 +43,8 @@ namespace shh Topic mask; };*/ +class Watch; + struct InstalledFilter { InstalledFilter(TopicFilter const& _f): filter(_f) {} @@ -87,9 +89,11 @@ struct WatshhChannel: public dev::LogChannel { static const char* name() { retur } } -/* -namespace std { void swap(shh::Watch& _a, shh::Watch& _b); } +namespace std { void swap(dev::shh::Watch& _a, dev::shh::Watch& _b); } + +namespace dev +{ namespace shh { @@ -99,28 +103,29 @@ class Watch: public boost::noncopyable public: Watch() {} - Watch(Whisper& _c, h256 _f): m_c(&_c), m_id(_c.installWatch(_f)) {} - Watch(Whisper& _c, TopicFilter const& _tf): m_c(&_c), m_id(_c.installWatch(_tf)) {} + Watch(Interface& _c, TopicMask const& _f): m_c(&_c), m_id(_c.installWatch(_f)) {} + Watch(Interface& _c, TopicFilter const& _tf): m_c(&_c), m_id(_c.installWatch(_tf)) {} ~Watch() { if (m_c) m_c->uninstallWatch(m_id); } - bool check() { return m_c ? m_c->checkWatch(m_id) : false; } - bool peek() { return m_c ? m_c->peekWatch(m_id) : false; } + h256s check() { return m_c ? m_c->checkWatch(m_id) : h256s(); } + h256s peek() { return m_c ? m_c->peekWatch(m_id) : h256s(); } private: - Whisper* m_c; + Interface* m_c; unsigned m_id; }; +} } -namespace shh +namespace std { -inline void swap(shh::Watch& _a, shh::Watch& _b) +inline void swap(dev::shh::Watch& _a, dev::shh::Watch& _b) { swap(_a.m_c, _b.m_c); swap(_a.m_id, _b.m_id); } } -*/ + From 7bab242f5fd598a8e30fc1cef78917d615834c51 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 24 Oct 2014 12:42:44 +0200 Subject: [PATCH 04/21] Use createTypeError everywhere and stream out Location. --- libsolidity/AST.cpp | 5 +---- libsolidity/AST.h | 3 +-- libsolidity/BaseTypes.h | 7 +++++++ libsolidity/Exceptions.h | 6 +++--- libsolidity/NameAndTypeResolver.cpp | 3 +-- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 50c53bf37..357b9bd94 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -257,8 +257,7 @@ void Statement::expectType(Expression& _expression, const Type& _expectedType) { _expression.checkTypeRequirements(); if (!_expression.getType()->isImplicitlyConvertibleTo(_expectedType)) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_sourceLocation(_expression.getLocation()) - << errinfo_comment("Type not implicitly convertible to expected type.")); + BOOST_THROW_EXCEPTION(_expression.createTypeError("Type not implicitly convertible to expected type.")); //@todo provide more information to the exception } @@ -407,9 +406,7 @@ void FunctionCall::checkTypeRequirements() m_type = fun.getReturnParameterList()->getParameters().front()->getType(); } else - { BOOST_THROW_EXCEPTION(createTypeError("Type does not support invocation.")); - } } void MemberAccess::checkTypeRequirements() diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 5679ed831..e94137a84 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -57,8 +57,7 @@ public: Location const& getLocation() const { return m_location; } -protected: - /// Creates a @ref TypeError exception and decorates it with the current location and + /// Creates a @ref TypeError exception and decorates it with the location of the node and /// the given description TypeError createTypeError(std::string const& _description); diff --git a/libsolidity/BaseTypes.h b/libsolidity/BaseTypes.h index fdf3f7b53..cfc14c7e9 100644 --- a/libsolidity/BaseTypes.h +++ b/libsolidity/BaseTypes.h @@ -22,6 +22,7 @@ #pragma once +#include namespace dev { @@ -41,5 +42,11 @@ struct Location int end; }; +/// Stream output for Location (used e.g. in boost exceptions). +inline std::ostream& operator<<(std::ostream& _out, Location const& _location) +{ + return _out << "[" << _location.start << "," << _location.end << ")"; +} + } } diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index 330c37788..5a48c47dd 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -31,9 +31,9 @@ namespace dev namespace solidity { -struct ParserError: public virtual Exception {}; -struct TypeError: public virtual Exception {}; -struct DeclarationError: public virtual Exception {}; +struct ParserError: virtual Exception {}; +struct TypeError: virtual Exception {}; +struct DeclarationError: virtual Exception {}; typedef boost::error_info errinfo_sourcePosition; typedef boost::error_info errinfo_sourceLocation; diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index a56502727..c0467b036 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -182,8 +182,7 @@ bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) StructDefinition* referencedStruct = dynamic_cast(declaration); //@todo later, contracts are also valid types if (referencedStruct == nullptr) - BOOST_THROW_EXCEPTION(TypeError() << errinfo_sourceLocation(_typeName.getLocation()) - << errinfo_comment("Identifier does not name a type name.")); + BOOST_THROW_EXCEPTION(_typeName.createTypeError("Identifier does not name a type name.")); _typeName.setReferencedStruct(*referencedStruct); return false; } From 19e7a08b0e042b53de65ddba1fb4b539bc9bc4e9 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 24 Oct 2014 16:43:11 +0200 Subject: [PATCH 05/21] Remove nullptr comparisons. --- libsolidity/AST.cpp | 16 ++++++++-------- libsolidity/AST.h | 2 +- libsolidity/ASTPrinter.cpp | 2 +- libsolidity/NameAndTypeResolver.cpp | 14 +++++++------- libsolidity/Scope.cpp | 2 +- libsolidity/SourceReferenceFormatter.cpp | 9 +++------ 6 files changed, 21 insertions(+), 24 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 357b9bd94..91b4a42b1 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -291,7 +291,7 @@ void Break::checkTypeRequirements() void Return::checkTypeRequirements() { - BOOST_ASSERT(m_returnParameters != nullptr); + BOOST_ASSERT(m_returnParameters); if (m_returnParameters->getParameters().size() != 1) BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement " "than in returns declaration.")); @@ -374,7 +374,7 @@ void FunctionCall::checkTypeRequirements() if (category == Type::Category::TYPE) { TypeType const* type = dynamic_cast(&expressionType); - BOOST_ASSERT(type != nullptr); + BOOST_ASSERT(type); //@todo for structs, we have to check the number of arguments to be equal to the // number of non-mapping members if (m_arguments.size() != 1) @@ -390,7 +390,7 @@ void FunctionCall::checkTypeRequirements() // and then ask if that is implicitly convertible to the struct represented by the // function parameters FunctionType const* function = dynamic_cast(&expressionType); - BOOST_ASSERT(function != nullptr); + BOOST_ASSERT(function); FunctionDefinition const& fun = function->getFunction(); std::vector> const& parameters = fun.getParameters(); if (parameters.size() != m_arguments.size()) @@ -423,7 +423,7 @@ void IndexAccess::checkTypeRequirements() void Identifier::checkTypeRequirements() { - BOOST_ASSERT(m_referencedDeclaration != nullptr); + BOOST_ASSERT(m_referencedDeclaration); //@todo these dynamic casts here are not really nice... // is i useful to have an AST visitor here? // or can this already be done in NameAndTypeResolver? @@ -433,7 +433,7 @@ void Identifier::checkTypeRequirements() // var y = x; // the type of x is not yet determined. VariableDeclaration* variable = dynamic_cast(m_referencedDeclaration); - if (variable != nullptr) + if (variable) { if (!variable->getType()) BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type " @@ -443,14 +443,14 @@ void Identifier::checkTypeRequirements() } //@todo can we unify these with TypeName::toType()? StructDefinition* structDef = dynamic_cast(m_referencedDeclaration); - if (structDef != nullptr) + if (structDef) { // note that we do not have a struct type here m_type = std::make_shared(std::make_shared(*structDef)); return; } FunctionDefinition* functionDef = dynamic_cast(m_referencedDeclaration); - if (functionDef != nullptr) + if (functionDef) { // a function reference is not a TypeType, because calling a TypeType converts to the type. // Calling a function (e.g. function(12), otherContract.function(34)) does not do a type @@ -459,7 +459,7 @@ void Identifier::checkTypeRequirements() return; } ContractDefinition* contractDef = dynamic_cast(m_referencedDeclaration); - if (contractDef != nullptr) + if (contractDef) { m_type = std::make_shared(std::make_shared(*contractDef)); return; diff --git a/libsolidity/AST.h b/libsolidity/AST.h index e94137a84..df146ab10 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -169,7 +169,7 @@ public: Declaration(_location, _name), m_typeName(_type) {} virtual void accept(ASTVisitor& _visitor) override; - bool isTypeGivenExplicitly() const { return m_typeName.get() != nullptr; } + bool isTypeGivenExplicitly() const { return bool(m_typeName); } TypeName* getTypeName() const { return m_typeName.get(); } //! Returns the declared or inferred type. Can be an empty pointer if no type was explicitly diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index c512bd3f9..6d782f274 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -243,7 +243,7 @@ bool ASTPrinter::visit(ElementaryTypeNameExpression& _node) bool ASTPrinter::visit(Literal& _node) { char const* tokenString = Token::toString(_node.getToken()); - if (tokenString == nullptr) + if (!tokenString) tokenString = "[no token]"; writeLine(std::string("Literal, token: ") + tokenString + " value: " + _node.getValue()); printSourcePart(_node); diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index c0467b036..e9d90dc88 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -129,13 +129,13 @@ void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _node) void DeclarationRegistrationHelper::closeCurrentScope() { - BOOST_ASSERT(m_currentScope != nullptr); + BOOST_ASSERT(m_currentScope); m_currentScope = m_currentScope->getOuterScope(); } void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) { - BOOST_ASSERT(m_currentScope != nullptr); + BOOST_ASSERT(m_currentScope); if (!m_currentScope->registerDeclaration(_declaration)) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) << errinfo_comment("Identifier already declared.")); @@ -155,14 +155,14 @@ void ReferencesResolver::endVisit(VariableDeclaration& _variable) { // endVisit because the internal type needs resolving if it is a user defined type // or mapping - if (_variable.getTypeName() != nullptr) + if (_variable.getTypeName()) _variable.setType(_variable.getTypeName()->toType()); // otherwise we have a "var"-declaration whose type is resolved by the first assignment } bool ReferencesResolver::visit(Return& _return) { - BOOST_ASSERT(m_returnParameters != nullptr); + BOOST_ASSERT(m_returnParameters); _return.setFunctionReturnParameters(*m_returnParameters); return true; } @@ -176,12 +176,12 @@ bool ReferencesResolver::visit(Mapping&) bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_typeName.getName()); - if (declaration == nullptr) + if (!declaration) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_typeName.getLocation()) << errinfo_comment("Undeclared identifier.")); StructDefinition* referencedStruct = dynamic_cast(declaration); //@todo later, contracts are also valid types - if (referencedStruct == nullptr) + if (!referencedStruct) BOOST_THROW_EXCEPTION(_typeName.createTypeError("Identifier does not name a type name.")); _typeName.setReferencedStruct(*referencedStruct); return false; @@ -190,7 +190,7 @@ bool ReferencesResolver::visit(UserDefinedTypeName& _typeName) bool ReferencesResolver::visit(Identifier& _identifier) { Declaration* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName()); - if (declaration == nullptr) + if (!declaration) BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_identifier.getLocation()) << errinfo_comment("Undeclared identifier.")); _identifier.setReferencedDeclaration(*declaration); diff --git a/libsolidity/Scope.cpp b/libsolidity/Scope.cpp index 28a54dd27..4fcd2f45e 100644 --- a/libsolidity/Scope.cpp +++ b/libsolidity/Scope.cpp @@ -41,7 +41,7 @@ Declaration* Scope::resolveName(ASTString const& _name, bool _recursive) const auto result = m_declarations.find(_name); if (result != m_declarations.end()) return result->second; - if (_recursive && m_outerScope != nullptr) + if (_recursive && m_outerScope) return m_outerScope->resolveName(_name, true); return nullptr; } diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/SourceReferenceFormatter.cpp index 6d2911165..665df32a4 100644 --- a/libsolidity/SourceReferenceFormatter.cpp +++ b/libsolidity/SourceReferenceFormatter.cpp @@ -74,18 +74,15 @@ void SourceReferenceFormatter::printExceptionInformation(std::ostream& _stream, Scanner const& _scanner) { std::cerr << _name; - std::string const* description = boost::get_error_info(_exception); - if (description != nullptr) + if (std::string const* description = boost::get_error_info(_exception)) std::cerr << ": " << *description; - int const* position = boost::get_error_info(_exception); - if (position != nullptr) + if (int const* position = boost::get_error_info(_exception)) { std::cerr << " "; printSourcePosition(std::cerr, *position, _scanner); } - Location const* location = boost::get_error_info(_exception); - if (location != nullptr) + if (Location const* location = boost::get_error_info(_exception)) { std::cerr << " "; printSourceLocation(_stream, *location, _scanner); From c5698b7341e426238487095aa871baff8222d286 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 24 Oct 2014 16:47:10 +0200 Subject: [PATCH 06/21] Use endl instead of "\n". --- libsolidity/ASTPrinter.cpp | 4 ++-- libsolidity/SourceReferenceFormatter.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index 6d782f274..e79146d05 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -406,7 +406,7 @@ void ASTPrinter::printSourcePart(ASTNode const& _node) { Location const& location(_node.getLocation()); *m_ostream << getIndentation() << " Source: |" - << m_source.substr(location.start, location.end - location.start) << "|\n"; + << m_source.substr(location.start, location.end - location.start) << "|" << std::endl; } } @@ -417,7 +417,7 @@ std::string ASTPrinter::getIndentation() const void ASTPrinter::writeLine(std::string const& _line) { - *m_ostream << getIndentation() << _line << '\n'; + *m_ostream << getIndentation() << _line << std::endl; } } diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/SourceReferenceFormatter.cpp index 665df32a4..bc9e8f262 100644 --- a/libsolidity/SourceReferenceFormatter.cpp +++ b/libsolidity/SourceReferenceFormatter.cpp @@ -42,16 +42,16 @@ void SourceReferenceFormatter::printSourceLocation(std::ostream& _stream, std::tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end); if (startLine == endLine) { - _stream << _scanner.getLineAtPosition(_location.start) << "\n" + _stream << _scanner.getLineAtPosition(_location.start) << std::endl << std::string(startColumn, ' ') << "^"; if (endColumn > startColumn + 2) _stream << std::string(endColumn - startColumn - 2, '-'); if (endColumn > startColumn + 1) _stream << "^"; - _stream << "\n"; + _stream << std::endl; } else - _stream << _scanner.getLineAtPosition(_location.start) << "\n" + _stream << _scanner.getLineAtPosition(_location.start) << std::endl << std::string(startColumn, ' ') << "^\n" << "Spanning multiple lines.\n"; } @@ -63,8 +63,8 @@ void SourceReferenceFormatter::printSourcePosition(std::ostream& _stream, int line; int column; std::tie(line, column) = _scanner.translatePositionToLineColumn(_position); - _stream << "at line " << (line + 1) << ", column " << (column + 1) << "\n" - << _scanner.getLineAtPosition(_position) << "\n" + _stream << "at line " << (line + 1) << ", column " << (column + 1) << std::endl + << _scanner.getLineAtPosition(_position) << std::endl << std::string(column, ' ') << "^" << std::endl; } From dfea1573130de8416462a9aa74b8d3dd9149d013 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 24 Oct 2014 19:08:31 +0200 Subject: [PATCH 07/21] Use the passed stream, not std::cerr. --- libsolidity/SourceReferenceFormatter.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/SourceReferenceFormatter.cpp index bc9e8f262..b270342c9 100644 --- a/libsolidity/SourceReferenceFormatter.cpp +++ b/libsolidity/SourceReferenceFormatter.cpp @@ -73,18 +73,18 @@ void SourceReferenceFormatter::printExceptionInformation(std::ostream& _stream, std::string const& _name, Scanner const& _scanner) { - std::cerr << _name; + _stream << _name; if (std::string const* description = boost::get_error_info(_exception)) - std::cerr << ": " << *description; + _stream << ": " << *description; if (int const* position = boost::get_error_info(_exception)) { - std::cerr << " "; - printSourcePosition(std::cerr, *position, _scanner); + _stream << " "; + printSourcePosition(_stream, *position, _scanner); } if (Location const* location = boost::get_error_info(_exception)) { - std::cerr << " "; + _stream << " "; printSourceLocation(_stream, *location, _scanner); } } From 6181b6d2c7a2d9a43a8fba35c8d24f54952f20bb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 24 Oct 2014 21:28:55 +0200 Subject: [PATCH 08/21] Whisper is functional from the JS API. --- alethzero/MainWin.cpp | 3 + libqethereum/QEthereum.cpp | 139 +++++++++++++++++++++++++++++++++---- libqethereum/QEthereum.h | 22 +++--- libwhisper/Common.cpp | 16 +++-- libwhisper/Common.h | 6 +- libwhisper/Interface.h | 4 +- libwhisper/Message.cpp | 7 +- libwhisper/Message.h | 14 ++-- libwhisper/WhisperHost.cpp | 2 +- third/MainWin.cpp | 3 + 10 files changed, 172 insertions(+), 44 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 68fe0a0f1..9a98f54ee 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -151,6 +151,7 @@ Main::Main(QWidget *parent) : connect(ui->webView, &QWebView::loadFinished, [=]() { m_ethereum->poll(); + m_whisper->poll(); }); connect(ui->webView, &QWebView::titleChanged, [=]() @@ -1001,6 +1002,8 @@ void Main::timerEvent(QTimerEvent*) if (m_ethereum) m_ethereum->poll(); + if (m_whisper) + m_whisper->poll(); for (auto const& i: m_handlers) if (ethereum()->checkWatch(i.first)) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 267fed35e..d87f4ecb3 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "QEthereum.h" using namespace std; using namespace dev; @@ -21,7 +23,7 @@ dev::bytes toBytes(QString const& _s) else { // Binary - cwarn << "THIS FUNCTIONALITY IS DEPRECATED. DO NOT ASSUME ASCII/BINARY-STRINGS WILL BE ACCEPTED. USE eth.fromAscii()."; + cwarn << "'" << _s.toStdString() << "': Unrecognised format for number/hash. USE eth.fromAscii() if you mean to convert from ASCII."; return asBytes(_s); } } @@ -558,37 +560,148 @@ void QWhisper::faceDieing() } -void QWhisper::send(QString /*dev::Address*/ _dest, QString /*ev::KeyPair*/ _from, QString /*dev::h256 const&*/ _topic, QString /*dev::bytes const&*/ _payload) +static shh::Message toMessage(QString _json) { - (void)_dest; - (void)_from; - (void)_topic; - (void)_payload; + shh::Message ret; + + QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); + if (f.contains("from")) + ret.setFrom(toPublic(f["from"].toString())); + if (f.contains("to")) + ret.setTo(toPublic(f["to"].toString())); + if (f.contains("payload")) + ret.setPayload(toBytes(f["payload"].toString())); + + return ret; } -unsigned QWhisper::newWatch(QString _json) +static shh::Envelope toSealed(QString _json, shh::Message const& _m, Secret _from) { - (void)_json; - return 0; + unsigned ttl = 50; + unsigned workToProve = 50; + + shh::BuildTopic bt; + + QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); + if (f.contains("ttl")) + ttl = f["ttl"].toInt(); + if (f.contains("workToProve")) + workToProve = f["workToProve"].toInt(); + if (f.contains("topic")) + { + if (f["topic"].isString()) + bt.shift(asBytes(padded(f["topic"].toString(), 32))); + else if (f["topic"].isArray()) + for (auto i: f["topic"].toArray()) + bt.shift(asBytes(padded(i.toString(), 32))); + } + return _m.seal(_from, bt, workToProve, ttl); } -QString QWhisper::watchMessages(unsigned _w) +void QWhisper::doPost(QString _json) { - (void)_w; - return ""; + shh::Message m = toMessage(_json); + Secret from; + + if (m.from() && m_ids.count(m.from())) + { + cwarn << "Silently signing message from identity" << m.from().abridged() << ": User validation hook goes here."; + // TODO: insert validification hook here. + from = m_ids[m.from()]; + } + + face()->inject(toSealed(_json, m, from)); +} + +static pair toWatch(QString _json) +{ + shh::BuildTopicMask bt(shh::BuildTopicMask::Empty); + Public to; + + QJsonObject f = QJsonDocument::fromJson(_json.toUtf8()).object(); + if (f.contains("to")) + to = toPublic(f["to"].toString()); + + if (f.contains("topic")) + { + if (f["topic"].isString()) + bt.shift(asBytes(padded(f["topic"].toString(), 32))); + else if (f["topic"].isArray()) + for (auto i: f["topic"].toArray()) + if (i.isString()) + bt.shift(asBytes(padded(i.toString(), 32))); + else + bt.shift(); + } + return make_pair(bt.toTopicMask(), to); +} + +// _json contains +// topic: the topic as an array of components, some may be null. +// to: specifies the id to which the message is encrypted. null if broadcast. +unsigned QWhisper::newWatch(QString _json) +{ + auto w = toWatch(_json); + auto ret = face()->installWatch(w.first); + m_watches.insert(make_pair(ret, w.second)); + return ret; } void QWhisper::killWatch(unsigned _w) { - (void)_w; + face()->uninstallWatch(_w); + m_watches.erase(_w); } void QWhisper::clearWatches() { + for (auto i: m_watches) + face()->uninstallWatch(i.first); + m_watches.clear(); +} + +QString QWhisper::newIdentity() +{ + KeyPair kp = KeyPair::create(); + m_ids[kp.pub()] = kp.sec(); + return toQJS(kp.pub()); +} + +static QString toJson(h256 const& _h, shh::Envelope const& _e, shh::Message const& _m) +{ + QJsonObject v; + v["hash"] = toQJS(_h); + + v["expiry"] = (int)_e.expiry(); + v["sent"] = (int)_e.sent(); + v["ttl"] = (int)_e.ttl(); + v["workProved"] = (int)_e.workProved(); + v["topic"] = toQJS(_e.topic()); + + v["payload"] = toQJS(_m.payload()); + v["from"] = toQJS(_m.from()); + v["to"] = toQJS(_m.to()); + + return QString::fromUtf8(QJsonDocument(v).toJson()); } void QWhisper::poll() { + for (auto const& w: m_watches) + if (!w.second || m_ids.count(w.second)) + for (h256 const& h: face()->checkWatch(w.first)) + { + auto e = face()->envelope(h); + shh::Message m; + if (w.second) + { + cwarn << "Silently decrypting message from identity" << w.second.abridged() << ": User validation hook goes here."; + m = e.open(m_ids[w.second]); + } + else + m = e.open(); + emit watchChanged(w.first, toJson(h, e, m)); + } } // extra bits needed to link on VS diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 2d6ea8b4c..42696d40c 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -59,8 +59,9 @@ template dev::FixedHash toFixed(QString const& _s) template inline boost::multiprecision::number> toInt(QString const& _s); -inline dev::Address toAddress(QString const& _s) { return toFixed<20>(_s); } -inline dev::Secret toSecret(QString const& _s) { return toFixed<32>(_s); } +inline dev::Address toAddress(QString const& _s) { return toFixed(_s); } +inline dev::Public toPublic(QString const& _s) { return toFixed(_s); } +inline dev::Secret toSecret(QString const& _s) { return toFixed(_s); } inline dev::u256 toU256(QString const& _s) { return toInt<32>(_s); } template QString toQJS(dev::FixedHash const& _h) { return QString::fromStdString("0x" + toHex(_h.ref())); } @@ -225,12 +226,12 @@ public: Q_INVOKABLE QWhisper* self() { return this; } /// Basic message send. - Q_INVOKABLE void send(QString /*dev::Address*/ _dest, QString /*ev::KeyPair*/ _from, QString /*dev::h256 const&*/ _topic, QString /*dev::bytes const&*/ _payload); + Q_INVOKABLE void doPost(QString _json); - // Watches interface + Q_INVOKABLE QString newIdentity(); + // Watches interface Q_INVOKABLE unsigned newWatch(QString _json); - Q_INVOKABLE QString watchMessages(unsigned _w); Q_INVOKABLE void killWatch(unsigned _w); void clearWatches(); @@ -240,11 +241,13 @@ public slots: void poll(); signals: - void watchChanged(unsigned _w); + void watchChanged(unsigned _w, QString _envelopeJson); private: std::weak_ptr m_face; - std::vector m_watches; + std::map m_watches; + + std::map m_ids; }; // TODO: add p2p object @@ -269,8 +272,9 @@ private: if (_shh) \ { \ _frame->addToJavaScriptWindowObject("_web3_dot_shh", _shh, QWebFrame::ScriptOwnership); \ - _frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(a) { var ww = _web3_dot_shh.newWatch(a); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(w); }; ret.changed = function(f) { _web3_dot_shh.watchChanged.connect(function(nw) { if (nw == ww) f() }); }; ret.messages = function() { return JSON.parse(_web3_dot_shh.watchMessages(this.w)) }; return ret; }"); \ - _frame->evaluateJavaScript("_web3_dot_shh.watch = function(a) { return _web3_dot_shh.makeWatch(JSON.stringify(a)) }"); \ + _frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(json) { var ww = _web3_dot_shh.newWatch(json); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(w); }; ret.arrived = function(f) { _web3_dot_shh.watchChanged.connect(function(nw, envelope) { if (nw == ww) f(JSON.parse(envelope)) }); }; return ret; }"); \ + _frame->evaluateJavaScript("_web3_dot_shh.watch = function(filter) { return _web3_dot_shh.makeWatch(JSON.stringify(filter)) }"); \ + _frame->evaluateJavaScript("_web3_dot_shh.post = function(message) { return _web3_dot_shh.doPost(JSON.stringify(message)) }"); \ _frame->evaluateJavaScript("web3.shh = _web3_dot_shh"); \ } \ } diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index e4903821c..c4c103de3 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -43,10 +43,16 @@ h256 TopicFilter::sha3() const TopicMask BuildTopicMask::toTopicMask() const { TopicMask ret; - for (auto i = 0; i < 32; ++i) - { - ret.first[i] = m_parts[i * m_parts.size() / 32][i]; - ret.second[i] = m_parts[i * m_parts.size() / 32] ? 255 : 0; - } + if (m_parts.size()) + for (auto i = 0; i < 32; ++i) + { + ret.first[i] = m_parts[i * m_parts.size() / 32][i]; + ret.second[i] = m_parts[i * m_parts.size() / 32] ? 255 : 0; + } return ret; } +/* +web3.shh.watch({}, function(m) { env.note("New message:\n"+JSON.stringify(m)); }) +k = web3.shh.newIdentity() +web3.shh.post({from: k, topic: web3.fromAscii("test"), payload: web3.fromAscii("Hello world!")}) +*/ diff --git a/libwhisper/Common.h b/libwhisper/Common.h index 1f4c4a17f..a85caafe1 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -64,6 +64,7 @@ using Topic = h256; class BuildTopic { public: + BuildTopic() {} template BuildTopic(T const& _t) { shift(_t); } template BuildTopic& shift(T const& _r) { return shiftBytes(RLPStream().append(_r).out()); } @@ -75,8 +76,6 @@ public: Topic toTopic() const { Topic ret; for (auto i = 0; i < 32; ++i) ret[i] = m_parts[i * m_parts.size() / 32][i]; return ret; } protected: - BuildTopic() {} - BuildTopic& shiftBytes(bytes const& _b); h256s m_parts; @@ -105,7 +104,10 @@ private: class BuildTopicMask: BuildTopic { public: + enum EmptyType { Empty }; + BuildTopicMask() { shift(); } + BuildTopicMask(EmptyType) {} template BuildTopicMask(T const& _t) { shift(_t); } template BuildTopicMask& shift(T const& _r) { BuildTopic::shift(_r); return *this; } diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index 63cc44a9b..8bc37ff5e 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -79,9 +79,9 @@ public: virtual Envelope envelope(h256 _m) const = 0; void post(bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topic, _ttl, _workToProve)); } - void post(Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_to, _topic, _ttl, _workToProve)); } + void post(Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_to, _topic, _ttl, _workToProve)); } void post(Secret _from, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topic, _ttl, _workToProve)); } - void post(Secret _from, Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _to, _topic, _ttl, _workToProve)); } + void post(Secret _from, Public _to, bytes const& _payload, Topic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topic, _ttl, _workToProve)); } }; struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index 80b493076..52caf2f90 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -60,7 +60,7 @@ void Message::populate(bytes const& _data) m_payload = bytesConstRef(&_data).cropped(1).toBytes(); } -Envelope Message::seal(Secret _from, Topic const& _topic, unsigned _ttl, unsigned _workToProve) +Envelope Message::seal(Secret _from, Topic const& _topic, unsigned _ttl, unsigned _workToProve) const { Envelope ret(time(0) + _ttl, _ttl, _topic); @@ -91,11 +91,6 @@ Message Envelope::open(Secret const& _s) const return Message(*this, _s); } -Message Envelope::open() const -{ - return Message(*this); -} - unsigned Envelope::workProved() const { h256 d[2]; diff --git a/libwhisper/Message.h b/libwhisper/Message.h index fa5cc3662..67b34e321 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -65,8 +65,7 @@ public: Topic const& topic() const { return m_topic; } bytes const& data() const { return m_data; } - Message open(Secret const& _s) const; - Message open() const; + Message open(Secret const& _s = Secret()) const; unsigned workProved() const; void proveWork(unsigned _ms); @@ -102,16 +101,19 @@ public: Public to() const { return m_to; } bytes const& payload() const { return m_payload; } + void setFrom(Public _from) { m_from = _from; } void setTo(Public _to) { m_to = _to; } + void setPayload(bytes const& _payload) { m_payload = _payload; } + void setPayload(bytes&& _payload) { swap(m_payload, _payload); } operator bool() const { return !!m_payload.size() || m_from || m_to; } /// Turn this message into a ditributable Envelope. - Envelope seal(Secret _from, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50); + Envelope seal(Secret _from, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) const; // Overloads for skipping _from or specifying _to. - Envelope seal(Topic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { return seal(Secret(), _topic, _workToProve, _ttl); } - Envelope seal(Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(Secret(), _topic, _workToProve, _ttl); } - Envelope seal(Secret _from, Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(_from, _topic, _workToProve, _ttl); } + Envelope seal(Topic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) const { return seal(Secret(), _topic, _workToProve, _ttl); } + Envelope sealTo(Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(Secret(), _topic, _workToProve, _ttl); } + Envelope sealTo(Secret _from, Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(_from, _topic, _workToProve, _ttl); } private: void populate(bytes const& _data); diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 2d9a5e6b6..b11b4af3a 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -62,7 +62,7 @@ void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) m_messages[h] = _m; } - if (_p) +// if (_p) { Guard l(m_filterLock); for (auto const& f: m_filters) diff --git a/third/MainWin.cpp b/third/MainWin.cpp index d1f5938aa..dd5b01733 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -120,6 +120,7 @@ Main::Main(QWidget *parent) : connect(ui->webView, &QWebView::loadFinished, [=]() { m_ethereum->poll(); + m_whisper->poll(); }); connect(ui->webView, &QWebView::titleChanged, [=]() @@ -522,6 +523,8 @@ void Main::timerEvent(QTimerEvent*) if (m_ethereum) m_ethereum->poll(); + if (m_whisper) + m_whisper->poll(); for (auto const& i: m_handlers) if (ethereum()->checkWatch(i.first)) From e1d42ee25042e2415dd014946713aa8f7bb727cc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 13:15:15 +0200 Subject: [PATCH 09/21] Update serpent. Disable wallet import for now. --- alethzero/Main.ui | 3 + libdevcrypto/CryptoPP.h | 6 +- libpyserpent/pyserpent.cpp | 12 +++ libserpent/compiler.cpp | 6 +- libserpent/funcs.cpp | 12 +++ libserpent/funcs.h | 6 ++ libserpent/parser.cpp | 22 ++-- libserpent/rewriter.cpp | 16 ++- libserpent/rewriter.h | 3 + libserpent/util.cpp | 6 +- libwhisper/Common.cpp | 2 +- sc/cmdline.cpp | 205 ++++++++++++++++++++----------------- 12 files changed, 184 insertions(+), 115 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 5a6eb6f32..16dcd8a4c 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -1789,6 +1789,9 @@ font-size: 14pt + + false + Claim Ether Presale &Wallet... diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index d7e4181ee..6070b651b 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -23,12 +23,11 @@ #pragma once -// need to leave this one disabled -//#pragma GCC diagnostic ignored "-Wunused-function" +// need to leave this one disabled for link-time. blame cryptopp. +#pragma GCC diagnostic ignored "-Wunused-function" #pragma warning(push) #pragma warning(disable:4100 4244) #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-variable" @@ -58,6 +57,7 @@ namespace crypto namespace pp { + /// RNG used by CryptoPP inline CryptoPP::AutoSeededRandomPool& PRNG() { static CryptoPP::AutoSeededRandomPool prng; return prng; } diff --git a/libpyserpent/pyserpent.cpp b/libpyserpent/pyserpent.cpp index d97fd8fed..ff8813fcf 100644 --- a/libpyserpent/pyserpent.cpp +++ b/libpyserpent/pyserpent.cpp @@ -120,11 +120,15 @@ std::vector cppifyNodeList(PyObject* o) { } PYMETHOD(ps_compile, FROMSTR, compile, pyifyString) +PYMETHOD(ps_compile_chunk, FROMSTR, compileChunk, pyifyString) PYMETHOD(ps_compile_to_lll, FROMSTR, compileToLLL, pyifyNode) +PYMETHOD(ps_compile_chunk_to_lll, FROMSTR, compileChunkToLLL, pyifyNode) PYMETHOD(ps_compile_lll, FROMNODE, compileLLL, pyifyString) PYMETHOD(ps_parse, FROMSTR, parseSerpent, pyifyNode) PYMETHOD(ps_rewrite, FROMNODE, rewrite, pyifyNode) +PYMETHOD(ps_rewrite_chunk, FROMNODE, rewriteChunk, pyifyNode) PYMETHOD(ps_pretty_compile, FROMSTR, prettyCompile, pyifyNodeList) +PYMETHOD(ps_pretty_compile_chunk, FROMSTR, prettyCompileChunk, pyifyNodeList) PYMETHOD(ps_pretty_compile_lll, FROMNODE, prettyCompileLLL, pyifyNodeList) PYMETHOD(ps_serialize, FROMLIST, serialize, pyifyString) PYMETHOD(ps_deserialize, FROMSTR, deserialize, pyifyNodeList) @@ -134,16 +138,24 @@ PYMETHOD(ps_parse_lll, FROMSTR, parseLLL, pyifyNode) static PyMethodDef PyextMethods[] = { {"compile", ps_compile, METH_VARARGS, "Compile code."}, + {"compile_chunk", ps_compile_chunk, METH_VARARGS, + "Compile code chunk (no wrappers)."}, {"compile_to_lll", ps_compile_to_lll, METH_VARARGS, "Compile code to LLL."}, + {"compile_chunk_to_lll", ps_compile_chunk_to_lll, METH_VARARGS, + "Compile code chunk to LLL (no wrappers)."}, {"compile_lll", ps_compile_lll, METH_VARARGS, "Compile LLL to EVM."}, {"parse", ps_parse, METH_VARARGS, "Parse serpent"}, {"rewrite", ps_rewrite, METH_VARARGS, "Rewrite parsed serpent to LLL"}, + {"rewrite_chunk", ps_rewrite_chunk, METH_VARARGS, + "Rewrite parsed serpent to LLL (no wrappers)"}, {"pretty_compile", ps_pretty_compile, METH_VARARGS, "Compile to EVM opcodes"}, + {"pretty_compile_chunk", ps_pretty_compile_chunk, METH_VARARGS, + "Compile chunk to EVM opcodes (no wrappers)"}, {"pretty_compile_lll", ps_pretty_compile_lll, METH_VARARGS, "Compile LLL to EVM opcodes"}, {"serialize", ps_serialize, METH_VARARGS, diff --git a/libserpent/compiler.cpp b/libserpent/compiler.cpp index 4360bfba6..61b70de05 100644 --- a/libserpent/compiler.cpp +++ b/libserpent/compiler.cpp @@ -298,7 +298,7 @@ Node finalize(programData c) { Metadata m = c.code.metadata; // If we are using both alloc and variables, we need to pre-zfill // some memory - if (c.aux.allocUsed && c.aux.vars.size() > 0) { + if ((c.aux.allocUsed || c.aux.calldataUsed) && c.aux.vars.size() > 0) { Node nodelist[] = { token("0", m), token(unsignedToDecimal(c.aux.vars.size() * 32 - 1)), @@ -309,8 +309,8 @@ Node finalize(programData c) { // If msg.data is being used as an array, then we need to copy it if (c.aux.calldataUsed) { Node nodelist[] = { - token("MSIZE", m), token("CALLDATASIZE", m), token("MSIZE", m), - token("0", m), token("CALLDATACOPY", m), + token("MSIZE", m), token("CALLDATASIZE", m), token("0", m), + token("MSIZE", m), token("CALLDATACOPY", m), token(c.aux.vars["'msg.data"], m), token("MSTORE", m) }; bottom.push_back(multiToken(nodelist, 7, m)); diff --git a/libserpent/funcs.cpp b/libserpent/funcs.cpp index e80fcff06..ea9be14a6 100644 --- a/libserpent/funcs.cpp +++ b/libserpent/funcs.cpp @@ -14,6 +14,10 @@ Node compileToLLL(std::string input) { return rewrite(parseSerpent(input)); } +Node compileChunkToLLL(std::string input) { + return rewriteChunk(parseSerpent(input)); +} + std::string compile(std::string input) { return compileLLL(compileToLLL(input)); } @@ -21,3 +25,11 @@ std::string compile(std::string input) { std::vector prettyCompile(std::string input) { return prettyCompileLLL(compileToLLL(input)); } + +std::string compileChunk(std::string input) { + return compileLLL(compileChunkToLLL(input)); +} + +std::vector prettyCompileChunk(std::string input) { + return prettyCompileLLL(compileChunkToLLL(input)); +} diff --git a/libserpent/funcs.h b/libserpent/funcs.h index 0f3355ec8..d9bf44549 100644 --- a/libserpent/funcs.h +++ b/libserpent/funcs.h @@ -24,6 +24,12 @@ Node compileToLLL(std::string input); +Node compileChunkToLLL(std::string input); + std::string compile(std::string input); std::vector prettyCompile(std::string input); + +std::string compileChunk(std::string input); + +std::vector prettyCompileChunk(std::string input); diff --git a/libserpent/parser.cpp b/libserpent/parser.cpp index 5adf1672d..09fcdfc47 100644 --- a/libserpent/parser.cpp +++ b/libserpent/parser.cpp @@ -32,7 +32,7 @@ int toktype(Node tok) { if (v == "(" || v == "[" || v == "{") return LPAREN; else if (v == ")" || v == "]" || v == "}") return RPAREN; else if (v == ",") return COMMA; - else if (v == "!" || v == "not") return UNARY_OP; + else if (v == "!" || v == "not" || v == "neg") return UNARY_OP; else if (precedence(tok) >= 0) return BINARY_OP; if (tok.val[0] != '"' && tok.val[0] != '\'') { for (unsigned i = 0; i < tok.val.length(); i++) { @@ -91,17 +91,19 @@ std::vector shuntingYard(std::vector tokens) { // If binary op, keep popping from stack while higher bedmas precedence else if (toktyp == BINARY_OP) { if (tok.val == "-" && prevtyp != ALPHANUM && prevtyp != RPAREN) { - oq.push_back(token("0", tok.metadata)); + stack.push_back(token("neg", tok.metadata)); } - int prec = precedence(tok); - while (stack.size() - && (toktype(stack.back()) == BINARY_OP - || toktype(stack.back()) == UNARY_OP) - && precedence(stack.back()) <= prec) { - oq.push_back(stack.back()); - stack.pop_back(); + else { + int prec = precedence(tok); + while (stack.size() + && (toktype(stack.back()) == BINARY_OP + || toktype(stack.back()) == UNARY_OP) + && precedence(stack.back()) <= prec) { + oq.push_back(stack.back()); + stack.pop_back(); + } + stack.push_back(tok); } - stack.push_back(tok); } // Comma means finish evaluating the argument else if (toktyp == COMMA) { diff --git a/libserpent/rewriter.cpp b/libserpent/rewriter.cpp index 72feb1277..eeefd2d09 100644 --- a/libserpent/rewriter.cpp +++ b/libserpent/rewriter.cpp @@ -28,6 +28,8 @@ std::string valid[][3] = { { "sha3", "1", "2" }, { "return", "1", "2" }, { "inset", "1", "1" }, + { "min", "2", "2" }, + { "max", "2", "2" }, { "array_lit", "0", tt256 }, { "seq", "0", tt256 }, { "---END---", "", "" } //Keep this line at the end of the list @@ -70,6 +72,14 @@ std::string macros[][2] = { "(!= $a $b)", "(not (eq $a $b))" }, + { + "(min a b)", + "(with $1 a (with $2 b (if (lt $1 $2) $1 $2)))" + }, + { + "(max a b)", + "(with $1 a (with $2 b (if (lt $1 $2) $2 $1)))" + }, { "(if $cond $do (else $else))", "(if $cond $do $else)" @@ -229,7 +239,7 @@ std::string macros[][2] = { }, { "(msg $gas $to $val $inp $inpsz $outsz)", - "(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (call $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2)))" + "(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (seq (call $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2))))" }, // Call stateless and msg stateless { @@ -561,4 +571,8 @@ Node rewrite(Node inp) { return optimize(apply_rules(validate(preprocess(inp)))); } +Node rewriteChunk(Node inp) { + return optimize(apply_rules(validate(inp))); +} + using namespace std; diff --git a/libserpent/rewriter.h b/libserpent/rewriter.h index b2e8f00dd..716815cee 100644 --- a/libserpent/rewriter.h +++ b/libserpent/rewriter.h @@ -10,4 +10,7 @@ // Applies rewrite rules Node rewrite(Node inp); +// Applies rewrite rules adding without wrapper +Node rewriteChunk(Node inp); + #endif diff --git a/libserpent/util.cpp b/libserpent/util.cpp index 693427c3f..cc1394a21 100644 --- a/libserpent/util.cpp +++ b/libserpent/util.cpp @@ -137,7 +137,7 @@ std::string strToNumeric(std::string inp) { } else if (inp.substr(0,2) == "0x") { for (unsigned i = 2; i < inp.length(); i++) { - int dig = std::string("0123456789abcdef").find(inp[i]); + int dig = std::string("0123456789abcdef0123456789ABCDEF").find(inp[i]) % 16; if (dig < 0) return ""; o = decimalAdd(decimalMul(o,"16"), unsignedToDecimal(dig)); } @@ -219,8 +219,8 @@ void err(std::string errtext, Metadata met) { std::string err = "Error (file \"" + met.file + "\", line " + unsignedToDecimal(met.ln + 1) + ", char " + unsignedToDecimal(met.ch) + "): " + errtext; - std::cerr << err << "\n"; - throw(err); + std::cerr << err << "\n"; + throw(err); } //Bin to hex diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index c4c103de3..11908d181 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -52,7 +52,7 @@ TopicMask BuildTopicMask::toTopicMask() const return ret; } /* -web3.shh.watch({}, function(m) { env.note("New message:\n"+JSON.stringify(m)); }) +web3.shh.watch({}).arrived(function(m) { env.note("New message:\n"+JSON.stringify(m)); }) k = web3.shh.newIdentity() web3.shh.post({from: k, topic: web3.fromAscii("test"), payload: web3.fromAscii("Hello world!")}) */ diff --git a/sc/cmdline.cpp b/sc/cmdline.cpp index d6602c56d..b44d2538c 100644 --- a/sc/cmdline.cpp +++ b/sc/cmdline.cpp @@ -3,100 +3,117 @@ #include #include #include -#include #include -#include -int main(int argv, char** argc) -{ - if (argv == 1) - { - std::cerr << "Must provide a command and arguments! Try parse, rewrite, compile, assemble\n"; - return 0; - } - std::string flag = ""; - std::string command = argc[1]; - std::string input; - std::string secondInput; - if (std::string(argc[1]) == "-s") - { - flag = command.substr(1); - command = argc[2]; - input = ""; - std::string line; - while (std::getline(std::cin, line)) - { - input += line + "\n"; - } - secondInput = argv == 3 ? "" : argc[3]; - } - else - { - if (argv == 2) - { - std::cerr << "Not enough arguments for serpent cmdline\n"; - BOOST_THROW_EXCEPTION(dev::Exception() << dev::errinfo_comment("Not enough arguments for serpent cmdline")); - } - input = argc[2]; - secondInput = argv == 3 ? "" : argc[3]; - } - bool haveSec = secondInput.length() > 0; - if (command == "parse" || command == "parse_serpent") - std::cout << printAST(parseSerpent(input), haveSec) << "\n"; - else if (command == "rewrite") - std::cout << printAST(rewrite(parseLLL(input, true)), haveSec) << "\n"; - else if (command == "compile_to_lll") - std::cout << printAST(compileToLLL(input), haveSec) << "\n"; - else if (command == "build_fragtree") - std::cout << printAST(buildFragmentTree(parseLLL(input, true))) << "\n"; - else if (command == "compile_lll") - std::cout << binToHex(compileLLL(parseLLL(input, true))) << "\n"; - else if (command == "dereference") - std::cout << printAST(dereference(parseLLL(input, true)), haveSec) <<"\n"; - else if (command == "pretty_assemble") - std::cout << printTokens(prettyAssemble(parseLLL(input, true))) <<"\n"; - else if (command == "pretty_compile_lll") - std::cout << printTokens(prettyCompileLLL(parseLLL(input, true))) << "\n"; - else if (command == "pretty_compile") - std::cout << printTokens(prettyCompile(input)) << "\n"; - else if (command == "assemble") - std::cout << assemble(parseLLL(input, true)) << "\n"; - else if (command == "serialize") - std::cout << binToHex(serialize(tokenize(input, Metadata(), false))) << "\n"; - else if (command == "flatten") - std::cout << printTokens(flatten(parseLLL(input, true))) << "\n"; - else if (command == "deserialize") - std::cout << printTokens(deserialize(hexToBin(input))) << "\n"; - else if (command == "compile") - std::cout << binToHex(compile(input)) << "\n"; - else if (command == "encode_datalist") - { - std::vector tokens = tokenize(input); - std::vector o; - for (int i = 0; i < (int)tokens.size(); i++) - o.push_back(tokens[i].val); - std::cout << binToHex(encodeDatalist(o)) << "\n"; - } - else if (command == "decode_datalist") - { - std::vector o = decodeDatalist(hexToBin(input)); - std::vector tokens; - for (int i = 0; i < (int)o.size(); i++) - tokens.push_back(token(o[i])); - std::cout << printTokens(tokens) << "\n"; - } - else if (command == "tokenize") - std::cout << printTokens(tokenize(input)); - else if (command == "biject") - { - if (argv == 3) - std::cerr << "Not enough arguments for biject\n"; - int pos = decimalToUnsigned(secondInput); - std::vector n = prettyCompile(input); - if (pos >= (int)n.size()) - std::cerr << "Code position too high\n"; - Metadata m = n[pos].metadata; - std::cout << "Opcode: " << n[pos].val << ", file: " << m.file << - ", line: " << m.ln << ", char: " << m.ch << "\n"; - } +int main(int argv, char** argc) { + if (argv == 1) { + std::cerr << "Must provide a command and arguments! Try parse, rewrite, compile, assemble\n"; + return 0; + } + std::string flag = ""; + std::string command = argc[1]; + std::string input; + std::string secondInput; + if (std::string(argc[1]) == "-s") { + flag = command.substr(1); + command = argc[2]; + input = ""; + std::string line; + while (std::getline(std::cin, line)) { + input += line + "\n"; + } + secondInput = argv == 3 ? "" : argc[3]; + } + else { + if (argv == 2) { + std::cerr << "Not enough arguments for serpent cmdline\n"; + throw(0); + } + input = argc[2]; + secondInput = argv == 3 ? "" : argc[3]; + } + bool haveSec = secondInput.length() > 0; + if (command == "parse" || command == "parse_serpent") { + std::cout << printAST(parseSerpent(input), haveSec) << "\n"; + } + else if (command == "rewrite") { + std::cout << printAST(rewrite(parseLLL(input, true)), haveSec) << "\n"; + } + else if (command == "compile_to_lll") { + std::cout << printAST(compileToLLL(input), haveSec) << "\n"; + } + else if (command == "rewrite_chunk") { + std::cout << printAST(rewriteChunk(parseLLL(input, true)), haveSec) << "\n"; + } + else if (command == "compile_chunk_to_lll") { + std::cout << printAST(compileChunkToLLL(input), haveSec) << "\n"; + } + else if (command == "build_fragtree") { + std::cout << printAST(buildFragmentTree(parseLLL(input, true))) << "\n"; + } + else if (command == "compile_lll") { + std::cout << binToHex(compileLLL(parseLLL(input, true))) << "\n"; + } + else if (command == "dereference") { + std::cout << printAST(dereference(parseLLL(input, true)), haveSec) <<"\n"; + } + else if (command == "pretty_assemble") { + std::cout << printTokens(prettyAssemble(parseLLL(input, true))) <<"\n"; + } + else if (command == "pretty_compile_lll") { + std::cout << printTokens(prettyCompileLLL(parseLLL(input, true))) << "\n"; + } + else if (command == "pretty_compile") { + std::cout << printTokens(prettyCompile(input)) << "\n"; + } + else if (command == "pretty_compile_chunk") { + std::cout << printTokens(prettyCompileChunk(input)) << "\n"; + } + else if (command == "assemble") { + std::cout << assemble(parseLLL(input, true)) << "\n"; + } + else if (command == "serialize") { + std::cout << binToHex(serialize(tokenize(input, Metadata(), false))) << "\n"; + } + else if (command == "flatten") { + std::cout << printTokens(flatten(parseLLL(input, true))) << "\n"; + } + else if (command == "deserialize") { + std::cout << printTokens(deserialize(hexToBin(input))) << "\n"; + } + else if (command == "compile") { + std::cout << binToHex(compile(input)) << "\n"; + } + else if (command == "compile_chunk") { + std::cout << binToHex(compileChunk(input)) << "\n"; + } + else if (command == "encode_datalist") { + std::vector tokens = tokenize(input); + std::vector o; + for (int i = 0; i < (int)tokens.size(); i++) { + o.push_back(tokens[i].val); + } + std::cout << binToHex(encodeDatalist(o)) << "\n"; + } + else if (command == "decode_datalist") { + std::vector o = decodeDatalist(hexToBin(input)); + std::vector tokens; + for (int i = 0; i < (int)o.size(); i++) + tokens.push_back(token(o[i])); + std::cout << printTokens(tokens) << "\n"; + } + else if (command == "tokenize") { + std::cout << printTokens(tokenize(input)); + } + else if (command == "biject") { + if (argv == 3) + std::cerr << "Not enough arguments for biject\n"; + int pos = decimalToUnsigned(secondInput); + std::vector n = prettyCompile(input); + if (pos >= (int)n.size()) + std::cerr << "Code position too high\n"; + Metadata m = n[pos].metadata; + std::cout << "Opcode: " << n[pos].val << ", file: " << m.file << + ", line: " << m.ln << ", char: " << m.ch << "\n"; + } } From b9ba1943c442a1e61e0395affe4be82ee0ea5f74 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 15:12:35 +0200 Subject: [PATCH 10/21] Latest PoC-7 serpent. --- libserpent/compiler.cpp | 26 ++++++++++++---------- libserpent/opcodes.h | 4 ++-- libserpent/parser.cpp | 2 +- libserpent/rewriter.cpp | 44 +++++++++++--------------------------- libwhisper/Interface.h | 1 + libwhisper/WhisperHost.cpp | 21 ++++++++++++++++++ libwhisper/WhisperHost.h | 17 ++++++++------- 7 files changed, 62 insertions(+), 53 deletions(-) diff --git a/libserpent/compiler.cpp b/libserpent/compiler.cpp index 61b70de05..251c7d9da 100644 --- a/libserpent/compiler.cpp +++ b/libserpent/compiler.cpp @@ -123,9 +123,10 @@ programData opcodeify(Node node, token("$begincode"+symb+".endcode"+symb, m), token("DUP1", m), token("$begincode"+symb, m), sub.code, token("CODECOPY", m), token("$endcode"+symb, m), token("JUMP", m), - token("~begincode"+symb, m), code, token("~endcode"+symb, m) + token("~begincode"+symb, m), code, token("~endcode"+symb, m), + token("JUMPDEST", m) }; - return pd(sub.aux, multiToken(nodelist, 10, m), 1); + return pd(sub.aux, multiToken(nodelist, 11, m), 1); } // Stack variables if (node.val == "with") { @@ -171,9 +172,9 @@ programData opcodeify(Node node, cond.code, token("$endif"+symb, m), token("JUMPI", m), action.code, - token("~endif"+symb, m) + token("~endif"+symb, m), token("JUMPDEST", m) }; - return pd(aux, multiToken(nodelist, 5, m), 0); + return pd(aux, multiToken(nodelist, 6, m), 0); } // 3-part conditional else if (node.val == "if" && node.args.size() == 3) { @@ -190,13 +191,15 @@ programData opcodeify(Node node, if (elsed.outs > outs) elsed.code = popwrap(elsed.code); Node nodelist[] = { ifd.code, - token("NOT", m), token("$else"+symb, m), token("JUMPI", m), + token("NOT", m), + token("$else"+symb, m), token("JUMPI", m), thend.code, - token("$endif"+symb, m), token("JUMP", m), token("~else"+symb, m), + token("$endif"+symb, m), token("JUMP", m), + token("~else"+symb, m), token("JUMPDEST", m), elsed.code, - token("~endif"+symb, m) + token("~endif"+symb, m), token("JUMPDEST", m) }; - return pd(aux, multiToken(nodelist, 10, m), outs); + return pd(aux, multiToken(nodelist, 12, m), outs); } // While (rewritten to this in rewrites) else if (node.val == "until") { @@ -207,13 +210,14 @@ programData opcodeify(Node node, err("Condition of while/until loop has arity 0", m); if (action.outs) action.code = popwrap(action.code); Node nodelist[] = { - token("~beg"+symb, m), + token("~beg"+symb, m), token("JUMPDEST", m), cond.code, token("$end"+symb, m), token("JUMPI", m), action.code, - token("$beg"+symb, m), token("JUMP", m), token("~end"+symb, m) + token("$beg"+symb, m), token("JUMP", m), + token("~end"+symb, m), token("JUMPDEST", m) }; - return pd(aux, multiToken(nodelist, 8, m)); + return pd(aux, multiToken(nodelist, 10, m)); } // Memory allocations else if (node.val == "alloc") { diff --git a/libserpent/opcodes.h b/libserpent/opcodes.h index f55834efa..552364731 100644 --- a/libserpent/opcodes.h +++ b/libserpent/opcodes.h @@ -72,11 +72,11 @@ Mapping mapping[] = { Mapping("PC", 0x5a, 0, 1), Mapping("MSIZE", 0x5b, 0, 1), Mapping("GAS", 0x5c, 0, 1), + Mapping("JUMPDEST", 0x5d, 0, 0), Mapping("CREATE", 0xf0, 3, 1), Mapping("CALL", 0xf1, 7, 1), Mapping("RETURN", 0xf2, 2, 0), - Mapping("POST", 0xf3, 5, 0), - Mapping("CALL_STATELESS", 0xf4, 7, 1), + Mapping("CALL_CODE", 0xf3, 7, 1), Mapping("SUICIDE", 0xff, 1, 0), Mapping("---END---", 0x00, 0, 0), }; diff --git a/libserpent/parser.cpp b/libserpent/parser.cpp index 09fcdfc47..0460c974c 100644 --- a/libserpent/parser.cpp +++ b/libserpent/parser.cpp @@ -155,10 +155,10 @@ Node treefy(std::vector stream) { else if (typ == RPAREN) { std::vector args; while (1) { - if (!oq.size()) err("Bracket without matching", tok.metadata); if (toktype(oq.back()) == LPAREN) break; args.push_back(oq.back()); oq.pop_back(); + if (!oq.size()) err("Bracket without matching", tok.metadata); } oq.pop_back(); args.push_back(oq.back()); diff --git a/libserpent/rewriter.cpp b/libserpent/rewriter.cpp index eeefd2d09..bf6a73828 100644 --- a/libserpent/rewriter.cpp +++ b/libserpent/rewriter.cpp @@ -17,9 +17,7 @@ std::string valid[][3] = { { "alloc", "1", "1" }, { "array", "1", "1" }, { "call", "2", "4" }, - { "call_stateless", "2", "4" }, - { "post", "4", "5" }, - { "postcall", "3", "4" }, + { "call_code", "2", "4" }, { "create", "1", "4" }, { "msg", "4", "6" }, { "msg_stateless", "4", "6" }, @@ -144,22 +142,6 @@ std::string macros[][2] = { "(send $to $value)", "(call (sub (gas) 25) $to $value 0 0 0 0)" }, - { - "(post $gas $to $value $datain $datainsz)", - "(~post $gas $to $value $datain (mul $datainsz 32))" - }, - { - "(post $gas $to $value $datain)", - "(seq (set $1 $datain) (~post $gas $to $value (ref $1) 32))" - }, - { - "(postcall $gas $to $datain)", - "(post $gas $to 0 $datain)", - }, - { - "(postcall $gas $to $datain $datainsz)", - "(post $gas $to 0 $datain $datainsz)", - }, { "(send $gas $to $value)", "(call $gas $to $value 0 0 0 0)" @@ -243,28 +225,28 @@ std::string macros[][2] = { }, // Call stateless and msg stateless { - "(call_stateless $f $dataval)", - "(msg_stateless (sub (gas) 45) $f 0 $dataval)" + "(call_code $f $dataval)", + "(msg_code (sub (gas) 45) $f 0 $dataval)" }, { - "(call_stateless $f $inp $inpsz)", - "(msg_stateless (sub (gas) 25) $f 0 $inp $inpsz)" + "(call_code $f $inp $inpsz)", + "(msg_code (sub (gas) 25) $f 0 $inp $inpsz)" }, { - "(call_stateless $f $inp $inpsz $outsz)", - "(with $1 $outsz (with $2 (alloc (mul 32 (get $1))) (seq (call_stateless (sub (gas) (add 25 (get $1))) $f 0 $inp (mul 32 $inpsz) (get $2) (mul 32 (get $1))) (get $2))))" + "(call_code $f $inp $inpsz $outsz)", + "(with $1 $outsz (with $2 (alloc (mul 32 (get $1))) (seq (call_code (sub (gas) (add 25 (get $1))) $f 0 $inp (mul 32 $inpsz) (get $2) (mul 32 (get $1))) (get $2))))" }, { - "(msg_stateless $gas $to $val $inp $inpsz)", - "(seq (call_stateless $gas $to $val $inp (mul 32 $inpsz) (ref $1) 32) (get $1))" + "(msg_code $gas $to $val $inp $inpsz)", + "(seq (call_code $gas $to $val $inp (mul 32 $inpsz) (ref $1) 32) (get $1))" }, { - "(msg_stateless $gas $to $val $dataval)", - "(seq (set $1 $dataval) (call_stateless $gas $to $val (ref $1) 32 (ref $2) 32) (get $2))" + "(msg_code $gas $to $val $dataval)", + "(seq (set $1 $dataval) (call_code $gas $to $val (ref $1) 32 (ref $2) 32) (get $2))" }, { - "(msg_stateless $gas $to $val $inp $inpsz $outsz)", - "(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (call_stateless $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2)))" + "(msg_code $gas $to $val $inp $inpsz $outsz)", + "(with $1 (mul 32 $outsz) (with $2 (alloc (get $1)) (call_code $gas $to $val $inp (mul 32 $inpsz) (get $2) (get $1)) (get $2)))" }, // Wrappers { diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index 8bc37ff5e..56b3be599 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -75,6 +75,7 @@ public: virtual void uninstallWatch(unsigned _watchId) = 0; virtual h256s peekWatch(unsigned _watchId) const = 0; virtual h256s checkWatch(unsigned _watchId) = 0; + virtual h256s watchMessages(unsigned _watchId) = 0; virtual Envelope envelope(h256 _m) const = 0; diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index b11b4af3a..25c1a06bf 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -107,6 +107,27 @@ unsigned WhisperHost::installWatch(shh::TopicFilter const& _f) return installWatchOnId(h); } +h256s WhisperHost::watchMessages(unsigned _watchId) +{ + h256s ret; + auto wit = m_watches.find(_watchId); + if (wit == m_watches.end()) + return ret; + TopicFilter f; + { + Guard l(m_filterLock); + auto fit = m_filters.find(wit->second.id); + if (fit == m_filters.end()) + return ret; + f = fit->second.filter; + } + ReadGuard l(x_messages); + for (auto const& m: m_messages) + if (f.matches(m.second)) + ret.push_back(m.first); + return ret; +} + void WhisperHost::uninstallWatch(unsigned _i) { cwatshh << "XXX" << _i; diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 2a8789956..9ad859967 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -48,16 +48,17 @@ public: unsigned protocolVersion() const { return 0; } - virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr); + virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override; using Interface::installWatch; - virtual unsigned installWatch(TopicFilter const& _filter); - virtual unsigned installWatchOnId(h256 _filterId); - virtual void uninstallWatch(unsigned _watchId); - virtual h256s peekWatch(unsigned _watchId) const { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } } - virtual h256s checkWatch(unsigned _watchId) { dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; } - - virtual Envelope envelope(h256 _m) const { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } } + virtual unsigned installWatch(TopicFilter const& _filter) override; + virtual unsigned installWatchOnId(h256 _filterId) override; + virtual void uninstallWatch(unsigned _watchId) override; + virtual h256s peekWatch(unsigned _watchId) const override { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } } + virtual h256s checkWatch(unsigned _watchId) override { dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; } + virtual h256s watchMessages(unsigned _watchId) override; + + virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } } private: void streamMessage(h256 _m, RLPStream& _s) const; From 91d6506e94d4b9de490ee802ee4897575b393dfb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 15:12:56 +0200 Subject: [PATCH 11/21] Whisper calls back for pre-existing messages. --- libqethereum/QEthereum.cpp | 42 +++++++++++++++++++++++++++++++------- libqethereum/QEthereum.h | 3 ++- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index d87f4ecb3..a71aca2b4 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -660,13 +660,6 @@ void QWhisper::clearWatches() m_watches.clear(); } -QString QWhisper::newIdentity() -{ - KeyPair kp = KeyPair::create(); - m_ids[kp.pub()] = kp.sec(); - return toQJS(kp.pub()); -} - static QString toJson(h256 const& _h, shh::Envelope const& _e, shh::Message const& _m) { QJsonObject v; @@ -685,6 +678,41 @@ static QString toJson(h256 const& _h, shh::Envelope const& _e, shh::Message cons return QString::fromUtf8(QJsonDocument(v).toJson()); } +QString QWhisper::watchMessages(unsigned _w) +{ + QString ret = "["; + auto wit = m_watches.find(_w); + if (wit == m_watches.end()) + { + cwarn << "watchMessages called with invalid watch id" << _w; + return ""; + } + Public p = wit->second; + if (!p || m_ids.count(p)) + for (h256 const& h: face()->watchMessages(_w)) + { + auto e = face()->envelope(h); + shh::Message m; + if (p) + { + cwarn << "Silently decrypting message from identity" << p.abridged() << ": User validation hook goes here."; + m = e.open(m_ids[p]); + } + else + m = e.open(); + ret.append((ret == "[" ? "" : ",") + toJson(h, e, m)); + } + + return ret + "]"; +} + +QString QWhisper::newIdentity() +{ + KeyPair kp = KeyPair::create(); + m_ids[kp.pub()] = kp.sec(); + return toQJS(kp.pub()); +} + void QWhisper::poll() { for (auto const& w: m_watches) diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 42696d40c..f17b967a4 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -234,6 +234,7 @@ public: Q_INVOKABLE unsigned newWatch(QString _json); Q_INVOKABLE void killWatch(unsigned _w); void clearWatches(); + Q_INVOKABLE QString watchMessages(unsigned _w); public slots: /// Check to see if anything has changed, fire off signals if so. @@ -272,7 +273,7 @@ private: if (_shh) \ { \ _frame->addToJavaScriptWindowObject("_web3_dot_shh", _shh, QWebFrame::ScriptOwnership); \ - _frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(json) { var ww = _web3_dot_shh.newWatch(json); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(w); }; ret.arrived = function(f) { _web3_dot_shh.watchChanged.connect(function(nw, envelope) { if (nw == ww) f(JSON.parse(envelope)) }); }; return ret; }"); \ + _frame->evaluateJavaScript("_web3_dot_shh.makeWatch = function(json) { var ww = _web3_dot_shh.newWatch(json); var ret = { w: ww }; ret.uninstall = function() { _web3_dot_shh.killWatch(w); }; ret.arrived = function(f) { _web3_dot_shh.watchChanged.connect(function(nw, envelope) { if (nw == ww) f(JSON.parse(envelope)) }); var existing = JSON.parse(_web3_dot_shh.watchMessages(ww)); for (var e in existing) f(existing[e]) }; return ret; }"); \ _frame->evaluateJavaScript("_web3_dot_shh.watch = function(filter) { return _web3_dot_shh.makeWatch(JSON.stringify(filter)) }"); \ _frame->evaluateJavaScript("_web3_dot_shh.post = function(message) { return _web3_dot_shh.doPost(JSON.stringify(message)) }"); \ _frame->evaluateJavaScript("web3.shh = _web3_dot_shh"); \ From 11015aba10c9a29efbd622448e596651196a23e8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 15:32:29 +0200 Subject: [PATCH 12/21] TTL works. --- libqethereum/QEthereum.cpp | 2 +- libwhisper/WhisperHost.cpp | 15 +++++++++++++++ libwhisper/WhisperHost.h | 5 ++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index a71aca2b4..e77c9d632 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -595,7 +595,7 @@ static shh::Envelope toSealed(QString _json, shh::Message const& _m, Secret _fro for (auto i: f["topic"].toArray()) bt.shift(asBytes(padded(i.toString(), 32))); } - return _m.seal(_from, bt, workToProve, ttl); + return _m.seal(_from, bt, ttl, workToProve); } void QWhisper::doPost(QString _json) diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 25c1a06bf..26ca3d93b 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -53,6 +53,9 @@ void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) { + if (_m.expiry() <= time(0)) + return; + auto h = _m.sha3(); { UpgradableGuard l(x_messages); @@ -60,6 +63,7 @@ void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) return; UpgradeGuard ll(l); m_messages[h] = _m; + m_expiryQueue[_m.expiry()] = h; } // if (_p) @@ -109,6 +113,7 @@ unsigned WhisperHost::installWatch(shh::TopicFilter const& _f) h256s WhisperHost::watchMessages(unsigned _watchId) { + cleanup(); h256s ret; auto wit = m_watches.find(_watchId); if (wit == m_watches.end()) @@ -145,3 +150,13 @@ void WhisperHost::uninstallWatch(unsigned _i) if (!--fit->second.refCount) m_filters.erase(fit); } + +void WhisperHost::cleanup() +{ + // remove old messages. + // should be called every now and again. + auto now = time(0); + WriteGuard l(x_messages); + for (auto it = m_expiryQueue.begin(); it != m_expiryQueue.end() && it->first <= now; it = m_expiryQueue.erase(it)) + m_messages.erase(it->second); +} diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 9ad859967..2eb4856ee 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -55,11 +55,13 @@ public: virtual unsigned installWatchOnId(h256 _filterId) override; virtual void uninstallWatch(unsigned _watchId) override; virtual h256s peekWatch(unsigned _watchId) const override { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } } - virtual h256s checkWatch(unsigned _watchId) override { dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; } + virtual h256s checkWatch(unsigned _watchId) override { cleanup(); dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; } virtual h256s watchMessages(unsigned _watchId) override; virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } } + void cleanup(); + private: void streamMessage(h256 _m, RLPStream& _s) const; @@ -67,6 +69,7 @@ private: mutable dev::SharedMutex x_messages; std::map m_messages; + std::map m_expiryQueue; mutable dev::Mutex m_filterLock; std::map m_filters; From 91e38ec706d0baf3641efd9007f8a66d29bea58f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 17:13:40 +0200 Subject: [PATCH 13/21] Remove stupid assertion. Add licence header to solc. --- libdevcrypto/EC.cpp | 2 +- libqethereum/QEthereum.cpp | 2 ++ libqethereum/QEthereum.h | 2 +- solc/main.cpp | 21 +++++++++++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index b38703ac3..75c2fcc3d 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -66,7 +66,7 @@ void dev::crypto::decrypt(Secret const& _k, bytes& io_text) p.resize(d.MaxPlaintextLength(io_text.size())); // todo: use StringSource with _c as input and output. DecodingResult r = d.Decrypt(pp::PRNG(), io_text.data(), clen, p.data()); - assert(r.messageLength); +// assert(r.messageLength); io_text.resize(r.messageLength); io_text = std::move(p); } diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index e77c9d632..92180817b 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -725,6 +725,8 @@ void QWhisper::poll() { cwarn << "Silently decrypting message from identity" << w.second.abridged() << ": User validation hook goes here."; m = e.open(m_ids[w.second]); + if (!m) + continue; } else m = e.open(); diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index f17b967a4..37f0800cc 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -233,7 +233,7 @@ public: // Watches interface Q_INVOKABLE unsigned newWatch(QString _json); Q_INVOKABLE void killWatch(unsigned _w); - void clearWatches(); + Q_INVOKABLE void clearWatches(); Q_INVOKABLE QString watchMessages(unsigned _w); public slots: diff --git a/solc/main.cpp b/solc/main.cpp index ba0b6ccf7..1acdefd8c 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -1,3 +1,24 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** + * @author Christian + * @date 2014 + * Solidity abstract syntax tree. + */ #include #include From c379bea27bec20f7c46306da73c08dd1a6a88c86 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 25 Oct 2014 17:56:44 +0200 Subject: [PATCH 14/21] CMakeLists library dependency cleanup for libdevcore, libevmface, libsolidity and solc. Fixes #417. --- libdevcore/CMakeLists.txt | 6 +++--- libevmface/CMakeLists.txt | 19 ------------------- libsolidity/CMakeLists.txt | 27 +-------------------------- solc/CMakeLists.txt | 17 ----------------- 4 files changed, 4 insertions(+), 65 deletions(-) diff --git a/libdevcore/CMakeLists.txt b/libdevcore/CMakeLists.txt index 81e210cad..7c54301c9 100644 --- a/libdevcore/CMakeLists.txt +++ b/libdevcore/CMakeLists.txt @@ -19,8 +19,6 @@ endif() include_directories(..) -target_link_libraries(${EXECUTABLE} devcore) - if("${TARGET_PLATFORM}" STREQUAL "w64") include_directories(/usr/x86_64-w64-mingw32/include/cryptopp) target_link_libraries(${EXECUTABLE} boost_system-mt-s) @@ -37,7 +35,9 @@ elseif (APPLE) find_package(Threads REQUIRED) target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) elseif (UNIX) - target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY}) + find_package(Boost 1.53 REQUIRED COMPONENTS thread system) + target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY}) + find_package(Threads REQUIRED) target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) else () target_link_libraries(${EXECUTABLE} boost_thread) diff --git a/libevmface/CMakeLists.txt b/libevmface/CMakeLists.txt index 874b9e397..f82d2b96b 100644 --- a/libevmface/CMakeLists.txt +++ b/libevmface/CMakeLists.txt @@ -17,25 +17,6 @@ include_directories(..) target_link_libraries(${EXECUTABLE} devcore) -if("${TARGET_PLATFORM}" STREQUAL "w64") - target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) - target_link_libraries(${EXECUTABLE} iphlpapi) - target_link_libraries(${EXECUTABLE} ws2_32) - target_link_libraries(${EXECUTABLE} mswsock) - target_link_libraries(${EXECUTABLE} shlwapi) -elseif (APPLE) - # Latest mavericks boost libraries only come with -mt - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -elseif (UNIX) - target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY}) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -else () - target_link_libraries(${EXECUTABLE} boost_thread) - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -endif () - install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 59aa78364..757d0cc06 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -16,33 +16,8 @@ file(GLOB HEADERS "*.h") include_directories(..) -target_link_libraries(${EXECUTABLE} evmface) target_link_libraries(${EXECUTABLE} devcore) - - -if("${TARGET_PLATFORM}" STREQUAL "w64") - target_link_libraries(${EXECUTABLE} boost_system-mt-s) - target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) - target_link_libraries(${EXECUTABLE} iphlpapi) - target_link_libraries(${EXECUTABLE} ws2_32) - target_link_libraries(${EXECUTABLE} mswsock) - target_link_libraries(${EXECUTABLE} shlwapi) -elseif (APPLE) - # Latest mavericks boost libraries only come with -mt - target_link_libraries(${EXECUTABLE} boost_system-mt) - target_link_libraries(${EXECUTABLE} boost_thread-mt) - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -elseif (UNIX) - target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARY}) - target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY}) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -else () - target_link_libraries(${EXECUTABLE} boost_system) - target_link_libraries(${EXECUTABLE} boost_thread) - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -endif () +target_link_libraries(${EXECUTABLE} evmface) install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/solc/CMakeLists.txt b/solc/CMakeLists.txt index 9224c109d..386d4a1a8 100644 --- a/solc/CMakeLists.txt +++ b/solc/CMakeLists.txt @@ -9,23 +9,6 @@ set(EXECUTABLE solc) add_executable(${EXECUTABLE} ${SRC_LIST}) target_link_libraries(${EXECUTABLE} solidity) -target_link_libraries(${EXECUTABLE} devcore) - -if ("${TARGET_PLATFORM}" STREQUAL "w64") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") - target_link_libraries(${EXECUTABLE} gcc) - target_link_libraries(${EXECUTABLE} gdi32) - target_link_libraries(${EXECUTABLE} ws2_32) - target_link_libraries(${EXECUTABLE} mswsock) - target_link_libraries(${EXECUTABLE} shlwapi) - target_link_libraries(${EXECUTABLE} iphlpapi) - target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) - set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) -elseif (UNIX) -else () - find_package(Threads REQUIRED) - target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) -endif () install( TARGETS ${EXECUTABLE} DESTINATION bin ) From b866e7f723ce430664e07715a768549b5742b7f2 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 25 Oct 2014 18:30:43 +0200 Subject: [PATCH 15/21] Corrected file description. --- solc/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solc/main.cpp b/solc/main.cpp index 1acdefd8c..0843cfa02 100644 --- a/solc/main.cpp +++ b/solc/main.cpp @@ -17,7 +17,7 @@ /** * @author Christian * @date 2014 - * Solidity abstract syntax tree. + * Solidity commandline compiler. */ #include From bfd797c3a17782898be4b8d7f24cbb140ea67f46 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 22:10:53 +0200 Subject: [PATCH 16/21] Whisperer in AZ. More Whisper fixups. --- alethzero/Main.ui | 217 ++++++++++++++++++++++++++++++++++++- alethzero/MainWin.cpp | 193 ++++++++++++++++++++++++--------- alethzero/MainWin.h | 4 + libdevcore/Common.cpp | 2 +- libdevcore/FixedHash.h | 2 +- libdevcrypto/EC.cpp | 6 +- libp2p/Host.h | 2 +- libqethereum/QEthereum.cpp | 8 +- libqethereum/QEthereum.h | 4 + libwhisper/WhisperHost.cpp | 6 +- 10 files changed, 385 insertions(+), 59 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 16dcd8a4c..db246107d 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -6,8 +6,8 @@ 0 0 - 1711 - 1138 + 1617 + 1371 @@ -116,7 +116,7 @@ 0 0 - 1711 + 1617 25 @@ -204,11 +204,18 @@ + + + &Whisper + + + + @@ -1514,6 +1521,205 @@ font-size: 14pt + + + QDockWidget::DockWidgetFeatureMask + + + Whisper + + + 1 + + + + + + + ms + + + 1 + + + 1000 + + + 50 + + + + + + + + 0 + 0 + + + + Topic + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + data + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + 0 + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + 0 + + + + + + + Post + + + + + + + + 0 + 0 + + + + TTL + + + destination + + + + + + + + 0 + 0 + + + + From + + + destination + + + + + + + + 0 + 0 + + + + To + + + destination + + + + + + + false + + + + + + + true + + + + + + + + 0 + 0 + + + + Data + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + data + + + + + + + seconds + + + 5 + + + 259200 + + + + + + + + 0 + 0 + + + + Work to Prove + + + destination + + + + + + &Quit @@ -1801,6 +2007,11 @@ font-size: 14pt Go! + + + New Identity + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 9a98f54ee..d4d0b6050 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -146,6 +146,7 @@ Main::Main(QWidget *parent) : auto qeth = m_ethereum; auto qshh = m_whisper; connect(f, &QWebFrame::javaScriptWindowObjectCleared, QETH_INSTALL_JS_NAMESPACE(f, this, qdev, qeth, qshh)); + connect(m_whisper, SIGNAL(idsChanged()), this, SLOT(refreshWhisper())); }); connect(ui->webView, &QWebView::loadFinished, [=]() @@ -332,8 +333,6 @@ void Main::load(QString _s) } } -// env.load("/home/gav/eth/init.eth") - void Main::on_loadJS_triggered() { QString f = QFileDialog::getOpenFileName(this, "Load Javascript", QString(), "Javascript (*.js);;All files (*)"); @@ -388,6 +387,17 @@ void Main::eval(QString const& _js) ui->jsConsole->setHtml(s); } +static Public stringToPublic(QString const& _a) +{ + string sn = _a.toStdString(); + if (_a.size() == sizeof(Public) * 2) + return Public(fromHex(_a.toStdString())); + else if (_a.size() == sizeof(Public) * 2 + 2 && _a.startsWith("0x")) + return Public(fromHex(_a.mid(2).toStdString())); + else + return Public(); +} + QString Main::pretty(dev::Address _a) const { h256 n; @@ -1385,6 +1395,112 @@ void Main::on_destination_currentTextChanged() // updateFee(); } +static bytes dataFromText(QString _s) +{ + bytes ret; + while (_s.size()) + { + QRegExp r("(@|\\$)?\"([^\"]*)\"(\\s.*)?"); + QRegExp d("(@|\\$)?([0-9]+)(\\s*(ether)|(finney)|(szabo))?(\\s.*)?"); + QRegExp h("(@|\\$)?(0x)?(([a-fA-F0-9])+)(\\s.*)?"); + if (r.exactMatch(_s)) + { + for (auto i: r.cap(2)) + ret.push_back((byte)i.toLatin1()); + if (r.cap(1) != "$") + for (int i = r.cap(2).size(); i < 32; ++i) + ret.push_back(0); + else + ret.push_back(0); + _s = r.cap(3); + } + else if (d.exactMatch(_s)) + { + u256 v(d.cap(2).toStdString()); + if (d.cap(6) == "szabo") + v *= dev::eth::szabo; + else if (d.cap(5) == "finney") + v *= dev::eth::finney; + else if (d.cap(4) == "ether") + v *= dev::eth::ether; + bytes bs = dev::toCompactBigEndian(v); + if (d.cap(1) != "$") + for (auto i = bs.size(); i < 32; ++i) + ret.push_back(0); + for (auto b: bs) + ret.push_back(b); + _s = d.cap(7); + } + else if (h.exactMatch(_s)) + { + bytes bs = fromHex((((h.cap(3).size() & 1) ? "0" : "") + h.cap(3)).toStdString()); + if (h.cap(1) != "$") + for (auto i = bs.size(); i < 32; ++i) + ret.push_back(0); + for (auto b: bs) + ret.push_back(b); + _s = h.cap(5); + } + else + _s = _s.mid(1); + } + return ret; +} + +static shh::Topic topicFromText(QString _s) +{ + shh::BuildTopic ret; + while (_s.size()) + { + QRegExp r("(@|\\$)?\"([^\"]*)\"(\\s.*)?"); + QRegExp d("(@|\\$)?([0-9]+)(\\s*(ether)|(finney)|(szabo))?(\\s.*)?"); + QRegExp h("(@|\\$)?(0x)?(([a-fA-F0-9])+)(\\s.*)?"); + bytes part; + if (r.exactMatch(_s)) + { + for (auto i: r.cap(2)) + part.push_back((byte)i.toLatin1()); + if (r.cap(1) != "$") + for (int i = r.cap(2).size(); i < 32; ++i) + part.push_back(0); + else + part.push_back(0); + _s = r.cap(3); + } + else if (d.exactMatch(_s)) + { + u256 v(d.cap(2).toStdString()); + if (d.cap(6) == "szabo") + v *= dev::eth::szabo; + else if (d.cap(5) == "finney") + v *= dev::eth::finney; + else if (d.cap(4) == "ether") + v *= dev::eth::ether; + bytes bs = dev::toCompactBigEndian(v); + if (d.cap(1) != "$") + for (auto i = bs.size(); i < 32; ++i) + part.push_back(0); + for (auto b: bs) + part.push_back(b); + _s = d.cap(7); + } + else if (h.exactMatch(_s)) + { + bytes bs = fromHex((((h.cap(3).size() & 1) ? "0" : "") + h.cap(3)).toStdString()); + if (h.cap(1) != "$") + for (auto i = bs.size(); i < 32; ++i) + part.push_back(0); + for (auto b: bs) + part.push_back(b); + _s = h.cap(5); + } + else + _s = _s.mid(1); + ret.shift(part); + } + return ret; +} + void Main::on_data_textChanged() { m_pcWarp.clear(); @@ -1439,54 +1555,7 @@ void Main::on_data_textChanged() } else { - m_data.clear(); - QString s = ui->data->toPlainText(); - while (s.size()) - { - QRegExp r("(@|\\$)?\"([^\"]*)\"(\\s.*)?"); - QRegExp d("(@|\\$)?([0-9]+)(\\s*(ether)|(finney)|(szabo))?(\\s.*)?"); - QRegExp h("(@|\\$)?(0x)?(([a-fA-F0-9])+)(\\s.*)?"); - if (r.exactMatch(s)) - { - for (auto i: r.cap(2)) - m_data.push_back((byte)i.toLatin1()); - if (r.cap(1) != "$") - for (int i = r.cap(2).size(); i < 32; ++i) - m_data.push_back(0); - else - m_data.push_back(0); - s = r.cap(3); - } - else if (d.exactMatch(s)) - { - u256 v(d.cap(2).toStdString()); - if (d.cap(6) == "szabo") - v *= dev::eth::szabo; - else if (d.cap(5) == "finney") - v *= dev::eth::finney; - else if (d.cap(4) == "ether") - v *= dev::eth::ether; - bytes bs = dev::toCompactBigEndian(v); - if (d.cap(1) != "$") - for (auto i = bs.size(); i < 32; ++i) - m_data.push_back(0); - for (auto b: bs) - m_data.push_back(b); - s = d.cap(7); - } - else if (h.exactMatch(s)) - { - bytes bs = fromHex((((h.cap(3).size() & 1) ? "0" : "") + h.cap(3)).toStdString()); - if (h.cap(1) != "$") - for (auto i = bs.size(); i < 32; ++i) - m_data.push_back(0); - for (auto b: bs) - m_data.push_back(b); - s = h.cap(5); - } - else - s = s.mid(1); - } + m_data = dataFromText(ui->data->toPlainText()); ui->code->setHtml(QString::fromStdString(dev::memDump(m_data, 8, true))); if (ethereum()->codeAt(fromString(ui->destination->currentText()), 0).size()) { @@ -2015,6 +2084,30 @@ void Main::updateDebugger() } } +void Main::on_post_clicked() +{ + shh::Message m; + m.setTo(stringToPublic(ui->shhTo->currentText())); + m.setPayload(dataFromText(ui->shhData->toPlainText())); + Public f = stringToPublic(ui->shhFrom->currentText()); + Secret from; + if (m_whisper->ids().count(f)) + from = m_whisper->ids().at(f); + whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhWork->value(), ui->shhTtl->value())); +} + +void Main::on_newIdentity_triggered() +{ + m_whisper->makeIdentity(); +} + +void Main::refreshWhisper() +{ + ui->shhFrom->clear(); + for (auto i: m_whisper->ids()) + ui->shhFrom->addItem(QString::fromStdString(toHex(i.first.ref()))); +} + // extra bits needed to link on VS #ifdef _MSC_VER diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index aa5fcf572..b8231ddf7 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -149,6 +149,10 @@ private slots: void on_turboMining_triggered(); void on_go_triggered(); void on_importKeyFile_triggered(); + void on_post_clicked(); + void on_newIdentity_triggered(); + + void refreshWhisper(); signals: void poll(); diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index d9192c79f..97c1d32c7 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.7.5"; +char const* Version = "0.7.6"; } diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index c8d250b35..0032a1314 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -59,7 +59,7 @@ public: FixedHash() { m_data.fill(0); } /// Construct from another hash, filling with zeroes or cropping as necessary. - template FixedHash(FixedHash const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; } + template explicit FixedHash(FixedHash const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; } /// Convert from the corresponding arithmetic type. FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); } diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 75c2fcc3d..7072753b1 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -66,7 +66,11 @@ void dev::crypto::decrypt(Secret const& _k, bytes& io_text) p.resize(d.MaxPlaintextLength(io_text.size())); // todo: use StringSource with _c as input and output. DecodingResult r = d.Decrypt(pp::PRNG(), io_text.data(), clen, p.data()); -// assert(r.messageLength); + if (!r.isValidCoding) + { + io_text.clear(); + return; + } io_text.resize(r.messageLength); io_text = std::move(p); } diff --git a/libp2p/Host.h b/libp2p/Host.h index 34179a3b4..6e60b915e 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -203,7 +203,7 @@ private: /// This won't touch alter the blockchain. virtual void doWork(); - std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = h256()); + std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = NodeId()); Nodes potentialPeers(RangeMask const& _known); std::string m_clientVersion; ///< Our version string. diff --git a/libqethereum/QEthereum.cpp b/libqethereum/QEthereum.cpp index 92180817b..535c43325 100644 --- a/libqethereum/QEthereum.cpp +++ b/libqethereum/QEthereum.cpp @@ -707,10 +707,16 @@ QString QWhisper::watchMessages(unsigned _w) } QString QWhisper::newIdentity() +{ + return toQJS(makeIdentity()); +} + +Public QWhisper::makeIdentity() { KeyPair kp = KeyPair::create(); m_ids[kp.pub()] = kp.sec(); - return toQJS(kp.pub()); + emit idsChanged(); + return kp.pub(); } void QWhisper::poll() diff --git a/libqethereum/QEthereum.h b/libqethereum/QEthereum.h index 37f0800cc..9866a4e7a 100644 --- a/libqethereum/QEthereum.h +++ b/libqethereum/QEthereum.h @@ -236,6 +236,9 @@ public: Q_INVOKABLE void clearWatches(); Q_INVOKABLE QString watchMessages(unsigned _w); + dev::Public makeIdentity(); + std::map const& ids() const { return m_ids; } + public slots: /// Check to see if anything has changed, fire off signals if so. /// @note Must be called in the QObject's thread. @@ -243,6 +246,7 @@ public slots: signals: void watchChanged(unsigned _w, QString _envelopeJson); + void idsChanged(); private: std::weak_ptr m_face; diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index 26ca3d93b..591574bf0 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -47,12 +47,16 @@ void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const if (m_messages.count(_m)) { UpgradeGuard ll(l); - m_messages.at(_m).streamOut(_s, true); + auto const& m = m_messages.at(_m); + cnote << "streamOut: " << m.expiry() << m.ttl() << m.topic() << toHex(m.data()); + m.streamOut(_s, true); } } void WhisperHost::inject(Envelope const& _m, WhisperPeer* _p) { + cnote << "inject: " << _m.expiry() << _m.ttl() << _m.topic() << toHex(_m.data()); + if (_m.expiry() <= time(0)) return; From 42cb5ae9f0ef82d9a8e2a0671b5fa7549446b9db Mon Sep 17 00:00:00 2001 From: nicksavers Date: Sat, 25 Oct 2014 22:33:41 +0200 Subject: [PATCH 17/21] Add files fix VS2013 --- libdevcrypto/All.h | 3 +++ windows/LibEthereum.vcxproj | 6 ++++++ windows/LibEthereum.vcxproj.filters | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/libdevcrypto/All.h b/libdevcrypto/All.h index 6d1844857..db6d7c615 100644 --- a/libdevcrypto/All.h +++ b/libdevcrypto/All.h @@ -1,9 +1,12 @@ #pragma once #include "Common.h" +#include "CryptoPP.h" +#include "EC.h" #include "FileSystem.h" #include "MemoryDB.h" #include "OverlayDB.h" #include "SHA3.h" +#include "SHA3MAC.h" #include "TrieCommon.h" #include "TrieDB.h" diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 8c08091ec..2ece3cd28 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -69,10 +69,13 @@ + + + @@ -270,10 +273,13 @@ + + + diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index 7d743d82d..b4d898890 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -193,6 +193,15 @@ libethcore + + libdevcrypto + + + libdevcrypto + + + libdevcrypto + @@ -417,6 +426,15 @@ libwebthree + + libdevcrypto + + + libdevcrypto + + + libdevcrypto + From 2df5cc9fda7f07567f635ac2146937dea491f666 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 23:23:51 +0200 Subject: [PATCH 18/21] Whispers pane. --- alethzero/Main.ui | 37 +++++++++++++++++++++++++++++++++++++ alethzero/MainWin.cpp | 29 ++++++++++++++++++++++++++++- alethzero/MainWin.h | 1 + libdevcrypto/EC.cpp | 2 +- libwhisper/Message.cpp | 11 +++++++---- libwhisper/Message.h | 2 +- libwhisper/WhisperHost.h | 2 ++ 7 files changed, 77 insertions(+), 7 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index db246107d..1fdf7de19 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -1720,6 +1720,43 @@ font-size: 14pt + + + QDockWidget::DockWidgetFeatureMask + + + Active Whispers + + + 2 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + + + + &Quit diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index d4d0b6050..b196c1dcc 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -763,7 +763,6 @@ void Main::refreshNetwork() { auto ps = web3()->peers(); - ui->peerCount->setText(QString::fromStdString(toString(ps.size())) + " peer(s)"); ui->peers->clear(); ui->nodes->clear(); @@ -1006,6 +1005,7 @@ void Main::timerEvent(QTimerEvent*) { interval = 0; refreshNetwork(); + refreshWhispers(); } else interval += 100; @@ -2108,6 +2108,33 @@ void Main::refreshWhisper() ui->shhFrom->addItem(QString::fromStdString(toHex(i.first.ref()))); } +void Main::refreshWhispers() +{ + ui->whispers->clear(); + for (auto const& w: whisper()->all()) + { + shh::Envelope const& e = w.second; + shh::Message m; + for (pair const& i: m_whisper->ids()) + if (!!(m = e.open(i.second))) + break; + if (!m) + m = e.open(); + + QString msg; + if (m.from()) + // Good message. + msg = QString("%1->%2: %3").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "?").arg(toHex(m.payload()).c_str()); + else if (m) + // Maybe message. + msg = QString("%1->%2: %3 (?)").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "?").arg(toHex(m.payload()).c_str()); + + time_t ex = e.expiry(); + QString item = QString("[%1 - %2s] *%3 %5 %4").arg(asctime(localtime(&ex))).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg); + ui->whispers->addItem(item); + } +} + // extra bits needed to link on VS #ifdef _MSC_VER diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index b8231ddf7..b6c4c85e1 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -206,6 +206,7 @@ private: void refreshNetwork(); void refreshMining(); + void refreshWhispers(); void refreshAll(); void refreshPending(); diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 7072753b1..5086e3203 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -52,7 +52,7 @@ void dev::crypto::encrypt(Public const& _key, bytes& io_cipher) c.resize(e.CiphertextLength(plen)); // todo: use StringSource with _plain as input and output. e.Encrypt(pp::PRNG(), io_cipher.data(), plen, c.data()); - bzero(io_cipher.data(), io_cipher.size()); + memset(io_cipher.data(), 0, io_cipher.size()); io_cipher = std::move(c); } diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index 52caf2f90..cdfc050d8 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -34,18 +34,18 @@ Message::Message(Envelope const& _e, Secret const& _s) if (_s) if (!decrypt(_s, &(_e.data()), b)) return; - populate(_s ? b : _e.data()); - m_to = KeyPair(_s).pub(); + if (populate(_s ? b : _e.data())) + m_to = KeyPair(_s).pub(); } catch (...) // Invalid secret? TODO: replace ... with InvalidSecret { } } -void Message::populate(bytes const& _data) +bool Message::populate(bytes const& _data) { if (!_data.size()) - return; + return false; byte flags = _data[0]; if (!!(flags & ContainsSignature) && _data.size() > sizeof(Signature) + 1) // has a signature @@ -54,10 +54,13 @@ void Message::populate(bytes const& _data) h256 h = sha3(payload); Signature const& sig = *(Signature const*)&(_data[1 + payload.size()]); m_from = recover(sig, h); + if (!m_from) + return false; m_payload = payload.toBytes(); } else m_payload = bytesConstRef(&_data).cropped(1).toBytes(); + return true; } Envelope Message::seal(Secret _from, Topic const& _topic, unsigned _ttl, unsigned _workToProve) const diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 67b34e321..84214fd18 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -116,7 +116,7 @@ public: Envelope sealTo(Secret _from, Public _to, Topic const& _topic, unsigned _workToProve = 50, unsigned _ttl = 50) { m_to = _to; return seal(_from, _topic, _workToProve, _ttl); } private: - void populate(bytes const& _data); + bool populate(bytes const& _data); Public m_from; Public m_to; diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index 2eb4856ee..4d761919c 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -60,6 +60,8 @@ public: virtual Envelope envelope(h256 _m) const override { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Envelope(); } } + std::map all() const { ReadGuard l(x_messages); return m_messages; } + void cleanup(); private: From 55ee4abe195242fca7a544b0ed2afda4857c5849 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 23:37:30 +0200 Subject: [PATCH 19/21] Nicer whispers. --- alethzero/MainWin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index b196c1dcc..982103e4c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -2124,13 +2124,13 @@ void Main::refreshWhispers() QString msg; if (m.from()) // Good message. - msg = QString("%1->%2: %3").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "?").arg(toHex(m.payload()).c_str()); + msg = QString("%1->%2: %3").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str()); else if (m) // Maybe message. - msg = QString("%1->%2: %3 (?)").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "?").arg(toHex(m.payload()).c_str()); + msg = QString("%1->%2: %3 (?)").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str()); time_t ex = e.expiry(); - QString item = QString("[%1 - %2s] *%3 %5 %4").arg(asctime(localtime(&ex))).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg); + QString item = QString("[%1 - %2s] *%3 %5 %4").arg(ctime(&ex)).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg); ui->whispers->addItem(item); } } From 41ce2597081042c41ae84c6deaacffdfdfbbefb7 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 23:42:34 +0200 Subject: [PATCH 20/21] Fix. --- alethzero/MainWin.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 982103e4c..e57397f04 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -2093,7 +2093,7 @@ void Main::on_post_clicked() Secret from; if (m_whisper->ids().count(f)) from = m_whisper->ids().at(f); - whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhWork->value(), ui->shhTtl->value())); + whisper()->inject(m.seal(from, topicFromText(ui->shhTopic->toPlainText()), ui->shhTtl->value(), ui->shhWork->value())); } void Main::on_newIdentity_triggered() @@ -2130,7 +2130,9 @@ void Main::refreshWhispers() msg = QString("%1->%2: %3 (?)").arg(m.from() ? m.from().abridged().c_str() : "?").arg(m.to() ? m.to().abridged().c_str() : "*").arg(toHex(m.payload()).c_str()); time_t ex = e.expiry(); - QString item = QString("[%1 - %2s] *%3 %5 %4").arg(ctime(&ex)).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg); + QString t(ctime(&ex)); + t.chop(1); + QString item = QString("[%1 - %2s] *%3 %5 %4").arg(t).arg(e.ttl()).arg(e.workProved()).arg(toString(e.topic()).c_str()).arg(msg); ui->whispers->addItem(item); } } From 9a16d80df794b253575872ae9253e4bafc61d054 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 25 Oct 2014 23:56:16 +0200 Subject: [PATCH 21/21] Warnings fixes. --- libdevcrypto/Common.cpp | 4 +++- libsolidity/Types.cpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 6d57bf2b2..b4623ba24 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -144,7 +144,9 @@ Public dev::recover(Signature _sig, h256 _message) cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl; #endif - return *(Public const*)&(pubkey[1]); + Public ret; + memcpy(&ret, &(pubkey[1]), sizeof(Public)); + return ret; } inline h256 kFromMessage(h256 _msg, h256 _priv) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 62324f8c2..301e95778 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -51,6 +51,7 @@ std::shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) return std::make_shared(); else BOOST_ASSERT(false); // @todo add other tyes + return std::shared_ptr(); } std::shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName)