aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/contracts.rst6
-rw-r--r--docs/security-considerations.rst4
-rw-r--r--docs/units-and-global-variables.rst4
-rw-r--r--libsolidity/analysis/TypeChecker.cpp2
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp5
-rw-r--r--test/libsolidity/Assembly.cpp2
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp15
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp10
8 files changed, 42 insertions, 6 deletions
diff --git a/docs/contracts.rst b/docs/contracts.rst
index d3a89c1e..a22a3544 100644
--- a/docs/contracts.rst
+++ b/docs/contracts.rst
@@ -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 {
diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst
index f8d099e4..7e846674 100644
--- a/docs/security-considerations.rst
+++ b/docs/security-considerations.rst
@@ -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).
diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst
index d1d578ed..3da3c547 100644
--- a/docs/units-and-global-variables.rst
+++ b/docs/units-and-global-variables.rst
@@ -109,6 +109,10 @@ This means that the following are all identical::
If padding is needed, explicit type conversions can be used: ``sha3("\x00\x12")`` is the
same as ``sha3(uint16(0x12))``.
+Note that constants will be packed using the minimum number of bytes required to store them.
+This means that, for example, ``sha3(0) == sha3(uint8(0))`` and
+``sha3(0x12345678) == sha3(uint32(0x12345678))``.
+
It might be that you run into Out-of-Gas for ``sha256``, ``ripemd160`` or ``ecrecover`` on a *private blockchain*. The reason for this is that those are implemented as so-called precompiled contracts and these contracts only really exist after they received the first message (although their contract code is hardcoded). Messages to non-existing contracts are more expensive and thus the execution runs into an Out-of-Gas error. A workaround for this problem is to first send e.g. 1 Wei to each of the contracts before you use them in your actual contracts. This is not an issue on the official or test net.
.. _address_related:
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 235fcabd..bc03da01 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -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())
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index 715852be..9d77ccdc 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -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)
{
diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp
index 557d496a..81332f4f 100644
--- a/test/libsolidity/Assembly.cpp
+++ b/test/libsolidity/Assembly.cpp
@@ -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)) +
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 8a61907a..a370aafa 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -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");
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index f0ab07c5..fdd8d7f4 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -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"(