Coverage Report

Created: 2022-08-24 06:55

/src/solidity/libsolidity/interface/CompilerStack.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
/**
19
 * @author Christian <c@ethdev.com>
20
 * @author Gav Wood <g@ethdev.com>
21
 * @date 2014
22
 * Full-stack compiler that converts a source code string to bytecode.
23
 */
24
25
26
#include <libsolidity/interface/CompilerStack.h>
27
#include <libsolidity/interface/ImportRemapper.h>
28
29
#include <libsolidity/analysis/ControlFlowAnalyzer.h>
30
#include <libsolidity/analysis/ControlFlowGraph.h>
31
#include <libsolidity/analysis/ControlFlowRevertPruner.h>
32
#include <libsolidity/analysis/ContractLevelChecker.h>
33
#include <libsolidity/analysis/DeclarationTypeChecker.h>
34
#include <libsolidity/analysis/DocStringAnalyser.h>
35
#include <libsolidity/analysis/DocStringTagParser.h>
36
#include <libsolidity/analysis/GlobalContext.h>
37
#include <libsolidity/analysis/NameAndTypeResolver.h>
38
#include <libsolidity/analysis/PostTypeChecker.h>
39
#include <libsolidity/analysis/PostTypeContractLevelChecker.h>
40
#include <libsolidity/analysis/StaticAnalyzer.h>
41
#include <libsolidity/analysis/SyntaxChecker.h>
42
#include <libsolidity/analysis/Scoper.h>
43
#include <libsolidity/analysis/TypeChecker.h>
44
#include <libsolidity/analysis/ViewPureChecker.h>
45
#include <libsolidity/analysis/ImmutableValidator.h>
46
47
#include <libsolidity/ast/AST.h>
48
#include <libsolidity/ast/TypeProvider.h>
49
#include <libsolidity/ast/ASTJsonImporter.h>
50
#include <libsolidity/codegen/Compiler.h>
51
#include <libsolidity/formal/ModelChecker.h>
52
#include <libsolidity/interface/ABI.h>
53
#include <libsolidity/interface/Natspec.h>
54
#include <libsolidity/interface/GasEstimator.h>
55
#include <libsolidity/interface/StorageLayout.h>
56
#include <libsolidity/interface/Version.h>
57
#include <libsolidity/parsing/Parser.h>
58
59
#include <libsolidity/codegen/ir/Common.h>
60
#include <libsolidity/codegen/ir/IRGenerator.h>
61
62
#include <libyul/YulString.h>
63
#include <libyul/AsmPrinter.h>
64
#include <libyul/AsmJsonConverter.h>
65
#include <libyul/YulStack.h>
66
#include <libyul/AST.h>
67
#include <libyul/AsmParser.h>
68
69
#include <liblangutil/Scanner.h>
70
#include <liblangutil/SemVerHandler.h>
71
72
#include <libevmasm/Exceptions.h>
73
74
#include <libsolutil/SwarmHash.h>
75
#include <libsolutil/IpfsHash.h>
76
#include <libsolutil/JSON.h>
77
#include <libsolutil/Algorithms.h>
78
#include <libsolutil/FunctionSelector.h>
79
80
#include <json/json.h>
81
82
#include <boost/algorithm/string/replace.hpp>
83
84
#include <range/v3/view/concat.hpp>
85
86
#include <utility>
87
#include <map>
88
#include <limits>
89
#include <string>
90
91
using namespace std;
92
using namespace solidity;
93
using namespace solidity::langutil;
94
using namespace solidity::frontend;
95
96
using solidity::util::errinfo_comment;
97
using solidity::util::toHex;
98
99
static int g_compilerStackCounts = 0;
100
101
CompilerStack::CompilerStack(ReadCallback::Callback _readFile):
102
  m_readFile{std::move(_readFile)},
103
  m_errorReporter{m_errorList}
104
4.55k
{
105
  // Because TypeProvider is currently a singleton API, we must ensure that
106
  // no more than one entity is actually using it at a time.
107
4.55k
  solAssert(g_compilerStackCounts == 0, "You shall not have another CompilerStack aside me.");
108
4.55k
  ++g_compilerStackCounts;
109
4.55k
}
110
111
CompilerStack::~CompilerStack()
112
4.55k
{
113
4.55k
  --g_compilerStackCounts;
114
4.55k
  TypeProvider::reset();
115
4.55k
}
116
117
void CompilerStack::createAndAssignCallGraphs()
118
4.55k
{
119
4.55k
  for (Source const* source: m_sourceOrder)
120
4.55k
  {
121
4.55k
    if (!source->ast)
122
0
      continue;
123
124
4.55k
    for (ContractDefinition const* contract: ASTNode::filteredNodes<ContractDefinition>(source->ast->nodes()))
125
4.55k
    {
126
4.55k
      ContractDefinitionAnnotation& annotation =
127
4.55k
        m_contracts.at(contract->fullyQualifiedName()).contract->annotation();
128
129
4.55k
      annotation.creationCallGraph = make_unique<CallGraph>(
130
4.55k
        FunctionCallGraphBuilder::buildCreationGraph(*contract)
131
4.55k
      );
132
4.55k
      annotation.deployedCallGraph = make_unique<CallGraph>(
133
4.55k
        FunctionCallGraphBuilder::buildDeployedGraph(
134
4.55k
          *contract,
135
4.55k
          **annotation.creationCallGraph
136
4.55k
        )
137
4.55k
      );
138
139
4.55k
      solAssert(annotation.contractDependencies.empty(), "contractDependencies expected to be empty?!");
140
141
4.55k
      annotation.contractDependencies = annotation.creationCallGraph->get()->bytecodeDependency;
142
143
4.55k
      for (auto const& [dependencyContract, referencee]: annotation.deployedCallGraph->get()->bytecodeDependency)
144
0
        annotation.contractDependencies.emplace(dependencyContract, referencee);
145
4.55k
    }
146
4.55k
  }
147
4.55k
}
148
149
void CompilerStack::findAndReportCyclicContractDependencies()
150
4.55k
{
151
  // Cycles we found, used to avoid duplicate reports for the same reference
152
4.55k
  set<ASTNode const*, ASTNode::CompareByID> foundCycles;
153
154
4.55k
  for (Source const* source: m_sourceOrder)
155
4.55k
  {
156
4.55k
    if (!source->ast)
157
0
      continue;
158
159
4.55k
    for (ContractDefinition const* contractDefinition: ASTNode::filteredNodes<ContractDefinition>(source->ast->nodes()))
160
4.55k
    {
161
4.55k
      util::CycleDetector<ContractDefinition> cycleDetector{[&](
162
4.55k
        ContractDefinition const& _contract,
163
4.55k
        util::CycleDetector<ContractDefinition>& _cycleDetector,
164
4.55k
        size_t _depth
165
4.55k
      )
166
4.55k
      {
167
        // No specific reason for exactly that number, just a limit we're unlikely to hit.
168
4.55k
        if (_depth >= 256)
169
0
          m_errorReporter.fatalTypeError(
170
0
            7864_error,
171
0
            _contract.location(),
172
0
            "Contract dependencies exhausting cyclic dependency validator"
173
0
          );
174
175
4.55k
        for (auto& [dependencyContract, referencee]: _contract.annotation().contractDependencies)
176
0
          if (_cycleDetector.run(*dependencyContract))
177
0
            return;
178
4.55k
      }};
179
180
4.55k
      ContractDefinition const* cycle = cycleDetector.run(*contractDefinition);
181
182
4.55k
      if (!cycle)
183
4.55k
        continue;
184
185
0
      ASTNode const* referencee = contractDefinition->annotation().contractDependencies.at(cycle);
186
187
0
      if (foundCycles.find(referencee) != foundCycles.end())
188
0
        continue;
189
190
0
      SecondarySourceLocation secondaryLocation{};
191
0
      secondaryLocation.append("Referenced contract is here:"s, cycle->location());
192
193
0
      m_errorReporter.typeError(
194
0
        7813_error,
195
0
        referencee->location(),
196
0
        secondaryLocation,
197
0
        "Circular reference to contract bytecode either via \"new\" or \"type(...).creationCode\" / \"type(...).runtimeCode\"."
198
0
      );
199
200
0
      foundCycles.emplace(referencee);
201
0
    }
202
4.55k
  }
203
4.55k
}
204
205
void CompilerStack::setRemappings(vector<ImportRemapper::Remapping> _remappings)
206
0
{
207
0
  if (m_stackState >= ParsedAndImported)
208
0
    solThrow(CompilerError, "Must set remappings before parsing.");
209
0
  for (auto const& remapping: _remappings)
210
0
    solAssert(!remapping.prefix.empty(), "");
211
0
  m_importRemapper.setRemappings(move(_remappings));
212
0
}
213
214
void CompilerStack::setViaIR(bool _viaIR)
215
4.55k
{
216
4.55k
  if (m_stackState >= ParsedAndImported)
217
0
    solThrow(CompilerError, "Must set viaIR before parsing.");
218
4.55k
  m_viaIR = _viaIR;
219
4.55k
}
220
221
void CompilerStack::setEVMVersion(langutil::EVMVersion _version)
222
4.55k
{
223
4.55k
  if (m_stackState >= ParsedAndImported)
224
0
    solThrow(CompilerError, "Must set EVM version before parsing.");
225
4.55k
  m_evmVersion = _version;
226
4.55k
}
227
228
void CompilerStack::setModelCheckerSettings(ModelCheckerSettings _settings)
229
0
{
230
0
  if (m_stackState >= ParsedAndImported)
231
0
    solThrow(CompilerError, "Must set model checking settings before parsing.");
232
0
  m_modelCheckerSettings = _settings;
233
0
}
234
235
void CompilerStack::setLibraries(std::map<std::string, util::h160> const& _libraries)
236
4.55k
{
237
4.55k
  if (m_stackState >= ParsedAndImported)
238
0
    solThrow(CompilerError, "Must set libraries before parsing.");
239
4.55k
  m_libraries = _libraries;
240
4.55k
}
241
242
void CompilerStack::setOptimiserSettings(bool _optimize, size_t _runs)
243
0
{
244
0
  OptimiserSettings settings = _optimize ? OptimiserSettings::standard() : OptimiserSettings::minimal();
245
0
  settings.expectedExecutionsPerDeployment = _runs;
246
0
  setOptimiserSettings(std::move(settings));
247
0
}
248
249
void CompilerStack::setOptimiserSettings(OptimiserSettings _settings)
250
4.55k
{
251
4.55k
  if (m_stackState >= ParsedAndImported)
252
0
    solThrow(CompilerError, "Must set optimiser settings before parsing.");
253
4.55k
  m_optimiserSettings = std::move(_settings);
254
4.55k
}
255
256
void CompilerStack::setRevertStringBehaviour(RevertStrings _revertStrings)
257
0
{
258
0
  if (m_stackState >= ParsedAndImported)
259
0
    solThrow(CompilerError, "Must set revert string settings before parsing.");
260
0
  solUnimplementedAssert(_revertStrings != RevertStrings::VerboseDebug);
261
0
  m_revertStrings = _revertStrings;
262
0
}
263
264
void CompilerStack::useMetadataLiteralSources(bool _metadataLiteralSources)
265
0
{
266
0
  if (m_stackState >= ParsedAndImported)
267
0
    solThrow(CompilerError, "Must set use literal sources before parsing.");
268
0
  m_metadataLiteralSources = _metadataLiteralSources;
269
0
}
270
271
void CompilerStack::setMetadataHash(MetadataHash _metadataHash)
272
0
{
273
0
  if (m_stackState >= ParsedAndImported)
274
0
    solThrow(CompilerError, "Must set metadata hash before parsing.");
275
0
  m_metadataHash = _metadataHash;
276
0
}
277
278
void CompilerStack::selectDebugInfo(DebugInfoSelection _debugInfoSelection)
279
0
{
280
0
  if (m_stackState >= CompilationSuccessful)
281
0
    BOOST_THROW_EXCEPTION(CompilerError() << util::errinfo_comment("Must select debug info components before compilation."));
282
0
  m_debugInfoSelection = _debugInfoSelection;
283
0
}
284
285
void CompilerStack::addSMTLib2Response(h256 const& _hash, string const& _response)
286
0
{
287
0
  if (m_stackState >= ParsedAndImported)
288
0
    solThrow(CompilerError, "Must add SMTLib2 responses before parsing.");
289
0
  m_smtlib2Responses[_hash] = _response;
290
0
}
291
292
void CompilerStack::reset(bool _keepSettings)
293
0
{
294
0
  m_stackState = Empty;
295
0
  m_hasError = false;
296
0
  m_sources.clear();
297
0
  m_smtlib2Responses.clear();
298
0
  m_unhandledSMTLib2Queries.clear();
299
0
  if (!_keepSettings)
300
0
  {
301
0
    m_importRemapper.clear();
302
0
    m_libraries.clear();
303
0
    m_viaIR = false;
304
0
    m_evmVersion = langutil::EVMVersion();
305
0
    m_modelCheckerSettings = ModelCheckerSettings{};
306
0
    m_generateIR = false;
307
0
    m_generateEwasm = false;
308
0
    m_revertStrings = RevertStrings::Default;
309
0
    m_optimiserSettings = OptimiserSettings::minimal();
310
0
    m_metadataLiteralSources = false;
311
0
    m_metadataHash = MetadataHash::IPFS;
312
0
    m_stopAfter = State::CompilationSuccessful;
313
0
  }
314
0
  m_globalContext.reset();
315
0
  m_sourceOrder.clear();
316
0
  m_contracts.clear();
317
0
  m_errorReporter.clear();
318
0
  TypeProvider::reset();
319
0
}
320
321
void CompilerStack::setSources(StringMap _sources)
322
4.55k
{
323
4.55k
  if (m_stackState == SourcesSet)
324
0
    solThrow(CompilerError, "Cannot change sources once set.");
325
4.55k
  if (m_stackState != Empty)
326
0
    solThrow(CompilerError, "Must set sources before parsing.");
327
4.55k
  for (auto source: _sources)
328
4.55k
    m_sources[source.first].charStream = make_unique<CharStream>(/*content*/std::move(source.second), /*name*/source.first);
329
4.55k
  m_stackState = SourcesSet;
330
4.55k
}
331
332
bool CompilerStack::parse()
333
4.55k
{
334
4.55k
  if (m_stackState != SourcesSet)
335
0
    solThrow(CompilerError, "Must call parse only after the SourcesSet state.");
336
4.55k
  m_errorReporter.clear();
337
338
4.55k
  if (SemVerVersion{string(VersionString)}.isPrerelease())
339
4.55k
    m_errorReporter.warning(3805_error, "This is a pre-release compiler version, please do not use it in production.");
340
341
4.55k
  Parser parser{m_errorReporter, m_evmVersion, m_parserErrorRecovery};
342
343
4.55k
  vector<string> sourcesToParse;
344
4.55k
  for (auto const& s: m_sources)
345
4.55k
    sourcesToParse.push_back(s.first);
346
347
9.10k
  for (size_t i = 0; i < sourcesToParse.size(); ++i)
348
4.55k
  {
349
4.55k
    string const& path = sourcesToParse[i];
350
4.55k
    Source& source = m_sources[path];
351
4.55k
    source.ast = parser.parse(*source.charStream);
352
4.55k
    if (!source.ast)
353
4.55k
      solAssert(Error::containsErrors(m_errorReporter.errors()), "Parser returned null but did not report error.");
354
4.55k
    else
355
4.55k
    {
356
4.55k
      source.ast->annotation().path = path;
357
358
4.55k
      for (auto const& import: ASTNode::filteredNodes<ImportDirective>(source.ast->nodes()))
359
0
      {
360
0
        solAssert(!import->path().empty(), "Import path cannot be empty.");
361
362
        // The current value of `path` is the absolute path as seen from this source file.
363
        // We first have to apply remappings before we can store the actual absolute path
364
        // as seen globally.
365
0
        import->annotation().absolutePath = applyRemapping(util::absolutePath(
366
0
          import->path(),
367
0
          path
368
0
        ), path);
369
0
      }
370
371
4.55k
      if (m_stopAfter >= ParsedAndImported)
372
4.55k
        for (auto const& newSource: loadMissingSources(*source.ast))
373
0
        {
374
0
          string const& newPath = newSource.first;
375
0
          string const& newContents = newSource.second;
376
0
          m_sources[newPath].charStream = make_shared<CharStream>(newContents, newPath);
377
0
          sourcesToParse.push_back(newPath);
378
0
        }
379
4.55k
    }
380
4.55k
  }
381
382
4.55k
  if (m_stopAfter <= Parsed)
383
0
    m_stackState = Parsed;
384
4.55k
  else
385
4.55k
    m_stackState = ParsedAndImported;
386
4.55k
  if (Error::containsErrors(m_errorReporter.errors()))
387
0
    m_hasError = true;
388
389
4.55k
  storeContractDefinitions();
390
391
4.55k
  return !m_hasError;
392
4.55k
}
393
394
void CompilerStack::importASTs(map<string, Json::Value> const& _sources)
395
0
{
396
0
  if (m_stackState != Empty)
397
0
    solThrow(CompilerError, "Must call importASTs only before the SourcesSet state.");
398
0
  m_sourceJsons = _sources;
399
0
  map<string, ASTPointer<SourceUnit>> reconstructedSources = ASTJsonImporter(m_evmVersion).jsonToSourceUnit(m_sourceJsons);
400
0
  for (auto& src: reconstructedSources)
401
0
  {
402
0
    string const& path = src.first;
403
0
    Source source;
404
0
    source.ast = src.second;
405
0
    source.charStream = make_shared<CharStream>(
406
0
      util::jsonCompactPrint(m_sourceJsons[src.first]),
407
0
      src.first,
408
0
      true // imported from AST
409
0
    );
410
0
    m_sources[path] = move(source);
411
0
  }
412
0
  m_stackState = ParsedAndImported;
413
0
  m_importedSources = true;
414
415
0
  storeContractDefinitions();
416
0
}
417
418
bool CompilerStack::analyze()
419
4.55k
{
420
4.55k
  if (m_stackState != ParsedAndImported || m_stackState >= AnalysisPerformed)
421
0
    solThrow(CompilerError, "Must call analyze only after parsing was performed.");
422
4.55k
  resolveImports();
423
424
4.55k
  for (Source const* source: m_sourceOrder)
425
4.55k
    if (source->ast)
426
4.55k
      Scoper::assignScopes(*source->ast);
427
428
4.55k
  bool noErrors = true;
429
430
4.55k
  try
431
4.55k
  {
432
4.55k
    SyntaxChecker syntaxChecker(m_errorReporter, m_optimiserSettings.runYulOptimiser);
433
4.55k
    for (Source const* source: m_sourceOrder)
434
4.55k
      if (source->ast && !syntaxChecker.checkSyntax(*source->ast))
435
0
        noErrors = false;
436
437
4.55k
    m_globalContext = make_shared<GlobalContext>();
438
    // We need to keep the same resolver during the whole process.
439
4.55k
    NameAndTypeResolver resolver(*m_globalContext, m_evmVersion, m_errorReporter);
440
4.55k
    for (Source const* source: m_sourceOrder)
441
4.55k
      if (source->ast && !resolver.registerDeclarations(*source->ast))
442
0
        return false;
443
444
4.55k
    map<string, SourceUnit const*> sourceUnitsByName;
445
4.55k
    for (auto& source: m_sources)
446
4.55k
      sourceUnitsByName[source.first] = source.second.ast.get();
447
4.55k
    for (Source const* source: m_sourceOrder)
448
4.55k
      if (source->ast && !resolver.performImports(*source->ast, sourceUnitsByName))
449
0
        return false;
450
451
4.55k
    resolver.warnHomonymDeclarations();
452
453
4.55k
    DocStringTagParser docStringTagParser(m_errorReporter);
454
4.55k
    for (Source const* source: m_sourceOrder)
455
4.55k
      if (source->ast && !docStringTagParser.parseDocStrings(*source->ast))
456
0
        noErrors = false;
457
458
    // Requires DocStringTagParser
459
4.55k
    for (Source const* source: m_sourceOrder)
460
4.55k
      if (source->ast && !resolver.resolveNamesAndTypes(*source->ast))
461
0
        return false;
462
463
4.55k
    DeclarationTypeChecker declarationTypeChecker(m_errorReporter, m_evmVersion);
464
4.55k
    for (Source const* source: m_sourceOrder)
465
4.55k
      if (source->ast && !declarationTypeChecker.check(*source->ast))
466
0
        return false;
467
468
    // Requires DeclarationTypeChecker to have run
469
4.55k
    for (Source const* source: m_sourceOrder)
470
4.55k
      if (source->ast && !docStringTagParser.validateDocStringsUsingTypes(*source->ast))
471
0
        noErrors = false;
472
473
    // Next, we check inheritance, overrides, function collisions and other things at
474
    // contract or function level.
475
    // This also calculates whether a contract is abstract, which is needed by the
476
    // type checker.
477
4.55k
    ContractLevelChecker contractLevelChecker(m_errorReporter);
478
479
4.55k
    for (Source const* source: m_sourceOrder)
480
4.55k
      if (auto sourceAst = source->ast)
481
4.55k
        noErrors = contractLevelChecker.check(*sourceAst);
482
483
    // Now we run full type checks that go down to the expression level. This
484
    // cannot be done earlier, because we need cross-contract types and information
485
    // about whether a contract is abstract for the `new` expression.
486
    // This populates the `type` annotation for all expressions.
487
    //
488
    // Note: this does not resolve overloaded functions. In order to do that, types of arguments are needed,
489
    // which is only done one step later.
490
4.55k
    TypeChecker typeChecker(m_evmVersion, m_errorReporter);
491
4.55k
    for (Source const* source: m_sourceOrder)
492
4.55k
      if (source->ast && !typeChecker.checkTypeRequirements(*source->ast))
493
0
        noErrors = false;
494
495
4.55k
    if (noErrors)
496
4.55k
    {
497
      // Requires ContractLevelChecker and TypeChecker
498
4.55k
      DocStringAnalyser docStringAnalyser(m_errorReporter);
499
4.55k
      for (Source const* source: m_sourceOrder)
500
4.55k
        if (source->ast && !docStringAnalyser.analyseDocStrings(*source->ast))
501
0
          noErrors = false;
502
4.55k
    }
503
504
4.55k
    if (noErrors)
505
4.55k
    {
506
      // Checks that can only be done when all types of all AST nodes are known.
507
4.55k
      PostTypeChecker postTypeChecker(m_errorReporter);
508
4.55k
      for (Source const* source: m_sourceOrder)
509
4.55k
        if (source->ast && !postTypeChecker.check(*source->ast))
510
0
          noErrors = false;
511
4.55k
      if (!postTypeChecker.finalize())
512
0
        noErrors = false;
513
4.55k
    }
514
515
    // Create & assign callgraphs and check for contract dependency cycles
516
4.55k
    if (noErrors)
517
4.55k
    {
518
4.55k
      createAndAssignCallGraphs();
519
4.55k
      findAndReportCyclicContractDependencies();
520
4.55k
    }
521
522
4.55k
    if (noErrors)
523
4.55k
      for (Source const* source: m_sourceOrder)
524
4.55k
        if (source->ast && !PostTypeContractLevelChecker{m_errorReporter}.check(*source->ast))
525
0
          noErrors = false;
526
527
    // Check that immutable variables are never read in c'tors and assigned
528
    // exactly once
529
4.55k
    if (noErrors)
530
4.55k
      for (Source const* source: m_sourceOrder)
531
4.55k
        if (source->ast)
532
4.55k
          for (ASTPointer<ASTNode> const& node: source->ast->nodes())
533
13.6k
            if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
534
4.55k
              ImmutableValidator(m_errorReporter, *contract).analyze();
535
536
4.55k
    if (noErrors)
537
4.55k
    {
538
      // Control flow graph generator and analyzer. It can check for issues such as
539
      // variable is used before it is assigned to.
540
4.55k
      CFG cfg(m_errorReporter);
541
4.55k
      for (Source const* source: m_sourceOrder)
542
4.55k
        if (source->ast && !cfg.constructFlow(*source->ast))
543
0
          noErrors = false;
544
545
4.55k
      if (noErrors)
546
4.55k
      {
547
4.55k
        ControlFlowRevertPruner pruner(cfg);
548
4.55k
        pruner.run();
549
550
4.55k
        ControlFlowAnalyzer controlFlowAnalyzer(cfg, m_errorReporter);
551
4.55k
        if (!controlFlowAnalyzer.run())
552
0
          noErrors = false;
553
4.55k
      }
554
4.55k
    }
555
556
4.55k
    if (noErrors)
557
4.55k
    {
558
      // Checks for common mistakes. Only generates warnings.
559
4.55k
      StaticAnalyzer staticAnalyzer(m_errorReporter);
560
4.55k
      for (Source const* source: m_sourceOrder)
561
4.55k
        if (source->ast && !staticAnalyzer.analyze(*source->ast))
562
0
          noErrors = false;
563
4.55k
    }
564
565
4.55k
    if (noErrors)
566
4.55k
    {
567
      // Check for state mutability in every function.
568
4.55k
      vector<ASTPointer<ASTNode>> ast;
569
4.55k
      for (Source const* source: m_sourceOrder)
570
4.55k
        if (source->ast)
571
4.55k
          ast.push_back(source->ast);
572
573
4.55k
      if (!ViewPureChecker(ast, m_errorReporter).check())
574
0
        noErrors = false;
575
4.55k
    }
576
577
4.55k
    if (noErrors)
578
4.55k
    {
579
4.55k
      ModelChecker modelChecker(m_errorReporter, *this, m_smtlib2Responses, m_modelCheckerSettings, m_readFile);
580
4.55k
      auto allSources = util::applyMap(m_sourceOrder, [](Source const* _source) { return _source->ast; });
581
4.55k
      modelChecker.enableAllEnginesIfPragmaPresent(allSources);
582
4.55k
      modelChecker.checkRequestedSourcesAndContracts(allSources);
583
4.55k
      for (Source const* source: m_sourceOrder)
584
4.55k
        if (source->ast)
585
4.55k
          modelChecker.analyze(*source->ast);
586
4.55k
      m_unhandledSMTLib2Queries += modelChecker.unhandledQueries();
587
4.55k
    }
588
4.55k
  }
589
4.55k
  catch (FatalError const&)
590
4.55k
  {
591
0
    if (m_errorReporter.errors().empty())
592
0
      throw; // Something is weird here, rather throw again.
593
0
    noErrors = false;
594
0
  }
595
596
4.55k
  m_stackState = AnalysisPerformed;
597
4.55k
  if (!noErrors)
598
0
    m_hasError = true;
599
600
4.55k
  return !m_hasError;
601
4.55k
}
602
603
bool CompilerStack::parseAndAnalyze(State _stopAfter)
604
4.55k
{
605
4.55k
  m_stopAfter = _stopAfter;
606
607
4.55k
  bool success = parse();
608
4.55k
  if (m_stackState >= m_stopAfter)
609
0
    return success;
610
4.55k
  if (success || m_parserErrorRecovery)
611
4.55k
    success = analyze();
612
4.55k
  return success;
613
4.55k
}
614
615
bool CompilerStack::isRequestedSource(string const& _sourceName) const
616
4.55k
{
617
4.55k
  return
618
4.55k
    m_requestedContractNames.empty() ||
619
4.55k
    m_requestedContractNames.count("") ||
620
4.55k
    m_requestedContractNames.count(_sourceName);
621
4.55k
}
622
623
bool CompilerStack::isRequestedContract(ContractDefinition const& _contract) const
624
4.55k
{
625
  /// In case nothing was specified in outputSelection.
626
4.55k
  if (m_requestedContractNames.empty())
627
4.55k
    return true;
628
629
0
  for (auto const& key: vector<string>{"", _contract.sourceUnitName()})
630
0
  {
631
0
    auto const& it = m_requestedContractNames.find(key);
632
0
    if (it != m_requestedContractNames.end())
633
0
      if (it->second.count(_contract.name()) || it->second.count(""))
634
0
        return true;
635
0
  }
636
637
0
  return false;
638
0
}
639
640
bool CompilerStack::compile(State _stopAfter)
641
4.55k
{
642
4.55k
  m_stopAfter = _stopAfter;
643
4.55k
  if (m_stackState < AnalysisPerformed)
644
4.55k
    if (!parseAndAnalyze(_stopAfter))
645
0
      return false;
646
647
4.55k
  if (m_stackState >= m_stopAfter)
648
0
    return true;
649
650
4.55k
  if (m_hasError)
651
0
    solThrow(CompilerError, "Called compile with errors.");
652
653
  // Only compile contracts individually which have been requested.
654
4.55k
  map<ContractDefinition const*, shared_ptr<Compiler const>> otherCompilers;
655
656
4.55k
  for (Source const* source: m_sourceOrder)
657
4.55k
    for (ASTPointer<ASTNode> const& node: source->ast->nodes())
658
13.6k
      if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
659
4.55k
        if (isRequestedContract(*contract))
660
4.55k
        {
661
4.55k
          try
662
4.55k
          {
663
4.55k
            if (m_viaIR || m_generateIR || m_generateEwasm)
664
0
              generateIR(*contract);
665
4.55k
            if (m_generateEvmBytecode)
666
4.55k
            {
667
4.55k
              if (m_viaIR)
668
0
                generateEVMFromIR(*contract);
669
4.55k
              else
670
4.55k
                compileContract(*contract, otherCompilers);
671
4.55k
            }
672
4.55k
            if (m_generateEwasm)
673
0
              generateEwasm(*contract);
674
4.55k
          }
675
4.55k
          catch (Error const& _error)
676
4.55k
          {
677
0
            if (_error.type() != Error::Type::CodeGenerationError)
678
0
              throw;
679
0
            m_errorReporter.error(_error.errorId(), _error.type(), SourceLocation(), _error.what());
680
0
            return false;
681
0
          }
682
4.55k
          catch (UnimplementedFeatureError const& _unimplementedError)
683
4.55k
          {
684
0
            if (
685
0
              SourceLocation const* sourceLocation =
686
0
              boost::get_error_info<langutil::errinfo_sourceLocation>(_unimplementedError)
687
0
            )
688
0
            {
689
0
              string const* comment = _unimplementedError.comment();
690
0
              m_errorReporter.error(
691
0
                1834_error,
692
0
                Error::Type::CodeGenerationError,
693
0
                *sourceLocation,
694
0
                "Unimplemented feature error" +
695
0
                ((comment && !comment->empty()) ? ": " + *comment : string{}) +
696
0
                " in " +
697
0
                _unimplementedError.lineInfo()
698
0
              );
699
0
              return false;
700
0
            }
701
0
            else
702
0
              throw;
703
0
          }
704
4.55k
        }
705
4.55k
  m_stackState = CompilationSuccessful;
706
4.55k
  this->link();
707
4.55k
  return true;
708
4.55k
}
709
710
void CompilerStack::link()
711
4.55k
{
712
4.55k
  solAssert(m_stackState >= CompilationSuccessful, "");
713
4.55k
  for (auto& contract: m_contracts)
714
4.55k
  {
715
4.55k
    contract.second.object.link(m_libraries);
716
4.55k
    contract.second.runtimeObject.link(m_libraries);
717
4.55k
  }
718
4.55k
}
719
720
vector<string> CompilerStack::contractNames() const
721
0
{
722
0
  if (m_stackState < Parsed)
723
0
    solThrow(CompilerError, "Parsing was not successful.");
724
0
  vector<string> contractNames;
725
0
  for (auto const& contract: m_contracts)
726
0
    contractNames.push_back(contract.first);
727
0
  return contractNames;
728
0
}
729
730
string const CompilerStack::lastContractName(optional<string> const& _sourceName) const
731
0
{
732
0
  if (m_stackState < AnalysisPerformed)
733
0
    solThrow(CompilerError, "Parsing was not successful.");
734
  // try to find some user-supplied contract
735
0
  string contractName;
736
0
  for (auto const& it: m_sources)
737
0
    if (_sourceName.value_or(it.first) == it.first)
738
0
      for (auto const* contract: ASTNode::filteredNodes<ContractDefinition>(it.second.ast->nodes()))
739
0
        contractName = contract->fullyQualifiedName();
740
0
  return contractName;
741
0
}
742
743
evmasm::AssemblyItems const* CompilerStack::assemblyItems(string const& _contractName) const
744
0
{
745
0
  if (m_stackState != CompilationSuccessful)
746
0
    solThrow(CompilerError, "Compilation was not successful.");
747
748
0
  Contract const& currentContract = contract(_contractName);
749
0
  return currentContract.evmAssembly ? &currentContract.evmAssembly->items() : nullptr;
750
0
}
751
752
evmasm::AssemblyItems const* CompilerStack::runtimeAssemblyItems(string const& _contractName) const
753
0
{
754
0
  if (m_stackState != CompilationSuccessful)
755
0
    solThrow(CompilerError, "Compilation was not successful.");
756
757
0
  Contract const& currentContract = contract(_contractName);
758
0
  return currentContract.evmRuntimeAssembly ? &currentContract.evmRuntimeAssembly->items() : nullptr;
759
0
}
760
761
Json::Value CompilerStack::generatedSources(string const& _contractName, bool _runtime) const
762
0
{
763
0
  if (m_stackState != CompilationSuccessful)
764
0
    solThrow(CompilerError, "Compilation was not successful.");
765
766
0
  Contract const& c = contract(_contractName);
767
0
  util::LazyInit<Json::Value const> const& sources =
768
0
    _runtime ?
769
0
    c.runtimeGeneratedSources :
770
0
    c.generatedSources;
771
0
  return sources.init([&]{
772
0
    Json::Value sources{Json::arrayValue};
773
    // If there is no compiler, then no bytecode was generated and thus no
774
    // sources were generated (or we compiled "via IR").
775
0
    if (c.compiler)
776
0
    {
777
0
      solAssert(!m_viaIR, "");
778
0
      string source =
779
0
        _runtime ?
780
0
        c.compiler->runtimeGeneratedYulUtilityCode() :
781
0
        c.compiler->generatedYulUtilityCode();
782
0
      if (!source.empty())
783
0
      {
784
0
        string sourceName = CompilerContext::yulUtilityFileName();
785
0
        unsigned sourceIndex = sourceIndices()[sourceName];
786
0
        ErrorList errors;
787
0
        ErrorReporter errorReporter(errors);
788
0
        CharStream charStream(source, sourceName);
789
0
        yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion);
790
0
        shared_ptr<yul::Block> parserResult = yul::Parser{errorReporter, dialect}.parse(charStream);
791
0
        solAssert(parserResult, "");
792
0
        sources[0]["ast"] = yul::AsmJsonConverter{sourceIndex}(*parserResult);
793
0
        sources[0]["name"] = sourceName;
794
0
        sources[0]["id"] = sourceIndex;
795
0
        sources[0]["language"] = "Yul";
796
0
        sources[0]["contents"] = move(source);
797
798
0
      }
799
0
    }
800
0
    return sources;
801
0
  });
802
0
}
803
804
string const* CompilerStack::sourceMapping(string const& _contractName) const
805
0
{
806
0
  if (m_stackState != CompilationSuccessful)
807
0
    solThrow(CompilerError, "Compilation was not successful.");
808
809
0
  Contract const& c = contract(_contractName);
810
0
  if (!c.sourceMapping)
811
0
  {
812
0
    if (auto items = assemblyItems(_contractName))
813
0
      c.sourceMapping.emplace(evmasm::AssemblyItem::computeSourceMapping(*items, sourceIndices()));
814
0
  }
815
0
  return c.sourceMapping ? &*c.sourceMapping : nullptr;
816
0
}
817
818
string const* CompilerStack::runtimeSourceMapping(string const& _contractName) const
819
0
{
820
0
  if (m_stackState != CompilationSuccessful)
821
0
    solThrow(CompilerError, "Compilation was not successful.");
822
823
0
  Contract const& c = contract(_contractName);
824
0
  if (!c.runtimeSourceMapping)
825
0
  {
826
0
    if (auto items = runtimeAssemblyItems(_contractName))
827
0
      c.runtimeSourceMapping.emplace(
828
0
        evmasm::AssemblyItem::computeSourceMapping(*items, sourceIndices())
829
0
      );
830
0
  }
831
0
  return c.runtimeSourceMapping ? &*c.runtimeSourceMapping : nullptr;
832
0
}
833
834
std::string const CompilerStack::filesystemFriendlyName(string const& _contractName) const
835
0
{
836
0
  if (m_stackState < AnalysisPerformed)
837
0
    solThrow(CompilerError, "No compiled contracts found.");
838
839
  // Look up the contract (by its fully-qualified name)
840
0
  Contract const& matchContract = m_contracts.at(_contractName);
841
  // Check to see if it could collide on name
842
0
  for (auto const& contract: m_contracts)
843
0
  {
844
0
    if (contract.second.contract->name() == matchContract.contract->name() &&
845
0
        contract.second.contract != matchContract.contract)
846
0
    {
847
      // If it does, then return its fully-qualified name, made fs-friendly
848
0
      std::string friendlyName = boost::algorithm::replace_all_copy(_contractName, "/", "_");
849
0
      boost::algorithm::replace_all(friendlyName, ":", "_");
850
0
      boost::algorithm::replace_all(friendlyName, ".", "_");
851
0
      return friendlyName;
852
0
    }
853
0
  }
854
  // If no collision, return the contract's name
855
0
  return matchContract.contract->name();
856
0
}
857
858
string const& CompilerStack::yulIR(string const& _contractName) const
859
0
{
860
0
  if (m_stackState != CompilationSuccessful)
861
0
    solThrow(CompilerError, "Compilation was not successful.");
862
863
0
  return contract(_contractName).yulIR;
864
0
}
865
866
string const& CompilerStack::yulIROptimized(string const& _contractName) const
867
0
{
868
0
  if (m_stackState != CompilationSuccessful)
869
0
    solThrow(CompilerError, "Compilation was not successful.");
870
871
0
  return contract(_contractName).yulIROptimized;
872
0
}
873
874
string const& CompilerStack::ewasm(string const& _contractName) const
875
0
{
876
0
  if (m_stackState != CompilationSuccessful)
877
0
    solThrow(CompilerError, "Compilation was not successful.");
878
879
0
  return contract(_contractName).ewasm;
880
0
}
881
882
evmasm::LinkerObject const& CompilerStack::ewasmObject(string const& _contractName) const
883
0
{
884
0
  if (m_stackState != CompilationSuccessful)
885
0
    solThrow(CompilerError, "Compilation was not successful.");
886
887
0
  return contract(_contractName).ewasmObject;
888
0
}
889
890
evmasm::LinkerObject const& CompilerStack::object(string const& _contractName) const
891
4.55k
{
892
4.55k
  if (m_stackState != CompilationSuccessful)
893
0
    solThrow(CompilerError, "Compilation was not successful.");
894
895
4.55k
  return contract(_contractName).object;
896
4.55k
}
897
898
evmasm::LinkerObject const& CompilerStack::runtimeObject(string const& _contractName) const
899
0
{
900
0
  if (m_stackState != CompilationSuccessful)
901
0
    solThrow(CompilerError, "Compilation was not successful.");
902
903
0
  return contract(_contractName).runtimeObject;
904
0
}
905
906
/// TODO: cache this string
907
string CompilerStack::assemblyString(string const& _contractName, StringMap const& _sourceCodes) const
908
0
{
909
0
  if (m_stackState != CompilationSuccessful)
910
0
    solThrow(CompilerError, "Compilation was not successful.");
911
912
0
  Contract const& currentContract = contract(_contractName);
913
0
  if (currentContract.evmAssembly)
914
0
    return currentContract.evmAssembly->assemblyString(m_debugInfoSelection, _sourceCodes);
915
0
  else
916
0
    return string();
917
0
}
918
919
/// TODO: cache the JSON
920
Json::Value CompilerStack::assemblyJSON(string const& _contractName) const
921
0
{
922
0
  if (m_stackState != CompilationSuccessful)
923
0
    solThrow(CompilerError, "Compilation was not successful.");
924
925
0
  Contract const& currentContract = contract(_contractName);
926
0
  if (currentContract.evmAssembly)
927
0
    return currentContract.evmAssembly->assemblyJSON(sourceIndices());
928
0
  else
929
0
    return Json::Value();
930
0
}
931
932
vector<string> CompilerStack::sourceNames() const
933
0
{
934
0
  vector<string> names;
935
0
  for (auto const& s: m_sources)
936
0
    names.push_back(s.first);
937
0
  return names;
938
0
}
939
940
map<string, unsigned> CompilerStack::sourceIndices() const
941
0
{
942
0
  map<string, unsigned> indices;
943
0
  unsigned index = 0;
944
0
  for (auto const& s: m_sources)
945
0
    indices[s.first] = index++;
946
0
  solAssert(!indices.count(CompilerContext::yulUtilityFileName()), "");
947
0
  indices[CompilerContext::yulUtilityFileName()] = index++;
948
0
  return indices;
949
0
}
950
951
Json::Value const& CompilerStack::contractABI(string const& _contractName) const
952
0
{
953
0
  if (m_stackState < AnalysisPerformed)
954
0
    solThrow(CompilerError, "Analysis was not successful.");
955
956
0
  return contractABI(contract(_contractName));
957
0
}
958
959
Json::Value const& CompilerStack::contractABI(Contract const& _contract) const
960
4.55k
{
961
4.55k
  if (m_stackState < AnalysisPerformed)
962
0
    solThrow(CompilerError, "Analysis was not successful.");
963
964
4.55k
  solAssert(_contract.contract, "");
965
966
4.55k
  return _contract.abi.init([&]{ return ABI::generate(*_contract.contract); });
967
4.55k
}
968
969
Json::Value const& CompilerStack::storageLayout(string const& _contractName) const
970
0
{
971
0
  if (m_stackState < AnalysisPerformed)
972
0
    solThrow(CompilerError, "Analysis was not successful.");
973
974
0
  return storageLayout(contract(_contractName));
975
0
}
976
977
Json::Value const& CompilerStack::storageLayout(Contract const& _contract) const
978
0
{
979
0
  if (m_stackState < AnalysisPerformed)
980
0
    solThrow(CompilerError, "Analysis was not successful.");
981
982
0
  solAssert(_contract.contract, "");
983
984
0
  return _contract.storageLayout.init([&]{ return StorageLayout().generate(*_contract.contract); });
985
0
}
986
987
Json::Value const& CompilerStack::natspecUser(string const& _contractName) const
988
0
{
989
0
  if (m_stackState < AnalysisPerformed)
990
0
    solThrow(CompilerError, "Analysis was not successful.");
991
992
0
  return natspecUser(contract(_contractName));
993
0
}
994
995
Json::Value const& CompilerStack::natspecUser(Contract const& _contract) const
996
4.55k
{
997
4.55k
  if (m_stackState < AnalysisPerformed)
998
0
    solThrow(CompilerError, "Analysis was not successful.");
999
1000
4.55k
  solAssert(_contract.contract, "");
1001
1002
4.55k
  return _contract.userDocumentation.init([&]{ return Natspec::userDocumentation(*_contract.contract); });
1003
4.55k
}
1004
1005
Json::Value const& CompilerStack::natspecDev(string const& _contractName) const
1006
0
{
1007
0
  if (m_stackState < AnalysisPerformed)
1008
0
    solThrow(CompilerError, "Analysis was not successful.");
1009
1010
0
  return natspecDev(contract(_contractName));
1011
0
}
1012
1013
Json::Value const& CompilerStack::natspecDev(Contract const& _contract) const
1014
4.55k
{
1015
4.55k
  if (m_stackState < AnalysisPerformed)
1016
0
    solThrow(CompilerError, "Analysis was not successful.");
1017
1018
4.55k
  solAssert(_contract.contract, "");
1019
1020
4.55k
  return _contract.devDocumentation.init([&]{ return Natspec::devDocumentation(*_contract.contract); });
1021
4.55k
}
1022
1023
Json::Value CompilerStack::interfaceSymbols(string const& _contractName) const
1024
4.55k
{
1025
4.55k
  if (m_stackState < AnalysisPerformed)
1026
0
    solThrow(CompilerError, "Analysis was not successful.");
1027
1028
4.55k
  Json::Value interfaceSymbols(Json::objectValue);
1029
  // Always have a methods object
1030
4.55k
  interfaceSymbols["methods"] = Json::objectValue;
1031
1032
4.55k
  for (auto const& it: contractDefinition(_contractName).interfaceFunctions())
1033
29.9k
    interfaceSymbols["methods"][it.second->externalSignature()] = it.first.hex();
1034
4.55k
  for (ErrorDefinition const* error: contractDefinition(_contractName).interfaceErrors())
1035
0
  {
1036
0
    string signature = error->functionType(true)->externalSignature();
1037
0
    interfaceSymbols["errors"][signature] = util::toHex(toCompactBigEndian(util::selectorFromSignature32(signature), 4));
1038
0
  }
1039
1040
4.55k
  for (EventDefinition const* event: ranges::concat_view(
1041
4.55k
    contractDefinition(_contractName).definedInterfaceEvents(),
1042
4.55k
    contractDefinition(_contractName).usedInterfaceEvents()
1043
4.55k
  ))
1044
0
    if (!event->isAnonymous())
1045
0
    {
1046
0
      string signature = event->functionType(true)->externalSignature();
1047
0
      interfaceSymbols["events"][signature] = toHex(u256(h256::Arith(util::keccak256(signature))));
1048
0
    }
1049
1050
4.55k
  return interfaceSymbols;
1051
4.55k
}
1052
1053
bytes CompilerStack::cborMetadata(string const& _contractName, bool _forIR) const
1054
0
{
1055
0
  if (m_stackState < AnalysisPerformed)
1056
0
    solThrow(CompilerError, "Analysis was not successful.");
1057
1058
0
  return createCBORMetadata(contract(_contractName), _forIR);
1059
0
}
1060
1061
string const& CompilerStack::metadata(Contract const& _contract) const
1062
4.55k
{
1063
4.55k
  if (m_stackState < AnalysisPerformed)
1064
0
    solThrow(CompilerError, "Analysis was not successful.");
1065
1066
4.55k
  solAssert(_contract.contract, "");
1067
1068
4.55k
  return _contract.metadata.init([&]{ return createMetadata(_contract, m_viaIR); });
1069
4.55k
}
1070
1071
CharStream const& CompilerStack::charStream(string const& _sourceName) const
1072
0
{
1073
0
  if (m_stackState < SourcesSet)
1074
0
    solThrow(CompilerError, "No sources set.");
1075
1076
0
  solAssert(source(_sourceName).charStream, "");
1077
1078
0
  return *source(_sourceName).charStream;
1079
0
}
1080
1081
SourceUnit const& CompilerStack::ast(string const& _sourceName) const
1082
0
{
1083
0
  if (m_stackState < Parsed)
1084
0
    solThrow(CompilerError, "Parsing not yet performed.");
1085
0
  if (!source(_sourceName).ast && !m_parserErrorRecovery)
1086
0
    solThrow(CompilerError, "Parsing was not successful.");
1087
1088
0
  return *source(_sourceName).ast;
1089
0
}
1090
1091
ContractDefinition const& CompilerStack::contractDefinition(string const& _contractName) const
1092
18.2k
{
1093
18.2k
  if (m_stackState < AnalysisPerformed)
1094
0
    solThrow(CompilerError, "Analysis was not successful.");
1095
1096
18.2k
  return *contract(_contractName).contract;
1097
18.2k
}
1098
1099
size_t CompilerStack::functionEntryPoint(
1100
  std::string const& _contractName,
1101
  FunctionDefinition const& _function
1102
) const
1103
0
{
1104
0
  if (m_stackState != CompilationSuccessful)
1105
0
    solThrow(CompilerError, "Compilation was not successful.");
1106
1107
0
  for (auto&& [name, data]: contract(_contractName).runtimeObject.functionDebugData)
1108
0
    if (data.sourceID == _function.id())
1109
0
      if (data.instructionIndex)
1110
0
        return *data.instructionIndex;
1111
0
  return 0;
1112
0
}
1113
1114
h256 const& CompilerStack::Source::keccak256() const
1115
4.55k
{
1116
4.55k
  if (keccak256HashCached == h256{})
1117
4.55k
    keccak256HashCached = util::keccak256(charStream->source());
1118
4.55k
  return keccak256HashCached;
1119
4.55k
}
1120
1121
h256 const& CompilerStack::Source::swarmHash() const
1122
4.55k
{
1123
4.55k
  if (swarmHashCached == h256{})
1124
4.55k
    swarmHashCached = util::bzzr1Hash(charStream->source());
1125
4.55k
  return swarmHashCached;
1126
4.55k
}
1127
1128
string const& CompilerStack::Source::ipfsUrl() const
1129
4.55k
{
1130
4.55k
  if (ipfsUrlCached.empty())
1131
4.55k
    ipfsUrlCached = "dweb:/ipfs/" + util::ipfsHashBase58(charStream->source());
1132
4.55k
  return ipfsUrlCached;
1133
4.55k
}
1134
1135
StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast)
1136
4.55k
{
1137
4.55k
  solAssert(m_stackState < ParsedAndImported, "");
1138
4.55k
  StringMap newSources;
1139
4.55k
  try
1140
4.55k
  {
1141
4.55k
    for (auto const& node: _ast.nodes())
1142
13.6k
      if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
1143
0
      {
1144
0
        string const& importPath = *import->annotation().absolutePath;
1145
1146
0
        if (m_sources.count(importPath) || newSources.count(importPath))
1147
0
          continue;
1148
1149
0
        ReadCallback::Result result{false, string("File not supplied initially.")};
1150
0
        if (m_readFile)
1151
0
          result = m_readFile(ReadCallback::kindString(ReadCallback::Kind::ReadFile), importPath);
1152
1153
0
        if (result.success)
1154
0
          newSources[importPath] = result.responseOrErrorMessage;
1155
0
        else
1156
0
        {
1157
0
          m_errorReporter.parserError(
1158
0
            6275_error,
1159
0
            import->location(),
1160
0
            string("Source \"" + importPath + "\" not found: " + result.responseOrErrorMessage)
1161
0
          );
1162
0
          continue;
1163
0
        }
1164
0
      }
1165
4.55k
  }
1166
4.55k
  catch (FatalError const&)
1167
4.55k
  {
1168
0
    solAssert(m_errorReporter.hasErrors(), "");
1169
0
  }
1170
4.55k
  return newSources;
1171
4.55k
}
1172
1173
string CompilerStack::applyRemapping(string const& _path, string const& _context)
1174
0
{
1175
0
  solAssert(m_stackState < ParsedAndImported, "");
1176
0
  return m_importRemapper.apply(_path, _context);
1177
0
}
1178
1179
void CompilerStack::resolveImports()
1180
4.55k
{
1181
4.55k
  solAssert(m_stackState == ParsedAndImported, "");
1182
1183
  // topological sorting (depth first search) of the import graph, cutting potential cycles
1184
4.55k
  vector<Source const*> sourceOrder;
1185
4.55k
  set<Source const*> sourcesSeen;
1186
1187
4.55k
  function<void(Source const*)> toposort = [&](Source const* _source)
1188
4.55k
  {
1189
4.55k
    if (sourcesSeen.count(_source))
1190
0
      return;
1191
4.55k
    sourcesSeen.insert(_source);
1192
4.55k
    if (_source->ast)
1193
4.55k
      for (ASTPointer<ASTNode> const& node: _source->ast->nodes())
1194
13.6k
        if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
1195
0
        {
1196
0
          string const& path = *import->annotation().absolutePath;
1197
0
          solAssert(m_sources.count(path), "");
1198
0
          import->annotation().sourceUnit = m_sources[path].ast.get();
1199
0
          toposort(&m_sources[path]);
1200
0
        }
1201
4.55k
    sourceOrder.push_back(_source);
1202
4.55k
  };
1203
1204
4.55k
  for (auto const& sourcePair: m_sources)
1205
4.55k
    if (isRequestedSource(sourcePair.first))
1206
4.55k
      toposort(&sourcePair.second);
1207
1208
4.55k
  swap(m_sourceOrder, sourceOrder);
1209
4.55k
}
1210
1211
void CompilerStack::storeContractDefinitions()
1212
4.55k
{
1213
4.55k
  for (auto const& pair: m_sources)
1214
4.55k
    if (pair.second.ast)
1215
4.55k
      for (
1216
4.55k
        ContractDefinition const* contract:
1217
4.55k
        ASTNode::filteredNodes<ContractDefinition>(pair.second.ast->nodes())
1218
4.55k
      )
1219
4.55k
      {
1220
4.55k
        string fullyQualifiedName = *pair.second.ast->annotation().path + ":" + contract->name();
1221
        // Note that we now reference contracts by their fully qualified names, and
1222
        // thus contracts can only conflict if declared in the same source file. This
1223
        // should already cause a double-declaration error elsewhere.
1224
4.55k
        if (!m_contracts.count(fullyQualifiedName))
1225
4.55k
          m_contracts[fullyQualifiedName].contract = contract;
1226
4.55k
      }
1227
4.55k
}
1228
1229
namespace
1230
{
1231
bool onlySafeExperimentalFeaturesActivated(set<ExperimentalFeature> const& features)
1232
4.55k
{
1233
4.55k
  for (auto const feature: features)
1234
4.55k
    if (!ExperimentalFeatureWithoutWarning.count(feature))
1235
0
      return false;
1236
4.55k
  return true;
1237
4.55k
}
1238
}
1239
1240
void CompilerStack::assemble(
1241
  ContractDefinition const& _contract,
1242
  std::shared_ptr<evmasm::Assembly> _assembly,
1243
  std::shared_ptr<evmasm::Assembly> _runtimeAssembly
1244
)
1245
4.55k
{
1246
4.55k
  solAssert(m_stackState >= AnalysisPerformed, "");
1247
4.55k
  solAssert(!m_hasError, "");
1248
1249
4.55k
  Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
1250
1251
4.55k
  compiledContract.evmAssembly = _assembly;
1252
4.55k
  solAssert(compiledContract.evmAssembly, "");
1253
4.55k
  try
1254
4.55k
  {
1255
    // Assemble deployment (incl. runtime)  object.
1256
4.55k
    compiledContract.object = compiledContract.evmAssembly->assemble();
1257
4.55k
  }
1258
4.55k
  catch (evmasm::AssemblyException const&)
1259
4.55k
  {
1260
0
    solAssert(false, "Assembly exception for bytecode");
1261
0
  }
1262
4.55k
  solAssert(compiledContract.object.immutableReferences.empty(), "Leftover immutables.");
1263
1264
4.55k
  compiledContract.evmRuntimeAssembly = _runtimeAssembly;
1265
4.55k
  solAssert(compiledContract.evmRuntimeAssembly, "");
1266
4.55k
  try
1267
4.55k
  {
1268
    // Assemble runtime object.
1269
4.55k
    compiledContract.runtimeObject = compiledContract.evmRuntimeAssembly->assemble();
1270
4.55k
  }
1271
4.55k
  catch (evmasm::AssemblyException const&)
1272
4.55k
  {
1273
0
    solAssert(false, "Assembly exception for deployed bytecode");
1274
0
  }
1275
1276
  // Throw a warning if EIP-170 limits are exceeded:
1277
  //   If contract creation returns data with length greater than 0x6000 (214 + 213) bytes,
1278
  //   contract creation fails with an out of gas error.
1279
4.55k
  if (
1280
4.55k
    m_evmVersion >= langutil::EVMVersion::spuriousDragon() &&
1281
4.55k
    compiledContract.runtimeObject.bytecode.size() > 0x6000
1282
4.55k
  )
1283
1.67k
    m_errorReporter.warning(
1284
1.67k
      5574_error,
1285
1.67k
      _contract.location(),
1286
1.67k
      "Contract code size is "s +
1287
1.67k
      to_string(compiledContract.runtimeObject.bytecode.size()) +
1288
1.67k
      " bytes and exceeds 24576 bytes (a limit introduced in Spurious Dragon). "
1289
1.67k
      "This contract may not be deployable on Mainnet. "
1290
1.67k
      "Consider enabling the optimizer (with a low \"runs\" value!), "
1291
1.67k
      "turning off revert strings, or using libraries."
1292
1.67k
    );
1293
4.55k
}
1294
1295
void CompilerStack::compileContract(
1296
  ContractDefinition const& _contract,
1297
  map<ContractDefinition const*, shared_ptr<Compiler const>>& _otherCompilers
1298
)
1299
4.55k
{
1300
4.55k
  solAssert(!m_viaIR, "");
1301
4.55k
  solAssert(m_stackState >= AnalysisPerformed, "");
1302
4.55k
  if (m_hasError)
1303
0
    solThrow(CompilerError, "Called compile with errors.");
1304
1305
4.55k
  if (_otherCompilers.count(&_contract))
1306
0
    return;
1307
1308
4.55k
  for (auto const& [dependency, referencee]: _contract.annotation().contractDependencies)
1309
0
    compileContract(*dependency, _otherCompilers);
1310
1311
4.55k
  if (!_contract.canBeDeployed())
1312
0
    return;
1313
1314
4.55k
  Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
1315
1316
4.55k
  shared_ptr<Compiler> compiler = make_shared<Compiler>(m_evmVersion, m_revertStrings, m_optimiserSettings);
1317
4.55k
  compiledContract.compiler = compiler;
1318
1319
4.55k
  solAssert(!m_viaIR, "");
1320
4.55k
  bytes cborEncodedMetadata = createCBORMetadata(compiledContract, /* _forIR */ false);
1321
1322
4.55k
  try
1323
4.55k
  {
1324
    // Run optimiser and compile the contract.
1325
4.55k
    compiler->compileContract(_contract, _otherCompilers, cborEncodedMetadata);
1326
4.55k
  }
1327
4.55k
  catch(evmasm::OptimizerException const&)
1328
4.55k
  {
1329
0
    solAssert(false, "Optimizer exception during compilation");
1330
0
  }
1331
1332
4.55k
  _otherCompilers[compiledContract.contract] = compiler;
1333
1334
4.55k
  assemble(_contract, compiler->assemblyPtr(), compiler->runtimeAssemblyPtr());
1335
4.55k
}
1336
1337
void CompilerStack::generateIR(ContractDefinition const& _contract)
1338
0
{
1339
0
  solAssert(m_stackState >= AnalysisPerformed, "");
1340
0
  if (m_hasError)
1341
0
    solThrow(CompilerError, "Called generateIR with errors.");
1342
1343
0
  Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
1344
0
  if (!compiledContract.yulIR.empty())
1345
0
    return;
1346
1347
0
  if (!*_contract.sourceUnit().annotation().useABICoderV2)
1348
0
    m_errorReporter.warning(
1349
0
      2066_error,
1350
0
      _contract.location(),
1351
0
      "Contract requests the ABI coder v1, which is incompatible with the IR. "
1352
0
      "Using ABI coder v2 instead."
1353
0
    );
1354
1355
0
  string dependenciesSource;
1356
0
  for (auto const& [dependency, referencee]: _contract.annotation().contractDependencies)
1357
0
    generateIR(*dependency);
1358
1359
0
  if (!_contract.canBeDeployed())
1360
0
    return;
1361
1362
0
  map<ContractDefinition const*, string_view const> otherYulSources;
1363
0
  for (auto const& pair: m_contracts)
1364
0
    otherYulSources.emplace(pair.second.contract, pair.second.yulIR);
1365
1366
0
  IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings, sourceIndices(), m_debugInfoSelection, this);
1367
0
  tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(
1368
0
    _contract,
1369
0
    createCBORMetadata(compiledContract, /* _forIR */ true),
1370
0
    otherYulSources
1371
0
  );
1372
0
}
1373
1374
void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract)
1375
0
{
1376
0
  solAssert(m_stackState >= AnalysisPerformed, "");
1377
0
  if (m_hasError)
1378
0
    solThrow(CompilerError, "Called generateEVMFromIR with errors.");
1379
1380
0
  if (!_contract.canBeDeployed())
1381
0
    return;
1382
1383
0
  Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
1384
0
  solAssert(!compiledContract.yulIROptimized.empty(), "");
1385
0
  if (!compiledContract.object.bytecode.empty())
1386
0
    return;
1387
1388
  // Re-parse the Yul IR in EVM dialect
1389
0
  yul::YulStack stack(
1390
0
    m_evmVersion,
1391
0
    yul::YulStack::Language::StrictAssembly,
1392
0
    m_optimiserSettings,
1393
0
    m_debugInfoSelection
1394
0
  );
1395
0
  stack.parseAndAnalyze("", compiledContract.yulIROptimized);
1396
0
  stack.optimize();
1397
1398
  //cout << yul::AsmPrinter{}(*stack.parserResult()->code) << endl;
1399
1400
0
  string deployedName = IRNames::deployedObject(_contract);
1401
0
  solAssert(!deployedName.empty(), "");
1402
0
  tie(compiledContract.evmAssembly, compiledContract.evmRuntimeAssembly) = stack.assembleEVMWithDeployed(deployedName);
1403
0
  assemble(_contract, compiledContract.evmAssembly, compiledContract.evmRuntimeAssembly);
1404
0
}
1405
1406
void CompilerStack::generateEwasm(ContractDefinition const& _contract)
1407
0
{
1408
0
  solAssert(m_stackState >= AnalysisPerformed, "");
1409
0
  if (m_hasError)
1410
0
    solThrow(CompilerError, "Called generateEwasm with errors.");
1411
1412
0
  if (!_contract.canBeDeployed())
1413
0
    return;
1414
1415
0
  Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
1416
0
  solAssert(!compiledContract.yulIROptimized.empty(), "");
1417
0
  if (!compiledContract.ewasm.empty())
1418
0
    return;
1419
1420
  // Re-parse the Yul IR in EVM dialect
1421
0
  yul::YulStack stack(
1422
0
    m_evmVersion,
1423
0
    yul::YulStack::Language::StrictAssembly,
1424
0
    m_optimiserSettings,
1425
0
    m_debugInfoSelection
1426
0
  );
1427
0
  stack.parseAndAnalyze("", compiledContract.yulIROptimized);
1428
1429
0
  stack.optimize();
1430
0
  stack.translate(yul::YulStack::Language::Ewasm);
1431
0
  stack.optimize();
1432
1433
  //cout << yul::AsmPrinter{}(*stack.parserResult()->code) << endl;
1434
1435
  // Turn into Ewasm text representation.
1436
0
  auto result = stack.assemble(yul::YulStack::Machine::Ewasm);
1437
0
  compiledContract.ewasm = std::move(result.assembly);
1438
0
  compiledContract.ewasmObject = std::move(*result.bytecode);
1439
0
}
1440
1441
CompilerStack::Contract const& CompilerStack::contract(string const& _contractName) const
1442
22.7k
{
1443
22.7k
  solAssert(m_stackState >= AnalysisPerformed, "");
1444
1445
22.7k
  auto it = m_contracts.find(_contractName);
1446
22.7k
  if (it != m_contracts.end())
1447
0
    return it->second;
1448
1449
  // To provide a measure of backward-compatibility, if a contract is not located by its
1450
  // fully-qualified name, a lookup will be attempted purely on the contract's name to see
1451
  // if anything will satisfy.
1452
22.7k
  if (_contractName.find(':') == string::npos)
1453
22.7k
  {
1454
22.7k
    for (auto const& contractEntry: m_contracts)
1455
22.7k
    {
1456
22.7k
      stringstream ss;
1457
22.7k
      ss.str(contractEntry.first);
1458
      // All entries are <source>:<contract>
1459
22.7k
      string source;
1460
22.7k
      string foundName;
1461
22.7k
      getline(ss, source, ':');
1462
22.7k
      getline(ss, foundName, ':');
1463
22.7k
      if (foundName == _contractName)
1464
22.7k
        return contractEntry.second;
1465
22.7k
    }
1466
22.7k
  }
1467
1468
  // If we get here, both lookup methods failed.
1469
22.7k
  solThrow(CompilerError, "Contract \"" + _contractName + "\" not found.");
1470
22.7k
}
1471
1472
CompilerStack::Source const& CompilerStack::source(string const& _sourceName) const
1473
0
{
1474
0
  auto it = m_sources.find(_sourceName);
1475
0
  if (it == m_sources.end())
1476
0
    solThrow(CompilerError, "Given source file not found: " + _sourceName);
1477
1478
0
  return it->second;
1479
0
}
1480
1481
string CompilerStack::createMetadata(Contract const& _contract, bool _forIR) const
1482
4.55k
{
1483
4.55k
  Json::Value meta{Json::objectValue};
1484
4.55k
  meta["version"] = 1;
1485
4.55k
  meta["language"] = m_importedSources ? "SolidityAST" : "Solidity";
1486
4.55k
  meta["compiler"]["version"] = VersionStringStrict;
1487
1488
  /// All the source files (including self), which should be included in the metadata.
1489
4.55k
  set<string> referencedSources;
1490
4.55k
  referencedSources.insert(*_contract.contract->sourceUnit().annotation().path);
1491
4.55k
  for (auto const sourceUnit: _contract.contract->sourceUnit().referencedSourceUnits(true))
1492
0
    referencedSources.insert(*sourceUnit->annotation().path);
1493
1494
4.55k
  meta["sources"] = Json::objectValue;
1495
4.55k
  for (auto const& s: m_sources)
1496
4.55k
  {
1497
4.55k
    if (!referencedSources.count(s.first))
1498
0
      continue;
1499
1500
4.55k
    solAssert(s.second.charStream, "Character stream not available");
1501
4.55k
    meta["sources"][s.first]["keccak256"] = "0x" + util::toHex(s.second.keccak256().asBytes());
1502
4.55k
    if (optional<string> licenseString = s.second.ast->licenseString())
1503
0
      meta["sources"][s.first]["license"] = *licenseString;
1504
4.55k
    if (m_metadataLiteralSources)
1505
0
      meta["sources"][s.first]["content"] = s.second.charStream->source();
1506
4.55k
    else
1507
4.55k
    {
1508
4.55k
      meta["sources"][s.first]["urls"] = Json::arrayValue;
1509
4.55k
      meta["sources"][s.first]["urls"].append("bzz-raw://" + util::toHex(s.second.swarmHash().asBytes()));
1510
4.55k
      meta["sources"][s.first]["urls"].append(s.second.ipfsUrl());
1511
4.55k
    }
1512
4.55k
  }
1513
1514
4.55k
  static_assert(sizeof(m_optimiserSettings.expectedExecutionsPerDeployment) <= sizeof(Json::LargestUInt), "Invalid word size.");
1515
4.55k
  solAssert(static_cast<Json::LargestUInt>(m_optimiserSettings.expectedExecutionsPerDeployment) < std::numeric_limits<Json::LargestUInt>::max(), "");
1516
4.55k
  meta["settings"]["optimizer"]["runs"] = Json::Value(Json::LargestUInt(m_optimiserSettings.expectedExecutionsPerDeployment));
1517
1518
  /// Backwards compatibility: If set to one of the default settings, do not provide details.
1519
4.55k
  OptimiserSettings settingsWithoutRuns = m_optimiserSettings;
1520
  // reset to default
1521
4.55k
  settingsWithoutRuns.expectedExecutionsPerDeployment = OptimiserSettings::minimal().expectedExecutionsPerDeployment;
1522
4.55k
  if (settingsWithoutRuns == OptimiserSettings::minimal())
1523
4.55k
    meta["settings"]["optimizer"]["enabled"] = false;
1524
0
  else if (settingsWithoutRuns == OptimiserSettings::standard())
1525
0
    meta["settings"]["optimizer"]["enabled"] = true;
1526
0
  else
1527
0
  {
1528
0
    Json::Value details{Json::objectValue};
1529
1530
0
    details["orderLiterals"] = m_optimiserSettings.runOrderLiterals;
1531
0
    details["inliner"] = m_optimiserSettings.runInliner;
1532
0
    details["jumpdestRemover"] = m_optimiserSettings.runJumpdestRemover;
1533
0
    details["peephole"] = m_optimiserSettings.runPeephole;
1534
0
    details["deduplicate"] = m_optimiserSettings.runDeduplicate;
1535
0
    details["cse"] = m_optimiserSettings.runCSE;
1536
0
    details["constantOptimizer"] = m_optimiserSettings.runConstantOptimiser;
1537
0
    details["yul"] = m_optimiserSettings.runYulOptimiser;
1538
0
    if (m_optimiserSettings.runYulOptimiser)
1539
0
    {
1540
0
      details["yulDetails"] = Json::objectValue;
1541
0
      details["yulDetails"]["stackAllocation"] = m_optimiserSettings.optimizeStackAllocation;
1542
0
      details["yulDetails"]["optimizerSteps"] = m_optimiserSettings.yulOptimiserSteps;
1543
0
    }
1544
1545
0
    meta["settings"]["optimizer"]["details"] = std::move(details);
1546
0
  }
1547
1548
4.55k
  if (m_revertStrings != RevertStrings::Default)
1549
0
    meta["settings"]["debug"]["revertStrings"] = revertStringsToString(m_revertStrings);
1550
1551
4.55k
  if (m_metadataLiteralSources)
1552
0
    meta["settings"]["metadata"]["useLiteralContent"] = true;
1553
1554
4.55k
  static vector<string> hashes{"ipfs", "bzzr1", "none"};
1555
4.55k
  meta["settings"]["metadata"]["bytecodeHash"] = hashes.at(unsigned(m_metadataHash));
1556
1557
4.55k
  if (_forIR)
1558
0
    meta["settings"]["viaIR"] = _forIR;
1559
4.55k
  meta["settings"]["evmVersion"] = m_evmVersion.name();
1560
4.55k
  meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] =
1561
4.55k
    *_contract.contract->annotation().canonicalName;
1562
1563
4.55k
  meta["settings"]["remappings"] = Json::arrayValue;
1564
4.55k
  set<string> remappings;
1565
4.55k
  for (auto const& r: m_importRemapper.remappings())
1566
0
    remappings.insert(r.context + ":" + r.prefix + "=" + r.target);
1567
4.55k
  for (auto const& r: remappings)
1568
0
    meta["settings"]["remappings"].append(r);
1569
1570
4.55k
  meta["settings"]["libraries"] = Json::objectValue;
1571
4.55k
  for (auto const& library: m_libraries)
1572
0
    meta["settings"]["libraries"][library.first] = "0x" + util::toHex(library.second.asBytes());
1573
1574
4.55k
  meta["output"]["abi"] = contractABI(_contract);
1575
4.55k
  meta["output"]["userdoc"] = natspecUser(_contract);
1576
4.55k
  meta["output"]["devdoc"] = natspecDev(_contract);
1577
1578
4.55k
  return util::jsonCompactPrint(meta);
1579
4.55k
}
1580
1581
class MetadataCBOREncoder
1582
{
1583
public:
1584
  void pushBytes(string const& key, bytes const& value)
1585
4.55k
  {
1586
4.55k
    m_entryCount++;
1587
4.55k
    pushTextString(key);
1588
4.55k
    pushByteString(value);
1589
4.55k
  }
1590
1591
  void pushString(string const& key, string const& value)
1592
4.55k
  {
1593
4.55k
    m_entryCount++;
1594
4.55k
    pushTextString(key);
1595
4.55k
    pushTextString(value);
1596
4.55k
  }
1597
1598
  void pushBool(string const& key, bool value)
1599
0
  {
1600
0
    m_entryCount++;
1601
0
    pushTextString(key);
1602
0
    pushBool(value);
1603
0
  }
1604
1605
  bytes serialise() const
1606
4.55k
  {
1607
4.55k
    size_t size = m_data.size() + 1;
1608
4.55k
    solAssert(size <= 0xffff, "Metadata too large.");
1609
4.55k
    solAssert(m_entryCount <= 0x1f, "Too many map entries.");
1610
1611
    // CBOR fixed-length map
1612
4.55k
    bytes ret{static_cast<unsigned char>(0xa0 + m_entryCount)};
1613
    // The already encoded key-value pairs
1614
4.55k
    ret += m_data;
1615
    // 16-bit big endian length
1616
4.55k
    ret += toCompactBigEndian(size, 2);
1617
4.55k
    return ret;
1618
4.55k
  }
1619
1620
private:
1621
  void pushTextString(string const& key)
1622
13.6k
  {
1623
13.6k
    size_t length = key.size();
1624
13.6k
    if (length < 24)
1625
9.10k
    {
1626
9.10k
      m_data += bytes{static_cast<unsigned char>(0x60 + length)};
1627
9.10k
      m_data += key;
1628
9.10k
    }
1629
4.55k
    else if (length <= 256)
1630
4.55k
    {
1631
4.55k
      m_data += bytes{0x78, static_cast<unsigned char>(length)};
1632
4.55k
      m_data += key;
1633
4.55k
    }
1634
0
    else
1635
4.55k
      solAssert(false, "Text string too large.");
1636
13.6k
  }
1637
  void pushByteString(bytes const& key)
1638
4.55k
  {
1639
4.55k
    size_t length = key.size();
1640
4.55k
    if (length < 24)
1641
0
    {
1642
0
      m_data += bytes{static_cast<unsigned char>(0x40 + length)};
1643
0
      m_data += key;
1644
0
    }
1645
4.55k
    else if (length <= 256)
1646
4.55k
    {
1647
4.55k
      m_data += bytes{0x58, static_cast<unsigned char>(length)};
1648
4.55k
      m_data += key;
1649
4.55k
    }
1650
0
    else
1651
4.55k
      solAssert(false, "Byte string too large.");
1652
4.55k
  }
1653
  void pushBool(bool value)
1654
0
  {
1655
0
    if (value)
1656
0
      m_data += bytes{0xf5};
1657
0
    else
1658
0
      m_data += bytes{0xf4};
1659
0
  }
1660
  unsigned m_entryCount = 0;
1661
  bytes m_data;
1662
};
1663
1664
bytes CompilerStack::createCBORMetadata(Contract const& _contract, bool _forIR) const
1665
4.55k
{
1666
4.55k
  if (m_metadataFormat == MetadataFormat::NoMetadata)
1667
0
    return bytes{};
1668
1669
4.55k
  bool const experimentalMode = !onlySafeExperimentalFeaturesActivated(
1670
4.55k
    _contract.contract->sourceUnit().annotation().experimentalFeatures
1671
4.55k
  );
1672
1673
4.55k
  string meta = (_forIR == m_viaIR ? metadata(_contract) : createMetadata(_contract, _forIR));
1674
1675
4.55k
  MetadataCBOREncoder encoder;
1676
1677
4.55k
  if (m_metadataHash == MetadataHash::IPFS)
1678
4.55k
    encoder.pushBytes("ipfs", util::ipfsHash(meta));
1679
0
  else if (m_metadataHash == MetadataHash::Bzzr1)
1680
0
    encoder.pushBytes("bzzr1", util::bzzr1Hash(meta).asBytes());
1681
0
  else
1682
0
    solAssert(m_metadataHash == MetadataHash::None, "Invalid metadata hash");
1683
1684
4.55k
  if (experimentalMode)
1685
0
    encoder.pushBool("experimental", true);
1686
4.55k
  if (m_metadataFormat == MetadataFormat::WithReleaseVersionTag)
1687
0
    encoder.pushBytes("solc", VersionCompactBytes);
1688
4.55k
  else
1689
4.55k
  {
1690
4.55k
    solAssert(
1691
4.55k
      m_metadataFormat == MetadataFormat::WithPrereleaseVersionTag,
1692
4.55k
      "Invalid metadata format."
1693
4.55k
    );
1694
4.55k
    encoder.pushString("solc", VersionStringStrict);
1695
4.55k
  }
1696
4.55k
  return encoder.serialise();
1697
4.55k
}
1698
1699
namespace
1700
{
1701
1702
Json::Value gasToJson(GasEstimator::GasConsumption const& _gas)
1703
0
{
1704
0
  if (_gas.isInfinite)
1705
0
    return Json::Value("infinite");
1706
0
  else
1707
0
    return Json::Value(util::toString(_gas.value));
1708
0
}
1709
1710
}
1711
1712
Json::Value CompilerStack::gasEstimates(string const& _contractName) const
1713
0
{
1714
0
  if (m_stackState != CompilationSuccessful)
1715
0
    solThrow(CompilerError, "Compilation was not successful.");
1716
1717
0
  if (!assemblyItems(_contractName) && !runtimeAssemblyItems(_contractName))
1718
0
    return Json::Value();
1719
1720
0
  using Gas = GasEstimator::GasConsumption;
1721
0
  GasEstimator gasEstimator(m_evmVersion);
1722
0
  Json::Value output(Json::objectValue);
1723
1724
0
  if (evmasm::AssemblyItems const* items = assemblyItems(_contractName))
1725
0
  {
1726
0
    Gas executionGas = gasEstimator.functionalEstimation(*items);
1727
0
    Gas codeDepositGas{evmasm::GasMeter::dataGas(runtimeObject(_contractName).bytecode, false, m_evmVersion)};
1728
1729
0
    Json::Value creation(Json::objectValue);
1730
0
    creation["codeDepositCost"] = gasToJson(codeDepositGas);
1731
0
    creation["executionCost"] = gasToJson(executionGas);
1732
    /// TODO: implement + overload to avoid the need of +=
1733
0
    executionGas += codeDepositGas;
1734
0
    creation["totalCost"] = gasToJson(executionGas);
1735
0
    output["creation"] = creation;
1736
0
  }
1737
1738
0
  if (evmasm::AssemblyItems const* items = runtimeAssemblyItems(_contractName))
1739
0
  {
1740
    /// External functions
1741
0
    ContractDefinition const& contract = contractDefinition(_contractName);
1742
0
    Json::Value externalFunctions(Json::objectValue);
1743
0
    for (auto it: contract.interfaceFunctions())
1744
0
    {
1745
0
      string sig = it.second->externalSignature();
1746
0
      externalFunctions[sig] = gasToJson(gasEstimator.functionalEstimation(*items, sig));
1747
0
    }
1748
1749
0
    if (contract.fallbackFunction())
1750
      /// This needs to be set to an invalid signature in order to trigger the fallback,
1751
      /// without the shortcut (of CALLDATSIZE == 0), and therefore to receive the upper bound.
1752
      /// An empty string ("") would work to trigger the shortcut only.
1753
0
      externalFunctions[""] = gasToJson(gasEstimator.functionalEstimation(*items, "INVALID"));
1754
1755
0
    if (!externalFunctions.empty())
1756
0
      output["external"] = externalFunctions;
1757
1758
    /// Internal functions
1759
0
    Json::Value internalFunctions(Json::objectValue);
1760
0
    for (auto const& it: contract.definedFunctions())
1761
0
    {
1762
      /// Exclude externally visible functions, constructor, fallback and receive ether function
1763
0
      if (it->isPartOfExternalInterface() || !it->isOrdinary())
1764
0
        continue;
1765
1766
0
      size_t entry = functionEntryPoint(_contractName, *it);
1767
0
      GasEstimator::GasConsumption gas = GasEstimator::GasConsumption::infinite();
1768
0
      if (entry > 0)
1769
0
        gas = gasEstimator.functionalEstimation(*items, entry, *it);
1770
1771
      /// TODO: This could move into a method shared with externalSignature()
1772
0
      FunctionType type(*it);
1773
0
      string sig = it->name() + "(";
1774
0
      auto paramTypes = type.parameterTypes();
1775
0
      for (auto it = paramTypes.begin(); it != paramTypes.end(); ++it)
1776
0
        sig += (*it)->toString() + (it + 1 == paramTypes.end() ? "" : ",");
1777
0
      sig += ")";
1778
1779
0
      internalFunctions[sig] = gasToJson(gas);
1780
0
    }
1781
1782
0
    if (!internalFunctions.empty())
1783
0
      output["internal"] = internalFunctions;
1784
0
  }
1785
1786
0
  return output;
1787
0
}