[isoltest] Adds support for fallback and ether functions.

This commit is contained in:
Erik Kundt 2019-09-09 20:09:15 +02:00
parent 02af613fa5
commit e92b921123
7 changed files with 62 additions and 30 deletions

View File

@ -92,6 +92,12 @@ public:
return callFallbackWithValue(0);
}
bytes const& callLowLevel(bytes const& _data, u256 const& _value)
{
sendMessage(_data, false, _value);
return m_output;
}
bytes const& callContractFunctionWithValueNoEncoding(std::string _sig, u256 const& _value, bytes const& _arguments)
{
FixedHash<4> hash(dev::keccak256(_sig));

View File

@ -98,11 +98,13 @@ TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePref
}
else
{
bytes output = callContractFunctionWithValueNoEncoding(
test.call().signature,
test.call().value,
test.call().arguments.rawBytes()
);
bytes output = test.call().useCallWithoutSignature ?
callLowLevel(test.call().arguments.rawBytes(), test.call().value) :
callContractFunctionWithValueNoEncoding(
test.call().signature,
test.call().value,
test.call().arguments.rawBytes()
);
if ((m_transactionSuccessful == test.call().expectations.failure) || (output != test.call().expectations.rawBytes()))
success = false;

View File

@ -2514,23 +2514,6 @@ BOOST_AUTO_TEST_CASE(super_alone)
)
}
BOOST_AUTO_TEST_CASE(fallback_function)
{
char const* sourceCode = R"(
contract A {
uint data;
function() external { data = 1; }
function getData() public returns (uint r) { return data; }
}
)";
ALSO_VIA_YUL(
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("getData()"), encodeArgs(0));
ABI_CHECK(callContractFunction(""), encodeArgs());
ABI_CHECK(callContractFunction("getData()"), encodeArgs(1));
)
}
BOOST_AUTO_TEST_CASE(inherited_fallback_function)
{
char const* sourceCode = R"(

View File

@ -0,0 +1,23 @@
contract A {
uint public data;
uint public balance;
bytes public externalData;
function() external payable {
data += 1;
balance = msg.value;
externalData = msg.data;
}
}
// ----
// data() -> 0
// ()
// data() -> 1
// (): hex"42ef"
// data() -> 2
// externalData() -> 0x20, 2, left(0x42ef)
// balance() -> 0
// (), 1 ether
// balance() -> 1
// (), 2 ether: hex"fefe"
// balance() -> 2
// externalData() -> 0x20, 2, left(0xfefe)

View File

@ -262,6 +262,9 @@ struct FunctionCall
DisplayMode displayMode = DisplayMode::SingleLine;
/// Marks this function call as the constructor.
bool isConstructor = false;
/// If this function call's signature has no name and no arguments,
/// a low-level call with unstructured calldata will be issued.
bool useCallWithoutSignature = false;
/// Marks this function call as "short-handed", meaning
/// no `->` declared.
bool omitsArrow = true;

View File

@ -75,7 +75,7 @@ vector<dev::solidity::test::FunctionCall> TestFileParser::parseFunctionCalls(siz
try
{
call.signature = parseFunctionSignature();
tie(call.signature, call.useCallWithoutSignature) = parseFunctionSignature();
if (accept(Token::Comma, true))
call.value = parseFunctionCallValue();
if (accept(Token::Colon, true))
@ -148,10 +148,17 @@ bool TestFileParser::expect(soltest::Token _token, bool const _advance)
return true;
}
string TestFileParser::parseFunctionSignature()
pair<string, bool> TestFileParser::parseFunctionSignature()
{
string signature = m_scanner.currentLiteral();
expect(Token::Identifier);
string signature;
bool hasName = false;
if (accept(Token::Identifier, false))
{
hasName = true;
signature = m_scanner.currentLiteral();
expect(Token::Identifier);
}
signature += formatToken(Token::LParen);
expect(Token::LParen);
@ -169,11 +176,15 @@ string TestFileParser::parseFunctionSignature()
if (accept(Token::Arrow, true))
throw Error(Error::Type::ParserError, "Invalid signature detected: " + signature);
signature += parameters;
if (!hasName && !parameters.empty())
throw Error(Error::Type::ParserError, "Signatures without a name cannot have parameters: " + signature);
else
signature += parameters;
expect(Token::RParen);
signature += formatToken(Token::RParen);
return signature;
return {signature, !hasName};
}
u256 TestFileParser::parseFunctionCallValue()

View File

@ -46,6 +46,8 @@ namespace test
* // -> 2, 3
* // h(uint256), 1 ether: 42
* // -> FAILURE # If REVERT or other EVM failure was detected #
* // () # Call fallback function #
* // (), 1 ether # Call ether function #
* ...
*/
class TestFileParser
@ -128,8 +130,10 @@ private:
bool accept(soltest::Token _token, bool const _expect = false);
bool expect(soltest::Token _token, bool const _advance = true);
/// Parses a function call signature in the form of f(uint256, ...).
std::string parseFunctionSignature();
/// Parses a function call signature in the form of `f(uint256, ...)` and
/// returns the signature and a flag that indicates if the function name was
/// empty. If so, the signature is not allowed to define any parameters.
std::pair<std::string, bool> parseFunctionSignature();
/// Parses the optional ether value that can be passed alongside the
/// function call arguments. Throws an InvalidEtherValueEncoding exception