mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #11682 from ethereum/fixedPointTypes
Fixed point types for isoltest
This commit is contained in:
commit
d7a802e4bf
@ -108,6 +108,7 @@ detect_stray_source_files("${libsolidity_sources}" "libsolidity/")
|
|||||||
|
|
||||||
set(libsolidity_util_sources
|
set(libsolidity_util_sources
|
||||||
libsolidity/util/BytesUtils.cpp
|
libsolidity/util/BytesUtils.cpp
|
||||||
|
libsolidity/util/BytesUtilsTests.cpp
|
||||||
libsolidity/util/BytesUtils.h
|
libsolidity/util/BytesUtils.h
|
||||||
libsolidity/util/ContractABIUtils.cpp
|
libsolidity/util/ContractABIUtils.cpp
|
||||||
libsolidity/util/ContractABIUtils.h
|
libsolidity/util/ContractABIUtils.h
|
||||||
|
@ -17,18 +17,13 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
#include <test/libsolidity/util/BytesUtils.h>
|
#include <test/libsolidity/util/BytesUtils.h>
|
||||||
|
|
||||||
#include <test/libsolidity/util/ContractABIUtils.h>
|
#include <test/libsolidity/util/ContractABIUtils.h>
|
||||||
#include <test/libsolidity/util/SoltestErrors.h>
|
#include <test/libsolidity/util/SoltestErrors.h>
|
||||||
|
|
||||||
#include <liblangutil/Common.h>
|
|
||||||
|
|
||||||
#include <libsolutil/CommonData.h>
|
#include <libsolutil/CommonData.h>
|
||||||
#include <libsolutil/StringUtils.h>
|
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
@ -96,6 +91,22 @@ bytes BytesUtils::convertNumber(string const& _literal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bytes BytesUtils::convertFixedPoint(string const& _literal, size_t& o_fractionalDigits)
|
||||||
|
{
|
||||||
|
size_t dotPos = _literal.find('.');
|
||||||
|
string valueInteger = _literal.substr(0, dotPos);
|
||||||
|
string valueFraction = _literal.substr(dotPos + 1);
|
||||||
|
o_fractionalDigits = valueFraction.length();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return util::toBigEndian(u256(valueInteger + valueFraction));
|
||||||
|
}
|
||||||
|
catch (std::exception const&)
|
||||||
|
{
|
||||||
|
BOOST_THROW_EXCEPTION(TestParserError("Number encoding invalid."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bytes BytesUtils::convertHexNumber(string const& _literal)
|
bytes BytesUtils::convertHexNumber(string const& _literal)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -206,6 +217,28 @@ string BytesUtils::formatString(bytes const& _bytes, size_t _cutOff)
|
|||||||
return os.str();
|
return os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string BytesUtils::formatFixedPoint(bytes const& _bytes, bool _signed, size_t _fractionalDigits)
|
||||||
|
{
|
||||||
|
string decimal;
|
||||||
|
bool negative = false;
|
||||||
|
if (_signed)
|
||||||
|
{
|
||||||
|
s256 signedValue{u2s(fromBigEndian<u256>(_bytes))};
|
||||||
|
negative = (signedValue < 0);
|
||||||
|
decimal = signedValue.str();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
decimal = fromBigEndian<u256>(_bytes).str();
|
||||||
|
if (_fractionalDigits > 0)
|
||||||
|
{
|
||||||
|
size_t numDigits = decimal.length() - (negative ? 1 : 0);
|
||||||
|
if (_fractionalDigits > numDigits)
|
||||||
|
decimal.insert(negative ? 1 : 0, string(_fractionalDigits - numDigits, '0'));
|
||||||
|
decimal.insert(decimal.length() - _fractionalDigits, ".");
|
||||||
|
}
|
||||||
|
return decimal;
|
||||||
|
}
|
||||||
|
|
||||||
string BytesUtils::formatRawBytes(
|
string BytesUtils::formatRawBytes(
|
||||||
bytes const& _bytes,
|
bytes const& _bytes,
|
||||||
solidity::frontend::test::ParameterList const& _parameters,
|
solidity::frontend::test::ParameterList const& _parameters,
|
||||||
@ -296,8 +329,11 @@ string BytesUtils::formatBytes(
|
|||||||
case ABIType::String:
|
case ABIType::String:
|
||||||
os << formatString(_bytes, _bytes.size() - countRightPaddedZeros(_bytes));
|
os << formatString(_bytes, _bytes.size() - countRightPaddedZeros(_bytes));
|
||||||
break;
|
break;
|
||||||
case ABIType::Failure:
|
case ABIType::UnsignedFixedPoint:
|
||||||
|
case ABIType::SignedFixedPoint:
|
||||||
|
os << formatFixedPoint(_bytes, _abiType.type == ABIType::SignedFixedPoint, _abiType.fractionalDigits);
|
||||||
break;
|
break;
|
||||||
|
case ABIType::Failure:
|
||||||
case ABIType::None:
|
case ABIType::None:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,10 @@ public:
|
|||||||
/// representation of the decimal number literal. Throws if conversion fails.
|
/// representation of the decimal number literal. Throws if conversion fails.
|
||||||
static bytes convertNumber(std::string const& _literal);
|
static bytes convertNumber(std::string const& _literal);
|
||||||
|
|
||||||
|
/// Tries to convert \param _literal to an unpadded `bytes`
|
||||||
|
/// representation of the decimal number literal. Throws if conversion fails.
|
||||||
|
static bytes convertFixedPoint(std::string const& _literal, size_t& o_fractionalDigits);
|
||||||
|
|
||||||
/// Tries to convert \param _literal to an unpadded `bytes`
|
/// Tries to convert \param _literal to an unpadded `bytes`
|
||||||
/// representation of the hex literal. Throws if conversion fails.
|
/// representation of the hex literal. Throws if conversion fails.
|
||||||
static bytes convertHexNumber(std::string const& _literal);
|
static bytes convertHexNumber(std::string const& _literal);
|
||||||
@ -98,6 +102,10 @@ public:
|
|||||||
return formatString(_bytes, _bytes.size());
|
return formatString(_bytes, _bytes.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts \param _bytes to a soltest-compliant and human-readable
|
||||||
|
/// decimal string representation of a byte array. Format of \param _bytes is binary.
|
||||||
|
static std::string formatFixedPoint(bytes const& _bytes, bool _signed, size_t _fractionalDigits);
|
||||||
|
|
||||||
/// Used to print returned bytes from function calls to the commandline.
|
/// Used to print returned bytes from function calls to the commandline.
|
||||||
/// Returns a string representation of given _bytes in ranges of 32 bytes.
|
/// Returns a string representation of given _bytes in ranges of 32 bytes.
|
||||||
/// If _withSignature is true, the first 4 bytes will be formatted separately.
|
/// If _withSignature is true, the first 4 bytes will be formatted separately.
|
||||||
|
82
test/libsolidity/util/BytesUtilsTests.cpp
Normal file
82
test/libsolidity/util/BytesUtilsTests.cpp
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include <test/libsolidity/util/BytesUtils.h>
|
||||||
|
|
||||||
|
#include <libsolutil/CommonData.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace solidity::util;
|
||||||
|
using namespace solidity::test;
|
||||||
|
|
||||||
|
namespace solidity::frontend::test
|
||||||
|
{
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(BytesUtilsTest)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(format_fixed)
|
||||||
|
{
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
BytesUtils::formatFixedPoint(toBigEndian(u256{0}), true, 2),
|
||||||
|
".00"
|
||||||
|
);
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
BytesUtils::formatFixedPoint(toBigEndian(u256{1}), true, 2),
|
||||||
|
".01"
|
||||||
|
);
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
BytesUtils::formatFixedPoint(toBigEndian(u256{123}), true, 2),
|
||||||
|
"1.23"
|
||||||
|
);
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
BytesUtils::formatFixedPoint(toBigEndian(u256{-1}), true, 2),
|
||||||
|
"-.01"
|
||||||
|
);
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
BytesUtils::formatFixedPoint(toBigEndian(u256{-12}), true, 2),
|
||||||
|
"-.12"
|
||||||
|
);
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
BytesUtils::formatFixedPoint(toBigEndian(u256{-123}), true, 2),
|
||||||
|
"-1.23"
|
||||||
|
);
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
BytesUtils::formatFixedPoint(toBigEndian(u256{-1234}), true, 2),
|
||||||
|
"-12.34"
|
||||||
|
);
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
BytesUtils::formatFixedPoint(toBigEndian(u256{-12345}), true, 2),
|
||||||
|
"-123.45"
|
||||||
|
);
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
BytesUtils::formatFixedPoint(toBigEndian(u256{-123456}), true, 2),
|
||||||
|
"-1234.56"
|
||||||
|
);
|
||||||
|
BOOST_CHECK_EQUAL(
|
||||||
|
BytesUtils::formatFixedPoint(toBigEndian(u256{-1234567}), true, 2),
|
||||||
|
"-12345.67"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
|
}
|
@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#include <test/libsolidity/util/SoltestErrors.h>
|
#include <test/libsolidity/util/SoltestErrors.h>
|
||||||
|
|
||||||
|
#include <libsolidity/ast/Types.h>
|
||||||
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
#include <libsolutil/FunctionSelector.h>
|
#include <libsolutil/FunctionSelector.h>
|
||||||
#include <libsolutil/CommonData.h>
|
#include <libsolutil/CommonData.h>
|
||||||
|
|
||||||
@ -124,6 +126,21 @@ bool isFixedTupleArray(string const& _type)
|
|||||||
return regex_match(_type, regex{"tuple\\[\\d+\\]"});
|
return regex_match(_type, regex{"tuple\\[\\d+\\]"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
optional<ABIType> isFixedPoint(string const& type)
|
||||||
|
{
|
||||||
|
optional<ABIType> fixedPointType;
|
||||||
|
smatch matches;
|
||||||
|
if (regex_match(type, matches, regex{"(u?)fixed(\\d+)x(\\d+)"}))
|
||||||
|
{
|
||||||
|
ABIType abiType(ABIType::SignedFixedPoint);
|
||||||
|
if (matches[1].str() == "u")
|
||||||
|
abiType.type = ABIType::UnsignedFixedPoint;
|
||||||
|
abiType.fractionalDigits = static_cast<unsigned>(std::stoi(matches[3].str()));
|
||||||
|
fixedPointType = abiType;
|
||||||
|
}
|
||||||
|
return fixedPointType;
|
||||||
|
}
|
||||||
|
|
||||||
string functionSignatureFromABI(Json::Value const& _functionABI)
|
string functionSignatureFromABI(Json::Value const& _functionABI)
|
||||||
{
|
{
|
||||||
auto inputs = _functionABI["inputs"];
|
auto inputs = _functionABI["inputs"];
|
||||||
@ -245,6 +262,8 @@ bool ContractABIUtils::appendTypesFromName(
|
|||||||
_dynamicTypes.push_back(ABIType{ABIType::String, ABIType::AlignLeft});
|
_dynamicTypes.push_back(ABIType{ABIType::String, ABIType::AlignLeft});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (optional<ABIType> fixedPointType = isFixedPoint(type))
|
||||||
|
_inplaceTypes.push_back(*fixedPointType);
|
||||||
else if (isBytes(type))
|
else if (isBytes(type))
|
||||||
return false;
|
return false;
|
||||||
else if (isFixedTupleArray(type))
|
else if (isFixedTupleArray(type))
|
||||||
@ -270,7 +289,8 @@ void ContractABIUtils::overwriteParameters(
|
|||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
_a.abiType.size != _b.abiType.size ||
|
_a.abiType.size != _b.abiType.size ||
|
||||||
_a.abiType.type != _b.abiType.type
|
_a.abiType.type != _b.abiType.type ||
|
||||||
|
_a.abiType.fractionalDigits != _b.abiType.fractionalDigits
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_errorReporter.warning("Type or size of parameter(s) does not match.");
|
_errorReporter.warning("Type or size of parameter(s) does not match.");
|
||||||
|
@ -107,7 +107,9 @@ struct ABIType
|
|||||||
SignedDec,
|
SignedDec,
|
||||||
Hex,
|
Hex,
|
||||||
HexString,
|
HexString,
|
||||||
String
|
String,
|
||||||
|
UnsignedFixedPoint,
|
||||||
|
SignedFixedPoint
|
||||||
};
|
};
|
||||||
enum Align
|
enum Align
|
||||||
{
|
{
|
||||||
@ -125,6 +127,9 @@ struct ABIType
|
|||||||
Type type = ABIType::None;
|
Type type = ABIType::None;
|
||||||
Align align = ABIType::AlignRight;
|
Align align = ABIType::AlignRight;
|
||||||
size_t size = 32;
|
size_t size = 32;
|
||||||
|
|
||||||
|
size_t fractionalDigits = 0;
|
||||||
|
|
||||||
bool alignDeclared = false;
|
bool alignDeclared = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -407,11 +407,17 @@ Parameter TestFileParser::parseParameter()
|
|||||||
if (isSigned)
|
if (isSigned)
|
||||||
parsed = "-" + parsed;
|
parsed = "-" + parsed;
|
||||||
|
|
||||||
parameter.rawBytes = BytesUtils::applyAlign(
|
if (parsed.find('.') == string::npos)
|
||||||
parameter.alignment,
|
parameter.rawBytes = BytesUtils::applyAlign(
|
||||||
parameter.abiType,
|
parameter.alignment,
|
||||||
BytesUtils::convertNumber(parsed)
|
parameter.abiType,
|
||||||
);
|
BytesUtils::convertNumber(parsed)
|
||||||
|
);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parameter.abiType.type = isSigned ? ABIType::SignedFixedPoint : ABIType::UnsignedFixedPoint;
|
||||||
|
parameter.rawBytes = BytesUtils::convertFixedPoint(parsed, parameter.abiType.fractionalDigits);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (accept(Token::Failure, true))
|
else if (accept(Token::Failure, true))
|
||||||
{
|
{
|
||||||
@ -667,7 +673,7 @@ string TestFileParser::Scanner::scanDecimalNumber()
|
|||||||
{
|
{
|
||||||
string number;
|
string number;
|
||||||
number += current();
|
number += current();
|
||||||
while (langutil::isDecimalDigit(peek()))
|
while (langutil::isDecimalDigit(peek()) || '.' == peek())
|
||||||
{
|
{
|
||||||
advance();
|
advance();
|
||||||
number += current();
|
number += current();
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include <libsolutil/AnsiColorized.h>
|
#include <libsolutil/AnsiColorized.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
@ -16,10 +16,12 @@
|
|||||||
|
|
||||||
#include <test/libsolidity/util/TestFileParser.h>
|
#include <test/libsolidity/util/TestFileParser.h>
|
||||||
#include <test/libsolidity/util/SoltestErrors.h>
|
#include <test/libsolidity/util/SoltestErrors.h>
|
||||||
|
#include <test/libsolidity/util/ContractABIUtils.h>
|
||||||
|
|
||||||
#include <liblangutil/Exceptions.h>
|
#include <liblangutil/Exceptions.h>
|
||||||
#include <libsolutil/AnsiColorized.h>
|
#include <libsolutil/AnsiColorized.h>
|
||||||
#include <libsolutil/CommonData.h>
|
#include <libsolutil/CommonData.h>
|
||||||
|
#include <libsolutil/JSON.h>
|
||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
@ -109,12 +111,6 @@ private:
|
|||||||
bool failure = false
|
bool failure = false
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
/// Formats a given _bytes applying the _abiType.
|
|
||||||
std::string formatBytesRange(
|
|
||||||
bytes const& _bytes,
|
|
||||||
ABIType const& _abiType
|
|
||||||
) const;
|
|
||||||
|
|
||||||
/// Formats a FAILURE plus additional parameters, if e.g. a revert message was returned.
|
/// Formats a FAILURE plus additional parameters, if e.g. a revert message was returned.
|
||||||
std::string formatFailure(
|
std::string formatFailure(
|
||||||
ErrorReporter& _errorReporter,
|
ErrorReporter& _errorReporter,
|
||||||
|
Loading…
Reference in New Issue
Block a user