Skip to content

Commit c8f4c7d

Browse files
authored
Merge pull request ethereum#14803 from ethereum/mehtavishwa30-patch-1
Clean up docs to with regards to changes in SELFDESTRUCT opcode
2 parents 7115a63 + a15da0a commit c8f4c7d

9 files changed

+207
-102
lines changed

docs/cheatsheet.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ Contract-related
118118

119119
- ``this`` (current contract's type): the current contract, explicitly convertible to ``address`` or ``address payable``
120120
- ``super``: a contract one level higher in the inheritance hierarchy
121-
- ``selfdestruct(address payable recipient)``: destroy the current contract, sending its funds to the given address
121+
- ``selfdestruct(address payable recipient)``: send all funds to the given address and (only on EVMs before Cancun or when invoked within the transaction creating the contract) destroy the contract.
122122

123123
.. index:: type;name, type;creationCode, type;runtimeCode, type;interfaceId, type;min, type;max
124124

docs/contracts/function-modifiers.rst

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ if they are marked ``virtual``. For details, please see
1919
2020
// SPDX-License-Identifier: GPL-3.0
2121
pragma solidity >=0.7.1 <0.9.0;
22-
// This will report a warning due to deprecated selfdestruct
2322
2423
contract owned {
2524
constructor() { owner = payable(msg.sender); }
@@ -41,16 +40,6 @@ if they are marked ``virtual``. For details, please see
4140
}
4241
}
4342
44-
contract destructible is owned {
45-
// This contract inherits the `onlyOwner` modifier from
46-
// `owned` and applies it to the `destroy` function, which
47-
// causes that calls to `destroy` only have an effect if
48-
// they are made by the stored owner.
49-
function destroy() public onlyOwner {
50-
selfdestruct(owner);
51-
}
52-
}
53-
5443
contract priced {
5544
// Modifiers can receive arguments:
5645
modifier costs(uint price) {
@@ -60,7 +49,7 @@ if they are marked ``virtual``. For details, please see
6049
}
6150
}
6251
63-
contract Register is priced, destructible {
52+
contract Register is priced, owned {
6453
mapping(address => bool) registeredAddresses;
6554
uint price;
6655
@@ -73,6 +62,9 @@ if they are marked ``virtual``. For details, please see
7362
registeredAddresses[msg.sender] = true;
7463
}
7564
65+
// This contract inherits the `onlyOwner` modifier from
66+
// the `owned` contract. As a result, calls to `changePrice` will
67+
// only take effect if they are made by the stored owner.
7668
function changePrice(uint price_) public onlyOwner {
7769
price = price_;
7870
}

docs/contracts/inheritance.rst

Lines changed: 85 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -40,27 +40,27 @@ Details are given in the following example.
4040
4141
// SPDX-License-Identifier: GPL-3.0
4242
pragma solidity >=0.7.0 <0.9.0;
43-
// This will report a warning due to deprecated selfdestruct
4443
4544
contract Owned {
46-
constructor() { owner = payable(msg.sender); }
4745
address payable owner;
46+
constructor() { owner = payable(msg.sender); }
4847
}
4948
50-
5149
// Use `is` to derive from another contract. Derived
5250
// contracts can access all non-private members including
5351
// internal functions and state variables. These cannot be
5452
// accessed externally via `this`, though.
55-
contract Destructible is Owned {
53+
contract Emittable is Owned {
54+
event Emitted();
55+
5656
// The keyword `virtual` means that the function can change
5757
// its behavior in derived classes ("overriding").
58-
function destroy() virtual public {
59-
if (msg.sender == owner) selfdestruct(owner);
58+
function emitEvent() virtual public {
59+
if (msg.sender == owner)
60+
emit Emitted();
6061
}
6162
}
6263
63-
6464
// These abstract contracts are only provided to make the
6565
// interface known to the compiler. Note the function
6666
// without body. If a contract does not implement all
@@ -69,37 +69,35 @@ Details are given in the following example.
6969
function lookup(uint id) public virtual returns (address adr);
7070
}
7171
72-
7372
abstract contract NameReg {
7473
function register(bytes32 name) public virtual;
7574
function unregister() public virtual;
7675
}
7776
78-
7977
// Multiple inheritance is possible. Note that `Owned` is
80-
// also a base class of `Destructible`, yet there is only a single
78+
// also a base class of `Emittable`, yet there is only a single
8179
// instance of `Owned` (as for virtual inheritance in C++).
82-
contract Named is Owned, Destructible {
80+
contract Named is Owned, Emittable {
8381
constructor(bytes32 name) {
8482
Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970);
8583
NameReg(config.lookup(1)).register(name);
8684
}
8785
8886
// Functions can be overridden by another function with the same name and
89-
// the same number/types of inputs. If the overriding function has different
87+
// the same number/types of inputs. If the overriding function has different
9088
// types of output parameters, that causes an error.
9189
// Both local and message-based function calls take these overrides
9290
// into account.
9391
// If you want the function to override, you need to use the
9492
// `override` keyword. You need to specify the `virtual` keyword again
9593
// if you want this function to be overridden again.
96-
function destroy() public virtual override {
94+
function emitEvent() public virtual override {
9795
if (msg.sender == owner) {
9896
Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970);
9997
NameReg(config.lookup(1)).unregister();
10098
// It is still possible to call a specific
10199
// overridden function.
102-
Destructible.destroy();
100+
Emittable.emitEvent();
103101
}
104102
}
105103
}
@@ -108,93 +106,132 @@ Details are given in the following example.
108106
// If a constructor takes an argument, it needs to be
109107
// provided in the header or modifier-invocation-style at
110108
// the constructor of the derived contract (see below).
111-
contract PriceFeed is Owned, Destructible, Named("GoldFeed") {
109+
contract PriceFeed is Owned, Emittable, Named("GoldFeed") {
110+
uint info;
111+
112112
function updateInfo(uint newInfo) public {
113113
if (msg.sender == owner) info = newInfo;
114114
}
115115
116116
// Here, we only specify `override` and not `virtual`.
117117
// This means that contracts deriving from `PriceFeed`
118-
// cannot change the behavior of `destroy` anymore.
119-
function destroy() public override(Destructible, Named) { Named.destroy(); }
118+
// cannot change the behavior of `emitEvent` anymore.
119+
function emitEvent() public override(Emittable, Named) { Named.emitEvent(); }
120120
function get() public view returns(uint r) { return info; }
121-
122-
uint info;
123121
}
124122
125-
Note that above, we call ``Destructible.destroy()`` to "forward" the
126-
destruction request. The way this is done is problematic, as
123+
Note that above, we call ``Emittable.emitEvent()`` to "forward" the
124+
emit event request. The way this is done is problematic, as
127125
seen in the following example:
128126

129127
.. code-block:: solidity
130128
131129
// SPDX-License-Identifier: GPL-3.0
132130
pragma solidity >=0.7.0 <0.9.0;
133-
// This will report a warning due to deprecated selfdestruct
134131
135-
contract owned {
136-
constructor() { owner = payable(msg.sender); }
132+
contract Owned {
137133
address payable owner;
134+
constructor() { owner = payable(msg.sender); }
138135
}
139136
140-
contract Destructible is owned {
141-
function destroy() public virtual {
142-
if (msg.sender == owner) selfdestruct(owner);
137+
contract Emittable is Owned {
138+
event Emitted();
139+
140+
function emitEvent() virtual public {
141+
if (msg.sender == owner) {
142+
emit Emitted();
143+
}
143144
}
144145
}
145146
146-
contract Base1 is Destructible {
147-
function destroy() public virtual override { /* do cleanup 1 */ Destructible.destroy(); }
147+
contract Base1 is Emittable {
148+
event Base1Emitted();
149+
function emitEvent() public virtual override {
150+
/* Here, we emit an event to simulate some Base1 logic */
151+
emit Base1Emitted();
152+
Emittable.emitEvent();
153+
}
148154
}
149155
150-
contract Base2 is Destructible {
151-
function destroy() public virtual override { /* do cleanup 2 */ Destructible.destroy(); }
156+
contract Base2 is Emittable {
157+
event Base2Emitted();
158+
function emitEvent() public virtual override {
159+
/* Here, we emit an event to simulate some Base2 logic */
160+
emit Base2Emitted();
161+
Emittable.emitEvent();
162+
}
152163
}
153164
154165
contract Final is Base1, Base2 {
155-
function destroy() public override(Base1, Base2) { Base2.destroy(); }
166+
event FinalEmitted();
167+
function emitEvent() public override(Base1, Base2) {
168+
/* Here, we emit an event to simulate some Final logic */
169+
emit FinalEmitted();
170+
Base2.emitEvent();
171+
}
156172
}
157173
158-
A call to ``Final.destroy()`` will call ``Base2.destroy`` because we specify it
174+
A call to ``Final.emitEvent()`` will call ``Base2.emitEvent`` because we specify it
159175
explicitly in the final override, but this function will bypass
160-
``Base1.destroy``. The way around this is to use ``super``:
176+
``Base1.emitEvent``, resulting in the following sequence of events:
177+
``FinalEmitted -> Base2Emitted -> Emitted``, instead of the expected sequence:
178+
``FinalEmitted -> Base2Emitted -> Base1Emitted -> Emitted``.
179+
The way around this is to use ``super``:
161180

162181
.. code-block:: solidity
163182
164183
// SPDX-License-Identifier: GPL-3.0
165184
pragma solidity >=0.7.0 <0.9.0;
166-
// This will report a warning due to deprecated selfdestruct
167185
168-
contract owned {
169-
constructor() { owner = payable(msg.sender); }
186+
contract Owned {
170187
address payable owner;
188+
constructor() { owner = payable(msg.sender); }
171189
}
172190
173-
contract Destructible is owned {
174-
function destroy() virtual public {
175-
if (msg.sender == owner) selfdestruct(owner);
191+
contract Emittable is Owned {
192+
event Emitted();
193+
194+
function emitEvent() virtual public {
195+
if (msg.sender == owner) {
196+
emit Emitted();
197+
}
176198
}
177199
}
178200
179-
contract Base1 is Destructible {
180-
function destroy() public virtual override { /* do cleanup 1 */ super.destroy(); }
201+
contract Base1 is Emittable {
202+
event Base1Emitted();
203+
function emitEvent() public virtual override {
204+
/* Here, we emit an event to simulate some Base1 logic */
205+
emit Base1Emitted();
206+
super.emitEvent();
207+
}
181208
}
182209
183210
184-
contract Base2 is Destructible {
185-
function destroy() public virtual override { /* do cleanup 2 */ super.destroy(); }
211+
contract Base2 is Emittable {
212+
event Base2Emitted();
213+
function emitEvent() public virtual override {
214+
/* Here, we emit an event to simulate some Base2 logic */
215+
emit Base2Emitted();
216+
super.emitEvent();
217+
}
186218
}
187219
188220
contract Final is Base1, Base2 {
189-
function destroy() public override(Base1, Base2) { super.destroy(); }
221+
event FinalEmitted();
222+
function emitEvent() public override(Base1, Base2) {
223+
/* Here, we emit an event to simulate some Final logic */
224+
emit FinalEmitted();
225+
super.emitEvent();
226+
}
190227
}
191228
192-
If ``Base2`` calls a function of ``super``, it does not simply
229+
If ``Final`` calls a function of ``super``, it does not simply
193230
call this function on one of its base contracts. Rather, it
194231
calls this function on the next base contract in the final
195-
inheritance graph, so it will call ``Base1.destroy()`` (note that
232+
inheritance graph, so it will call ``Base1.emitEvent()`` (note that
196233
the final inheritance sequence is -- starting with the most
197-
derived contract: Final, Base2, Base1, Destructible, owned).
234+
derived contract: Final, Base2, Base1, Emittable, Owned).
198235
The actual function that is called when using super is
199236
not known in the context of the class where it is used,
200237
although its type is known. This is similar for ordinary

0 commit comments

Comments
 (0)