Merge pull request #7091 from ethereum/isoltest-value-format-fix

[isoltest] Fix (aligned) hex parsing and formatting
This commit is contained in:
chriseth 2019-08-07 17:55:37 +02:00 committed by GitHub
commit d44f680a51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 119 additions and 116 deletions

View File

@ -101,7 +101,7 @@ contract C {
// g1() -> FAILURE // g1() -> FAILURE
// h(uint256,uint256): 1, -2 -> 3 // h(uint256,uint256): 1, -2 -> 3
// j(bool): true -> false // j(bool): true -> false
// k(bytes32): 0x10 -> 0x10, 0x10 // k(bytes32): 0x10001 -> 0x10001, 0x10001
// l(): hex"4200efef" -> 8 // l(): hex"4200efef" -> 8
// m(bytes): 32, 32, 0x20 -> 32, 32, 0x20 // m(bytes): 32, 32, 0x20 -> 32, 32, 0x20
// m(bytes): 32, 3, hex"AB33BB" -> 32, 3, left(0xAB33BB) // m(bytes): 32, 3, hex"AB33BB" -> 32, 3, left(0xAB33BB)

View File

@ -21,6 +21,8 @@
#include <liblangutil/Common.h> #include <liblangutil/Common.h>
#include <libdevcore/StringUtils.h>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <fstream> #include <fstream>
@ -96,10 +98,7 @@ bytes BytesUtils::convertHexNumber(string const& _literal)
{ {
try try
{ {
if (_literal.size() % 2) return fromHex(_literal);
throw Error(Error::Type::ParserError, "Hex number encoding invalid.");
else
return fromHex(_literal);
} }
catch (std::exception const&) catch (std::exception const&)
{ {
@ -159,13 +158,10 @@ string BytesUtils::formatBoolean(bytes const& _bytes)
string BytesUtils::formatHex(bytes const& _bytes) string BytesUtils::formatHex(bytes const& _bytes)
{ {
stringstream os; soltestAssert(!_bytes.empty() && _bytes.size() <= 32, "");
u256 value = fromBigEndian<u256>(_bytes);
string hex{toHex(_bytes, HexPrefix::Add)}; return toCompactHexWithPrefix(value);
boost::algorithm::replace_all(hex, "00", "");
os << hex;
return os.str();
} }
string BytesUtils::formatHexString(bytes const& _bytes) string BytesUtils::formatHexString(bytes const& _bytes)

View File

@ -252,104 +252,97 @@ Parameter TestFileParser::parseParameter()
parameter.alignment = Parameter::Alignment::Right; parameter.alignment = Parameter::Alignment::Right;
} }
try if (accept(Token::Sub, true))
{ {
if (accept(Token::Sub, true)) parameter.rawString += formatToken(Token::Sub);
{ isSigned = true;
parameter.rawString += formatToken(Token::Sub);
isSigned = true;
}
if (accept(Token::Boolean))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid boolean literal.");
parameter.abiType = ABIType{ABIType::Boolean, ABIType::AlignRight, 32};
string parsed = parseBoolean();
parameter.rawString += parsed;
parameter.rawBytes = BytesUtils::applyAlign(
parameter.alignment,
parameter.abiType,
BytesUtils::convertBoolean(parsed)
);
}
else if (accept(Token::HexNumber))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid hex number literal.");
parameter.abiType = ABIType{ABIType::Hex, ABIType::AlignRight, 32};
string parsed = parseHexNumber();
parameter.rawString += parsed;
parameter.rawBytes = BytesUtils::applyAlign(
parameter.alignment,
parameter.abiType,
BytesUtils::convertHexNumber(parsed)
);
}
else if (accept(Token::Hex, true))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid hex string literal.");
if (parameter.alignment != Parameter::Alignment::None)
throw Error(Error::Type::ParserError, "Hex string literals cannot be aligned or padded.");
string parsed = parseString();
parameter.rawString += "hex\"" + parsed + "\"";
parameter.rawBytes = BytesUtils::convertHexNumber(parsed);
parameter.abiType = ABIType{
ABIType::HexString, ABIType::AlignNone, parameter.rawBytes.size()
};
}
else if (accept(Token::String))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid string literal.");
if (parameter.alignment != Parameter::Alignment::None)
throw Error(Error::Type::ParserError, "String literals cannot be aligned or padded.");
string parsed = parseString();
parameter.abiType = ABIType{ABIType::String, ABIType::AlignLeft, parsed.size()};
parameter.rawString += "\"" + parsed + "\"";
parameter.rawBytes = BytesUtils::applyAlign(
Parameter::Alignment::Left,
parameter.abiType,
BytesUtils::convertString(parsed)
);
}
else if (accept(Token::Number))
{
auto type = isSigned ? ABIType::SignedDec : ABIType::UnsignedDec;
parameter.abiType = ABIType{type, ABIType::AlignRight, 32};
string parsed = parseDecimalNumber();
parameter.rawString += parsed;
if (isSigned)
parsed = "-" + parsed;
parameter.rawBytes = BytesUtils::applyAlign(
parameter.alignment,
parameter.abiType,
BytesUtils::convertNumber(parsed)
);
}
else if (accept(Token::Failure, true))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid failure literal.");
parameter.abiType = ABIType{ABIType::Failure, ABIType::AlignRight, 0};
parameter.rawBytes = bytes{};
}
if (parameter.alignment != Parameter::Alignment::None)
{
expect(Token::RParen);
parameter.rawString += formatToken(Token::RParen);
}
} }
catch (std::exception const&) if (accept(Token::Boolean))
{ {
throw Error(Error::Type::ParserError, "Literal encoding invalid."); if (isSigned)
throw Error(Error::Type::ParserError, "Invalid boolean literal.");
parameter.abiType = ABIType{ABIType::Boolean, ABIType::AlignRight, 32};
string parsed = parseBoolean();
parameter.rawString += parsed;
parameter.rawBytes = BytesUtils::applyAlign(
parameter.alignment,
parameter.abiType,
BytesUtils::convertBoolean(parsed)
);
}
else if (accept(Token::HexNumber))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid hex number literal.");
parameter.abiType = ABIType{ABIType::Hex, ABIType::AlignRight, 32};
string parsed = parseHexNumber();
parameter.rawString += parsed;
parameter.rawBytes = BytesUtils::applyAlign(
parameter.alignment,
parameter.abiType,
BytesUtils::convertHexNumber(parsed)
);
}
else if (accept(Token::Hex, true))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid hex string literal.");
if (parameter.alignment != Parameter::Alignment::None)
throw Error(Error::Type::ParserError, "Hex string literals cannot be aligned or padded.");
string parsed = parseString();
parameter.rawString += "hex\"" + parsed + "\"";
parameter.rawBytes = BytesUtils::convertHexNumber(parsed);
parameter.abiType = ABIType{
ABIType::HexString, ABIType::AlignNone, parameter.rawBytes.size()
};
}
else if (accept(Token::String))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid string literal.");
if (parameter.alignment != Parameter::Alignment::None)
throw Error(Error::Type::ParserError, "String literals cannot be aligned or padded.");
string parsed = parseString();
parameter.abiType = ABIType{ABIType::String, ABIType::AlignLeft, parsed.size()};
parameter.rawString += "\"" + parsed + "\"";
parameter.rawBytes = BytesUtils::applyAlign(
Parameter::Alignment::Left,
parameter.abiType,
BytesUtils::convertString(parsed)
);
}
else if (accept(Token::Number))
{
auto type = isSigned ? ABIType::SignedDec : ABIType::UnsignedDec;
parameter.abiType = ABIType{type, ABIType::AlignRight, 32};
string parsed = parseDecimalNumber();
parameter.rawString += parsed;
if (isSigned)
parsed = "-" + parsed;
parameter.rawBytes = BytesUtils::applyAlign(
parameter.alignment,
parameter.abiType,
BytesUtils::convertNumber(parsed)
);
}
else if (accept(Token::Failure, true))
{
if (isSigned)
throw Error(Error::Type::ParserError, "Invalid failure literal.");
parameter.abiType = ABIType{ABIType::Failure, ABIType::AlignRight, 0};
parameter.rawBytes = bytes{};
}
if (parameter.alignment != Parameter::Alignment::None)
{
expect(Token::RParen);
parameter.rawString += formatToken(Token::RParen);
} }
return parameter; return parameter;

View File

@ -404,6 +404,27 @@ BOOST_AUTO_TEST_CASE(call_arguments_string)
); );
} }
BOOST_AUTO_TEST_CASE(call_hex_number)
{
char const* source = R"(
// f(bytes32, bytes32): 0x616, 0x1042 -> 1
)";
auto const calls = parse(source);
BOOST_REQUIRE_EQUAL(calls.size(), 1);
testFunctionCall(
calls.at(0),
Mode::SingleLine,
"f(bytes32,bytes32)",
false,
fmt::encodeArgs(
fromHex("0x616"),
fromHex("0x1042")
),
fmt::encodeArgs(1)
);
}
BOOST_AUTO_TEST_CASE(call_return_string) BOOST_AUTO_TEST_CASE(call_return_string)
{ {
char const* source = R"( char const* source = R"(
@ -786,14 +807,6 @@ BOOST_AUTO_TEST_CASE(call_ether_type_invalid)
BOOST_REQUIRE_THROW(parse(source), langutil::Error); BOOST_REQUIRE_THROW(parse(source), langutil::Error);
} }
BOOST_AUTO_TEST_CASE(call_hex_number_invalid)
{
char const* source = R"(
// f(bytes32, bytes32): 0x616, 0x042 -> 1
)";
BOOST_REQUIRE_THROW(parse(source), langutil::Error);
}
BOOST_AUTO_TEST_CASE(call_signed_bool_invalid) BOOST_AUTO_TEST_CASE(call_signed_bool_invalid)
{ {
char const* source = R"( char const* source = R"(

View File

@ -193,7 +193,7 @@ string TestFunctionCall::formatBytesParameters(
fill_n( fill_n(
back_inserter(defaultParameters), back_inserter(defaultParameters),
ceil(_bytes.size() / 32), ceil(_bytes.size() / 32),
Parameter{bytes(), "", ABIType{ABIType::UnsignedDec}, FormatInfo{}} Parameter{bytes(), "", ABIType{ABIType::Hex}, FormatInfo{}}
); );
ContractABIUtils::overwriteParameters(_errorReporter, defaultParameters, _parameters); ContractABIUtils::overwriteParameters(_errorReporter, defaultParameters, _parameters);
os << BytesUtils::formatBytesRange(_bytes, defaultParameters, _highlight); os << BytesUtils::formatBytesRange(_bytes, defaultParameters, _highlight);

View File

@ -139,7 +139,8 @@ BOOST_AUTO_TEST_CASE(format_hex_singleline)
BOOST_REQUIRE_EQUAL(test.format(), "// f(bytes32): 0x31 -> 0x31"); BOOST_REQUIRE_EQUAL(test.format(), "// f(bytes32): 0x31 -> 0x31");
bytes actualResult = fromHex("0x32"); bytes actualResult = fromHex("0x32");
bytes actualBytes = actualResult + bytes(32 - actualResult.size(), 0); bytes actualBytes = bytes(32 - actualResult.size(), 0) + actualResult;
test.setRawBytes(actualBytes); test.setRawBytes(actualBytes);
test.setFailure(false); test.setFailure(false);