-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathShowcaseGas.t.sol
More file actions
189 lines (163 loc) · 8.1 KB
/
ShowcaseGas.t.sol
File metadata and controls
189 lines (163 loc) · 8.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import {Test} from "forge-std/Test.sol";
import {
QuantizedETHStakingShowcase,
QuantizedExtremePackingShowcase,
RawETHStakingShowcase,
RawExtremePackingShowcase
} from "src/showcase/ShowcaseSolidityFixtures.sol";
contract ShowcaseGasTest is Test {
uint256 internal constant REAL_SHIFT = 16;
uint256 internal constant REAL_AMOUNT_BITS = 96;
uint256 internal constant REAL_AMOUNT_MAX = (uint256(1) << REAL_AMOUNT_BITS) - 1;
uint256 internal constant EXT_SHIFT = 8;
uint256 internal constant EXT_WIDTH = 20;
uint256 internal constant EXT_LANES = 12;
uint256 internal constant EXT_LANE_MAX = (uint256(1) << EXT_WIDTH) - 1;
uint256 internal constant MIN_REAL_SAVINGS_BPS = 3_200; // >=32%
uint256 internal constant REAL_STAKE_STRICT = uint256(2_500_000) << REAL_SHIFT;
uint256 internal constant REAL_STAKE_STRICT_ALT = uint256(2_750_000) << REAL_SHIFT;
uint256 internal constant REAL_STAKE_FLOOR = REAL_STAKE_STRICT + 321;
uint256 internal constant EXT_E0 = 1_000_000;
uint256 internal constant EXT_E1 = 970_000;
uint256 internal constant EXT_E2 = 940_000;
uint256 internal constant EXT_E3 = 910_000;
uint256 internal constant EXT_E4 = 880_000;
uint256 internal constant EXT_E5 = 850_000;
uint256 internal constant EXT_E6 = 820_000;
uint256 internal constant EXT_E7 = 790_000;
uint256 internal constant EXT_E8 = 760_000;
uint256 internal constant EXT_E9 = 730_000;
uint256 internal constant EXT_E10 = 700_000;
uint256 internal constant EXT_E11 = 670_000;
uint256 internal constant EXT_R0 = 13;
uint256 internal constant EXT_R1 = 27;
uint256 internal constant EXT_R2 = 55;
uint256 internal constant EXT_R3 = 89;
uint256 internal constant EXT_R4 = 144;
uint256 internal constant EXT_R5 = 233;
uint256 internal constant EXT_R6 = 7;
uint256 internal constant EXT_R7 = 31;
uint256 internal constant EXT_R8 = 63;
uint256 internal constant EXT_R9 = 95;
uint256 internal constant EXT_R10 = 127;
uint256 internal constant EXT_R11 = 191;
receive() external payable {}
function setUp() public {
vm.deal(address(this), 1_000_000 ether);
}
function test_gas_real_life_solidity_zero_to_nonzero_savings_ge_target() public {
uint256 rawGas = _measureSolidityRealRawStake();
uint256 floorGas = _measureSolidityRealQuantFloorStake();
uint256 strictGas = _measureSolidityRealQuantStrictStake();
emit log_named_uint("staking raw gas", rawGas);
emit log_named_uint("staking strict gas", strictGas);
emit log_named_uint("staking strict savings bps", _savingsBps(rawGas, strictGas));
assertGt(rawGas, floorGas);
assertGt(rawGas, strictGas);
assertGe(_savingsBps(rawGas, floorGas), MIN_REAL_SAVINGS_BPS);
assertGe(_savingsBps(rawGas, strictGas), MIN_REAL_SAVINGS_BPS);
}
/// @notice Logs extreme-packing gas numbers for documentation. Not a regression gate:
/// the savings are a property of the 12:1 slot ratio, not the library's efficiency.
function test_gas_extreme_solidity_zero_to_nonzero_logs() public {
uint256 rawGas = _measureSolidityExtremeRaw();
uint256 floorGas = _measureSolidityExtremeQuantFloor();
uint256 strictGas = _measureSolidityExtremeQuantStrict();
emit log_named_uint("extreme raw gas", rawGas);
emit log_named_uint("extreme strict gas", strictGas);
emit log_named_uint("extreme strict savings bps", _savingsBps(rawGas, strictGas));
}
function test_showcase_inputs_fit_lanes() public pure {
assertLe(REAL_STAKE_FLOOR >> REAL_SHIFT, REAL_AMOUNT_MAX);
assertLe(REAL_STAKE_STRICT >> REAL_SHIFT, REAL_AMOUNT_MAX);
assertLe(REAL_STAKE_STRICT_ALT >> REAL_SHIFT, REAL_AMOUNT_MAX);
uint256[12] memory strictValues = _extremeStrictValues();
uint256[12] memory strictValuesAlt = _extremeStrictValuesAlt();
uint256[12] memory floorValues = _extremeFloorValues();
for (uint256 i; i < EXT_LANES; ++i) {
assertLe(strictValues[i] >> EXT_SHIFT, EXT_LANE_MAX);
assertLe(strictValuesAlt[i] >> EXT_SHIFT, EXT_LANE_MAX);
assertLe(floorValues[i] >> EXT_SHIFT, EXT_LANE_MAX);
}
}
function _extremeStrictValues() internal pure returns (uint256[12] memory values) {
values[0] = EXT_E0 << EXT_SHIFT;
values[1] = EXT_E1 << EXT_SHIFT;
values[2] = EXT_E2 << EXT_SHIFT;
values[3] = EXT_E3 << EXT_SHIFT;
values[4] = EXT_E4 << EXT_SHIFT;
values[5] = EXT_E5 << EXT_SHIFT;
values[6] = EXT_E6 << EXT_SHIFT;
values[7] = EXT_E7 << EXT_SHIFT;
values[8] = EXT_E8 << EXT_SHIFT;
values[9] = EXT_E9 << EXT_SHIFT;
values[10] = EXT_E10 << EXT_SHIFT;
values[11] = EXT_E11 << EXT_SHIFT;
}
function _extremeFloorValues() internal pure returns (uint256[12] memory values) {
values[0] = (EXT_E0 << EXT_SHIFT) + EXT_R0;
values[1] = (EXT_E1 << EXT_SHIFT) + EXT_R1;
values[2] = (EXT_E2 << EXT_SHIFT) + EXT_R2;
values[3] = (EXT_E3 << EXT_SHIFT) + EXT_R3;
values[4] = (EXT_E4 << EXT_SHIFT) + EXT_R4;
values[5] = (EXT_E5 << EXT_SHIFT) + EXT_R5;
values[6] = (EXT_E6 << EXT_SHIFT) + EXT_R6;
values[7] = (EXT_E7 << EXT_SHIFT) + EXT_R7;
values[8] = (EXT_E8 << EXT_SHIFT) + EXT_R8;
values[9] = (EXT_E9 << EXT_SHIFT) + EXT_R9;
values[10] = (EXT_E10 << EXT_SHIFT) + EXT_R10;
values[11] = (EXT_E11 << EXT_SHIFT) + EXT_R11;
}
function _extremeStrictValuesAlt() internal pure returns (uint256[12] memory values) {
values[0] = (EXT_E0 + 1) << EXT_SHIFT;
values[1] = (EXT_E1 + 1) << EXT_SHIFT;
values[2] = (EXT_E2 + 1) << EXT_SHIFT;
values[3] = (EXT_E3 + 1) << EXT_SHIFT;
values[4] = (EXT_E4 + 1) << EXT_SHIFT;
values[5] = (EXT_E5 + 1) << EXT_SHIFT;
values[6] = (EXT_E6 + 1) << EXT_SHIFT;
values[7] = (EXT_E7 + 1) << EXT_SHIFT;
values[8] = (EXT_E8 + 1) << EXT_SHIFT;
values[9] = (EXT_E9 + 1) << EXT_SHIFT;
values[10] = (EXT_E10 + 1) << EXT_SHIFT;
values[11] = (EXT_E11 + 1) << EXT_SHIFT;
}
function _savingsBps(uint256 rawGas, uint256 quantizedGas) internal pure returns (uint256) {
return ((rawGas - quantizedGas) * 10_000) / rawGas;
}
function _measureSolidityRealRawStake() internal returns (uint256) {
RawETHStakingShowcase raw = new RawETHStakingShowcase();
raw.stake{value: REAL_STAKE_FLOOR}();
return uint256(vm.lastCallGas().gasTotalUsed);
}
function _measureSolidityRealQuantFloorStake() internal returns (uint256) {
QuantizedETHStakingShowcase quantized = new QuantizedETHStakingShowcase();
quantized.stake{value: REAL_STAKE_FLOOR}();
return uint256(vm.lastCallGas().gasTotalUsed);
}
function _measureSolidityRealQuantStrictStake() internal returns (uint256) {
QuantizedETHStakingShowcase quantized = new QuantizedETHStakingShowcase();
quantized.stakeExact{value: REAL_STAKE_STRICT}();
return uint256(vm.lastCallGas().gasTotalUsed);
}
function _measureSolidityExtremeRaw() internal returns (uint256) {
RawExtremePackingShowcase raw = new RawExtremePackingShowcase();
uint256[12] memory values = _extremeFloorValues();
raw.setExtremeRaw(values);
return uint256(vm.lastCallGas().gasTotalUsed);
}
function _measureSolidityExtremeQuantFloor() internal returns (uint256) {
QuantizedExtremePackingShowcase quantized = new QuantizedExtremePackingShowcase();
uint256[12] memory values = _extremeFloorValues();
quantized.setExtremeFloor(values);
return uint256(vm.lastCallGas().gasTotalUsed);
}
function _measureSolidityExtremeQuantStrict() internal returns (uint256) {
QuantizedExtremePackingShowcase quantized = new QuantizedExtremePackingShowcase();
uint256[12] memory values = _extremeStrictValues();
quantized.setExtremeStrict(values);
return uint256(vm.lastCallGas().gasTotalUsed);
}
}