1
+ import { Chain } from '@/../script/index' ;
1
2
import { Collapsible } from '@/components/diff/utils/Collapsible' ;
2
3
import { Markdown } from '@/components/diff/utils/Markdown' ;
3
4
import { RenderDiff } from '@/components/diff/utils/RenderDiff' ;
4
5
import { ExternalLink } from '@/components/layout/ExternalLink' ;
5
6
import { Copyable } from '@/components/ui/Copyable' ;
6
7
import { classNames , formatPrefixByte } from '@/lib/utils' ;
7
8
import { toUppercase } from '@/lib/utils' ;
8
- import { Example , Opcode , Variable } from '@/types' ;
9
9
import { GasComputation } from '@/types/opcode' ;
10
10
import { formatHardfork , formatStringList } from './utils/format' ;
11
11
12
+ type Opcodes = Chain [ 'opcodes' ] ;
13
+ type Opcode = Opcodes [ 0 ] ;
14
+
12
15
type Props = {
13
- base : Opcode [ ] ;
14
- target : Opcode [ ] ;
16
+ base : Opcodes ;
17
+ target : Opcodes ;
15
18
onlyShowDiff : boolean ;
16
19
} ;
17
20
18
- const formatVariables = ( title : string , array ?: Variable [ ] ) : JSX . Element => {
19
- return (
20
- < >
21
- < h3 className = { classNames ( 'font-bold' , 'mt-2' ) } > { toUppercase ( title ) } </ h3 >
22
- { array === undefined || array . length === 0 ? (
23
- < > None</ >
24
- ) : (
25
- < ul >
26
- { array . map ( ( v , id ) => (
27
- < li key = { id } > { formatVariable ( v ) } </ li >
28
- ) ) }
29
- </ ul >
30
- ) }
31
- </ >
32
- ) ;
33
- } ;
34
-
35
- const formatVariable = ( v : Variable ) : JSX . Element => {
36
- return (
37
- < div key = { v . name } className = 'text-secondary' >
38
- < p >
39
- < code className = 'text-sm' > { v . name } </ code > : < span > { v . description } </ span >
40
- </ p >
41
- { v . expression && (
42
- < >
43
- < div className = 'text-sm' >
44
- < h5 className = 'text-primary mt-4 font-semibold' >
45
- Sub-variables (< code > { v . name } </ code > )
46
- </ h5 >
47
- < code >
48
- { v . name } = { v . expression }
49
- </ code >
50
- { v . variables && (
51
- < >
52
- < ul > { v . variables . map ( ( subvariables ) => formatVariable ( subvariables ) ) } </ ul >
53
- </ >
54
- ) }
55
- </ div >
56
- < br />
57
- </ >
58
- ) }
59
- </ div >
60
- ) ;
61
- } ;
62
-
63
- const formatExamples = ( opcode : Opcode ) : JSX . Element => {
64
- if ( ! opcode . examples || opcode . examples . length === 0 ) return < > </ > ;
65
- const contents = (
66
- < >
67
- < div className = 'text-secondary text-sm' >
68
- Stack inputs are shown on the left of the arrow symbol and stack outputs on the right.{ ' ' }
69
- { opcode . playgroundLink && (
70
- < span >
71
- Or,{ ' ' }
72
- < ExternalLink className = 'text-sm' href = { opcode . playgroundLink } >
73
- try it out
74
- </ ExternalLink > { ' ' }
75
- on the playground.
76
- </ span >
77
- ) }
78
- </ div >
79
- < ul >
80
- { opcode . examples . map ( ( e , id ) => (
81
- < li key = { id } > { formatExample ( e , id ) } </ li >
82
- ) ) }
83
- </ ul >
84
- </ >
85
- ) ;
86
-
87
- return < Collapsible kind = 'custom' title = 'Examples' contents = { contents } /> ;
88
- } ;
89
-
90
- const formatExample = ( e : Example , id : number ) : JSX . Element => {
91
- const input = e . input ? '[' + e . input . toString ( ) + ']' : '[]' ;
92
- const output = '[' + ( e . output ? e . output : '' ) + ']' ;
93
- return (
94
- < >
95
- < h4 className = 'mt-3 font-semibold' > Example #{ id } </ h4 >
96
- < div className = 'ml-3' >
97
- { e . description && < p > { e . description } </ p > }
98
- < code className = 'text-secondary text-sm' >
99
- { input } { '=>' } { output }
100
- </ code >
101
- { e . memory && (
102
- < >
103
- < h5 className = 'mt-4 font-bold' > Memory</ h5 >
104
- < h6 className = 'text-secondary font-semibold' > Before</ h6 >
105
- < code className = 'text-secondary text-sm' >
106
- { e . memory . before ? e . memory . before : '[]' }
107
- </ code >
108
- < h6 className = 'text-secondary mt-2 font-semibold' > After</ h6 >
109
- < code className = 'text-secondary text-sm' > { e . memory . after ? e . memory . after : '[]' } </ code >
110
- </ >
111
- ) }
112
- { e . storage && (
113
- < >
114
- < h5 className = 'mt-4 font-bold' > Storage</ h5 >
115
- < h6 className = 'text-secondary font-semibold' > Before</ h6 >
116
- < code className = 'text-secondary text-sm' >
117
- { e . storage . before && formatStorage ( e . storage . before ) }
118
- </ code >
119
- < h6 className = 'text-secondary mt-2 font-semibold' > After</ h6 >
120
- < code className = 'text-secondary text-sm' >
121
- { e . storage . after && formatStorage ( e . storage . after ) }
122
- </ code >
123
- </ >
124
- ) }
125
- { e . calldata && (
126
- < >
127
- < h5 className = 'mt-4 font-bold' > Calldata</ h5 >
128
- < code className = 'text-secondary text-sm' > { e . calldata } </ code >
129
- </ >
130
- ) }
131
- { e . code && (
132
- < >
133
- < h5 className = 'mt-4 font-bold' > Code</ h5 >
134
- < code className = 'text-secondary text-sm' > { e . code } </ code >
135
- </ >
136
- ) }
137
- { e . returndata && (
138
- < >
139
- < h5 className = 'mt-4 font-bold' > Return Data</ h5 >
140
- < code className = 'text-secondary text-sm' > { e . returndata } </ code >
141
- </ >
142
- ) }
143
- </ div >
144
- </ >
145
- ) ;
146
- } ;
147
-
148
- const formatStorage = ( record : Record < string , string > ) : JSX . Element => {
149
- if ( ! record || record === undefined ) return < > </ > ;
150
- const keyValues : JSX . Element [ ] = [ ] ;
151
- for ( const key in record ) {
152
- keyValues . push (
153
- < li key = { key } >
154
- { key } : { record [ key ] }
155
- </ li >
156
- ) ;
157
- }
158
- return < ul > { keyValues } </ ul > ;
159
- } ;
160
-
161
- const formatGasComputation = ( gc : GasComputation | undefined ) : JSX . Element => {
162
- if ( ! gc ) return < > </ > ;
163
- const contents = (
164
- < >
165
- < code className = 'text-secondary text-sm' > gas_cost = static_gas_cost + dynamic_gas_cost</ code >
166
-
167
- < div >
168
- { gc . staticGasCost && (
169
- < >
170
- < code className = 'text-secondary text-sm' >
171
- static_gas_cost = { gc . staticGasCost . expression }
172
- </ code >
173
- { gc . staticGasCost . variables && (
174
- < >
175
- < h5 className = 'mt-4 font-bold' > Sub-variables (static_gas_cost)</ h5 >
176
- < ul >
177
- { gc . staticGasCost . variables . map ( ( v ) => (
178
- < li key = { v . name } > { formatVariable ( v ) } </ li >
179
- ) ) }
180
- </ ul >
181
- </ >
182
- ) }
183
- </ >
184
- ) }
185
- </ div >
186
-
187
- < div >
188
- { gc . dynamicGasCost && (
189
- < >
190
- < code className = 'text-secondary text-sm' >
191
- dynamic_gas_cost = { gc . dynamicGasCost . expression }
192
- </ code >
193
- { gc . dynamicGasCost . variables && (
194
- < >
195
- < h5 className = 'mt-4 font-semibold' >
196
- Sub-variables (< code className = 'text-sm' > dynamic_gas_cost</ code > )
197
- </ h5 >
198
- < ul >
199
- { gc . dynamicGasCost . variables . map ( ( v ) => (
200
- < li key = { v . name } > { formatVariable ( v ) } </ li >
201
- ) ) }
202
- </ ul >
203
- </ >
204
- ) }
205
- </ >
206
- ) }
207
- </ div >
208
-
209
- < h4 className = 'mt-3 font-semibold' > Refunds</ h4 >
210
- < p className = 'text-secondary' > { gc . refunds || 'No refunds' } </ p >
211
- </ >
212
- ) ;
213
- return < Collapsible kind = 'custom' title = 'Gas Computation' contents = { contents } /> ;
214
- } ;
215
-
216
21
const formatOpcode = ( opcode : Opcode | undefined ) : JSX . Element => {
217
- if ( ! opcode ) return < p > Not present</ p > ;
218
22
return (
219
- < >
220
- < Markdown className = 'mb-4' content = { opcode . description } />
221
- { formatHardfork ( opcode . supportedHardforks ) }
222
- < p className = 'text-secondary text-sm' > ⛽️ Minimum Gas: { opcode . minGas } </ p >
223
- { formatVariables ( 'Inputs' , opcode . inputs ) }
224
- { formatVariables ( 'Outputs' , opcode . outputs ) }
225
- { formatStringList ( 'Error Cases' , opcode . errorCases ) }
226
- { formatStringList ( 'Notes' , opcode . notes ) }
227
- < div className = 'mt-4' >
228
- { formatExamples ( opcode ) }
229
- { formatGasComputation ( opcode . gasComputation ) }
230
- < Collapsible kind = 'references' contents = { opcode . references } />
231
- </ div >
232
- </ >
23
+ < div > { opcode ?. supported === 'unknown' ? 'Unknown' : opcode ?. supported ? 'Yes' : 'No' } </ div >
233
24
) ;
234
25
} ;
235
26
236
27
export const DiffOpcodes = ( { base, target, onlyShowDiff } : Props ) : JSX . Element => {
237
28
if ( ! Array . isArray ( base ) || ! Array . isArray ( target ) ) return < > </ > ;
238
29
239
- // Generate a sorted list of all opcode numbers from both base and target.
240
- const sortedOpcodeNumbers = [
241
- ...base . map ( ( opcode ) => opcode . number ) ,
242
- ...target . map ( ( opcode ) => opcode . number ) ,
243
- ] . sort ( ( a , b ) => a - b ) ;
244
- const opcodeNumbers = [ ...new Set ( sortedOpcodeNumbers ) ] ;
30
+ const opcodeNumbers = Array . from ( Array ( 0xff + 1 ) . keys ( ) ) ;
245
31
246
32
const diffContent = (
247
33
< >
248
34
{ opcodeNumbers . map ( ( number ) => {
249
- const baseOpcode = base . find ( ( opcode ) => opcode . number === number ) ;
250
- const targetOpcode = target . find ( ( opcode ) => opcode . number === number ) ;
35
+ const baseOpcode = base . find ( ( opcode ) => Number ( opcode . number ) === number ) ;
36
+ const targetOpcode = target . find ( ( opcode ) => Number ( opcode . number ) === number ) ;
251
37
if ( ! baseOpcode || ! targetOpcode ) {
252
- return < > </ > ;
38
+ return < div key = { number } > </ div > ;
253
39
}
254
40
255
- const isEqual =
256
- JSON . stringify ( convertToComparableOpcode ( baseOpcode ) ) ===
257
- JSON . stringify ( convertToComparableOpcode ( targetOpcode ) ) ;
41
+ const isEqual = JSON . stringify ( baseOpcode ) === JSON . stringify ( targetOpcode ) ;
258
42
const showOpcode = ! isEqual || ! onlyShowDiff ;
259
43
260
44
return (
@@ -265,7 +49,7 @@ export const DiffOpcodes = ({ base, target, onlyShowDiff }: Props): JSX.Element
265
49
>
266
50
< div className = 'col-span-2' >
267
51
< Copyable content = { baseOpcode ?. name . toLocaleUpperCase ( ) } />
268
- < Copyable content = { formatPrefixByte ( baseOpcode ?. number ) } />
52
+ < Copyable content = { formatPrefixByte ( Number ( baseOpcode ?. number ) ) } />
269
53
</ div >
270
54
< div className = 'col-span-5 pr-4' > { formatOpcode ( baseOpcode ) } </ div >
271
55
< div className = 'col-span-5' > { formatOpcode ( targetOpcode ) } </ div >
@@ -278,22 +62,3 @@ export const DiffOpcodes = ({ base, target, onlyShowDiff }: Props): JSX.Element
278
62
279
63
return < RenderDiff content = { diffContent } /> ;
280
64
} ;
281
-
282
- // Convert an `Opcode` object to a simpler struct in order to compare it to other opcodes.
283
- // Note: casting an object from a type with properties X, Y and Z to a subset type with properties
284
- // X and Y using the `as` keyword will still retain the field Z unless you explicitly remove it.
285
- // That's why this function exists.
286
- export const convertToComparableOpcode = (
287
- opcode : Opcode
288
- ) : Omit < Opcode , 'examples' | 'playgroundLink' | 'notes' | 'references' | 'supportedHardforks' > => {
289
- return {
290
- number : opcode . number ,
291
- name : opcode . name ,
292
- description : opcode . description ,
293
- minGas : opcode . minGas ,
294
- gasComputation : opcode . gasComputation ,
295
- inputs : opcode . inputs ,
296
- outputs : opcode . outputs ,
297
- errorCases : opcode . errorCases ,
298
- } ;
299
- } ;
0 commit comments