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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
//! Script verification flag combination testing
//!
//! Tests all script verification flag combinations to ensure consensus correctness.
//! consensus uses 32 different flag combinations, and all must be tested.
//!
//! Flags tested:
//! - SCRIPT_VERIFY_P2SH (0x01)
//! - SCRIPT_VERIFY_STRICTENC (0x02)
//! - SCRIPT_VERIFY_DERSIG (0x04)
//! - SCRIPT_VERIFY_LOW_S (0x08)
//! - SCRIPT_VERIFY_NULLDUMMY (0x10)
//! - SCRIPT_VERIFY_SIGPUSHONLY (0x20)
//! - SCRIPT_VERIFY_MINIMALDATA (0x40)
//! - SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS (0x80)
//! - SCRIPT_VERIFY_CLEANSTACK (0x100)
//! - SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY (0x200)
//! - SCRIPT_VERIFY_CHECKSEQUENCEVERIFY (0x400)
//! - SCRIPT_VERIFY_WITNESS (0x800)
//! - SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM (0x1000)
//! - SCRIPT_VERIFY_MINIMALIF (0x2000)
//! - SCRIPT_VERIFY_TAPROOT (0x4000)
use blvm_consensus::script::{eval_script, verify_script, SigVersion};
/// All script verification flags
pub const ALL_FLAGS: &[u32] = &[
0x01, // SCRIPT_VERIFY_P2SH
0x02, // SCRIPT_VERIFY_STRICTENC
0x04, // SCRIPT_VERIFY_DERSIG
0x08, // SCRIPT_VERIFY_LOW_S
0x10, // SCRIPT_VERIFY_NULLDUMMY
0x20, // SCRIPT_VERIFY_SIGPUSHONLY
0x40, // SCRIPT_VERIFY_MINIMALDATA
0x80, // SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS
0x100, // SCRIPT_VERIFY_CLEANSTACK
0x200, // SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY
0x400, // SCRIPT_VERIFY_CHECKSEQUENCEVERIFY
0x800, // SCRIPT_VERIFY_WITNESS
0x1000, // SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM
0x2000, // SCRIPT_VERIFY_MINIMALIF
0x4000, // SCRIPT_VERIFY_TAPROOT
];
/// Generate all 32 flag combinations (2^5 = 32)
///
/// Tests combinations of the 5 most common flags:
/// - P2SH, STRICTENC, DERSIG, WITNESS, TAPROOT
pub fn generate_all_flag_combinations() -> Vec<u32> {
let mut combinations = Vec::new();
// Generate all 32 combinations (2^5)
for i in 0..32 {
let mut flags = 0u32;
if i & 0x01 != 0 {
flags |= 0x01;
} // P2SH
if i & 0x02 != 0 {
flags |= 0x02;
} // STRICTENC
if i & 0x04 != 0 {
flags |= 0x04;
} // DERSIG
if i & 0x08 != 0 {
flags |= 0x800;
} // WITNESS
if i & 0x10 != 0 {
flags |= 0x4000;
} // TAPROOT
combinations.push(flags);
}
combinations
}
/// Test all flag combinations with a simple script
#[test]
fn test_all_flag_combinations_simple() {
let flag_combinations = generate_all_flag_combinations();
let script = vec![0x51]; // OP_1
for flags in flag_combinations {
let mut stack = Vec::new();
let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
// Should not panic with any flag combination
assert!(
result.is_ok() || result.is_err(),
"Script failed with flags 0x{flags:x}"
);
}
}
/// Test flag combinations with P2SH scripts
#[test]
fn test_flag_combinations_p2sh() {
let flag_combinations = generate_all_flag_combinations();
// P2SH script: OP_HASH160 <hash> OP_EQUAL
let script_pubkey = vec![
0xa9, // OP_HASH160
0x14, // Push 20 bytes
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x87, // OP_EQUAL
];
let script_sig = vec![0x51]; // OP_1
for flags in flag_combinations {
let result = verify_script(&script_sig, &script_pubkey, None, flags);
// Should not panic
assert!(
result.is_ok() || result.is_err(),
"P2SH script failed with flags 0x{flags:x}"
);
}
}
/// Test flag interactions
///
/// Verifies that flags interact correctly when combined.
#[test]
fn test_flag_interactions() {
// Test P2SH + WITNESS combination
let flags = 0x01 | 0x800; // P2SH + WITNESS
let script = vec![0x51]; // OP_1
let mut stack = Vec::new();
let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
assert!(result.is_ok() || result.is_err());
// Test STRICTENC + DERSIG combination
let flags = 0x02 | 0x04; // STRICTENC + DERSIG
let script = vec![0x51]; // OP_1
let mut stack = Vec::new();
let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
assert!(result.is_ok() || result.is_err());
// Test TAPROOT + WITNESS combination
let flags = 0x4000 | 0x800; // TAPROOT + WITNESS (legacy mapping in this test module)
let script = vec![0x51]; // OP_1
let mut stack = Vec::new();
let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
assert!(result.is_ok() || result.is_err());
}
/// Test historical flag changes
///
/// Verifies behavior with flags that were added at different times:
/// - Pre-SegWit: No WITNESS flag
/// - Post-SegWit: WITNESS flag enabled
/// - Post-Taproot: TAPROOT flag enabled
#[test]
fn test_historical_flag_changes() {
// Pre-SegWit flags (no WITNESS)
let pre_segwit_flags = 0x01 | 0x02 | 0x04; // P2SH + STRICTENC + DERSIG
let script = vec![0x51]; // OP_1
let mut stack = Vec::new();
let result = eval_script(&script, &mut stack, pre_segwit_flags, SigVersion::Base);
assert!(result.is_ok() || result.is_err());
// Post-SegWit flags (WITNESS enabled)
let post_segwit_flags = 0x01 | 0x02 | 0x04 | 0x800; // + WITNESS
let script = vec![0x51]; // OP_1
let mut stack = Vec::new();
let result = eval_script(&script, &mut stack, post_segwit_flags, SigVersion::Base);
assert!(result.is_ok() || result.is_err());
// Post-Taproot flags (TAPROOT enabled)
let post_taproot_flags = 0x01 | 0x02 | 0x04 | 0x800 | 0x4000; // + TAPROOT (legacy mapping in this test module)
let script = vec![0x51]; // OP_1
let mut stack = Vec::new();
let result = eval_script(&script, &mut stack, post_taproot_flags, SigVersion::Base);
assert!(result.is_ok() || result.is_err());
}
/// Test flag inheritance in transaction chains
///
/// Verifies that flags are correctly inherited when validating
/// transaction chains (e.g., P2SH transactions).
#[test]
fn test_flag_inheritance() {
// Test that flags are properly applied in nested script execution
// (e.g., P2SH redeem script execution)
let flags = 0x01; // P2SH
let script = vec![0x51]; // OP_1
let mut stack = Vec::new();
let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
// Flags should be inherited correctly
assert!(result.is_ok() || result.is_err());
}
/// Test all individual flags
///
/// Verifies that each flag works correctly when used alone.
#[test]
fn test_individual_flags() {
for &flag in ALL_FLAGS {
let script = vec![0x51]; // OP_1
let mut stack = Vec::new();
let result = eval_script(&script, &mut stack, flag, SigVersion::Base);
// Each flag should work correctly
assert!(
result.is_ok() || result.is_err(),
"Flag 0x{flag:x} caused error"
);
}
}
/// Test flag combinations with edge case scripts
///
/// Tests flag combinations with scripts that trigger edge cases.
#[test]
fn test_flag_combinations_edge_cases() {
let flag_combinations = generate_all_flag_combinations();
// Edge case scripts
let edge_case_scripts = vec![
vec![], // Empty script
vec![0x51; 10], // Repeated opcodes
vec![0x00], // OP_0
vec![0xff], // Invalid opcode
];
for script in edge_case_scripts {
for flags in &flag_combinations {
let mut stack = Vec::new();
let result = eval_script(&script, &mut stack, *flags, SigVersion::Base);
// Should handle edge cases with any flag combination
assert!(result.is_ok() || result.is_err());
}
}
}
/// Comprehensive flag combination test
///
/// Tests all flag combinations with multiple script types.
#[test]
fn test_comprehensive_flag_combinations() {
let flag_combinations = generate_all_flag_combinations();
// Test scripts
let test_scripts = vec![
(vec![0x51], vec![0x51]), // Simple: OP_1, OP_1
(vec![0x51, 0x76], vec![0x51]), // OP_1 OP_DUP, OP_1
(vec![], vec![0x51]), // Empty scriptSig, OP_1 scriptPubKey
];
for (script_sig, script_pubkey) in test_scripts {
for flags in &flag_combinations {
let result = verify_script(&script_sig, &script_pubkey, None, *flags);
// Should handle all combinations
assert!(
result.is_ok() || result.is_err(),
"Script failed with flags 0x{flags:x}"
);
}
}
}