aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md3
-rw-r--r--docs/types.rst13
-rw-r--r--libdevcore/CommonData.cpp40
-rw-r--r--libdevcore/CommonData.h5
-rw-r--r--libsolidity/analysis/TypeChecker.cpp10
-rw-r--r--libsolidity/ast/AST.cpp23
-rw-r--r--libsolidity/ast/AST.h5
-rw-r--r--libsolidity/ast/Types.cpp26
-rw-r--r--libsolidity/ast/Types.h4
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp1
-rw-r--r--libsolidity/inlineasm/AsmParser.cpp16
-rw-r--r--libsolidity/inlineasm/AsmParser.h1
-rw-r--r--libsolidity/interface/CompilerStack.cpp13
-rw-r--r--libsolidity/interface/CompilerStack.h2
-rw-r--r--libsolidity/interface/InterfaceHandler.cpp48
-rw-r--r--libsolidity/interface/InterfaceHandler.h10
-rwxr-xr-xscripts/install_deps.sh2
-rwxr-xr-xscripts/tests.sh16
-rw-r--r--solc/CommandLineInterface.cpp63
-rw-r--r--solc/CommandLineInterface.h8
-rwxr-xr-xtest/cmdlineTests.sh51
-rw-r--r--test/libdevcore/Checksum.cpp83
-rw-r--r--test/libsolidity/InlineAssembly.cpp18
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp71
-rw-r--r--test/libsolidity/SolidityParser.cpp1
25 files changed, 429 insertions, 104 deletions
diff --git a/Changelog.md b/Changelog.md
index 4edf76f0..7c09407a 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -5,11 +5,14 @@ Features:
* Compiler interface: Report source location for "stack too deep" errors.
* AST: Use deterministic node identifiers.
* Type system: Introduce type identifier strings.
+ * Type checker: Warn about invalid checksum for addresses and deduce type from valid ones.
* Metadata: Do not include platform in the version number.
+ * Metadata: Add option to store sources as literal content.
* Code generator: Extract array utils into low-level functions.
Bugfixes:
* Code generator: Allow recursive structs.
+ * Inline assembly: Disallow variables named like opcodes.
* Type checker: Allow multiple events of the same name (but with different arities or argument types)
* Natspec parser: Fix error with ``@param`` parsing and whitespace.
diff --git a/docs/types.rst b/docs/types.rst
index 6b67e684..3fb1db95 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -171,6 +171,19 @@ Fixed Point Numbers
**COMING SOON...**
+.. index:: address, literal;address
+
+.. _address_literals:
+
+Address Literals
+----------------
+
+Hexadecimal literals that pass the address checksum test, for example
+``0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF`` are of ``address`` type.
+Hexadecimal literals that are between 39 and 41 digits
+long and do not pass the checksum test produce
+a warning and are treated as regular rational number literals.
+
.. index:: literal, literal;rational
.. _rational_literals:
diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp
index 062d1b29..a53d9628 100644
--- a/libdevcore/CommonData.cpp
+++ b/libdevcore/CommonData.cpp
@@ -19,8 +19,12 @@
* @date 2014
*/
-#include "CommonData.h"
-#include "Exceptions.h"
+#include <libdevcore/CommonData.h>
+#include <libdevcore/Exceptions.h>
+#include <libdevcore/SHA3.h>
+
+#include <boost/algorithm/string.hpp>
+
using namespace std;
using namespace dev;
@@ -95,3 +99,35 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw)
}
return ret;
}
+
+
+bool dev::passesAddressChecksum(string const& _str, bool _strict)
+{
+ string s = _str.substr(0, 2) == "0x" ? _str.substr(2) : _str;
+
+ if (s.length() != 40)
+ return false;
+
+ if (!_strict && (
+ _str.find_first_of("abcdef") == string::npos ||
+ _str.find_first_of("ABCDEF") == string::npos
+ ))
+ return true;
+
+ h256 hash = keccak256(boost::algorithm::to_lower_copy(s, std::locale::classic()));
+ for (size_t i = 0; i < 40; ++i)
+ {
+ char addressCharacter = s[i];
+ bool lowerCase;
+ if ('a' <= addressCharacter && addressCharacter <= 'f')
+ lowerCase = true;
+ else if ('A' <= addressCharacter && addressCharacter <= 'F')
+ lowerCase = false;
+ else
+ continue;
+ unsigned nibble = (unsigned(hash[i / 2]) >> (4 * (1 - (i % 2)))) & 0xf;
+ if ((nibble >= 8) == lowerCase)
+ return false;
+ }
+ return true;
+}
diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h
index 5ffcdcca..e0a6d221 100644
--- a/libdevcore/CommonData.h
+++ b/libdevcore/CommonData.h
@@ -179,4 +179,9 @@ bool contains(T const& _t, V const& _v)
return std::end(_t) != std::find(std::begin(_t), std::end(_t), _v);
}
+/// @returns true iff @a _str passess the hex address checksum test.
+/// @param _strict if false, hex strings with only uppercase or only lowercase letters
+/// are considered valid.
+bool passesAddressChecksum(std::string const& _str, bool _strict);
+
}
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index adb3d54f..533c787b 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -1565,6 +1565,16 @@ void TypeChecker::endVisit(ElementaryTypeNameExpression const& _expr)
void TypeChecker::endVisit(Literal const& _literal)
{
+ if (_literal.looksLikeAddress())
+ {
+ if (_literal.passesAddressChecksum())
+ {
+ _literal.annotation().type = make_shared<IntegerType>(0, IntegerType::Modifier::Address);
+ return;
+ }
+ else
+ warning(_literal.location(), "This looks like an address but has an invalid checksum.");
+ }
_literal.annotation().type = Type::forLiteral(_literal);
if (!_literal.annotation().type)
fatalTypeError(_literal.location(), "Invalid literal value.");
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
index 8a43c3f7..616de54e 100644
--- a/libsolidity/ast/AST.cpp
+++ b/libsolidity/ast/AST.cpp
@@ -20,8 +20,6 @@
* Solidity abstract syntax tree.
*/
-#include <algorithm>
-#include <functional>
#include <libsolidity/interface/Utils.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ASTVisitor.h>
@@ -30,6 +28,11 @@
#include <libdevcore/SHA3.h>
+#include <boost/algorithm/string.hpp>
+
+#include <algorithm>
+#include <functional>
+
using namespace std;
using namespace dev;
using namespace dev::solidity;
@@ -522,3 +525,19 @@ IdentifierAnnotation& Identifier::annotation() const
m_annotation = new IdentifierAnnotation();
return static_cast<IdentifierAnnotation&>(*m_annotation);
}
+
+bool Literal::looksLikeAddress() const
+{
+ if (subDenomination() != SubDenomination::None)
+ return false;
+
+ string lit = value();
+ return lit.substr(0, 2) == "0x" && abs(int(lit.length()) - 42) <= 1;
+}
+
+bool Literal::passesAddressChecksum() const
+{
+ string lit = value();
+ solAssert(lit.substr(0, 2) == "0x", "Expected hex prefix");
+ return dev::passesAddressChecksum(lit, true);
+}
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index 4c75f7ea..743fdaa1 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -1584,6 +1584,11 @@ public:
SubDenomination subDenomination() const { return m_subDenomination; }
+ /// @returns true if this looks like a checksummed address.
+ bool looksLikeAddress() const;
+ /// @returns true if it passes the address checksum test.
+ bool passesAddressChecksum() const;
+
private:
Token::Value m_token;
ASTPointer<ASTString> m_value;
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index cefd0603..dbabc8db 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -405,6 +405,14 @@ string IntegerType::toString(bool) const
return prefix + dev::toString(m_bits);
}
+u256 IntegerType::literalValue(Literal const* _literal) const
+{
+ solAssert(m_modifier == Modifier::Address, "");
+ solAssert(_literal, "");
+ solAssert(_literal->value().substr(0, 2) == "0x", "");
+ return u256(_literal->value());
+}
+
TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
{
if (
@@ -2504,24 +2512,6 @@ FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound)
);
}
-vector<string> const FunctionType::parameterTypeNames(bool _addDataLocation) const
-{
- vector<string> names;
- for (TypePointer const& t: parameterTypes())
- names.push_back(t->canonicalName(_addDataLocation));
-
- return names;
-}
-
-vector<string> const FunctionType::returnParameterTypeNames(bool _addDataLocation) const
-{
- vector<string> names;
- for (TypePointer const& t: m_returnParameterTypes)
- names.push_back(t->canonicalName(_addDataLocation));
-
- return names;
-}
-
TypePointer const& FunctionType::selfType() const
{
solAssert(bound(), "Function is not bound.");
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 1e94631e..a5147f17 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -314,6 +314,8 @@ public:
virtual std::string toString(bool _short) const override;
+ virtual u256 literalValue(Literal const* _literal) const override;
+
virtual TypePointer encodingType() const override { return shared_from_this(); }
virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
@@ -913,10 +915,8 @@ public:
TypePointers parameterTypes() const;
std::vector<std::string> parameterNames() const;
- std::vector<std::string> const parameterTypeNames(bool _addDataLocation) const;
TypePointers const& returnParameterTypes() const { return m_returnParameterTypes; }
std::vector<std::string> const& returnParameterNames() const { return m_returnParameterNames; }
- std::vector<std::string> const returnParameterTypeNames(bool _addDataLocation) const;
/// @returns the "self" parameter type for a bound function
TypePointer const& selfType() const;
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index fe0eeb1c..bda4e04d 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -1308,6 +1308,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
{
case Type::Category::RationalNumber:
case Type::Category::Bool:
+ case Type::Category::Integer:
m_context << type->literalValue(&_literal);
break;
case Type::Category::StringLiteral:
diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp
index ef3da255..fcc92dbb 100644
--- a/libsolidity/inlineasm/AsmParser.cpp
+++ b/libsolidity/inlineasm/AsmParser.cpp
@@ -71,6 +71,8 @@ assembly::Statement Parser::parseStatement()
expectToken(Token::Colon);
assignment.variableName.location = location();
assignment.variableName.name = m_scanner->currentLiteral();
+ if (instructions().count(assignment.variableName.name))
+ fatalParserError("Identifier expected, got instruction name.");
assignment.location.end = endPosition();
expectToken(Token::Identifier);
return assignment;
@@ -101,6 +103,8 @@ assembly::Statement Parser::parseStatement()
{
// functional assignment
FunctionalAssignment funAss = createWithLocation<FunctionalAssignment>(identifier.location);
+ if (instructions().count(identifier.name))
+ fatalParserError("Cannot use instruction names for identifier names.");
m_scanner->next();
funAss.variableName = identifier;
funAss.value.reset(new Statement(parseExpression()));
@@ -130,7 +134,7 @@ assembly::Statement Parser::parseExpression()
return operation;
}
-assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
+std::map<string, dev::solidity::Instruction> const& Parser::instructions()
{
// Allowed instructions, lowercase names.
static map<string, dev::solidity::Instruction> s_instructions;
@@ -151,7 +155,11 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
// add alias for selfdestruct
s_instructions["selfdestruct"] = solidity::Instruction::SUICIDE;
}
+ return s_instructions;
+}
+assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
+{
Statement ret;
switch (m_scanner->currentToken())
{
@@ -170,9 +178,9 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
else
literal = m_scanner->currentLiteral();
// first search the set of instructions.
- if (s_instructions.count(literal))
+ if (instructions().count(literal))
{
- dev::solidity::Instruction const& instr = s_instructions[literal];
+ dev::solidity::Instruction const& instr = instructions().at(literal);
if (_onlySinglePusher)
{
InstructionInfo info = dev::solidity::instructionInfo(instr);
@@ -207,6 +215,8 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration()
VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
expectToken(Token::Let);
varDecl.name = m_scanner->currentLiteral();
+ if (instructions().count(varDecl.name))
+ fatalParserError("Cannot use instruction names for identifier names.");
expectToken(Token::Identifier);
expectToken(Token::Colon);
expectToken(Token::Assign);
diff --git a/libsolidity/inlineasm/AsmParser.h b/libsolidity/inlineasm/AsmParser.h
index 8b56ab90..643548dd 100644
--- a/libsolidity/inlineasm/AsmParser.h
+++ b/libsolidity/inlineasm/AsmParser.h
@@ -64,6 +64,7 @@ protected:
Statement parseStatement();
/// Parses a functional expression that has to push exactly one stack element
Statement parseExpression();
+ std::map<std::string, dev::solidity::Instruction> const& instructions();
Statement parseElementaryOperation(bool _onlySinglePusher = false);
VariableDeclaration parseVariableDeclaration();
FunctionalInstruction parseFunctionalInstruction(Statement&& _instruction);
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index b26bd501..3335c40e 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -726,10 +726,15 @@ string CompilerStack::createOnChainMetadata(Contract const& _contract) const
solAssert(s.second.scanner, "Scanner not available");
meta["sources"][s.first]["keccak256"] =
"0x" + toHex(dev::keccak256(s.second.scanner->source()).asBytes());
- meta["sources"][s.first]["urls"] = Json::arrayValue;
- meta["sources"][s.first]["urls"].append(
- "bzzr://" + toHex(dev::swarmHash(s.second.scanner->source()).asBytes())
- );
+ if (m_metadataLiteralSources)
+ meta["sources"][s.first]["content"] = s.second.scanner->source();
+ else
+ {
+ meta["sources"][s.first]["urls"] = Json::arrayValue;
+ meta["sources"][s.first]["urls"].append(
+ "bzzr://" + toHex(dev::swarmHash(s.second.scanner->source()).asBytes())
+ );
+ }
}
meta["settings"]["optimizer"]["enabled"] = m_optimize;
meta["settings"]["optimizer"]["runs"] = m_optimizeRuns;
diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h
index 61edc284..9ee70215 100644
--- a/libsolidity/interface/CompilerStack.h
+++ b/libsolidity/interface/CompilerStack.h
@@ -177,6 +177,7 @@ public:
/// Can be one of 4 types defined at @c DocumentationType
Json::Value const& metadata(std::string const& _contractName, DocumentationType _type) const;
std::string const& onChainMetadata(std::string const& _contractName) const;
+ void useMetadataLiteralSources(bool _metadataLiteralSources) { m_metadataLiteralSources = _metadataLiteralSources; }
/// @returns the previously used scanner, useful for counting lines during error reporting.
Scanner const& scanner(std::string const& _sourceName = "") const;
@@ -274,6 +275,7 @@ private:
std::map<std::string const, Contract> m_contracts;
std::string m_formalTranslation;
ErrorList m_errors;
+ bool m_metadataLiteralSources = false;
};
}
diff --git a/libsolidity/interface/InterfaceHandler.cpp b/libsolidity/interface/InterfaceHandler.cpp
index 9944bb22..6c1bb0c4 100644
--- a/libsolidity/interface/InterfaceHandler.cpp
+++ b/libsolidity/interface/InterfaceHandler.cpp
@@ -30,20 +30,6 @@ Json::Value InterfaceHandler::abiInterface(ContractDefinition const& _contractDe
{
Json::Value abi(Json::arrayValue);
- auto populateParameters = [](vector<string> const& _paramNames, vector<string> const& _paramTypes)
- {
- Json::Value params(Json::arrayValue);
- solAssert(_paramNames.size() == _paramTypes.size(), "Names and types vector size does not match");
- for (unsigned i = 0; i < _paramNames.size(); ++i)
- {
- Json::Value param;
- param["name"] = _paramNames[i];
- param["type"] = _paramTypes[i];
- params.append(param);
- }
- return params;
- };
-
for (auto it: _contractDef.interfaceFunctions())
{
auto externalFunctionType = it.second->interfaceFunctionType();
@@ -52,13 +38,15 @@ Json::Value InterfaceHandler::abiInterface(ContractDefinition const& _contractDe
method["name"] = it.second->declaration().name();
method["constant"] = it.second->isConstant();
method["payable"] = it.second->isPayable();
- method["inputs"] = populateParameters(
+ method["inputs"] = formatTypeList(
externalFunctionType->parameterNames(),
- externalFunctionType->parameterTypeNames(_contractDef.isLibrary())
+ externalFunctionType->parameterTypes(),
+ _contractDef.isLibrary()
);
- method["outputs"] = populateParameters(
+ method["outputs"] = formatTypeList(
externalFunctionType->returnParameterNames(),
- externalFunctionType->returnParameterTypeNames(_contractDef.isLibrary())
+ externalFunctionType->returnParameterTypes(),
+ _contractDef.isLibrary()
);
abi.append(method);
}
@@ -69,9 +57,10 @@ Json::Value InterfaceHandler::abiInterface(ContractDefinition const& _contractDe
auto externalFunction = FunctionType(*_contractDef.constructor(), false).interfaceFunctionType();
solAssert(!!externalFunction, "");
method["payable"] = externalFunction->isPayable();
- method["inputs"] = populateParameters(
+ method["inputs"] = formatTypeList(
externalFunction->parameterNames(),
- externalFunction->parameterTypeNames(_contractDef.isLibrary())
+ externalFunction->parameterTypes(),
+ _contractDef.isLibrary()
);
abi.append(method);
}
@@ -179,6 +168,25 @@ Json::Value InterfaceHandler::devDocumentation(ContractDefinition const& _contra
return doc;
}
+Json::Value InterfaceHandler::formatTypeList(
+ vector<string> const& _names,
+ vector<TypePointer> const& _types,
+ bool _forLibrary
+)
+{
+ Json::Value params(Json::arrayValue);
+ solAssert(_names.size() == _types.size(), "Names and types vector size does not match");
+ for (unsigned i = 0; i < _names.size(); ++i)
+ {
+ solAssert(_types[i], "");
+ Json::Value param;
+ param["name"] = _names[i];
+ param["type"] = _types[i]->canonicalName(_forLibrary);
+ params.append(param);
+ }
+ return params;
+}
+
string InterfaceHandler::extractDoc(multimap<string, DocTag> const& _tags, string const& _name)
{
string value;
diff --git a/libsolidity/interface/InterfaceHandler.h b/libsolidity/interface/InterfaceHandler.h
index b7e1bb00..56927d44 100644
--- a/libsolidity/interface/InterfaceHandler.h
+++ b/libsolidity/interface/InterfaceHandler.h
@@ -37,6 +37,8 @@ namespace solidity
// Forward declarations
class ContractDefinition;
+class Type;
+using TypePointer = std::shared_ptr<Type const>;
struct DocTag;
enum class DocumentationType: uint8_t;
@@ -84,6 +86,14 @@ public:
static Json::Value devDocumentation(ContractDefinition const& _contractDef);
private:
+ /// @returns a json value suitable for a list of types in function input or output
+ /// parameters or other places. If @a _forLibrary is true, complex types are referenced
+ /// by name, otherwise they are anonymously expanded.
+ static Json::Value formatTypeList(
+ std::vector<std::string> const& _names,
+ std::vector<TypePointer> const& _types,
+ bool _forLibrary
+ );
/// @returns concatenation of all content under the given tag name.
static std::string extractDoc(std::multimap<std::string, DocTag> const& _tags, std::string const& _name);
};
diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh
index 255176ab..f21c48d0 100755
--- a/scripts/install_deps.sh
+++ b/scripts/install_deps.sh
@@ -138,11 +138,13 @@ case $(uname -s) in
# All our dependencies can be found in the Arch Linux official repositories.
# See https://wiki.archlinux.org/index.php/Official_repositories
+ # Also adding ethereum-git to allow for testing with the `eth` client
sudo pacman -Sy \
base-devel \
boost \
cmake \
git \
+ ethereum-git \
;;
#------------------------------------------------------------------------------
diff --git a/scripts/tests.sh b/scripts/tests.sh
index dfbda734..cf18cb26 100755
--- a/scripts/tests.sh
+++ b/scripts/tests.sh
@@ -30,20 +30,8 @@ set -e
REPO_ROOT="$(dirname "$0")"/..
- # Compile all files in std and examples.
-
-for f in "$REPO_ROOT"/std/*.sol
-do
- echo "Compiling $f..."
- set +e
- output=$("$REPO_ROOT"/build/solc/solc "$f" 2>&1)
- failed=$?
- # Remove the pre-release warning from the compiler output
- output=$(echo "$output" | grep -v 'pre-release')
- echo "$output"
- set -e
- test -z "$output" -a "$failed" -eq 0
-done
+echo "Running commandline tests..."
+"$REPO_ROOT/test/cmdlineTests.sh"
# This conditional is only needed because we don't have a working Homebrew
# install for `eth` at the time of writing, so we unzip the ZIP file locally
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index e49e8517..2c1f0644 100644
--- a/solc/CommandLineInterface.cpp
+++ b/solc/CommandLineInterface.cpp
@@ -22,28 +22,8 @@
*/
#include "CommandLineInterface.h"
-#ifdef _WIN32 // windows
- #include <io.h>
- #define isatty _isatty
- #define fileno _fileno
-#else // unix
- #include <unistd.h>
-#endif
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/operations.hpp>
-#include <boost/algorithm/string.hpp>
-
#include "solidity/BuildInfo.h"
-#include <libdevcore/Common.h>
-#include <libdevcore/CommonData.h>
-#include <libdevcore/CommonIO.h>
-#include <libdevcore/JSON.h>
-#include <libevmasm/Instruction.h>
-#include <libevmasm/GasMeter.h>
+
#include <libsolidity/interface/Version.h>
#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/parsing/Parser.h>
@@ -54,9 +34,31 @@
#include <libsolidity/interface/CompilerStack.h>
#include <libsolidity/interface/SourceReferenceFormatter.h>
#include <libsolidity/interface/GasEstimator.h>
-#include <libsolidity/inlineasm/AsmParser.h>
#include <libsolidity/formal/Why3Translator.h>
+#include <libevmasm/Instruction.h>
+#include <libevmasm/GasMeter.h>
+
+#include <libdevcore/Common.h>
+#include <libdevcore/CommonData.h>
+#include <libdevcore/CommonIO.h>
+#include <libdevcore/JSON.h>
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/algorithm/string.hpp>
+
+#ifdef _WIN32 // windows
+ #include <io.h>
+ #define isatty _isatty
+ #define fileno _fileno
+#else // unix
+ #include <unistd.h>
+#endif
+#include <string>
+#include <iostream>
+#include <fstream>
+
using namespace std;
namespace po = boost::program_options;
@@ -98,6 +100,7 @@ static string const g_strSrcMap = "srcmap";
static string const g_strSrcMapRuntime = "srcmap-runtime";
static string const g_strVersion = "version";
static string const g_stdinFileNameStr = "<stdin>";
+static string const g_strMetadataLiteral = "metadata-literal";
static string const g_argAbi = g_strAbi;
static string const g_argAddStandard = g_strAddStandard;
@@ -126,6 +129,7 @@ static string const g_argOutputDir = g_strOutputDir;
static string const g_argSignatureHashes = g_strSignatureHashes;
static string const g_argVersion = g_strVersion;
static string const g_stdinFileName = g_stdinFileNameStr;
+static string const g_argMetadataLiteral = g_strMetadataLiteral;
/// Possible arguments to for --combined-json
static set<string> const g_combinedJsonArgs{
@@ -432,6 +436,11 @@ bool CommandLineInterface::parseLibraryOption(string const& _input)
string addrString(lib.begin() + colon + 1, lib.end());
boost::trim(libName);
boost::trim(addrString);
+ if (!passesAddressChecksum(addrString, false))
+ {
+ cerr << "Invalid checksum on library address \"" << libName << "\": " << addrString << endl;
+ return false;
+ }
bytes binAddr = fromHex(addrString);
h160 address(binAddr, h160::AlignRight);
if (binAddr.size() > 20 || address == h160())
@@ -511,7 +520,8 @@ Allowed options)",
g_argLink.c_str(),
"Switch to linker mode, ignoring all options apart from --libraries "
"and modify binaries in place."
- );
+ )
+ (g_argMetadataLiteral.c_str(), "Store referenced sources are literal data in the metadata output.");
po::options_description outputComponents("Output Components");
outputComponents.add_options()
(g_argAst.c_str(), "AST of all source files.")
@@ -634,6 +644,8 @@ bool CommandLineInterface::processInput()
auto scannerFromSourceName = [&](string const& _sourceName) -> solidity::Scanner const& { return m_compiler->scanner(_sourceName); };
try
{
+ if (m_args.count(g_argMetadataLiteral) > 0)
+ m_compiler->useMetadataLiteralSources(true);
if (m_args.count(g_argInputFile))
m_compiler->setRemappings(m_args[g_argInputFile].as<vector<string>>());
for (auto const& sourceCode: m_sourceCodes)
@@ -907,7 +919,6 @@ void CommandLineInterface::writeLinkedFiles()
bool CommandLineInterface::assemble()
{
- //@TODO later, we will use the convenience interface and should also remove the include above
bool successful = true;
map<string, shared_ptr<Scanner>> scanners;
for (auto const& src: m_sourceCodes)
@@ -921,6 +932,7 @@ bool CommandLineInterface::assemble()
m_assemblyStacks[src.first].assemble();
}
for (auto const& stack: m_assemblyStacks)
+ {
for (auto const& error: stack.second.errors())
SourceReferenceFormatter::printExceptionInformation(
cerr,
@@ -928,6 +940,9 @@ bool CommandLineInterface::assemble()
(error->type() == Error::Type::Warning) ? "Warning" : "Error",
[&](string const& _source) -> Scanner const& { return *scanners.at(_source); }
);
+ if (!Error::containsOnlyWarnings(stack.second.errors()))
+ successful = false;
+ }
return successful;
}
diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h
index b8fc1823..bcfc43d7 100644
--- a/solc/CommandLineInterface.h
+++ b/solc/CommandLineInterface.h
@@ -21,12 +21,14 @@
*/
#pragma once
-#include <memory>
-#include <boost/program_options.hpp>
-#include <boost/filesystem/path.hpp>
#include <libsolidity/interface/CompilerStack.h>
#include <libsolidity/inlineasm/AsmStack.h>
+#include <boost/program_options.hpp>
+#include <boost/filesystem/path.hpp>
+
+#include <memory>
+
namespace dev
{
namespace solidity
diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh
new file mode 100755
index 00000000..fc48654a
--- /dev/null
+++ b/test/cmdlineTests.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+
+#------------------------------------------------------------------------------
+# Bash script to run commandline Solidity tests.
+#
+# The documentation for solidity is hosted at:
+#
+# https://solidity.readthedocs.org
+#
+# ------------------------------------------------------------------------------
+# This file is part of solidity.
+#
+# solidity 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.
+#
+# solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>
+#
+# (c) 2016 solidity contributors.
+#------------------------------------------------------------------------------
+
+set -e
+
+REPO_ROOT="$(dirname "$0")"/..
+SOLC="$REPO_ROOT/build/solc/solc"
+
+ # Compile all files in std and examples.
+
+for f in "$REPO_ROOT"/std/*.sol
+do
+ echo "Compiling $f..."
+ set +e
+ output=$("$SOLC" "$f" 2>&1)
+ failed=$?
+ # Remove the pre-release warning from the compiler output
+ output=$(echo "$output" | grep -v 'pre-release')
+ echo "$output"
+ set -e
+ test -z "$output" -a "$failed" -eq 0
+done
+
+# Test library checksum
+echo 'contact C {}' | "$SOLC" --link --libraries a:0x90f20564390eAe531E810af625A22f51385Cd222
+! echo 'contract C {}' | "$SOLC" --link --libraries a:0x80f20564390eAe531E810af625A22f51385Cd222 2>/dev/null
diff --git a/test/libdevcore/Checksum.cpp b/test/libdevcore/Checksum.cpp
new file mode 100644
index 00000000..32260888
--- /dev/null
+++ b/test/libdevcore/Checksum.cpp
@@ -0,0 +1,83 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * Unit tests for the address checksum.
+ */
+
+#include <libdevcore/CommonData.h>
+
+#include "../TestHelper.h"
+
+using namespace std;
+
+namespace dev
+{
+namespace test
+{
+
+BOOST_AUTO_TEST_SUITE(Checksum)
+
+BOOST_AUTO_TEST_CASE(regular)
+{
+ BOOST_CHECK(passesAddressChecksum("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", true));
+ BOOST_CHECK(passesAddressChecksum("0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", true));
+ BOOST_CHECK(passesAddressChecksum("0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", true));
+ BOOST_CHECK(passesAddressChecksum("0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", true));
+}
+
+BOOST_AUTO_TEST_CASE(regular_negative)
+{
+ BOOST_CHECK(!passesAddressChecksum("0x6aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", true));
+ BOOST_CHECK(!passesAddressChecksum("0xeB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", true));
+ BOOST_CHECK(!passesAddressChecksum("0xebF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", true));
+ BOOST_CHECK(!passesAddressChecksum("0xE1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", true));
+}
+
+BOOST_AUTO_TEST_CASE(regular_invalid_length)
+{
+ BOOST_CHECK(passesAddressChecksum("0x9426cbfc57389778d313268E7F85F1CDc2fdad60", true));
+ BOOST_CHECK(!passesAddressChecksum("0x9426cbfc57389778d313268E7F85F1CDc2fdad6", true));
+ BOOST_CHECK(passesAddressChecksum("0x08A61851FFa4637dE289D630Ae8c5dFb0ff9171F", true));
+ BOOST_CHECK(!passesAddressChecksum("0x8A61851FFa4637dE289D630Ae8c5dFb0ff9171F", true));
+ BOOST_CHECK(passesAddressChecksum("0x00c40cC30cb4675673c9ee382de805c19734986A", true));
+ BOOST_CHECK(!passesAddressChecksum("0xc40cC30cb4675673c9ee382de805c19734986A", true));
+ BOOST_CHECK(passesAddressChecksum("0xC40CC30cb4675673C9ee382dE805c19734986a00", true));
+ BOOST_CHECK(!passesAddressChecksum("0xC40CC30cb4675673C9ee382dE805c19734986a", true));
+}
+
+BOOST_AUTO_TEST_CASE(homocaps_valid)
+{
+ BOOST_CHECK(passesAddressChecksum("0x52908400098527886E0F7030069857D2E4169EE7", true));
+ BOOST_CHECK(passesAddressChecksum("0x8617E340B3D01FA5F11F306F4090FD50E238070D", true));
+ BOOST_CHECK(passesAddressChecksum("0xde709f2102306220921060314715629080e2fb77", true));
+ BOOST_CHECK(passesAddressChecksum("0x27b1fdb04752bbc536007a920d24acb045561c26", true));
+}
+
+BOOST_AUTO_TEST_CASE(homocaps_invalid)
+{
+ string upper = "0x00AA0000000012400000000DDEEFF000000000BB";
+ BOOST_CHECK(passesAddressChecksum(upper, false));
+ BOOST_CHECK(!passesAddressChecksum(upper, true));
+ string lower = "0x11aa000000000000000d00cc00000000000000bb";
+ BOOST_CHECK(passesAddressChecksum(lower, false));
+ BOOST_CHECK(!passesAddressChecksum(lower, true));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp
index 64073edc..c051a982 100644
--- a/test/libsolidity/InlineAssembly.cpp
+++ b/test/libsolidity/InlineAssembly.cpp
@@ -182,6 +182,24 @@ BOOST_AUTO_TEST_CASE(error_tag)
BOOST_CHECK(successAssemble("{ invalidJumpLabel }"));
}
+BOOST_AUTO_TEST_CASE(inline_assembly_shadowed_instruction_declaration)
+{
+ // Error message: "Cannot use instruction names for identifier names."
+ BOOST_CHECK(!successAssemble("{ let gas := 1 }"));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_shadowed_instruction_assignment)
+{
+ // Error message: "Identifier expected, got instruction name."
+ BOOST_CHECK(!successAssemble("{ 2 =: gas }"));
+}
+
+BOOST_AUTO_TEST_CASE(inline_assembly_shadowed_instruction_functional_assignment)
+{
+ // Error message: "Cannot use instruction names for identifier names."
+ BOOST_CHECK(!successAssemble("{ gas := 2 }"));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index ce241c78..472067ec 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -1102,25 +1102,25 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors)
BOOST_REQUIRE((contract = retrieveContract(source, 0)) != nullptr);
FunctionTypePointer function = retrieveFunctionBySignature(*contract, "foo()");
BOOST_REQUIRE(function && function->hasDeclaration());
- auto returnParams = function->returnParameterTypeNames(false);
- BOOST_CHECK_EQUAL(returnParams.at(0), "uint256");
+ auto returnParams = function->returnParameterTypes();
+ BOOST_CHECK_EQUAL(returnParams.at(0)->canonicalName(false), "uint256");
BOOST_CHECK(function->isConstant());
function = retrieveFunctionBySignature(*contract, "map(uint256)");
BOOST_REQUIRE(function && function->hasDeclaration());
- auto params = function->parameterTypeNames(false);
- BOOST_CHECK_EQUAL(params.at(0), "uint256");
- returnParams = function->returnParameterTypeNames(false);
- BOOST_CHECK_EQUAL(returnParams.at(0), "bytes4");
+ auto params = function->parameterTypes();
+ BOOST_CHECK_EQUAL(params.at(0)->canonicalName(false), "uint256");
+ returnParams = function->returnParameterTypes();
+ BOOST_CHECK_EQUAL(returnParams.at(0)->canonicalName(false), "bytes4");
BOOST_CHECK(function->isConstant());
function = retrieveFunctionBySignature(*contract, "multiple_map(uint256,uint256)");
BOOST_REQUIRE(function && function->hasDeclaration());
- params = function->parameterTypeNames(false);
- BOOST_CHECK_EQUAL(params.at(0), "uint256");
- BOOST_CHECK_EQUAL(params.at(1), "uint256");
- returnParams = function->returnParameterTypeNames(false);
- BOOST_CHECK_EQUAL(returnParams.at(0), "bytes4");
+ params = function->parameterTypes();
+ BOOST_CHECK_EQUAL(params.at(0)->canonicalName(false), "uint256");
+ BOOST_CHECK_EQUAL(params.at(1)->canonicalName(false), "uint256");
+ returnParams = function->returnParameterTypes();
+ BOOST_CHECK_EQUAL(returnParams.at(0)->canonicalName(false), "bytes4");
BOOST_CHECK(function->isConstant());
}
@@ -4983,6 +4983,55 @@ BOOST_AUTO_TEST_CASE(constructible_internal_constructor)
success(text);
}
+BOOST_AUTO_TEST_CASE(address_checksum_type_deduction)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ var x = 0xfA0bFc97E48458494Ccd857e1A85DC91F7F0046E;
+ x.send(2);
+ }
+ }
+ )";
+ success(text);
+}
+
+BOOST_AUTO_TEST_CASE(invalid_address_checksum)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ var x = 0xFA0bFc97E48458494Ccd857e1A85DC91F7F0046E;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "checksum");
+}
+
+BOOST_AUTO_TEST_CASE(invalid_address_no_checksum)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ var x = 0xfa0bfc97e48458494ccd857e1a85dc91f7f0046e;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "checksum");
+}
+
+BOOST_AUTO_TEST_CASE(invalid_address_length)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ var x = 0xA0bFc97E48458494Ccd857e1A85DC91F7F0046E;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "checksum");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp
index a3bfab75..e5362e78 100644
--- a/test/libsolidity/SolidityParser.cpp
+++ b/test/libsolidity/SolidityParser.cpp
@@ -1479,7 +1479,6 @@ BOOST_AUTO_TEST_CASE(function_type_state_variable)
BOOST_CHECK(successParse(text));
}
-
BOOST_AUTO_TEST_SUITE_END()
}