Merge pull request #954 from chriseth/fallbackThrows

Fallback throws
This commit is contained in:
chriseth 2016-08-30 16:09:41 +02:00 committed by GitHub
commit 79f9a04236
7 changed files with 38 additions and 6 deletions

View File

@ -447,6 +447,12 @@ In particular, the following operations will consume more gas than the stipend p
Please ensure you test your fallback function thoroughly to ensure the execution cost is less than 2300 gas before deploying a contract.
.. warning::
Contracts that receive Ether but do not define a fallback function
throw an exception, sending back the Ether (this was different
before Solidity v0.4.0). So if you want your contract to receive Ether,
you have to implement a fallback function.
::
contract Test {

View File

@ -103,7 +103,9 @@ and stall those. Please be explicit about such cases in the documentation of you
Sending and Receiving Ether
===========================
- If a contract receives Ether (without a function being called), the fallback function is executed. The contract can only rely
- If a contract receives Ether (without a function being called), the fallback function is executed.
If it does not have a fallback function, the Ether will be rejected (by throwing an exception).
During the execution of the fallback function, the contract can only rely
on the "gas stipend" (2300 gas) being available to it at that time. This stipend is not enough to access storage in any way.
To be sure that your contract can receive Ether in that way, check the gas requirements of the fallback function
(for example in the "details" section in browser-solidity).

View File

@ -92,6 +92,8 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
else
{
fallbackFunction = function;
if (_contract.isLibrary())
typeError(fallbackFunction->location(), "Libraries cannot have fallback functions.");
if (!fallbackFunction->parameters().empty())
typeError(fallbackFunction->parameterList().location(), "Fallback function cannot take parameters.");
if (!fallbackFunction->returnParameters().empty())

View File

@ -247,11 +247,8 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
m_context << returnTag;
appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes(), _contract.isLibrary());
}
else if (_contract.isLibrary())
// Reject invalid library calls and ether sent to a library.
m_context.appendJumpTo(m_context.errorTag());
else
m_context << Instruction::STOP; // function not found
m_context.appendJumpTo(m_context.errorTag());
for (auto const& it: interfaceFunctions)
{

View File

@ -114,7 +114,7 @@ BOOST_AUTO_TEST_CASE(location_test)
shared_ptr<string const> n = make_shared<string>("source");
AssemblyItems items = compileContract(sourceCode);
vector<SourceLocation> locations =
vector<SourceLocation>(17, SourceLocation(2, 75, n)) +
vector<SourceLocation>(18, SourceLocation(2, 75, n)) +
vector<SourceLocation>(28, SourceLocation(20, 72, n)) +
vector<SourceLocation>{SourceLocation(42, 51, n), SourceLocation(65, 67, n)} +
vector<SourceLocation>(4, SourceLocation(58, 67, n)) +

View File

@ -2053,6 +2053,7 @@ BOOST_AUTO_TEST_CASE(contracts_as_addresses)
{
char const* sourceCode = R"(
contract helper {
function() { } // can receive ether
}
contract test {
helper h;
@ -2540,6 +2541,19 @@ BOOST_AUTO_TEST_CASE(inherited_fallback_function)
BOOST_CHECK(callContractFunction("getData()") == encodeArgs(1));
}
BOOST_AUTO_TEST_CASE(default_fallback_throws)
{
char const* sourceCode = R"(
contract A {
function f() returns (bool) {
return this.call();
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("f()") == encodeArgs(0));
}
BOOST_AUTO_TEST_CASE(event)
{
char const* sourceCode = R"(
@ -5943,6 +5957,7 @@ BOOST_AUTO_TEST_CASE(reject_ether_sent_to_library)
function f(address x) returns (bool) {
return x.send(1);
}
function () {}
}
)";
compileAndRun(sourceCode, 0, "lib");

View File

@ -1102,6 +1102,16 @@ BOOST_AUTO_TEST_CASE(fallback_function_with_arguments)
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_CASE(fallback_function_in_library)
{
char const* text = R"(
library C {
function() {}
}
)";
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_CASE(fallback_function_with_return_parameters)
{
char const* text = R"(