Skip to content

[soltest] Introduce explicit alignment #6183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions test/libsolidity/SemanticTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ bool SemanticTest::run(ostream& _stream, string const& _linePrefix, bool const _
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl;
for (auto const& test: m_tests)
_stream << test.format(_linePrefix, false, _formatted) << endl;

_stream << endl;
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl;
for (auto const& test: m_tests)
_stream << test.format(_linePrefix, true, _formatted) << endl;

AnsiColorized(_stream, _formatted, {BOLD, RED}) << _linePrefix
AnsiColorized(_stream, _formatted, {BOLD, RED}) << _linePrefix << endl << _linePrefix
<< "Attention: Updates on the test will apply the detected format displayed." << endl;
return false;
}
Expand Down
20 changes: 11 additions & 9 deletions test/libsolidity/semanticTests/smoke_test.sol
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
contract C {
function f() public returns (uint) {
return 1;
return 2;
}
function g(uint x, uint y) public returns (uint) {
return x - y;
}
function h() public payable returns (uint) {
return f();
}
function x(bytes32 b) public returns (bytes32) {
function i(bytes32 b) public returns (bytes32) {
return b;
}
function t(bool b) public returns (bool) {
function j(bool b) public returns (bool) {
return !b;
}
function k(bytes32 b) public returns (bytes32) {
return b;
}
}
// ----
// f() -> 1
// f() -> 2
// g(uint256,uint256): 1, -2 -> 3
// h(), 1 ether -> 1
// j() -> FAILURE
// i() # Does not exist. # -> FAILURE # Reverts. #
// x(bytes32): 0x31 -> 0x31
// t(bool): true -> false
// h(), 1 ether -> 2
// i() -> FAILURE
// j(bool): true -> false
// k(bytes32): 0x31 -> 0x31
28 changes: 28 additions & 0 deletions test/libsolidity/semanticTests/smoke_test_alignment.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
contract C {
uint256 public stateDecimal = 0x20;
}

contract D {
bool public stateBool = true;
uint256 public stateDecimal = 42;
bytes32 public stateBytes = "\x42\x00\xef";

function internalStateDecimal() public returns (uint256) {
return (new C()).stateDecimal();
}

function update(bool _bool, uint256 _decimal, bytes32 _bytes) public returns (bool, uint256, bytes32) {
stateBool = _bool;
stateDecimal = _decimal;
stateBytes = _bytes;
return (stateBool, stateDecimal, stateBytes);
}
}
// ----
// stateBool() -> true
// stateBool() -> right(true)
// stateDecimal() -> 42
// stateDecimal() -> right(42)
// stateBytes() -> left(0x4200ef)
// internalStateDecimal() -> 0x20
// update(bool,uint256,bytes32): false, -23, left(0x2300ef) -> false, -23, left(0x2300ef)
163 changes: 117 additions & 46 deletions test/libsolidity/util/TestFileParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,45 @@ using namespace dev::solidity::test;
using namespace std;
using namespace soltest;

namespace
{
enum class DeclaredAlignment
{
Left,
Right,
None,
};

inline bytes alignLeft(bytes _bytes)
{
return std::move(_bytes) + bytes(32 - _bytes.size(), 0);
}

inline bytes alignRight(bytes _bytes)
{
return bytes(32 - _bytes.size(), 0) + std::move(_bytes);
}

inline bytes applyAlign(DeclaredAlignment _alignment, ABIType& _abiType, bytes _converted)
{
if (_alignment != DeclaredAlignment::None)
_abiType.alignDeclared = true;

switch (_alignment)
{
case DeclaredAlignment::Left:
_abiType.align = ABIType::AlignLeft;
return alignLeft(std::move(_converted));
case DeclaredAlignment::Right:
_abiType.align = ABIType::AlignRight;
return alignRight(std::move(_converted));
default:
_abiType.align = ABIType::AlignRight;
return alignRight(std::move(_converted));
}
}
}

vector<dev::solidity::test::FunctionCall> TestFileParser::parseFunctionCalls()
{
vector<FunctionCall> calls;
Expand Down Expand Up @@ -137,9 +176,16 @@ string TestFileParser::parseFunctionSignature()

u256 TestFileParser::parseFunctionCallValue()
{
u256 value = convertNumber(parseDecimalNumber());
expect(Token::Ether);
return value;
try
{
u256 value{parseDecimalNumber()};
expect(Token::Ether);
return value;
}
catch (std::exception const&)
{
throw Error(Error::Type::ParserError, "Ether value encoding invalid.");
}
}

FunctionCallArgs TestFileParser::parseFunctionCallArguments()
Expand Down Expand Up @@ -192,51 +238,75 @@ Parameter TestFileParser::parseParameter()

tuple<bytes, ABIType, string> TestFileParser::parseABITypeLiteral()
{
try
ABIType abiType{ABIType::None, ABIType::AlignNone, 0};
DeclaredAlignment alignment{DeclaredAlignment::None};
bytes result{toBigEndian(u256{0})};
string rawString;
bool isSigned = false;

if (accept(Token::Left, true))
{
u256 number{0};
ABIType abiType{ABIType::None, ABIType::AlignRight, 0};
string rawString;
rawString += formatToken(Token::Left);
expect(Token::LParen);
rawString += formatToken(Token::LParen);
alignment = DeclaredAlignment::Left;
}
if (accept(Token::Right, true))
{
rawString += formatToken(Token::Right);
expect(Token::LParen);
rawString += formatToken(Token::LParen);
alignment = DeclaredAlignment::Right;
}

if (accept(Token::Sub))
try
{
if (accept(Token::Sub, true))
{
abiType = ABIType{ABIType::SignedDec, ABIType::AlignRight, 32};
expect(Token::Sub);
rawString += formatToken(Token::Sub);
isSigned = true;
}
if (accept(Token::Boolean))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid boolean literal.");
abiType = ABIType{ABIType::Boolean, ABIType::AlignRight, 32};
string parsed = parseBoolean();
rawString += parsed;
result = applyAlign(alignment, abiType, convertBoolean(parsed));
}
else if (accept(Token::HexNumber))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid hex number literal.");
abiType = ABIType{ABIType::Hex, ABIType::AlignRight, 32};
string parsed = parseHexNumber();
rawString += parsed;
result = applyAlign(alignment, abiType, convertHexNumber(parsed));
}
else if (accept(Token::Number))
{
auto type = isSigned ? ABIType::SignedDec : ABIType::UnsignedDec;
abiType = ABIType{type, ABIType::AlignRight, 32};
string parsed = parseDecimalNumber();
rawString += parsed;
number = convertNumber(parsed) * -1;
if (isSigned)
parsed = "-" + parsed;
result = applyAlign(alignment, abiType, convertNumber(parsed));
}
else
else if (accept(Token::Failure, true))
{
if (accept(Token::Boolean))
{
abiType = ABIType{ABIType::Boolean, ABIType::AlignRight, 32};
string parsed = parseBoolean();
rawString += parsed;
return make_tuple(toBigEndian(u256{convertBoolean(parsed)}), abiType, rawString);
}
else if (accept(Token::HexNumber))
{
abiType = ABIType{ABIType::Hex, ABIType::AlignLeft, 32};
string parsed = parseHexNumber();
rawString += parsed;
return make_tuple(convertHexNumber(parsed), abiType, rawString);
}
else if (accept(Token::Number))
{
abiType = ABIType{ABIType::UnsignedDec, ABIType::AlignRight, 32};
string parsed = parseDecimalNumber();
rawString += parsed;
number = convertNumber(parsed);
}
else if (accept(Token::Failure, true))
{
abiType = ABIType{ABIType::Failure, ABIType::AlignRight, 0};
return make_tuple(bytes{}, abiType, rawString);
}
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid failure literal.");
abiType = ABIType{ABIType::Failure, ABIType::AlignRight, 0};
result = bytes{};
}
return make_tuple(toBigEndian(number), abiType, rawString);
if (alignment != DeclaredAlignment::None)
{
expect(Token::RParen);
rawString += formatToken(Token::RParen);
}
return make_tuple(result, abiType, rawString);
}
catch (std::exception const&)
{
Expand Down Expand Up @@ -298,21 +368,21 @@ string TestFileParser::parseHexNumber()
return literal;
}

bool TestFileParser::convertBoolean(string const& _literal)
bytes TestFileParser::convertBoolean(string const& _literal)
{
if (_literal == "true")
return true;
return bytes{true};
else if (_literal == "false")
return false;
return bytes{false};
else
throw Error(Error::Type::ParserError, "Boolean literal invalid.");
}

u256 TestFileParser::convertNumber(string const& _literal)
bytes TestFileParser::convertNumber(string const& _literal)
{
try
{
return u256{_literal};
return toCompactBigEndian(u256{_literal});
}
catch (std::exception const&)
{
Expand All @@ -330,8 +400,7 @@ bytes TestFileParser::convertHexNumber(string const& _literal)
}
else
{
bytes result = fromHex(_literal);
return result + bytes(32 - result.size(), 0);
return fromHex(_literal);
}
}
catch (std::exception const&)
Expand All @@ -357,6 +426,8 @@ void TestFileParser::Scanner::scanNextToken()
if (_literal == "true") return TokenDesc{Token::Boolean, _literal};
if (_literal == "false") return TokenDesc{Token::Boolean, _literal};
if (_literal == "ether") return TokenDesc{Token::Ether, _literal};
if (_literal == "left") return TokenDesc{Token::Left, _literal};
if (_literal == "right") return TokenDesc{Token::Right, _literal};
if (_literal == "FAILURE") return TokenDesc{Token::Failure, _literal};
return TokenDesc{Token::Identifier, _literal};
};
Expand Down
22 changes: 12 additions & 10 deletions test/libsolidity/util/TestFileParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ namespace test
K(Ether, "ether", 0) \
K(Boolean, "boolean", 0) \
/* special keywords */ \
K(Left, "left", 0) \
K(Right, "right", 0) \
K(Failure, "FAILURE", 0) \

namespace soltest
Expand Down Expand Up @@ -112,12 +114,13 @@ struct ABIType
enum Align
{
AlignLeft,
AlignRight
AlignRight,
AlignNone,
};

Type type = ABIType::None;
Align align = ABIType::AlignRight;
size_t size = 0;
bool alignDeclared = false;
};

/**
Expand Down Expand Up @@ -370,16 +373,15 @@ class TestFileParser
/// Parses the current hex number literal.
std::string parseHexNumber();

/// Coverts "true" to `true`, "false" to `false` and throws
/// otherwise.
bool convertBoolean(std::string const& _literal);
/// Tries to convert \param _literal to an unpadded `bytes`
/// representation of the boolean number literal. Throws if conversion fails.
bytes convertBoolean(std::string const& _literal);

/// Tries to convert \param _literal to right-aligned, padded `u256`
/// representation of the decimal number literal.
/// Throws if conversion fails.
u256 convertNumber(std::string const& _literal);
/// Tries to convert \param _literal to an unpadded `bytes`
/// representation of the decimal number literal. Throws if conversion fails.
bytes convertNumber(std::string const& _literal);

/// Tries to convert \param _literal to left-aligned, padded `bytes`
/// Tries to convert \param _literal to an unpadded `bytes`
/// representation of the hex literal. Throws if conversion fails.
bytes convertHexNumber(std::string const& _literal);

Expand Down
Loading