Skip to content

Commit 5df36e5

Browse files
authored
Merge branch 'ethereum:develop' into develop
2 parents 24a269a + d084819 commit 5df36e5

File tree

395 files changed

+14342
-738
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

395 files changed

+14342
-738
lines changed

Changelog.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
### 0.8.29 (unreleased)
22

33
Language Features:
4-
* Introduce syntax for specifying contract storage layout base.
4+
* Allow relocating contract storage to an arbitrary location.
55

66

77
Compiler Features:
@@ -16,6 +16,8 @@ Compiler Features:
1616

1717

1818
Bugfixes:
19+
* Commandline Interface: Report StackTooDeep errors in compiler mode as proper errors instead of printing diagnostic information meant for internal compiler errors.
20+
* Error Reporting: Fix error locations not being shown for source files with empty names.
1921
* General: Fix internal compiler error when requesting IR AST outputs for interfaces and abstract contracts.
2022
* Metadata: Fix custom cleanup sequence missing from metadata when other optimizer settings have default values.
2123
* SMTChecker: Fix internal compiler error when analyzing overflowing expressions or bitwise negation of unsigned types involving constants.
@@ -27,13 +29,19 @@ Bugfixes:
2729
* SMTChecker: Fix SMT logic error when translating invariants involving array store and select operations.
2830
* SMTChecker: Fix wrong encoding of string literals as arguments of ``ecrecover`` precompile.
2931
* Standard JSON Interface: Fix ``generatedSources`` and ``sourceMap`` being generated internally even when not requested.
32+
* TypeChecker: Fix supurious compilation errors due to incorrect computation of contract storage size which erroneously included transient storage variables.
3033
* Yul: Fix internal compiler error when a code generation error should be reported instead.
34+
* Yul Optimizer: Fix failing debug assertion due to dereferencing of an empty ``optional`` value.
3135

3236

3337
Build system:
3438
* Linux release builds are fully static again and no longer depend on ``glibc``.
3539
* Switch from C++17 to C++20 as the target standard.
3640

41+
42+
Solc-Js:
43+
* The wrapper now requires at least nodejs v12.
44+
3745
### 0.8.28 (2024-10-09)
3846

3947
Language Features:

libevmasm/GasMeter.cpp

+36-8
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,11 @@ GasMeter::GasConsumption GasMeter::memoryGas(int _stackPosOffset, int _stackPosS
263263
}));
264264
}
265265

266-
unsigned GasMeter::runGas(Instruction _instruction, langutil::EVMVersion _evmVersion)
266+
namespace
267267
{
268-
if (_instruction == Instruction::JUMPDEST)
269-
return 1;
270-
271-
switch (instructionInfo(_instruction, _evmVersion).gasPriceTier)
268+
std::optional<unsigned> gasCostForTier(Tier _tier)
269+
{
270+
switch (_tier)
272271
{
273272
case Tier::Zero: return GasCosts::tier0Gas;
274273
case Tier::Base: return GasCosts::tier1Gas;
@@ -286,10 +285,21 @@ unsigned GasMeter::runGas(Instruction _instruction, langutil::EVMVersion _evmVer
286285

287286
case Tier::Special:
288287
case Tier::Invalid:
289-
assertThrow(false, OptimizerException, "Invalid gas tier for instruction " + instructionInfo(_instruction, _evmVersion).name);
288+
return std::nullopt;
290289
}
291290
util::unreachable();
292291
}
292+
}
293+
294+
unsigned GasMeter::runGas(Instruction _instruction, langutil::EVMVersion _evmVersion)
295+
{
296+
if (_instruction == Instruction::JUMPDEST)
297+
return 1;
298+
299+
if (auto gasCost = gasCostForTier(instructionInfo(_instruction, _evmVersion).gasPriceTier))
300+
return *gasCost;
301+
solAssert(false, "Invalid gas tier for instruction " + instructionInfo(_instruction, _evmVersion).name);
302+
}
293303

294304
unsigned GasMeter::pushGas(u256 _value, langutil::EVMVersion _evmVersion)
295305
{
@@ -299,6 +309,24 @@ unsigned GasMeter::pushGas(u256 _value, langutil::EVMVersion _evmVersion)
299309
);
300310
}
301311

312+
unsigned GasMeter::swapGas(size_t _depth, langutil::EVMVersion _evmVersion)
313+
{
314+
if (_depth <= 16)
315+
return runGas(evmasm::swapInstruction(static_cast<unsigned>(_depth)), _evmVersion);
316+
auto gasCost = gasCostForTier(instructionInfo(evmasm::Instruction::SWAPN, _evmVersion).gasPriceTier);
317+
solAssert(gasCost.has_value(), "Expected gas cost for SWAPN to be defined.");
318+
return *gasCost;
319+
}
320+
321+
unsigned GasMeter::dupGas(size_t _depth, langutil::EVMVersion _evmVersion)
322+
{
323+
if (_depth <= 16)
324+
return runGas(evmasm::swapInstruction(static_cast<unsigned>(_depth)), _evmVersion);
325+
auto gasCost = gasCostForTier(instructionInfo(evmasm::Instruction::DUPN, _evmVersion).gasPriceTier);
326+
solAssert(gasCost.has_value(), "Expected gas cost for DUPN to be defined.");
327+
return *gasCost;
328+
}
329+
302330
u256 GasMeter::dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersion _evmVersion)
303331
{
304332
bigint gas = 0;
@@ -309,14 +337,14 @@ u256 GasMeter::dataGas(bytes const& _data, bool _inCreation, langutil::EVMVersio
309337
}
310338
else
311339
gas = bigint(GasCosts::createDataGas) * _data.size();
312-
assertThrow(gas < bigint(u256(-1)), OptimizerException, "Gas cost exceeds 256 bits.");
340+
solAssert(gas < bigint(u256(-1)), "Gas cost exceeds 256 bits.");
313341
return u256(gas);
314342
}
315343

316344

317345
u256 GasMeter::dataGas(uint64_t _length, bool _inCreation, langutil::EVMVersion _evmVersion)
318346
{
319347
bigint gas = bigint(_length) * (_inCreation ? GasCosts::txDataNonZeroGas(_evmVersion) : GasCosts::createDataGas);
320-
assertThrow(gas < bigint(u256(-1)), OptimizerException, "Gas cost exceeds 256 bits.");
348+
solAssert(gas < bigint(u256(-1)), "Gas cost exceeds 256 bits.");
321349
return u256(gas);
322350
}

libevmasm/GasMeter.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,18 @@ class GasMeter
226226
/// change with EVM versions)
227227
static unsigned runGas(Instruction _instruction, langutil::EVMVersion _evmVersion);
228228

229-
/// @returns gas costs for push instructions (may change depending on EVM version)
229+
/// @returns gas costs for the cheapest push instructions for the given @a _value
230+
/// (may change depending on EVM version)
230231
static unsigned pushGas(u256 _value, langutil::EVMVersion _evmVersion);
231232

233+
/// @returns gas costs for the cheapest swap instructions for the given @a _depth
234+
/// (may change depending on EVM version)
235+
static unsigned swapGas(size_t _depth, langutil::EVMVersion _evmVersion);
236+
237+
/// @returns gas costs for the cheapest dup instructions for the given @a _depth
238+
/// (may change depending on EVM version)
239+
static unsigned dupGas(size_t _depth, langutil::EVMVersion _evmVersion);
240+
232241
/// @returns the gas cost of the supplied data, depending whether it is in creation code, or not.
233242
/// In case of @a _inCreation, the data is only sent as a transaction and is not stored, whereas
234243
/// otherwise code will be stored and have to pay "createDataGas" cost.

liblangutil/ErrorReporter.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323

2424
#include <liblangutil/ErrorReporter.h>
2525
#include <liblangutil/SourceLocation.h>
26+
27+
#include <libsolutil/Exceptions.h>
28+
2629
#include <range/v3/algorithm/find_if.hpp>
2730
#include <memory>
2831

@@ -121,7 +124,7 @@ bool ErrorReporter::checkForExcessiveErrors(Error::Type _type)
121124
if (m_errorCount > c_maxErrorsAllowed)
122125
{
123126
m_errorList.push_back(std::make_shared<Error>(4013_error, Error::Type::Warning, "There are more than 256 errors. Aborting."));
124-
BOOST_THROW_EXCEPTION(FatalError());
127+
solThrow(FatalError, "There are more than 256 errors. Aborting.");
125128
}
126129
}
127130

@@ -131,13 +134,13 @@ bool ErrorReporter::checkForExcessiveErrors(Error::Type _type)
131134
void ErrorReporter::fatalError(ErrorId _error, Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, std::string const& _description)
132135
{
133136
error(_error, _type, _location, _secondaryLocation, _description);
134-
BOOST_THROW_EXCEPTION(FatalError());
137+
solThrow(FatalError, _description);
135138
}
136139

137140
void ErrorReporter::fatalError(ErrorId _error, Error::Type _type, SourceLocation const& _location, std::string const& _description)
138141
{
139142
error(_error, _type, _location, _description);
140-
BOOST_THROW_EXCEPTION(FatalError());
143+
solThrow(FatalError, _description);
141144
}
142145

143146
ErrorList const& ErrorReporter::errors() const

liblangutil/SourceReferenceFormatter.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,11 @@ AnsiColorized SourceReferenceFormatter::diagColored() const
114114

115115
void SourceReferenceFormatter::printSourceLocation(SourceReference const& _ref)
116116
{
117-
if (_ref.sourceName.empty())
118-
return; // Nothing we can print here
119-
120117
if (_ref.position.line < 0)
121118
{
119+
if (_ref.sourceName.empty())
120+
return; // Nothing we can print here
121+
122122
frameColored() << "-->";
123123
m_stream << ' ' << _ref.sourceName << '\n';
124124
return; // No line available, nothing else to print

libsolc/libsolc.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ std::string takeOverAllocation(char const* _data)
6363
abort();
6464
}
6565

66-
/// Resizes a std::std::string to the proper length based on the occurrence of a zero terminator.
66+
/// Resizes a std::string to the proper length based on the occurrence of a zero terminator.
6767
void truncateCString(std::string& _data)
6868
{
6969
size_t pos = _data.find('\0');

libsolidity/analysis/ContractLevelChecker.cpp

+48-12
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@
2323
#include <libsolidity/analysis/ContractLevelChecker.h>
2424

2525
#include <libsolidity/ast/AST.h>
26+
#include <libsolidity/ast/ASTUtils.h>
2627
#include <libsolidity/ast/TypeProvider.h>
2728
#include <libsolidity/analysis/TypeChecker.h>
2829
#include <libsolutil/FunctionSelector.h>
2930
#include <liblangutil/ErrorReporter.h>
3031

3132
#include <fmt/format.h>
3233

34+
#include <range/v3/algorithm/find_if.hpp>
3335
#include <range/v3/view/reverse.hpp>
3436

3537
using namespace solidity;
@@ -97,10 +99,44 @@ bool ContractLevelChecker::check(ContractDefinition const& _contract)
9799
checkBaseABICompatibility(_contract);
98100
checkPayableFallbackWithoutReceive(_contract);
99101
checkStorageSize(_contract);
102+
checkStorageLayoutSpecifier(_contract);
100103

101104
return !Error::containsErrors(m_errorReporter.errors());
102105
}
103106

107+
void ContractLevelChecker::checkStorageLayoutSpecifier(ContractDefinition const& _contract)
108+
{
109+
if (_contract.storageLayoutSpecifier())
110+
{
111+
solAssert(!_contract.isLibrary() && !_contract.isInterface());
112+
113+
if (_contract.abstract())
114+
m_errorReporter.typeError(
115+
7587_error,
116+
_contract.storageLayoutSpecifier()->location(),
117+
"Storage layout cannot be specified for abstract contracts."
118+
);
119+
}
120+
121+
for (auto const& baseContractSpecifier: _contract.baseContracts())
122+
{
123+
auto const* baseContract = dynamic_cast<ContractDefinition const*>(
124+
baseContractSpecifier->name().annotation().referencedDeclaration
125+
);
126+
127+
solAssert(baseContract);
128+
if (baseContract->storageLayoutSpecifier())
129+
m_errorReporter.typeError(
130+
8894_error,
131+
baseContractSpecifier->location(),
132+
SecondarySourceLocation().append(
133+
"Custom storage layout defined here:",
134+
baseContract->storageLayoutSpecifier()->location()
135+
),
136+
"Cannot inherit from a contract with a custom storage layout."
137+
);
138+
}
139+
}
104140
void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _contract)
105141
{
106142
/// Checks that two functions with the same name defined in this contract have different
@@ -555,16 +591,16 @@ void ContractLevelChecker::checkPayableFallbackWithoutReceive(ContractDefinition
555591

556592
void ContractLevelChecker::checkStorageSize(ContractDefinition const& _contract)
557593
{
558-
bigint size = 0;
559-
for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts | ranges::views::reverse)
560-
for (VariableDeclaration const* variable: contract->stateVariables())
561-
if (!(variable->isConstant() || variable->immutable()))
562-
{
563-
size += variable->annotation().type->storageSizeUpperBound();
564-
if (size >= bigint(1) << 256)
565-
{
566-
m_errorReporter.typeError(7676_error, _contract.location(), "Contract requires too much storage.");
567-
break;
568-
}
569-
}
594+
using enum VariableDeclaration::Location;
595+
for (VariableDeclaration::Location location: {Unspecified, Transient})
596+
{
597+
bigint size = contractStorageSizeUpperBound(_contract, location);
598+
if (size >= bigint(1) << 256)
599+
{
600+
if (location == Unspecified)
601+
m_errorReporter.typeError(7676_error, _contract.location(), "Contract requires too much storage.");
602+
else
603+
m_errorReporter.typeError(5026_error, _contract.location(), "Contract requires too much transient storage.");
604+
}
605+
}
570606
}

libsolidity/analysis/ContractLevelChecker.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,10 @@ class ContractLevelChecker
8888

8989
/// Warns if the contract has a payable fallback, but no receive ether function.
9090
void checkPayableFallbackWithoutReceive(ContractDefinition const& _contract);
91-
/// Error if the contract requires too much storage
91+
/// Error if the contract requires too much storage or transient storage
9292
void checkStorageSize(ContractDefinition const& _contract);
93+
/// Checks if the storage layout specifier is properly assigned in the inheritance tree and not applied to an abstract contract
94+
void checkStorageLayoutSpecifier(ContractDefinition const& _contract);
9395

9496
OverrideChecker m_overrideChecker;
9597
langutil::ErrorReporter& m_errorReporter;

libsolidity/analysis/ControlFlowBuilder.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class ControlFlowBuilder: private ASTConstVisitor, private yul::ASTWalker
137137
}
138138

139139
/// Merges the control flow of @a _nodes to @a _endNode.
140-
/// If @a _endNode is nullptr, a new node is creates and used as end node.
140+
/// If @a _endNode is nullptr, a new node is created and used as end node.
141141
/// Sets the merge destination as current node.
142142
/// Note: @a _endNode may be one of the nodes in @a _nodes.
143143
template<typename C>

libsolidity/analysis/NameAndTypeResolver.cpp

+21-6
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,14 @@ bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit, ASTNode
6161
{
6262
DeclarationRegistrationHelper registrar(m_scopes, _sourceUnit, m_errorReporter, m_globalContext, _currentScope);
6363
}
64-
catch (langutil::FatalError const& error)
64+
catch (FatalError const&)
6565
{
66-
solAssert(m_errorReporter.hasErrors(), "Unreported fatal error: "s + error.what());
66+
if (!m_errorReporter.hasErrors())
67+
{
68+
std::cerr << "Unreported fatal error:" << std::endl;
69+
std::cerr << boost::current_exception_diagnostic_information() << std::endl;
70+
solAssert(false, "Unreported fatal error.");
71+
}
6772
return false;
6873
}
6974
return true;
@@ -135,9 +140,14 @@ bool NameAndTypeResolver::resolveNamesAndTypes(SourceUnit& _source)
135140
return false;
136141
}
137142
}
138-
catch (langutil::FatalError const& error)
143+
catch (FatalError const&)
139144
{
140-
solAssert(m_errorReporter.hasErrors(), "Unreported fatal error: "s + error.what());
145+
if (!m_errorReporter.hasErrors())
146+
{
147+
std::cerr << "Unreported fatal error:" << std::endl;
148+
std::cerr << boost::current_exception_diagnostic_information() << std::endl;
149+
solAssert(false, "Unreported fatal error.");
150+
}
141151
return false;
142152
}
143153
return true;
@@ -150,9 +160,14 @@ bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
150160
m_scopes[nullptr]->registerDeclaration(_declaration, false, true);
151161
solAssert(_declaration.scope() == nullptr, "Updated declaration outside global scope.");
152162
}
153-
catch (langutil::FatalError const& error)
163+
catch (FatalError const&)
154164
{
155-
solAssert(m_errorReporter.hasErrors(), "Unreported fatal error: "s + error.what());
165+
if (!m_errorReporter.hasErrors())
166+
{
167+
std::cerr << "Unreported fatal error:" << std::endl;
168+
std::cerr << boost::current_exception_diagnostic_information() << std::endl;
169+
solAssert(false, "Unreported fatal error.");
170+
}
156171
return false;
157172
}
158173
return true;

0 commit comments

Comments
 (0)