mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Warn about invalid checksums of addresses.
This commit is contained in:
parent
ba9a045002
commit
1316bb7565
@ -5,6 +5,7 @@ Features:
|
|||||||
* Compiler interface: Report source location for "stack too deep" errors.
|
* Compiler interface: Report source location for "stack too deep" errors.
|
||||||
* AST: Use deterministic node identifiers.
|
* AST: Use deterministic node identifiers.
|
||||||
* Type system: Introduce type identifier strings.
|
* 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: Do not include platform in the version number.
|
||||||
* Code generator: Extract array utils into low-level functions.
|
* Code generator: Extract array utils into low-level functions.
|
||||||
|
|
||||||
|
@ -1565,6 +1565,16 @@ void TypeChecker::endVisit(ElementaryTypeNameExpression const& _expr)
|
|||||||
|
|
||||||
void TypeChecker::endVisit(Literal const& _literal)
|
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);
|
_literal.annotation().type = Type::forLiteral(_literal);
|
||||||
if (!_literal.annotation().type)
|
if (!_literal.annotation().type)
|
||||||
fatalTypeError(_literal.location(), "Invalid literal value.");
|
fatalTypeError(_literal.location(), "Invalid literal value.");
|
||||||
|
@ -20,8 +20,6 @@
|
|||||||
* Solidity abstract syntax tree.
|
* Solidity abstract syntax tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <functional>
|
|
||||||
#include <libsolidity/interface/Utils.h>
|
#include <libsolidity/interface/Utils.h>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
#include <libsolidity/ast/ASTVisitor.h>
|
#include <libsolidity/ast/ASTVisitor.h>
|
||||||
@ -30,6 +28,11 @@
|
|||||||
|
|
||||||
#include <libdevcore/SHA3.h>
|
#include <libdevcore/SHA3.h>
|
||||||
|
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace dev::solidity;
|
using namespace dev::solidity;
|
||||||
@ -522,3 +525,39 @@ IdentifierAnnotation& Identifier::annotation() const
|
|||||||
m_annotation = new IdentifierAnnotation();
|
m_annotation = new IdentifierAnnotation();
|
||||||
return static_cast<IdentifierAnnotation&>(*m_annotation);
|
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");
|
||||||
|
lit = lit.substr(2);
|
||||||
|
|
||||||
|
if (lit.length() != 40)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
h256 hash = keccak256(boost::algorithm::to_lower_copy(lit, std::locale::classic()));
|
||||||
|
for (size_t i = 0; i < 40; ++i)
|
||||||
|
{
|
||||||
|
char addressCharacter = lit[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;
|
||||||
|
}
|
||||||
|
@ -1584,6 +1584,11 @@ public:
|
|||||||
|
|
||||||
SubDenomination subDenomination() const { return m_subDenomination; }
|
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:
|
private:
|
||||||
Token::Value m_token;
|
Token::Value m_token;
|
||||||
ASTPointer<ASTString> m_value;
|
ASTPointer<ASTString> m_value;
|
||||||
|
@ -405,6 +405,14 @@ string IntegerType::toString(bool) const
|
|||||||
return prefix + dev::toString(m_bits);
|
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
|
TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
|
@ -314,6 +314,8 @@ public:
|
|||||||
|
|
||||||
virtual std::string toString(bool _short) const override;
|
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 encodingType() const override { return shared_from_this(); }
|
||||||
virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
|
virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
|
||||||
|
|
||||||
|
@ -1308,6 +1308,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
|
|||||||
{
|
{
|
||||||
case Type::Category::RationalNumber:
|
case Type::Category::RationalNumber:
|
||||||
case Type::Category::Bool:
|
case Type::Category::Bool:
|
||||||
|
case Type::Category::Integer:
|
||||||
m_context << type->literalValue(&_literal);
|
m_context << type->literalValue(&_literal);
|
||||||
break;
|
break;
|
||||||
case Type::Category::StringLiteral:
|
case Type::Category::StringLiteral:
|
||||||
|
@ -4983,6 +4983,55 @@ BOOST_AUTO_TEST_CASE(constructible_internal_constructor)
|
|||||||
success(text);
|
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()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user