Merge pull request #1107 from ethereum/develop

Version 0.4.2
This commit is contained in:
chriseth 2016-09-17 15:25:54 +02:00 committed by GitHub
commit af6afb0415
18 changed files with 276 additions and 50 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
.commit_hash.txt
.prerelease.txt
# Compiled Object files # Compiled Object files
*.slo *.slo
*.lo *.lo

View File

@ -8,7 +8,7 @@ include(EthPolicy)
eth_policy() eth_policy()
# project name and version should be set after cmake_policy CMP0048 # project name and version should be set after cmake_policy CMP0048
set(PROJECT_VERSION "0.4.1") set(PROJECT_VERSION "0.4.2")
project(solidity VERSION ${PROJECT_VERSION}) project(solidity VERSION ${PROJECT_VERSION})
# Let's find our dependencies # Let's find our dependencies

View File

@ -1,3 +1,16 @@
### 0.4.2 (2016-09-17)
Bugfixes:
* Code Generator: Fix library functions being called from payable functions.
* Type Checker: Fixed a crash about invalid array types.
* Code Generator: Fixed a call gas bug that became visible after
version 0.4.0 for calls where the output is larger than the input.
### 0.4.1 (2016-09-09)
* Build System: Fixes to allow library compilation.
### 0.4.0 (2016-09-08) ### 0.4.0 (2016-09-08)
This release deliberately breaks backwards compatibility mostly to This release deliberately breaks backwards compatibility mostly to

View File

@ -26,6 +26,7 @@ if (EXISTS ${ETH_SOURCE_DIR}/prerelease.txt)
string(STRIP "${SOL_VERSION_PRERELEASE}" SOL_VERSION_PRERELEASE) string(STRIP "${SOL_VERSION_PRERELEASE}" SOL_VERSION_PRERELEASE)
else() else()
string(TIMESTAMP SOL_VERSION_PRERELEASE "develop.%Y.%m.%d" UTC) string(TIMESTAMP SOL_VERSION_PRERELEASE "develop.%Y.%m.%d" UTC)
string(REPLACE .0 . SOL_VERSION_PRERELEASE "${SOL_VERSION_PRERELEASE}")
endif() endif()
if (EXISTS ${ETH_SOURCE_DIR}/commit_hash.txt) if (EXISTS ${ETH_SOURCE_DIR}/commit_hash.txt)
@ -33,7 +34,7 @@ if (EXISTS ${ETH_SOURCE_DIR}/commit_hash.txt)
string(STRIP ${SOL_COMMIT_HASH} SOL_COMMIT_HASH) string(STRIP ${SOL_COMMIT_HASH} SOL_COMMIT_HASH)
else() else()
execute_process( execute_process(
COMMAND git --git-dir=${ETH_SOURCE_DIR}/.git --work-tree=${ETH_SOURCE_DIR} rev-parse HEAD COMMAND git --git-dir=${ETH_SOURCE_DIR}/.git --work-tree=${ETH_SOURCE_DIR} rev-parse --short=8 HEAD
OUTPUT_VARIABLE SOL_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET OUTPUT_VARIABLE SOL_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET
) )
execute_process( execute_process(
@ -47,14 +48,17 @@ if (SOL_COMMIT_HASH)
string(SUBSTRING ${SOL_COMMIT_HASH} 0 8 SOL_COMMIT_HASH) string(SUBSTRING ${SOL_COMMIT_HASH} 0 8 SOL_COMMIT_HASH)
endif() endif()
if (SOL_COMMIT_HASH AND SOL_LOCAL_CHANGES)
set(SOL_COMMIT_HASH "${SOL_COMMIT_HASH}.mod")
endif()
if (NOT SOL_COMMIT_HASH) if (NOT SOL_COMMIT_HASH)
message(FATAL_ERROR "Unable to determine commit hash. Either compile from within git repository or " message(FATAL_ERROR "Unable to determine commit hash. Either compile from within git repository or "
"supply a file called commit_hash.txt") "supply a file called commit_hash.txt")
endif() endif()
if (NOT SOL_COMMIT_HASH MATCHES [a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9])
message(FATAL_ERROR "Malformed commit hash \"${SOL_COMMIT_HASH}\". It has to consist of exactly 8 hex digits.")
endif()
if (SOL_COMMIT_HASH AND SOL_LOCAL_CHANGES)
set(SOL_COMMIT_HASH "${SOL_COMMIT_HASH}.mod")
endif()
set(SOL_VERSION_BUILDINFO "commit.${SOL_COMMIT_HASH}.${ETH_BUILD_PLATFORM}") set(SOL_VERSION_BUILDINFO "commit.${SOL_COMMIT_HASH}.${ETH_BUILD_PLATFORM}")

View File

@ -56,9 +56,9 @@ copyright = '2016, Ethereum'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.2.0' version = '0.4.1'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.2.0' release = '0.4.1-develop'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -6,6 +6,15 @@
Installing Solidity Installing Solidity
################### ###################
Versioning
==========
Solidity versions follow `semantic versioning <https://semver.org>` and in addition to
releases, **nightly development builds** are also made available. The nightly builds
are not guaranteed to be working and despite best efforts they might contain undocumented
and/or broken changes. We recommend to use the latest release. Package installers below
will use the latest release.
Browser-Solidity Browser-Solidity
================ ================
@ -186,3 +195,20 @@ Alternatively, you can build for Windows on the command-line, like so:
.. code:: bash .. code:: bash
cmake --build . --config RelWithDebInfo cmake --build . --config RelWithDebInfo
Important information about versioning
======================================
After a release is made, the patch version level is bumped, because we assume that only
patch level changes follow. When changes are merged, the version should be bumped according
to semver and the severity of the change. Finally, a release is always made with the version
of the current nightly build, but without the ``prerelease`` specifier.
Example:
- 0) the 0.4.0 release is made
- 1) nightly build has a version of 0.4.1 from now on
- 2) non-breaking changes are introduced - no change in version
- 3) a breaking change is introduced - version is bumped to 0.5.0
- 4) the 0.5.0 release is made
This behaviour works well with the version pragma.

View File

@ -73,7 +73,7 @@ inline bool assertEqualAux(A const& _a, B const& _b, char const* _aStr, char con
/// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong."); /// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong.");
/// Do NOT supply an exception object as the second parameter. /// Do NOT supply an exception object as the second parameter.
#define assertThrow(_condition, _ExceptionType, _description) \ #define assertThrow(_condition, _ExceptionType, _description) \
::dev::assertThrowAux<_ExceptionType>(_condition, _description, __LINE__, __FILE__, ETH_FUNC) ::dev::assertThrowAux<_ExceptionType>(!!(_condition), _description, __LINE__, __FILE__, ETH_FUNC)
using errinfo_comment = boost::error_info<struct tag_comment, std::string>; using errinfo_comment = boost::error_info<struct tag_comment, std::string>;
@ -96,16 +96,4 @@ inline void assertThrowAux(
); );
} }
template <class _ExceptionType>
inline void assertThrowAux(
void const* _pointer,
::std::string const& _errorDescription,
unsigned _line,
char const* _file,
char const* _function
)
{
assertThrowAux<_ExceptionType>(_pointer != nullptr, _errorDescription, _line, _file, _function);
}
} }

View File

@ -1438,7 +1438,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
length->literalValue(nullptr) length->literalValue(nullptr)
)); ));
else else
typeError(index->location(), "Integer constant expected."); fatalTypeError(index->location(), "Integer constant expected.");
} }
break; break;
} }

View File

@ -263,7 +263,9 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
CompilerContext::LocationSetter locationSetter(m_context, functionType->declaration()); CompilerContext::LocationSetter locationSetter(m_context, functionType->declaration());
m_context << callDataUnpackerEntryPoints.at(it.first); m_context << callDataUnpackerEntryPoints.at(it.first);
if (!functionType->isPayable()) // We have to allow this for libraries, because value of the previous
// call is still visible in the delegatecall.
if (!functionType->isPayable() && !_contract.isLibrary())
{ {
// Throw if function is not payable but call contained ether. // Throw if function is not payable but call contained ether.
m_context << Instruction::CALLVALUE; m_context << Instruction::CALLVALUE;

View File

@ -1476,6 +1476,18 @@ void ExpressionCompiler::appendExternalFunctionCall(
utils().storeFreeMemoryPointer(); utils().storeFreeMemoryPointer();
} }
// Touch the end of the output area so that we do not pay for memory resize during the call
// (which we would have to subtract from the gas left)
// We could also just use MLOAD; POP right before the gas calculation, but the optimizer
// would remove that, so we use MSTORE here.
if (!_functionType.gasSet() && retSize > 0)
{
m_context << u256(0);
utils().fetchFreeMemoryPointer();
// This touches too much, but that way we save some rounding arithmetics
m_context << u256(retSize) << Instruction::ADD << Instruction::MSTORE;
}
// Copy function identifier to memory. // Copy function identifier to memory.
utils().fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
if (!_functionType.isBareCall() || manualFunctionId) if (!_functionType.isBareCall() || manualFunctionId)
@ -1551,10 +1563,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
gasNeededByCaller += eth::GasCosts::callValueTransferGas; gasNeededByCaller += eth::GasCosts::callValueTransferGas;
if (!isCallCode && !isDelegateCall && !existenceChecked) if (!isCallCode && !isDelegateCall && !existenceChecked)
gasNeededByCaller += eth::GasCosts::callNewAccountGas; // we never know gasNeededByCaller += eth::GasCosts::callNewAccountGas; // we never know
m_context << m_context << gasNeededByCaller << Instruction::GAS << Instruction::SUB;
gasNeededByCaller <<
Instruction::GAS <<
Instruction::SUB;
} }
if (isDelegateCall) if (isDelegateCall)
m_context << Instruction::DELEGATECALL; m_context << Instruction::DELEGATECALL;

View File

@ -36,6 +36,10 @@ bool Why3Translator::process(SourceUnit const& _source)
appendPreface(); appendPreface();
_source.accept(*this); _source.accept(*this);
} }
catch (NoFormalType&)
{
solAssert(false, "There is a call to toFormalType() that does not catch NoFormalType exceptions.");
}
catch (FatalError& /*_e*/) catch (FatalError& /*_e*/)
{ {
solAssert(m_errorOccured, ""); solAssert(m_errorOccured, "");
@ -77,14 +81,30 @@ string Why3Translator::toFormalType(Type const& _type) const
return "uint256"; return "uint256";
} }
else if (auto type = dynamic_cast<ArrayType const*>(&_type)) else if (auto type = dynamic_cast<ArrayType const*>(&_type))
{
if (!type->isByteArray() && type->isDynamicallySized() && type->dataStoredIn(DataLocation::Memory)) if (!type->isByteArray() && type->isDynamicallySized() && type->dataStoredIn(DataLocation::Memory))
{ {
// Not catching NoFormalType exception. Let the caller deal with it.
string base = toFormalType(*type->baseType()); string base = toFormalType(*type->baseType());
if (!base.empty())
return "array " + base; return "array " + base;
} }
}
else if (auto mappingType = dynamic_cast<MappingType const*>(&_type))
{
solAssert(mappingType->keyType(), "A mappingType misses a keyType.");
if (dynamic_cast<IntegerType const*>(&*mappingType->keyType()))
{
//@TODO Use the information from the key type and specify the length of the array as an invariant.
// Also the constructor need to specify the length of the array.
solAssert(mappingType->valueType(), "A mappingType misses a valueType.");
// Not catching NoFormalType exception. Let the caller deal with it.
string valueTypeFormal = toFormalType(*mappingType->valueType());
return "array " + valueTypeFormal;
}
}
return ""; BOOST_THROW_EXCEPTION(NoFormalType()
<< errinfo_noFormalTypeFrom(_type.toString(true)));
} }
void Why3Translator::addLine(string const& _line) void Why3Translator::addLine(string const& _line)
@ -142,9 +162,17 @@ bool Why3Translator::visit(ContractDefinition const& _contract)
m_currentContract.stateVariables = _contract.stateVariables(); m_currentContract.stateVariables = _contract.stateVariables();
for (VariableDeclaration const* variable: m_currentContract.stateVariables) for (VariableDeclaration const* variable: m_currentContract.stateVariables)
{ {
string varType = toFormalType(*variable->annotation().type); string varType;
if (varType.empty()) try
fatalError(*variable, "Type not supported for state variable."); {
varType = toFormalType(*variable->annotation().type);
}
catch (NoFormalType &err)
{
string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err);
string typeName = typeNamePtr ? " \"" + *typeNamePtr + "\"" : "";
fatalError(*variable, "Type" + typeName + " not supported for state variable.");
}
addLine("mutable _" + variable->name() + ": " + varType); addLine("mutable _" + variable->name() + ": " + varType);
} }
unindent(); unindent();
@ -218,9 +246,16 @@ bool Why3Translator::visit(FunctionDefinition const& _function)
add(" (this: account)"); add(" (this: account)");
for (auto const& param: _function.parameters()) for (auto const& param: _function.parameters())
{ {
string paramType = toFormalType(*param->annotation().type); string paramType;
if (paramType.empty()) try
error(*param, "Parameter type not supported."); {
paramType = toFormalType(*param->annotation().type);
}
catch (NoFormalType &err)
{
string const* typeName = boost::get_error_info<errinfo_noFormalTypeFrom>(err);
error(*param, "Parameter type \"" + (typeName ? *typeName : "") + "\" not supported.");
}
if (param->name().empty()) if (param->name().empty())
error(*param, "Anonymous function parameters not supported."); error(*param, "Anonymous function parameters not supported.");
add(" (arg_" + param->name() + ": " + paramType + ")"); add(" (arg_" + param->name() + ": " + paramType + ")");
@ -232,9 +267,16 @@ bool Why3Translator::visit(FunctionDefinition const& _function)
string retString = "("; string retString = "(";
for (auto const& retParam: _function.returnParameters()) for (auto const& retParam: _function.returnParameters())
{ {
string paramType = toFormalType(*retParam->annotation().type); string paramType;
if (paramType.empty()) try
error(*retParam, "Parameter type not supported."); {
paramType = toFormalType(*retParam->annotation().type);
}
catch (NoFormalType &err)
{
string const* typeName = boost::get_error_info<errinfo_noFormalTypeFrom>(err);
error(*retParam, "Parameter type " + (typeName ? *typeName : "") + " not supported.");
}
if (retString.size() != 1) if (retString.size() != 1)
retString += ", "; retString += ", ";
retString += paramType; retString += paramType;
@ -264,14 +306,32 @@ bool Why3Translator::visit(FunctionDefinition const& _function)
{ {
if (variable->name().empty()) if (variable->name().empty())
error(*variable, "Unnamed return variables not yet supported."); error(*variable, "Unnamed return variables not yet supported.");
string varType = toFormalType(*variable->annotation().type); string varType;
try
{
varType = toFormalType(*variable->annotation().type);
}
catch (NoFormalType &err)
{
string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err);
error(*variable, "Type " + (typeNamePtr ? *typeNamePtr : "") + "in return parameter not yet supported.");
}
addLine("let _" + variable->name() + ": ref " + varType + " = ref (of_int 0) in"); addLine("let _" + variable->name() + ": ref " + varType + " = ref (of_int 0) in");
} }
for (VariableDeclaration const* variable: _function.localVariables()) for (VariableDeclaration const* variable: _function.localVariables())
{ {
if (variable->name().empty()) if (variable->name().empty())
error(*variable, "Unnamed variables not yet supported."); error(*variable, "Unnamed variables not yet supported.");
string varType = toFormalType(*variable->annotation().type); string varType;
try
{
varType = toFormalType(*variable->annotation().type);
}
catch (NoFormalType &err)
{
string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err);
error(*variable, "Type " + (typeNamePtr ? *typeNamePtr : "") + "in variable declaration not yet supported.");
}
addLine("let _" + variable->name() + ": ref " + varType + " = ref (of_int 0) in"); addLine("let _" + variable->name() + ": ref " + varType + " = ref (of_int 0) in");
} }
addLine("try"); addLine("try");
@ -434,8 +494,15 @@ bool Why3Translator::visit(TupleExpression const& _node)
bool Why3Translator::visit(UnaryOperation const& _unaryOperation) bool Why3Translator::visit(UnaryOperation const& _unaryOperation)
{ {
if (toFormalType(*_unaryOperation.annotation().type).empty()) try
error(_unaryOperation, "Type not supported in unary operation."); {
toFormalType(*_unaryOperation.annotation().type);
}
catch (NoFormalType &err)
{
string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err);
error(_unaryOperation, "Type \"" + (typeNamePtr ? *typeNamePtr : "") + "\" supported in unary operation.");
}
switch (_unaryOperation.getOperator()) switch (_unaryOperation.getOperator())
{ {
@ -798,5 +865,14 @@ module UInt256
type t = uint256, type t = uint256,
constant max = max_uint256 constant max = max_uint256
end end
module Address
use import mach.int.Unsigned
type address
constant max_address: int = 0xffffffffffffffffffffffffffffffffffffffff (* 160 bit = 40 f's *)
clone export mach.int.Unsigned with
type t = address,
constant max = max_address
end
)", 0}); )", 0});
} }

View File

@ -60,9 +60,10 @@ private:
/// Appends imports and constants use throughout the formal code. /// Appends imports and constants use throughout the formal code.
void appendPreface(); void appendPreface();
/// @returns a string representation of the corresponding formal type or the empty string /// @returns a string representation of the corresponding formal type or throws NoFormalType exception.
/// if the type is not supported.
std::string toFormalType(Type const& _type) const; std::string toFormalType(Type const& _type) const;
using errinfo_noFormalTypeFrom = boost::error_info<struct tag_noFormalTypeFrom, std::string /* name of the type that cannot be translated */ >;
struct NoFormalType: virtual Exception {};
void indent() { newLine(); m_lines.back().indentation++; } void indent() { newLine(); m_lines.back().indentation++; }
void unindent(); void unindent();

View File

@ -29,7 +29,7 @@
set -e set -e
if [[ "$OSTYPE" != "darwin"* ]]; then if [[ "$OSTYPE" != "darwin"* ]]; then
date -u +"nightly.%Y.%m.%d" > prerelease.txt date -u +"nightly.%Y.%-m.%-d" > prerelease.txt
./scripts/travis-emscripten/install_deps.sh ./scripts/travis-emscripten/install_deps.sh
docker run -v $(pwd):/src trzeci/emscripten:sdk-tag-1.35.4-64bit ./scripts/travis-emscripten/build_emscripten.sh docker run -v $(pwd):/src trzeci/emscripten:sdk-tag-1.35.4-64bit ./scripts/travis-emscripten/build_emscripten.sh
fi fi

View File

@ -56,6 +56,8 @@ detect_linux_distro() {
elif [ -f /etc/os-release ]; then elif [ -f /etc/os-release ]; then
# extract 'foo' from NAME=foo, only on the line with NAME=foo # extract 'foo' from NAME=foo, only on the line with NAME=foo
DISTRO=$(sed -n -e 's/^NAME="\(.*\)\"/\1/p' /etc/os-release) DISTRO=$(sed -n -e 's/^NAME="\(.*\)\"/\1/p' /etc/os-release)
elif [ -f /etc/centos-release ]; then
DISTRO=CentOS
else else
DISTRO='' DISTRO=''
fi fi
@ -329,6 +331,51 @@ case $(uname -s) in
sudo apt-get -y install eth sudo apt-get -y install eth
;; ;;
#------------------------------------------------------------------------------
# CentOS
# CentOS needs some more testing. This is the general idea of packages
# needed, but some tweaking/improvements can definitely happen
#------------------------------------------------------------------------------
CentOS)
read -p "This script will heavily modify your system in order to allow for compilation of Solidity. Are you sure? [Y/N]" -n 1 -r
if [[ $REPLY =~ ^[Yy]$ ]]; then
# Make Sure we have the EPEL repos
sudo yum -y install epel-release
# Get g++ 4.8
sudo rpm --import http://ftp.scientificlinux.org/linux/scientific/5x/x86_64/RPM-GPG-KEYs/RPM-GPG-KEY-cern
wget -O /etc/yum.repos.d/slc6-devtoolset.repo http://linuxsoft.cern.ch/cern/devtoolset/slc6-devtoolset.repo
sudo yum -y install devtoolset-2-gcc devtoolset-2-gcc-c++ devtoolset-2-binutils
# Enable the devtoolset2 usage so global gcc/g++ become the 4.8 one.
# As per https://gist.github.com/stephenturner/e3bc5cfacc2dc67eca8b, what you should do afterwards is
# to add this line:
# source /opt/rh/devtoolset-2/enable
# to your bashrc so that this happens automatically at login
scl enable devtoolset-2 bash
# Get cmake
sudo yum -y remove cmake
sudo yum -y install cmake3
sudo ln -s /usr/bin/cmake3 /usr/bin/cmake
# Get latest boost thanks to this guy: http://vicendominguez.blogspot.de/2014/04/boost-c-library-rpm-packages-for-centos.html
sudo yum -y remove boost-devel
sudo wget http://repo.enetres.net/enetres.repo -O /etc/yum.repos.d/enetres.repo
sudo yum install boost-devel
# And finally jsoncpp
sudo yum -y install jsoncpp-devel
else
echo "Aborted CentOS Solidity Dependency Installation";
exit 1
fi
;;
*) *)
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------

View File

@ -52,9 +52,9 @@ mv solidity solc
# Determine version # Determine version
cd solc cd solc
version=`grep -oP "PROJECT_VERSION \"?\K[0-9.]+(?=\")"? CMakeLists.txt` version=`grep -oP "PROJECT_VERSION \"?\K[0-9.]+(?=\")"? CMakeLists.txt`
commithash=`git rev-parse --short HEAD` commithash=`git rev-parse --short=8 HEAD`
committimestamp=`git show --format=%ci HEAD | head -n 1` committimestamp=`git show --format=%ci HEAD | head -n 1`
commitdate=`git show --format=%ci HEAD | head -n 1 | cut - -b1-10` commitdate=`git show --format=%ci HEAD | head -n 1 | cut - -b1-10 | sed -e 's/-0?/./' | sed -e 's/-0?/./'`
echo "$commithash" > commit_hash.txt echo "$commithash" > commit_hash.txt
if [ $branch = develop ] if [ $branch = develop ]

View File

@ -33,8 +33,11 @@ set -e
VER=$(cat CMakeLists.txt | grep 'set(PROJECT_VERSION' | sed -e 's/.*set(PROJECT_VERSION "\(.*\)".*/\1/') VER=$(cat CMakeLists.txt | grep 'set(PROJECT_VERSION' | sed -e 's/.*set(PROJECT_VERSION "\(.*\)".*/\1/')
test -n "$VER" test -n "$VER"
VER="v$VER" VER="v$VER"
COMMIT=$(git rev-parse --short HEAD) COMMIT=$(git rev-parse --short=8 HEAD)
DATE=$(date --date="$(git log -1 --date=iso --format=%ad HEAD)" --utc +%Y.%m.%d) DATE=$(date --date="$(git log -1 --date=iso --format=%ad HEAD)" --utc +%Y.%-m.%-d)
# remove leading zeros in components - they are not semver-compatible
COMMIT=$(echo "$COMMIT" | sed -e 's/^0*//')
ENCRYPTED_KEY_VAR="encrypted_${ENCRYPTION_LABEL}_key" ENCRYPTED_KEY_VAR="encrypted_${ENCRYPTION_LABEL}_key"
ENCRYPTED_IV_VAR="encrypted_${ENCRYPTION_LABEL}_iv" ENCRYPTED_IV_VAR="encrypted_${ENCRYPTION_LABEL}_iv"

View File

@ -7144,6 +7144,23 @@ BOOST_AUTO_TEST_CASE(payable_function)
BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 27 + 27); BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 27 + 27);
} }
BOOST_AUTO_TEST_CASE(payable_function_calls_library)
{
char const* sourceCode = R"(
library L {
function f() returns (uint) { return 7; }
}
contract C {
function f() payable returns (uint) {
return L.f();
}
}
)";
compileAndRun(sourceCode, 0, "L");
compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"L", m_contractAddress}});
BOOST_CHECK(callContractFunctionWithValue("f()", 27) == encodeArgs(u256(7)));
}
BOOST_AUTO_TEST_CASE(non_payable_throw) BOOST_AUTO_TEST_CASE(non_payable_throw)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(
@ -7186,6 +7203,33 @@ BOOST_AUTO_TEST_CASE(no_nonpayable_circumvention_by_modifier)
BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0); BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0);
} }
BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call)
{
// This tests that memory resize for return values is not paid during the call, which would
// make the gas calculation overly complex. We access the end of the output area before
// the call is made.
// Tests that this also survives the optimizer.
char const* sourceCode = R"(
contract C {
function f() returns (uint[200]) {}
}
contract D {
function f(C c) returns (uint) { c.f(); return 7; }
}
)";
compileAndRun(sourceCode, 0, "C");
u160 cAddr = m_contractAddress;
compileAndRun(sourceCode, 0, "D");
BOOST_CHECK(callContractFunction("f(address)", cAddr) == encodeArgs(u256(7)));
m_optimize = true;
compileAndRun(sourceCode, 0, "C");
u160 cAddrOpt = m_contractAddress;
compileAndRun(sourceCode, 0, "D");
BOOST_CHECK(callContractFunction("f(address)", cAddrOpt) == encodeArgs(u256(7)));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

View File

@ -4009,6 +4009,16 @@ BOOST_AUTO_TEST_CASE(external_constructor)
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError); BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
} }
BOOST_AUTO_TEST_CASE(invalid_array_as_statement)
{
char const* text = R"(
contract test {
struct S { uint x; }
function test(uint k) { S[k]; }
}
)";
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()