Coverage Report

Created: 2025-09-08 08:10

/src/solidity/liblangutil/EVMVersion.h
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
 * EVM versioning.
20
 */
21
22
#pragma once
23
24
#include <libsolutil/Assertions.h>
25
26
#include <array>
27
#include <cstdint>
28
#include <optional>
29
#include <string>
30
31
32
namespace solidity::evmasm
33
{
34
/// Virtual machine bytecode instruction. Forward declared from libevmasm/Instruction.h
35
enum class Instruction: uint8_t;
36
}
37
38
namespace solidity::langutil
39
{
40
41
/**
42
 * A version specifier of the EVM we want to compile to.
43
 * Defaults to the latest version deployed on Ethereum Mainnet at the time of compiler release.
44
 */
45
class EVMVersion
46
{
47
public:
48
132M
  EVMVersion() = default;
49
50
1.53k
  static EVMVersion current() { return {currentVersion}; }
51
52
817k
  static EVMVersion constexpr homestead() { return {Version::Homestead}; }
53
271k
  static EVMVersion constexpr tangerineWhistle() { return {Version::TangerineWhistle}; }
54
50.6M
  static EVMVersion constexpr spuriousDragon() { return {Version::SpuriousDragon}; }
55
25.7M
  static EVMVersion constexpr byzantium() { return {Version::Byzantium}; }
56
60.8M
  static EVMVersion constexpr constantinople() { return {Version::Constantinople}; }
57
11.6k
  static EVMVersion constexpr petersburg() { return {Version::Petersburg}; }
58
56.2M
  static EVMVersion constexpr istanbul() { return {Version::Istanbul}; }
59
22.0k
  static EVMVersion constexpr berlin() { return {Version::Berlin}; }
60
667k
  static EVMVersion constexpr london() { return {Version::London}; }
61
623k
  static EVMVersion constexpr paris() { return {Version::Paris}; }
62
266M
  static EVMVersion constexpr shanghai() { return {Version::Shanghai}; }
63
35.9M
  static EVMVersion constexpr cancun() { return {Version::Cancun}; }
64
10.9k
  static EVMVersion constexpr prague() { return {Version::Prague}; }
65
262
  static EVMVersion constexpr osaka() { return {Version::Osaka}; }
66
67
0
  static auto constexpr allVersions() {
68
0
    return std::array{
69
0
      homestead(),
70
0
      tangerineWhistle(),
71
0
      spuriousDragon(),
72
0
      byzantium(),
73
0
      constantinople(),
74
0
      petersburg(),
75
0
      istanbul(),
76
0
      berlin(),
77
0
      london(),
78
0
      paris(),
79
0
      shanghai(),
80
0
      cancun(),
81
0
      prague(),
82
0
      osaka(),
83
0
    };
84
0
  }
85
86
  static auto constexpr allEOFVersions()
87
0
  {
88
0
    return std::array{
89
0
      std::optional<uint8_t>(),
90
0
      std::make_optional<uint8_t>(1)
91
0
    };
92
0
  }
93
94
  static std::optional<EVMVersion> fromString(std::string const& _version)
95
0
  {
96
0
    for (auto const& v: allVersions())
97
0
      if (_version == v.name())
98
0
        return v;
99
0
    return std::nullopt;
100
0
  }
101
102
55.9M
  static EVMVersion firstWithEOF() { return {Version::Osaka}; }
103
104
0
  bool isExperimental() const {
105
0
    return m_version > currentVersion;
106
0
  }
107
108
1.20G
  auto operator<=>(EVMVersion const&) const = default;
109
110
  std::string name() const
111
76.8k
  {
112
76.8k
    switch (m_version)
113
76.8k
    {
114
2.51k
    case Version::Homestead: return "homestead";
115
2.27k
    case Version::TangerineWhistle: return "tangerineWhistle";
116
2.29k
    case Version::SpuriousDragon: return "spuriousDragon";
117
1.86k
    case Version::Byzantium: return "byzantium";
118
2.51k
    case Version::Constantinople: return "constantinople";
119
1.82k
    case Version::Petersburg: return "petersburg";
120
1.70k
    case Version::Istanbul: return "istanbul";
121
1.85k
    case Version::Berlin: return "berlin";
122
1.85k
    case Version::London: return "london";
123
1.68k
    case Version::Paris: return "paris";
124
1.99k
    case Version::Shanghai: return "shanghai";
125
1.72k
    case Version::Cancun: return "cancun";
126
51.0k
    case Version::Prague: return "prague";
127
1.70k
    case Version::Osaka: return "osaka";
128
76.8k
    }
129
0
    util::unreachable();
130
0
  }
131
132
  /// Has the RETURNDATACOPY and RETURNDATASIZE opcodes.
133
13.3M
  bool supportsReturndata() const { return *this >= byzantium(); }
134
12.3M
  bool hasStaticCall() const { return *this >= byzantium(); }
135
48.3M
  bool hasBitwiseShifting() const { return *this >= constantinople(); }
136
12.3M
  bool hasCreate2() const { return *this >= constantinople(); }
137
168k
  bool hasExtCodeHash() const { return *this >= constantinople(); }
138
538k
  bool hasChainID() const { return *this >= istanbul(); }
139
730k
  bool hasSelfBalance() const { return *this >= istanbul(); }
140
455k
  bool hasBaseFee() const { return *this >= london(); }
141
440k
  bool hasBlobBaseFee() const { return *this >= cancun(); }
142
39
  bool hasPrevRandao() const { return *this >= paris(); }
143
266M
  bool hasPush0() const { return *this >= shanghai(); }
144
488k
  bool hasBlobHash() const { return *this >= cancun(); }
145
454k
  bool hasMcopy() const { return *this >= cancun(); }
146
1.33M
  bool supportsTransientStorage() const { return *this >= cancun(); }
147
6.81M
  bool supportsEOF() const { return *this >= firstWithEOF(); }
148
149
  bool hasOpcode(evmasm::Instruction _opcode, std::optional<uint8_t> _eofVersion) const;
150
151
  /// Whether we have to retain the costs for the call opcode itself (false),
152
  /// or whether we can just forward easily all remaining gas (true).
153
258k
  bool canOverchargeGasForCall() const { return *this >= tangerineWhistle(); }
154
155
private:
156
  enum class Version {
157
    Homestead,
158
    TangerineWhistle,
159
    SpuriousDragon,
160
    Byzantium,
161
    Constantinople,
162
    Petersburg,
163
    Istanbul,
164
    Berlin,
165
    London,
166
    Paris,
167
    Shanghai,
168
    Cancun,
169
    Prague,
170
    Osaka,
171
  };
172
  static auto constexpr currentVersion = Version::Prague;
173
174
554M
  constexpr EVMVersion(Version _version): m_version(_version) {}
175
176
  Version m_version = currentVersion;
177
};
178
179
}