1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum Opcode {
7 Op0,
9 Op1Negate,
10 Op1,
11 Op2,
12 Op3,
13 Op4,
14 Op5,
15 Op6,
16 Op7,
17 Op8,
18 Op9,
19 Op10,
20 Op11,
21 Op12,
22 Op13,
23 Op14,
24 Op15,
25 Op16,
26
27 OpNop,
29 OpIf,
30 OpNotIf,
31 OpElse,
32 OpEndIf,
33 OpVerify,
34 OpReturn,
35
36 Op2Drop,
38 Op2Dup,
39 OpDepth,
40 OpDrop,
41 OpDup,
42 OpNip,
43 OpOver,
44 OpSwap,
45 OpTuck,
46
47 OpSize,
49
50 OpEqual,
52 OpEqualVerify,
53
54 OpNot,
56
57 OpRipemd160,
59 OpSha256,
60 OpHash160,
61 OpHash256,
62 OpCheckSig,
63 OpCheckSigVerify,
64}
65
66impl Opcode {
67 pub fn from_byte(byte: u8) -> Option<Opcode> {
73 match byte {
74 0x00 => Some(Opcode::Op0),
75 0x4f => Some(Opcode::Op1Negate),
76 0x51 => Some(Opcode::Op1),
77 0x52 => Some(Opcode::Op2),
78 0x53 => Some(Opcode::Op3),
79 0x54 => Some(Opcode::Op4),
80 0x55 => Some(Opcode::Op5),
81 0x56 => Some(Opcode::Op6),
82 0x57 => Some(Opcode::Op7),
83 0x58 => Some(Opcode::Op8),
84 0x59 => Some(Opcode::Op9),
85 0x5a => Some(Opcode::Op10),
86 0x5b => Some(Opcode::Op11),
87 0x5c => Some(Opcode::Op12),
88 0x5d => Some(Opcode::Op13),
89 0x5e => Some(Opcode::Op14),
90 0x5f => Some(Opcode::Op15),
91 0x60 => Some(Opcode::Op16),
92 0x61 => Some(Opcode::OpNop),
93 0x63 => Some(Opcode::OpIf),
94 0x64 => Some(Opcode::OpNotIf),
95 0x67 => Some(Opcode::OpElse),
96 0x68 => Some(Opcode::OpEndIf),
97 0x69 => Some(Opcode::OpVerify),
98 0x6a => Some(Opcode::OpReturn),
99 0x6d => Some(Opcode::Op2Drop),
100 0x6e => Some(Opcode::Op2Dup),
101 0x74 => Some(Opcode::OpDepth),
102 0x75 => Some(Opcode::OpDrop),
103 0x76 => Some(Opcode::OpDup),
104 0x77 => Some(Opcode::OpNip),
105 0x78 => Some(Opcode::OpOver),
106 0x7c => Some(Opcode::OpSwap),
107 0x7d => Some(Opcode::OpTuck),
108 0x82 => Some(Opcode::OpSize),
109 0x87 => Some(Opcode::OpEqual),
110 0x88 => Some(Opcode::OpEqualVerify),
111 0x91 => Some(Opcode::OpNot),
112 0xa6 => Some(Opcode::OpRipemd160),
113 0xa8 => Some(Opcode::OpSha256),
114 0xa9 => Some(Opcode::OpHash160),
115 0xaa => Some(Opcode::OpHash256),
116 0xac => Some(Opcode::OpCheckSig),
117 0xad => Some(Opcode::OpCheckSigVerify),
118 _ => None,
119 }
120 }
121
122 pub fn to_byte(self) -> u8 {
124 match self {
125 Opcode::Op0 => 0x00,
126 Opcode::Op1Negate => 0x4f,
127 Opcode::Op1 => 0x51,
128 Opcode::Op2 => 0x52,
129 Opcode::Op3 => 0x53,
130 Opcode::Op4 => 0x54,
131 Opcode::Op5 => 0x55,
132 Opcode::Op6 => 0x56,
133 Opcode::Op7 => 0x57,
134 Opcode::Op8 => 0x58,
135 Opcode::Op9 => 0x59,
136 Opcode::Op10 => 0x5a,
137 Opcode::Op11 => 0x5b,
138 Opcode::Op12 => 0x5c,
139 Opcode::Op13 => 0x5d,
140 Opcode::Op14 => 0x5e,
141 Opcode::Op15 => 0x5f,
142 Opcode::Op16 => 0x60,
143 Opcode::OpNop => 0x61,
144 Opcode::OpIf => 0x63,
145 Opcode::OpNotIf => 0x64,
146 Opcode::OpElse => 0x67,
147 Opcode::OpEndIf => 0x68,
148 Opcode::OpVerify => 0x69,
149 Opcode::OpReturn => 0x6a,
150 Opcode::Op2Drop => 0x6d,
151 Opcode::Op2Dup => 0x6e,
152 Opcode::OpDepth => 0x74,
153 Opcode::OpDrop => 0x75,
154 Opcode::OpDup => 0x76,
155 Opcode::OpNip => 0x77,
156 Opcode::OpOver => 0x78,
157 Opcode::OpSwap => 0x7c,
158 Opcode::OpTuck => 0x7d,
159 Opcode::OpSize => 0x82,
160 Opcode::OpEqual => 0x87,
161 Opcode::OpEqualVerify => 0x88,
162 Opcode::OpNot => 0x91,
163 Opcode::OpRipemd160 => 0xa6,
164 Opcode::OpSha256 => 0xa8,
165 Opcode::OpHash160 => 0xa9,
166 Opcode::OpHash256 => 0xaa,
167 Opcode::OpCheckSig => 0xac,
168 Opcode::OpCheckSigVerify => 0xad,
169 }
170 }
171}
172
173impl std::fmt::Display for Opcode {
174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175 let name = match self {
176 Opcode::Op0 => "OP_0",
177 Opcode::Op1Negate => "OP_1NEGATE",
178 Opcode::Op1 => "OP_1",
179 Opcode::Op2 => "OP_2",
180 Opcode::Op3 => "OP_3",
181 Opcode::Op4 => "OP_4",
182 Opcode::Op5 => "OP_5",
183 Opcode::Op6 => "OP_6",
184 Opcode::Op7 => "OP_7",
185 Opcode::Op8 => "OP_8",
186 Opcode::Op9 => "OP_9",
187 Opcode::Op10 => "OP_10",
188 Opcode::Op11 => "OP_11",
189 Opcode::Op12 => "OP_12",
190 Opcode::Op13 => "OP_13",
191 Opcode::Op14 => "OP_14",
192 Opcode::Op15 => "OP_15",
193 Opcode::Op16 => "OP_16",
194 Opcode::OpNop => "OP_NOP",
195 Opcode::OpIf => "OP_IF",
196 Opcode::OpNotIf => "OP_NOTIF",
197 Opcode::OpElse => "OP_ELSE",
198 Opcode::OpEndIf => "OP_ENDIF",
199 Opcode::OpVerify => "OP_VERIFY",
200 Opcode::OpReturn => "OP_RETURN",
201 Opcode::Op2Drop => "OP_2DROP",
202 Opcode::Op2Dup => "OP_2DUP",
203 Opcode::OpDepth => "OP_DEPTH",
204 Opcode::OpDrop => "OP_DROP",
205 Opcode::OpDup => "OP_DUP",
206 Opcode::OpNip => "OP_NIP",
207 Opcode::OpOver => "OP_OVER",
208 Opcode::OpSwap => "OP_SWAP",
209 Opcode::OpTuck => "OP_TUCK",
210 Opcode::OpSize => "OP_SIZE",
211 Opcode::OpEqual => "OP_EQUAL",
212 Opcode::OpEqualVerify => "OP_EQUALVERIFY",
213 Opcode::OpNot => "OP_NOT",
214 Opcode::OpRipemd160 => "OP_RIPEMD160",
215 Opcode::OpSha256 => "OP_SHA256",
216 Opcode::OpHash160 => "OP_HASH160",
217 Opcode::OpHash256 => "OP_HASH256",
218 Opcode::OpCheckSig => "OP_CHECKSIG",
219 Opcode::OpCheckSigVerify => "OP_CHECKSIGVERIFY",
220 };
221 write!(f, "{name}")
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn roundtrip_all_opcodes() {
231 let opcodes = [
232 Opcode::Op0,
233 Opcode::Op1Negate,
234 Opcode::Op1,
235 Opcode::Op2,
236 Opcode::Op3,
237 Opcode::Op4,
238 Opcode::Op5,
239 Opcode::Op6,
240 Opcode::Op7,
241 Opcode::Op8,
242 Opcode::Op9,
243 Opcode::Op10,
244 Opcode::Op11,
245 Opcode::Op12,
246 Opcode::Op13,
247 Opcode::Op14,
248 Opcode::Op15,
249 Opcode::Op16,
250 Opcode::OpNop,
251 Opcode::OpIf,
252 Opcode::OpNotIf,
253 Opcode::OpElse,
254 Opcode::OpEndIf,
255 Opcode::OpVerify,
256 Opcode::OpReturn,
257 Opcode::Op2Drop,
258 Opcode::Op2Dup,
259 Opcode::OpDepth,
260 Opcode::OpDrop,
261 Opcode::OpDup,
262 Opcode::OpNip,
263 Opcode::OpOver,
264 Opcode::OpSwap,
265 Opcode::OpTuck,
266 Opcode::OpSize,
267 Opcode::OpEqual,
268 Opcode::OpEqualVerify,
269 Opcode::OpNot,
270 Opcode::OpRipemd160,
271 Opcode::OpSha256,
272 Opcode::OpHash160,
273 Opcode::OpHash256,
274 Opcode::OpCheckSig,
275 Opcode::OpCheckSigVerify,
276 ];
277
278 for opcode in &opcodes {
279 let byte = opcode.to_byte();
280 let recovered = Opcode::from_byte(byte);
281 assert_eq!(recovered, Some(*opcode), "roundtrip failed for {opcode}");
282 }
283 }
284
285 #[test]
286 fn push_data_bytes_return_none() {
287 for byte in 0x01..=0x4bu8 {
288 assert_eq!(
289 Opcode::from_byte(byte),
290 None,
291 "byte 0x{byte:02x} should be None"
292 );
293 }
294 assert_eq!(Opcode::from_byte(0x4c), None);
296 assert_eq!(Opcode::from_byte(0x4d), None);
297 assert_eq!(Opcode::from_byte(0x4e), None);
298 }
299
300 #[test]
301 fn unsupported_bytes_return_none() {
302 assert_eq!(Opcode::from_byte(0x50), None); assert_eq!(Opcode::from_byte(0xb0), None);
304 assert_eq!(Opcode::from_byte(0xff), None);
305 }
306
307 #[test]
308 fn display_formatting() {
309 assert_eq!(format!("{}", Opcode::OpDup), "OP_DUP");
310 assert_eq!(format!("{}", Opcode::OpHash160), "OP_HASH160");
311 assert_eq!(format!("{}", Opcode::Op0), "OP_0");
312 assert_eq!(format!("{}", Opcode::OpCheckSig), "OP_CHECKSIG");
313 }
314}